first commit
This commit is contained in:
492
frontend/node_modules/leaflet/src/layer/vector/Canvas.js
generated
vendored
Normal file
492
frontend/node_modules/leaflet/src/layer/vector/Canvas.js
generated
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
import {Renderer} from './Renderer';
|
||||
import * as DomUtil from '../../dom/DomUtil';
|
||||
import * as DomEvent from '../../dom/DomEvent';
|
||||
import Browser from '../../core/Browser';
|
||||
import * as Util from '../../core/Util';
|
||||
import {Bounds} from '../../geometry/Bounds';
|
||||
|
||||
/*
|
||||
* @class Canvas
|
||||
* @inherits Renderer
|
||||
* @aka L.Canvas
|
||||
*
|
||||
* Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
|
||||
* Inherits `Renderer`.
|
||||
*
|
||||
* Due to [technical limitations](https://caniuse.com/canvas), Canvas is not
|
||||
* available in all web browsers, notably IE8, and overlapping geometries might
|
||||
* not display properly in some edge cases.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* Use Canvas by default for all paths in the map:
|
||||
*
|
||||
* ```js
|
||||
* var map = L.map('map', {
|
||||
* renderer: L.canvas()
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Use a Canvas renderer with extra padding for specific vector geometries:
|
||||
*
|
||||
* ```js
|
||||
* var map = L.map('map');
|
||||
* var myRenderer = L.canvas({ padding: 0.5 });
|
||||
* var line = L.polyline( coordinates, { renderer: myRenderer } );
|
||||
* var circle = L.circle( center, { renderer: myRenderer } );
|
||||
* ```
|
||||
*/
|
||||
|
||||
export var Canvas = Renderer.extend({
|
||||
|
||||
// @section
|
||||
// @aka Canvas options
|
||||
options: {
|
||||
// @option tolerance: Number = 0
|
||||
// How much to extend the click tolerance around a path/object on the map.
|
||||
tolerance: 0
|
||||
},
|
||||
|
||||
getEvents: function () {
|
||||
var events = Renderer.prototype.getEvents.call(this);
|
||||
events.viewprereset = this._onViewPreReset;
|
||||
return events;
|
||||
},
|
||||
|
||||
_onViewPreReset: function () {
|
||||
// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
|
||||
this._postponeUpdatePaths = true;
|
||||
},
|
||||
|
||||
onAdd: function () {
|
||||
Renderer.prototype.onAdd.call(this);
|
||||
|
||||
// Redraw vectors since canvas is cleared upon removal,
|
||||
// in case of removing the renderer itself from the map.
|
||||
this._draw();
|
||||
},
|
||||
|
||||
_initContainer: function () {
|
||||
var container = this._container = document.createElement('canvas');
|
||||
|
||||
DomEvent.on(container, 'mousemove', this._onMouseMove, this);
|
||||
DomEvent.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
|
||||
DomEvent.on(container, 'mouseout', this._handleMouseOut, this);
|
||||
container['_leaflet_disable_events'] = true;
|
||||
|
||||
this._ctx = container.getContext('2d');
|
||||
},
|
||||
|
||||
_destroyContainer: function () {
|
||||
Util.cancelAnimFrame(this._redrawRequest);
|
||||
delete this._ctx;
|
||||
DomUtil.remove(this._container);
|
||||
DomEvent.off(this._container);
|
||||
delete this._container;
|
||||
},
|
||||
|
||||
_updatePaths: function () {
|
||||
if (this._postponeUpdatePaths) { return; }
|
||||
|
||||
var layer;
|
||||
this._redrawBounds = null;
|
||||
for (var id in this._layers) {
|
||||
layer = this._layers[id];
|
||||
layer._update();
|
||||
}
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_update: function () {
|
||||
if (this._map._animatingZoom && this._bounds) { return; }
|
||||
|
||||
Renderer.prototype._update.call(this);
|
||||
|
||||
var b = this._bounds,
|
||||
container = this._container,
|
||||
size = b.getSize(),
|
||||
m = Browser.retina ? 2 : 1;
|
||||
|
||||
DomUtil.setPosition(container, b.min);
|
||||
|
||||
// set canvas size (also clearing it); use double size on retina
|
||||
container.width = m * size.x;
|
||||
container.height = m * size.y;
|
||||
container.style.width = size.x + 'px';
|
||||
container.style.height = size.y + 'px';
|
||||
|
||||
if (Browser.retina) {
|
||||
this._ctx.scale(2, 2);
|
||||
}
|
||||
|
||||
// translate so we use the same path coordinates after canvas element moves
|
||||
this._ctx.translate(-b.min.x, -b.min.y);
|
||||
|
||||
// Tell paths to redraw themselves
|
||||
this.fire('update');
|
||||
},
|
||||
|
||||
_reset: function () {
|
||||
Renderer.prototype._reset.call(this);
|
||||
|
||||
if (this._postponeUpdatePaths) {
|
||||
this._postponeUpdatePaths = false;
|
||||
this._updatePaths();
|
||||
}
|
||||
},
|
||||
|
||||
_initPath: function (layer) {
|
||||
this._updateDashArray(layer);
|
||||
this._layers[Util.stamp(layer)] = layer;
|
||||
|
||||
var order = layer._order = {
|
||||
layer: layer,
|
||||
prev: this._drawLast,
|
||||
next: null
|
||||
};
|
||||
if (this._drawLast) { this._drawLast.next = order; }
|
||||
this._drawLast = order;
|
||||
this._drawFirst = this._drawFirst || this._drawLast;
|
||||
},
|
||||
|
||||
_addPath: function (layer) {
|
||||
this._requestRedraw(layer);
|
||||
},
|
||||
|
||||
_removePath: function (layer) {
|
||||
var order = layer._order;
|
||||
var next = order.next;
|
||||
var prev = order.prev;
|
||||
|
||||
if (next) {
|
||||
next.prev = prev;
|
||||
} else {
|
||||
this._drawLast = prev;
|
||||
}
|
||||
if (prev) {
|
||||
prev.next = next;
|
||||
} else {
|
||||
this._drawFirst = next;
|
||||
}
|
||||
|
||||
delete layer._order;
|
||||
|
||||
delete this._layers[Util.stamp(layer)];
|
||||
|
||||
this._requestRedraw(layer);
|
||||
},
|
||||
|
||||
_updatePath: function (layer) {
|
||||
// Redraw the union of the layer's old pixel
|
||||
// bounds and the new pixel bounds.
|
||||
this._extendRedrawBounds(layer);
|
||||
layer._project();
|
||||
layer._update();
|
||||
// The redraw will extend the redraw bounds
|
||||
// with the new pixel bounds.
|
||||
this._requestRedraw(layer);
|
||||
},
|
||||
|
||||
_updateStyle: function (layer) {
|
||||
this._updateDashArray(layer);
|
||||
this._requestRedraw(layer);
|
||||
},
|
||||
|
||||
_updateDashArray: function (layer) {
|
||||
if (typeof layer.options.dashArray === 'string') {
|
||||
var parts = layer.options.dashArray.split(/[, ]+/),
|
||||
dashArray = [],
|
||||
dashValue,
|
||||
i;
|
||||
for (i = 0; i < parts.length; i++) {
|
||||
dashValue = Number(parts[i]);
|
||||
// Ignore dash array containing invalid lengths
|
||||
if (isNaN(dashValue)) { return; }
|
||||
dashArray.push(dashValue);
|
||||
}
|
||||
layer.options._dashArray = dashArray;
|
||||
} else {
|
||||
layer.options._dashArray = layer.options.dashArray;
|
||||
}
|
||||
},
|
||||
|
||||
_requestRedraw: function (layer) {
|
||||
if (!this._map) { return; }
|
||||
|
||||
this._extendRedrawBounds(layer);
|
||||
this._redrawRequest = this._redrawRequest || Util.requestAnimFrame(this._redraw, this);
|
||||
},
|
||||
|
||||
_extendRedrawBounds: function (layer) {
|
||||
if (layer._pxBounds) {
|
||||
var padding = (layer.options.weight || 0) + 1;
|
||||
this._redrawBounds = this._redrawBounds || new Bounds();
|
||||
this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
|
||||
this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
|
||||
}
|
||||
},
|
||||
|
||||
_redraw: function () {
|
||||
this._redrawRequest = null;
|
||||
|
||||
if (this._redrawBounds) {
|
||||
this._redrawBounds.min._floor();
|
||||
this._redrawBounds.max._ceil();
|
||||
}
|
||||
|
||||
this._clear(); // clear layers in redraw bounds
|
||||
this._draw(); // draw layers
|
||||
|
||||
this._redrawBounds = null;
|
||||
},
|
||||
|
||||
_clear: function () {
|
||||
var bounds = this._redrawBounds;
|
||||
if (bounds) {
|
||||
var size = bounds.getSize();
|
||||
this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
|
||||
} else {
|
||||
this._ctx.save();
|
||||
this._ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
this._ctx.clearRect(0, 0, this._container.width, this._container.height);
|
||||
this._ctx.restore();
|
||||
}
|
||||
},
|
||||
|
||||
_draw: function () {
|
||||
var layer, bounds = this._redrawBounds;
|
||||
this._ctx.save();
|
||||
if (bounds) {
|
||||
var size = bounds.getSize();
|
||||
this._ctx.beginPath();
|
||||
this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
|
||||
this._ctx.clip();
|
||||
}
|
||||
|
||||
this._drawing = true;
|
||||
|
||||
for (var order = this._drawFirst; order; order = order.next) {
|
||||
layer = order.layer;
|
||||
if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
|
||||
layer._updatePath();
|
||||
}
|
||||
}
|
||||
|
||||
this._drawing = false;
|
||||
|
||||
this._ctx.restore(); // Restore state before clipping.
|
||||
},
|
||||
|
||||
_updatePoly: function (layer, closed) {
|
||||
if (!this._drawing) { return; }
|
||||
|
||||
var i, j, len2, p,
|
||||
parts = layer._parts,
|
||||
len = parts.length,
|
||||
ctx = this._ctx;
|
||||
|
||||
if (!len) { return; }
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
for (j = 0, len2 = parts[i].length; j < len2; j++) {
|
||||
p = parts[i][j];
|
||||
ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
|
||||
}
|
||||
if (closed) {
|
||||
ctx.closePath();
|
||||
}
|
||||
}
|
||||
|
||||
this._fillStroke(ctx, layer);
|
||||
|
||||
// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
|
||||
},
|
||||
|
||||
_updateCircle: function (layer) {
|
||||
|
||||
if (!this._drawing || layer._empty()) { return; }
|
||||
|
||||
var p = layer._point,
|
||||
ctx = this._ctx,
|
||||
r = Math.max(Math.round(layer._radius), 1),
|
||||
s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
|
||||
|
||||
if (s !== 1) {
|
||||
ctx.save();
|
||||
ctx.scale(1, s);
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
|
||||
|
||||
if (s !== 1) {
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
this._fillStroke(ctx, layer);
|
||||
},
|
||||
|
||||
_fillStroke: function (ctx, layer) {
|
||||
var options = layer.options;
|
||||
|
||||
if (options.fill) {
|
||||
ctx.globalAlpha = options.fillOpacity;
|
||||
ctx.fillStyle = options.fillColor || options.color;
|
||||
ctx.fill(options.fillRule || 'evenodd');
|
||||
}
|
||||
|
||||
if (options.stroke && options.weight !== 0) {
|
||||
if (ctx.setLineDash) {
|
||||
ctx.setLineDash(layer.options && layer.options._dashArray || []);
|
||||
}
|
||||
ctx.globalAlpha = options.opacity;
|
||||
ctx.lineWidth = options.weight;
|
||||
ctx.strokeStyle = options.color;
|
||||
ctx.lineCap = options.lineCap;
|
||||
ctx.lineJoin = options.lineJoin;
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
// Canvas obviously doesn't have mouse events for individual drawn objects,
|
||||
// so we emulate that by calculating what's under the mouse on mousemove/click manually
|
||||
|
||||
_onClick: function (e) {
|
||||
var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
|
||||
|
||||
for (var order = this._drawFirst; order; order = order.next) {
|
||||
layer = order.layer;
|
||||
if (layer.options.interactive && layer._containsPoint(point)) {
|
||||
if (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {
|
||||
clickedLayer = layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._fireEvent(clickedLayer ? [clickedLayer] : false, e);
|
||||
},
|
||||
|
||||
_onMouseMove: function (e) {
|
||||
if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
|
||||
|
||||
var point = this._map.mouseEventToLayerPoint(e);
|
||||
this._handleMouseHover(e, point);
|
||||
},
|
||||
|
||||
|
||||
_handleMouseOut: function (e) {
|
||||
var layer = this._hoveredLayer;
|
||||
if (layer) {
|
||||
// if we're leaving the layer, fire mouseout
|
||||
DomUtil.removeClass(this._container, 'leaflet-interactive');
|
||||
this._fireEvent([layer], e, 'mouseout');
|
||||
this._hoveredLayer = null;
|
||||
this._mouseHoverThrottled = false;
|
||||
}
|
||||
},
|
||||
|
||||
_handleMouseHover: function (e, point) {
|
||||
if (this._mouseHoverThrottled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var layer, candidateHoveredLayer;
|
||||
|
||||
for (var order = this._drawFirst; order; order = order.next) {
|
||||
layer = order.layer;
|
||||
if (layer.options.interactive && layer._containsPoint(point)) {
|
||||
candidateHoveredLayer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidateHoveredLayer !== this._hoveredLayer) {
|
||||
this._handleMouseOut(e);
|
||||
|
||||
if (candidateHoveredLayer) {
|
||||
DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
|
||||
this._fireEvent([candidateHoveredLayer], e, 'mouseover');
|
||||
this._hoveredLayer = candidateHoveredLayer;
|
||||
}
|
||||
}
|
||||
|
||||
this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);
|
||||
|
||||
this._mouseHoverThrottled = true;
|
||||
setTimeout(Util.bind(function () {
|
||||
this._mouseHoverThrottled = false;
|
||||
}, this), 32);
|
||||
},
|
||||
|
||||
_fireEvent: function (layers, e, type) {
|
||||
this._map._fireDOMEvent(e, type || e.type, layers);
|
||||
},
|
||||
|
||||
_bringToFront: function (layer) {
|
||||
var order = layer._order;
|
||||
|
||||
if (!order) { return; }
|
||||
|
||||
var next = order.next;
|
||||
var prev = order.prev;
|
||||
|
||||
if (next) {
|
||||
next.prev = prev;
|
||||
} else {
|
||||
// Already last
|
||||
return;
|
||||
}
|
||||
if (prev) {
|
||||
prev.next = next;
|
||||
} else if (next) {
|
||||
// Update first entry unless this is the
|
||||
// single entry
|
||||
this._drawFirst = next;
|
||||
}
|
||||
|
||||
order.prev = this._drawLast;
|
||||
this._drawLast.next = order;
|
||||
|
||||
order.next = null;
|
||||
this._drawLast = order;
|
||||
|
||||
this._requestRedraw(layer);
|
||||
},
|
||||
|
||||
_bringToBack: function (layer) {
|
||||
var order = layer._order;
|
||||
|
||||
if (!order) { return; }
|
||||
|
||||
var next = order.next;
|
||||
var prev = order.prev;
|
||||
|
||||
if (prev) {
|
||||
prev.next = next;
|
||||
} else {
|
||||
// Already first
|
||||
return;
|
||||
}
|
||||
if (next) {
|
||||
next.prev = prev;
|
||||
} else if (prev) {
|
||||
// Update last entry unless this is the
|
||||
// single entry
|
||||
this._drawLast = prev;
|
||||
}
|
||||
|
||||
order.prev = null;
|
||||
|
||||
order.next = this._drawFirst;
|
||||
this._drawFirst.prev = order;
|
||||
this._drawFirst = order;
|
||||
|
||||
this._requestRedraw(layer);
|
||||
}
|
||||
});
|
||||
|
||||
// @factory L.canvas(options?: Renderer options)
|
||||
// Creates a Canvas renderer with the given options.
|
||||
export function canvas(options) {
|
||||
return Browser.canvas ? new Canvas(options) : null;
|
||||
}
|
||||
Reference in New Issue
Block a user