289 lines
8.4 KiB
JavaScript
289 lines
8.4 KiB
JavaScript
/* Copyright (c) 2015 Jean-Marc VIGLINO,
|
|
released under the CeCILL-B license (French BSD license)
|
|
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
|
|
|
|
ol_source_GeoImage is a layer source with georeferencement to place it on a map.
|
|
*/
|
|
/** @typedef {Object} GeoImageOptions
|
|
* @property {url} url url of the static image
|
|
* @property {image} image the static image, if not provided, use url to load an image
|
|
* @property {ol.Coordinate} imageCenter coordinate of the center of the image
|
|
* @property {ol.Size|number} imageScale [scalex, scaley] of the image
|
|
* @property {number} imageRotate angle of the image in radian, default 0
|
|
* @property {ol.Extent} imageCrop of the image to be show (in the image) default: [0,0,imageWidth,imageHeight]
|
|
* @property {Array.<ol.Coordinate>} imageMask linestring to mask the image on the map
|
|
* @property {string} [crossOrigin] how the element handles cross-origin requests
|
|
*/
|
|
|
|
import ol_source_ImageCanvas from 'ol/source/ImageCanvas.js'
|
|
import ol_geom_Polygon from 'ol/geom/Polygon.js'
|
|
import {boundingExtent as ol_extent_boundingExtent} from 'ol/extent.js'
|
|
import {fromExtent as ol_geom_Polygon_fromExtent} from 'ol/geom/Polygon.js'
|
|
|
|
/** Layer source with georeferencement to place it on a map
|
|
* @constructor
|
|
* @extends {ol_source_ImageCanvas}
|
|
* @param {GeoImageOptions} options
|
|
*/
|
|
var ol_source_GeoImage = class olsourceGeoImage extends ol_source_ImageCanvas {
|
|
constructor(opt_options) {
|
|
var options = {
|
|
attributions: opt_options.attributions,
|
|
logo: opt_options.logo,
|
|
projection: opt_options.projection
|
|
}
|
|
// Draw image on canvas
|
|
options.canvasFunction = function (extent, resolution, pixelRatio, size) {
|
|
return this.calculateImage(extent, resolution, pixelRatio, size)
|
|
}
|
|
|
|
super(options)
|
|
|
|
// options.projection = opt_options.projection;
|
|
// Load Image
|
|
this._image = (opt_options.image ? opt_options.image : new Image)
|
|
this._image.crossOrigin = opt_options.crossOrigin // 'anonymous';
|
|
|
|
// Show image on load
|
|
this._image.onload = function () {
|
|
this.setCrop(this.crop)
|
|
this.changed()
|
|
}.bind(this)
|
|
if (!opt_options.image) this._image.src = opt_options.url
|
|
|
|
// Coordinate of the image center
|
|
this.center = opt_options.imageCenter
|
|
// Image scale
|
|
this.setScale(opt_options.imageScale)
|
|
// Rotation of the image
|
|
this.rotate = opt_options.imageRotate ? opt_options.imageRotate : 0
|
|
// Crop of the image
|
|
this.crop = opt_options.imageCrop
|
|
// Mask of the image
|
|
this.mask = opt_options.imageMask
|
|
// Crop
|
|
this.setCrop(this.crop)
|
|
|
|
// Calculate extent on change
|
|
this.on('change', function () {
|
|
this.set('extent', this.calculateExtent())
|
|
}.bind(this))
|
|
}
|
|
/** calculate image at extent / resolution
|
|
* @param {ol/extent/Extent} extent
|
|
* @param {number} resolution
|
|
* @param {number} pixelRatio
|
|
* @param {ol/size/Size} size
|
|
* @return {HTMLCanvasElement}
|
|
*/
|
|
calculateImage(extent, resolution, pixelRatio, size) {
|
|
if (!this.center)
|
|
return
|
|
var canvas = document.createElement('canvas')
|
|
canvas.width = size[0]
|
|
canvas.height = size[1]
|
|
var ctx = canvas.getContext('2d')
|
|
|
|
if (!this._imageSize)
|
|
return canvas
|
|
// transform coords to pixel
|
|
function tr(xy) {
|
|
return [
|
|
(xy[0] - extent[0]) / (extent[2] - extent[0]) * size[0],
|
|
(xy[1] - extent[3]) / (extent[1] - extent[3]) * size[1]
|
|
]
|
|
}
|
|
// Clipping mask
|
|
if (this.mask) {
|
|
ctx.beginPath()
|
|
var p = tr(this.mask[0])
|
|
ctx.moveTo(p[0], p[1])
|
|
for (var i = 1; i < this.mask.length; i++) {
|
|
p = tr(this.mask[i])
|
|
ctx.lineTo(p[0], p[1])
|
|
}
|
|
ctx.clip()
|
|
}
|
|
|
|
// Draw
|
|
var pixel = tr(this.center)
|
|
var dx = (this._image.naturalWidth / 2 - this.crop[0]) * this.scale[0] / resolution * pixelRatio
|
|
var dy = (this._image.naturalHeight / 2 - this.crop[1]) * this.scale[1] / resolution * pixelRatio
|
|
var sx = this._imageSize[0] * this.scale[0] / resolution * pixelRatio
|
|
var sy = this._imageSize[1] * this.scale[1] / resolution * pixelRatio
|
|
|
|
ctx.translate(pixel[0], pixel[1])
|
|
if (this.rotate)
|
|
ctx.rotate(this.rotate)
|
|
ctx.drawImage(this._image, this.crop[0], this.crop[1], this._imageSize[0], this._imageSize[1], -dx, -dy, sx, sy)
|
|
return canvas
|
|
}
|
|
/**
|
|
* Get coordinate of the image center.
|
|
* @return {ol.Coordinate} coordinate of the image center.
|
|
* @api stable
|
|
*/
|
|
getCenter() {
|
|
return this.center
|
|
}
|
|
/**
|
|
* Set coordinate of the image center.
|
|
* @param {ol.Coordinate} coordinate of the image center.
|
|
* @api stable
|
|
*/
|
|
setCenter(center) {
|
|
this.center = center
|
|
this.changed()
|
|
}
|
|
/**
|
|
* Get image scale.
|
|
* @return {ol.size} image scale (along x and y axis).
|
|
* @api stable
|
|
*/
|
|
getScale() {
|
|
return this.scale
|
|
}
|
|
/**
|
|
* Set image scale.
|
|
* @param {ol.size|Number} image scale (along x and y axis or both).
|
|
* @api stable
|
|
*/
|
|
setScale(scale) {
|
|
switch (typeof (scale)) {
|
|
case 'number':
|
|
scale = [scale, scale]
|
|
break
|
|
case 'object':
|
|
if (scale.length != 2)
|
|
return
|
|
break
|
|
default: return
|
|
}
|
|
this.scale = scale
|
|
this.changed()
|
|
}
|
|
/**
|
|
* Get image rotation.
|
|
* @return {Number} rotation in radian.
|
|
* @api stable
|
|
*/
|
|
getRotation() {
|
|
return this.rotate
|
|
}
|
|
/**
|
|
* Set image rotation.
|
|
* @param {Number} rotation in radian.
|
|
* @api stable
|
|
*/
|
|
setRotation(angle) {
|
|
this.rotate = angle
|
|
this.changed()
|
|
}
|
|
/**
|
|
* Get the image.
|
|
* @api stable
|
|
*/
|
|
getGeoImage() {
|
|
return this._image
|
|
}
|
|
/**
|
|
* Get image crop extent.
|
|
* @return {ol.extent} image crop extent.
|
|
* @api stable
|
|
*/
|
|
getCrop() {
|
|
return this.crop
|
|
}
|
|
/**
|
|
* Set image mask.
|
|
* @param {ol.geom.LineString} coords of the mask
|
|
* @api stable
|
|
*/
|
|
setMask(mask) {
|
|
this.mask = mask
|
|
this.changed()
|
|
}
|
|
/**
|
|
* Get image mask.
|
|
* @return {ol.geom.LineString} coords of the mask
|
|
* @api stable
|
|
*/
|
|
getMask() {
|
|
return this.mask
|
|
}
|
|
/**
|
|
* Set image crop extent.
|
|
* @param {ol.extent|Number} image crop extent or a number to crop from original size.
|
|
* @api stable
|
|
*/
|
|
setCrop(crop) {
|
|
// Image not loaded => get it latter
|
|
if (!this._image.naturalWidth) {
|
|
this.crop = crop
|
|
return
|
|
}
|
|
if (crop) {
|
|
switch (typeof (crop)) {
|
|
case 'number':
|
|
crop = [crop, crop, this._image.naturalWidth - crop, this._image.naturalHeight - crop]
|
|
break
|
|
case 'object':
|
|
if (crop.length != 4)
|
|
return
|
|
break
|
|
default: return
|
|
}
|
|
crop = ol_extent_boundingExtent([[crop[0], crop[1]], [crop[2], crop[3]]])
|
|
this.crop = [Math.max(0, crop[0]), Math.max(0, crop[1]), Math.min(this._image.naturalWidth, crop[2]), Math.min(this._image.naturalHeight, crop[3])]
|
|
}
|
|
else
|
|
this.crop = [0, 0, this._image.naturalWidth, this._image.naturalHeight]
|
|
if (this.crop[2] <= this.crop[0])
|
|
this.crop[2] = this.crop[0] + 1
|
|
if (this.crop[3] <= this.crop[1])
|
|
this.crop[3] = this.crop[1] + 1
|
|
this._imageSize = [this.crop[2] - this.crop[0], this.crop[3] - this.crop[1]]
|
|
this.changed()
|
|
}
|
|
/** Get the extent of the source.
|
|
* @param {module:ol/extent~Extent} extent If provided, no new extent will be created. Instead, that extent's coordinates will be overwritten.
|
|
* @return {ol.extent}
|
|
*/
|
|
getExtent(opt_extent) {
|
|
var ext = this.get('extent')
|
|
if (!ext)
|
|
ext = this.calculateExtent()
|
|
if (opt_extent) {
|
|
for (var i = 0; i < opt_extent.length; i++) {
|
|
opt_extent[i] = ext[i]
|
|
}
|
|
}
|
|
return ext
|
|
}
|
|
/** Calculate the extent of the source image.
|
|
* @param {boolean} usemask return the mask extent, default return the image extent
|
|
* @return {ol.extent}
|
|
*/
|
|
calculateExtent(usemask) {
|
|
var polygon
|
|
if (usemask !== false && this.getMask()) {
|
|
polygon = new ol_geom_Polygon([this.getMask()])
|
|
} else {
|
|
var center = this.getCenter()
|
|
var scale = this.getScale()
|
|
var width = this.getGeoImage().width * scale[0]
|
|
var height = this.getGeoImage().height * scale[1]
|
|
var extent = ol_extent_boundingExtent([
|
|
[center[0] - width / 2, center[1] - height / 2],
|
|
[center[0] + width / 2, center[1] + height / 2]
|
|
])
|
|
polygon = ol_geom_Polygon_fromExtent(extent)
|
|
polygon.rotate(-this.getRotation(), center)
|
|
}
|
|
var ext = polygon.getExtent()
|
|
return ext
|
|
}
|
|
}
|
|
|
|
export default ol_source_GeoImage
|