271 lines
7.0 KiB
JavaScript
271 lines
7.0 KiB
JavaScript
import {Layer} from './Layer';
|
|
import * as Util from '../core/Util';
|
|
import {toLatLngBounds} from '../geo/LatLngBounds';
|
|
import {Bounds} from '../geometry/Bounds';
|
|
import * as DomUtil from '../dom/DomUtil';
|
|
|
|
/*
|
|
* @class ImageOverlay
|
|
* @aka L.ImageOverlay
|
|
* @inherits Interactive layer
|
|
*
|
|
* Used to load and display a single image over specific bounds of the map. Extends `Layer`.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
|
|
* imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
|
|
* L.imageOverlay(imageUrl, imageBounds).addTo(map);
|
|
* ```
|
|
*/
|
|
|
|
export var ImageOverlay = Layer.extend({
|
|
|
|
// @section
|
|
// @aka ImageOverlay options
|
|
options: {
|
|
// @option opacity: Number = 1.0
|
|
// The opacity of the image overlay.
|
|
opacity: 1,
|
|
|
|
// @option alt: String = ''
|
|
// Text for the `alt` attribute of the image (useful for accessibility).
|
|
alt: '',
|
|
|
|
// @option interactive: Boolean = false
|
|
// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
|
|
interactive: false,
|
|
|
|
// @option crossOrigin: Boolean|String = false
|
|
// Whether the crossOrigin attribute will be added to the image.
|
|
// If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.
|
|
// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
|
|
crossOrigin: false,
|
|
|
|
// @option errorOverlayUrl: String = ''
|
|
// URL to the overlay image to show in place of the overlay that failed to load.
|
|
errorOverlayUrl: '',
|
|
|
|
// @option zIndex: Number = 1
|
|
// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
|
|
zIndex: 1,
|
|
|
|
// @option className: String = ''
|
|
// A custom class name to assign to the image. Empty by default.
|
|
className: ''
|
|
},
|
|
|
|
initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
|
|
this._url = url;
|
|
this._bounds = toLatLngBounds(bounds);
|
|
|
|
Util.setOptions(this, options);
|
|
},
|
|
|
|
onAdd: function () {
|
|
if (!this._image) {
|
|
this._initImage();
|
|
|
|
if (this.options.opacity < 1) {
|
|
this._updateOpacity();
|
|
}
|
|
}
|
|
|
|
if (this.options.interactive) {
|
|
DomUtil.addClass(this._image, 'leaflet-interactive');
|
|
this.addInteractiveTarget(this._image);
|
|
}
|
|
|
|
this.getPane().appendChild(this._image);
|
|
this._reset();
|
|
},
|
|
|
|
onRemove: function () {
|
|
DomUtil.remove(this._image);
|
|
if (this.options.interactive) {
|
|
this.removeInteractiveTarget(this._image);
|
|
}
|
|
},
|
|
|
|
// @method setOpacity(opacity: Number): this
|
|
// Sets the opacity of the overlay.
|
|
setOpacity: function (opacity) {
|
|
this.options.opacity = opacity;
|
|
|
|
if (this._image) {
|
|
this._updateOpacity();
|
|
}
|
|
return this;
|
|
},
|
|
|
|
setStyle: function (styleOpts) {
|
|
if (styleOpts.opacity) {
|
|
this.setOpacity(styleOpts.opacity);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// @method bringToFront(): this
|
|
// Brings the layer to the top of all overlays.
|
|
bringToFront: function () {
|
|
if (this._map) {
|
|
DomUtil.toFront(this._image);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// @method bringToBack(): this
|
|
// Brings the layer to the bottom of all overlays.
|
|
bringToBack: function () {
|
|
if (this._map) {
|
|
DomUtil.toBack(this._image);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// @method setUrl(url: String): this
|
|
// Changes the URL of the image.
|
|
setUrl: function (url) {
|
|
this._url = url;
|
|
|
|
if (this._image) {
|
|
this._image.src = url;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// @method setBounds(bounds: LatLngBounds): this
|
|
// Update the bounds that this ImageOverlay covers
|
|
setBounds: function (bounds) {
|
|
this._bounds = toLatLngBounds(bounds);
|
|
|
|
if (this._map) {
|
|
this._reset();
|
|
}
|
|
return this;
|
|
},
|
|
|
|
getEvents: function () {
|
|
var events = {
|
|
zoom: this._reset,
|
|
viewreset: this._reset
|
|
};
|
|
|
|
if (this._zoomAnimated) {
|
|
events.zoomanim = this._animateZoom;
|
|
}
|
|
|
|
return events;
|
|
},
|
|
|
|
// @method setZIndex(value: Number): this
|
|
// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
|
|
setZIndex: function (value) {
|
|
this.options.zIndex = value;
|
|
this._updateZIndex();
|
|
return this;
|
|
},
|
|
|
|
// @method getBounds(): LatLngBounds
|
|
// Get the bounds that this ImageOverlay covers
|
|
getBounds: function () {
|
|
return this._bounds;
|
|
},
|
|
|
|
// @method getElement(): HTMLElement
|
|
// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
|
|
// used by this overlay.
|
|
getElement: function () {
|
|
return this._image;
|
|
},
|
|
|
|
_initImage: function () {
|
|
var wasElementSupplied = this._url.tagName === 'IMG';
|
|
var img = this._image = wasElementSupplied ? this._url : DomUtil.create('img');
|
|
|
|
DomUtil.addClass(img, 'leaflet-image-layer');
|
|
if (this._zoomAnimated) { DomUtil.addClass(img, 'leaflet-zoom-animated'); }
|
|
if (this.options.className) { DomUtil.addClass(img, this.options.className); }
|
|
|
|
img.onselectstart = Util.falseFn;
|
|
img.onmousemove = Util.falseFn;
|
|
|
|
// @event load: Event
|
|
// Fired when the ImageOverlay layer has loaded its image
|
|
img.onload = Util.bind(this.fire, this, 'load');
|
|
img.onerror = Util.bind(this._overlayOnError, this, 'error');
|
|
|
|
if (this.options.crossOrigin || this.options.crossOrigin === '') {
|
|
img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
|
|
}
|
|
|
|
if (this.options.zIndex) {
|
|
this._updateZIndex();
|
|
}
|
|
|
|
if (wasElementSupplied) {
|
|
this._url = img.src;
|
|
return;
|
|
}
|
|
|
|
img.src = this._url;
|
|
img.alt = this.options.alt;
|
|
},
|
|
|
|
_animateZoom: function (e) {
|
|
var scale = this._map.getZoomScale(e.zoom),
|
|
offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
|
|
|
|
DomUtil.setTransform(this._image, offset, scale);
|
|
},
|
|
|
|
_reset: function () {
|
|
var image = this._image,
|
|
bounds = new Bounds(
|
|
this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
|
|
this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
|
|
size = bounds.getSize();
|
|
|
|
DomUtil.setPosition(image, bounds.min);
|
|
|
|
image.style.width = size.x + 'px';
|
|
image.style.height = size.y + 'px';
|
|
},
|
|
|
|
_updateOpacity: function () {
|
|
DomUtil.setOpacity(this._image, this.options.opacity);
|
|
},
|
|
|
|
_updateZIndex: function () {
|
|
if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {
|
|
this._image.style.zIndex = this.options.zIndex;
|
|
}
|
|
},
|
|
|
|
_overlayOnError: function () {
|
|
// @event error: Event
|
|
// Fired when the ImageOverlay layer fails to load its image
|
|
this.fire('error');
|
|
|
|
var errorUrl = this.options.errorOverlayUrl;
|
|
if (errorUrl && this._url !== errorUrl) {
|
|
this._url = errorUrl;
|
|
this._image.src = errorUrl;
|
|
}
|
|
},
|
|
|
|
// @method getCenter(): LatLng
|
|
// Returns the center of the ImageOverlay.
|
|
getCenter: function () {
|
|
return this._bounds.getCenter();
|
|
}
|
|
});
|
|
|
|
// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
|
|
// Instantiates an image overlay object given the URL of the image and the
|
|
// geographical bounds it is tied to.
|
|
export var imageOverlay = function (url, bounds, options) {
|
|
return new ImageOverlay(url, bounds, options);
|
|
};
|