You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
13 KiB
355 lines
13 KiB
2 years ago
|
(function (factory, window) {
|
||
|
// define an AMD module that relies on 'leaflet'
|
||
|
if (typeof define === "function" && define.amd) {
|
||
|
define(["leaflet"], factory);
|
||
|
|
||
|
// define a Common JS module that relies on 'leaflet'
|
||
|
} else if (typeof exports === "object") {
|
||
|
module.exports = factory(require("leaflet"));
|
||
|
}
|
||
|
|
||
|
// attach your plugin to the global 'L' variable
|
||
|
if (typeof window !== "undefined" && window.L) {
|
||
|
factory(L);
|
||
|
}
|
||
|
})(function (L) {
|
||
|
class LegendSymbol {
|
||
|
constructor(control, container, legend) {
|
||
|
this._control = control;
|
||
|
this._container = container;
|
||
|
this._legend = legend;
|
||
|
this._width = this._control.options.symbolWidth;
|
||
|
this._height = this._control.options.symbolHeight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class GeometricSymbol extends LegendSymbol {
|
||
|
constructor(control, container, legend) {
|
||
|
super(control, container, legend);
|
||
|
|
||
|
this._canvas = this._buildCanvas();
|
||
|
if (this._drawSymbol) {
|
||
|
this._drawSymbol();
|
||
|
}
|
||
|
this._style();
|
||
|
}
|
||
|
|
||
|
_buildCanvas() {
|
||
|
var canvas = L.DomUtil.create("canvas", null, this._container);
|
||
|
canvas.height = this._control.options.symbolHeight;
|
||
|
canvas.width = this._control.options.symbolWidth;
|
||
|
return canvas;
|
||
|
}
|
||
|
|
||
|
_drawSymbol() {}
|
||
|
|
||
|
_style() {
|
||
|
var ctx = (this._ctx = this._canvas.getContext("2d"));
|
||
|
if (this._legend.fill || this._legend.fillColor) {
|
||
|
ctx.globalAlpha = this._legend.fillOpacity || 1;
|
||
|
ctx.fillStyle = this._legend.fillColor || this._legend.color;
|
||
|
ctx.fill(this._legend.fillRule || "evenodd");
|
||
|
}
|
||
|
|
||
|
if (this._legend.stroke || this._legend.color) {
|
||
|
if (this._legend.dashArray) {
|
||
|
ctx.setLineDash(this._legend.dashArray || []);
|
||
|
}
|
||
|
ctx.globalAlpha = this._legend.opacity || 1.0;
|
||
|
ctx.lineWidth = this._legend.weight || 2;
|
||
|
ctx.strokeStyle = this._legend.color || "#3388ff";
|
||
|
ctx.lineCap = this._legend.lineCap || "round";
|
||
|
ctx.lineJoin = this._legend.lineJoin || "round";
|
||
|
ctx.stroke();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rescale() {}
|
||
|
|
||
|
center() {}
|
||
|
}
|
||
|
|
||
|
class CircleSymbol extends GeometricSymbol {
|
||
|
_drawSymbol() {
|
||
|
var ctx = (this._ctx = this._canvas.getContext("2d"));
|
||
|
|
||
|
var legend = this._legend;
|
||
|
var linelWeight = legend.weight || 3;
|
||
|
|
||
|
var centerX = this._control.options.symbolWidth / 2;
|
||
|
var centerY = this._control.options.symbolHeight / 2;
|
||
|
var maxRadius = Math.min(centerX, centerY) - linelWeight;
|
||
|
var radius = maxRadius;
|
||
|
if (legend.radius) {
|
||
|
radius = Math.min(legend.radius, maxRadius);
|
||
|
}
|
||
|
|
||
|
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class PolylineSymbol extends GeometricSymbol {
|
||
|
_drawSymbol() {
|
||
|
var ctx = (this._ctx = this._canvas.getContext("2d"));
|
||
|
|
||
|
var x1 = 0;
|
||
|
var x2 = this._control.options.symbolWidth;
|
||
|
var y = this._control.options.symbolHeight / 2;
|
||
|
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(x1, y);
|
||
|
ctx.lineTo(x2, y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class RectangleSymbol extends GeometricSymbol {
|
||
|
_drawSymbol() {
|
||
|
var ctx = (this._ctx = this._canvas.getContext("2d"));
|
||
|
var linelWeight = this._legend.weight || 3;
|
||
|
|
||
|
var x0 = this._control.options.symbolWidth / 2;
|
||
|
var y0 = this._control.options.symbolHeight / 2;
|
||
|
|
||
|
var rx = x0 - linelWeight;
|
||
|
var ry = y0 - linelWeight;
|
||
|
if (rx == ry) {
|
||
|
ry = ry / 2;
|
||
|
}
|
||
|
ctx.rect(x0 - rx, y0 - ry, rx * 2, ry * 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 圆心坐标:(x0,y0) 半径:r 角度(X轴顺时针旋转):a
|
||
|
* 弧度 = 角度 * Math.PI / 180
|
||
|
* 则圆上任一点为:(x1,y1)
|
||
|
* x1 = x0 + r * Math.cos( a * Math.PI / 180)
|
||
|
* y1 = y0 + r * Math.sin( a * Math.PI / 180)
|
||
|
*/
|
||
|
class PolygonSymbol extends GeometricSymbol {
|
||
|
_drawSymbol() {
|
||
|
var ctx = (this._ctx = this._canvas.getContext("2d"));
|
||
|
|
||
|
var linelWeight = this._legend.weight || 3;
|
||
|
var x0 = this._control.options.symbolWidth / 2;
|
||
|
var y0 = this._control.options.symbolHeight / 2;
|
||
|
var r = Math.min(x0, y0) - linelWeight;
|
||
|
var a = 360 / this._legend.sides;
|
||
|
ctx.beginPath();
|
||
|
for (var i = 0; i <= this._legend.sides; i++) {
|
||
|
var x1 = x0 + r * Math.cos(((a * i + (90 - a / 2)) * Math.PI) / 180);
|
||
|
var y1 = y0 + r * Math.sin(((a * i + (90 - a / 2)) * Math.PI) / 180);
|
||
|
if (i == 0) {
|
||
|
ctx.moveTo(x1, y1);
|
||
|
} else {
|
||
|
ctx.lineTo(x1, y1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ImageSymbol extends LegendSymbol {
|
||
|
constructor(control, container, legend) {
|
||
|
super(control, container, legend);
|
||
|
this._img = null;
|
||
|
this._loadImages();
|
||
|
}
|
||
|
|
||
|
_loadImages() {
|
||
|
var imageLoaded = () => {
|
||
|
this.rescale();
|
||
|
};
|
||
|
var img = L.DomUtil.create("img", null, this._container);
|
||
|
this._img = img;
|
||
|
img.onload = imageLoaded;
|
||
|
img.src = this._legend.url;
|
||
|
}
|
||
|
|
||
|
rescale() {
|
||
|
if (this._img) {
|
||
|
var _options = this._control.options;
|
||
|
if (this._img.width > _options.symbolWidth || this._img.height > _options.symbolHeight) {
|
||
|
var imgW = this._img.width;
|
||
|
var imgH = this._img.height;
|
||
|
var scaleW = _options.symbolWidth / imgW;
|
||
|
var scaleH = _options.symbolHeight / imgH;
|
||
|
var scale = Math.min(scaleW, scaleH);
|
||
|
this._img.width = imgW * scale;
|
||
|
this._img.height = imgH * scale;
|
||
|
}
|
||
|
this.center();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
center() {
|
||
|
var containerCenterX = this._container.offsetWidth / 2;
|
||
|
var containerCenterY = this._container.offsetHeight / 2;
|
||
|
var imageCenterX = parseInt(this._img.width) / 2;
|
||
|
var imageCenterY = parseInt(this._img.height) / 2;
|
||
|
|
||
|
var shiftX = containerCenterX - imageCenterX;
|
||
|
var shiftY = containerCenterY - imageCenterY;
|
||
|
|
||
|
this._img.style.left = shiftX.toString() + "px";
|
||
|
this._img.style.top = shiftY.toString() + "px";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
L.Control.Legend = L.Control.extend({
|
||
|
options: {
|
||
|
position: "topleft",
|
||
|
title: "Legend",
|
||
|
legends: [],
|
||
|
symbolWidth: 24,
|
||
|
symbolHeight: 24,
|
||
|
opacity: 1.0,
|
||
|
column: 1,
|
||
|
collapsed: false,
|
||
|
},
|
||
|
|
||
|
initialize: function (options) {
|
||
|
L.Util.setOptions(this, options);
|
||
|
this._legendSymbols = [];
|
||
|
this._buildContainer();
|
||
|
},
|
||
|
|
||
|
onAdd: function (map) {
|
||
|
this._map = map;
|
||
|
this._initLayout();
|
||
|
return this._container;
|
||
|
},
|
||
|
|
||
|
_buildContainer: function () {
|
||
|
this._container = L.DomUtil.create("div", "leaflet-legend leaflet-bar leaflet-control");
|
||
|
this._container.style.backgroundColor = "rgba(255,255,255, " + this.options.opacity + ")";
|
||
|
|
||
|
this._contents = L.DomUtil.create("section", "leaflet-legend-contents", this._container);
|
||
|
this._link = L.DomUtil.create("a", "leaflet-legend-toggle", this._container);
|
||
|
this._link.title = "Legend";
|
||
|
this._link.href = "#";
|
||
|
|
||
|
var title = L.DomUtil.create("h3", "leaflet-legend-title", this._contents);
|
||
|
title.innerText = this.options.title || "Legend";
|
||
|
|
||
|
var len = this.options.legends.length;
|
||
|
var colSize = Math.ceil(len / this.options.column);
|
||
|
var legendContainer = this._contents;
|
||
|
for (var i = 0; i < len; i++) {
|
||
|
if (i % colSize == 0) {
|
||
|
legendContainer = L.DomUtil.create("div", "leaflet-legend-column", this._contents);
|
||
|
}
|
||
|
var legend = this.options.legends[i];
|
||
|
this._buildLegendItems(legendContainer, legend);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_buildLegendItems: function (legendContainer, legend) {
|
||
|
var legendItemDiv = L.DomUtil.create("div", "leaflet-legend-item", legendContainer);
|
||
|
if (legend.inactive) {
|
||
|
L.DomUtil.addClass(legendItemDiv, "leaflet-legend-item-inactive");
|
||
|
}
|
||
|
var symbolContainer = L.DomUtil.create("i", null, legendItemDiv);
|
||
|
|
||
|
var legendSymbol;
|
||
|
if (legend.type === "image") {
|
||
|
legendSymbol = new ImageSymbol(this, symbolContainer, legend);
|
||
|
} else if (legend.type === "circle") {
|
||
|
legendSymbol = new CircleSymbol(this, symbolContainer, legend);
|
||
|
} else if (legend.type === "rectangle") {
|
||
|
legendSymbol = new RectangleSymbol(this, symbolContainer, legend);
|
||
|
} else if (legend.type === "polygon") {
|
||
|
legendSymbol = new PolygonSymbol(this, symbolContainer, legend);
|
||
|
} else if (legend.type === "polyline") {
|
||
|
legendSymbol = new PolylineSymbol(this, symbolContainer, legend);
|
||
|
} else {
|
||
|
L.DomUtil.remove(legendItemDiv);
|
||
|
return;
|
||
|
}
|
||
|
this._legendSymbols.push(legendSymbol);
|
||
|
|
||
|
symbolContainer.style.width = this.options.symbolWidth + "px";
|
||
|
symbolContainer.style.height = this.options.symbolHeight + "px";
|
||
|
|
||
|
var legendLabel = L.DomUtil.create("span", null, legendItemDiv);
|
||
|
legendLabel.innerText = legend.label;
|
||
|
if (legend.layers) {
|
||
|
L.DomUtil.addClass(legendItemDiv, "leaflet-legend-item-clickable");
|
||
|
L.DomEvent.on(
|
||
|
legendItemDiv,
|
||
|
"click",
|
||
|
function () {
|
||
|
this._toggleLegend.call(this, legendItemDiv, legend.layers);
|
||
|
},
|
||
|
this
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_initLayout: function () {
|
||
|
L.DomEvent.disableClickPropagation(this._container);
|
||
|
L.DomEvent.disableScrollPropagation(this._container);
|
||
|
|
||
|
if (this.options.collapsed) {
|
||
|
this._map.on("click", this.collapse, this);
|
||
|
|
||
|
L.DomEvent.on(
|
||
|
this._container,
|
||
|
{
|
||
|
mouseenter: this.expand,
|
||
|
mouseleave: this.collapse,
|
||
|
},
|
||
|
this
|
||
|
);
|
||
|
} else {
|
||
|
this.expand();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_toggleLegend: function (legendDiv, layers) {
|
||
|
if (L.DomUtil.hasClass(legendDiv, "leaflet-legend-item-inactive")) {
|
||
|
L.DomUtil.removeClass(legendDiv, "leaflet-legend-item-inactive");
|
||
|
if (L.Util.isArray(layers)) {
|
||
|
for (var i = 0, len = layers.length; i < len; i++) {
|
||
|
this._map.addLayer(layers[i]);
|
||
|
}
|
||
|
} else {
|
||
|
this._map.addLayer(layers);
|
||
|
}
|
||
|
} else {
|
||
|
L.DomUtil.addClass(legendDiv, "leaflet-legend-item-inactive");
|
||
|
if (L.Util.isArray(layers)) {
|
||
|
for (var i = 0, len = layers.length; i < len; i++) {
|
||
|
this._map.removeLayer(layers[i]);
|
||
|
}
|
||
|
} else {
|
||
|
this._map.removeLayer(layers);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
expand: function () {
|
||
|
this._link.style.display = "none";
|
||
|
L.DomUtil.addClass(this._container, "leaflet-legend-expanded");
|
||
|
for (var legendSymbol of this._legendSymbols) {
|
||
|
legendSymbol.rescale();
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
collapse: function () {
|
||
|
this._link.style.display = "block";
|
||
|
L.DomUtil.removeClass(this._container, "leaflet-legend-expanded");
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
redraw: function () {
|
||
|
L.DomUtil.empty(this._contents);
|
||
|
this._buildLegendItems();
|
||
|
},
|
||
|
});
|
||
|
|
||
|
L.control.legend = L.control.Legend = function (options) {
|
||
|
return new L.Control.Legend(options);
|
||
|
};
|
||
|
}, window);
|