leaflet渲染大量点 + 旋转点
Icon2CircleMarker 类
十万点加载需要比较久
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import Icon2CircleMarker from "./service/Icon2CircleMarker.js";
icon2Canvas() {
if (this.markerLayer) {
this.map.removeLayer(this.markerLayer);
}
const icm = new Icon2CircleMarker();
const max = 1000;
this.markerLayer = L.layerGroup();
const zoom = this.map.getZoom();
for (let i = 0; i < max; i++) {
const icon = L.icon({
iconUrl: miniship,
iconSize: [38, 75],
iconAnchor: [22, 94],
popupAnchor: [-3, -76],
});
const iconPoint = L.icon({
iconUrl: point,
iconSize: [20, 20],
iconAnchor: [10, 10],
});
icon.options["angle"] = Math.random() * 100; //角度
icon.options["string"] = "xxxsxxx";
icon.options["fontcolor"] = "white";
const marker = icm.getMarker(
[
this.center[0] + Math.random() * 0.01,
this.center[1] + Math.random() * 0.01,
],
{
popupAnchor: icon.options.popupAnchor,
radius: 10,
icon: zoom > 15 ? icon : iconPoint,
}
);
this.markerLayer.addLayer(marker);
}
// 一次性将所有标记添加到 LayerGroup
this.markerLayer.addTo(this.map); // 添加到地图
},
Icon2CircleMarker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
"use strict";
/*
L.Iconを渡すとアイコン付きのL.CircleMarkerが返ってくる。
*/
export default class Icon2CircleMarker {
constructor() {
//既存クラスのメソッド上書き
this.icon2Canvas = L.CircleMarker.extend({
_containsPoint: function (makerPoint) {
//L.IconのoffsetをCircleMarkerへ適用
const offset = this.options.icon.options.pointOffset;
if (offset) {
return L.CircleMarker.prototype._containsPoint.call(
this,
makerPoint.subtract([offset.x, offset.y])
);
}
},
_updatePath() {
const op = this.options.icon.options;
if (op.element) {
const ctx = this._renderer._ctx,
p = this._point.round();
p.x += op.offset[0];
p.y += op.offset[1];
//Canvasへ描画開始
ctx.save();
ctx.translate(p.x, p.y);
//アイコンの回転を適用
if (op.angle) {
ctx.rotate(op.angle * 0.0174); //Math.PI / 180;
}
const x = op.iconSize[0],
y = op.iconSize[1];
//drawImageでは描画位置は整数にすること (https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas)
ctx.drawImage(
op.element,
-Math.floor(x / 2),
-Math.floor(y / 2),
Math.floor(x),
Math.floor(y)
);
//文字は前面に出すため、drawImageの後に追加
if (op.string) {
const count = op.string.length;
//文字を中央にするため苦戦(アイコン、フォントによって変わるため適宜変更のこと)
const fontsize = x / count < x / 2 ? x / count + 4 : x / 2;
ctx.font = fontsize + "px sans serif";
const offset = Math.floor((count * fontsize * 1.3) / 4);
ctx.fillStyle = op.fontcolor;
ctx.fillText(op.string, -offset, 0);
}
ctx.restore();
} else {
const element = document.createElement("img");
//element.onload = () => this.redraw();//redrawしないと画像が切れることがあるが、パフォーマンス優先
element.src = op.iconUrl; //キャッシュが効かないと重いため、なるべく同一画像を
op.element = element;
}
},
});
}
getMarker(latlng, options) {
const op = options.icon.options;
op.offset = [
op.iconSize[0] / 2 - op.iconAnchor[0],
op.iconSize[1] / 2 - op.iconAnchor[1],
];
op.popupAnchor = [0, 0];
return new this.icon2Canvas(latlng, options);
}
}
This post is licensed under CC BY 4.0 by the author.