使用 Leaflet,我试图将很多点 (+ 10000) 渲染为 GeoJSON 功能以提高性能。为了获得更好的结果,我发现 this answer 指示如何扩展 Leaflet 的 circleMarker
以改变它的形状,如下所示:
L.Canvas.include({
_updateMarkerPin: function(layer) {
if (!this._drawing || layer._empty()) {
return
}
var p = layer._point,
ctx = this._ctx,
r = layer._radius
this._drawnLayers[layer._leaflet_id] = layer
ctx.beginPath()
ctx.moveTo(p.x, p.y)
ctx.lineTo(p.x - 0.58 * r, p.y - r)
ctx.arc(p.x, p.y - 2 * r, r, -Math.PI * 1.161, Math.PI * 0.161)
ctx.closePath()
this._fillStroke(ctx, layer)
},
})
const MarkerPin = L.CircleMarker.extend({
_updatePath: function() {
this._renderer._updateMarkerPin(this)
},
})
这是我的 MarkerPin 形状:
然后在
MarkerPin
的 L.GeoJSON
选项中使用 pointToLayer
,如下所示:const myPointToLayer = (feature, latlng) => {
var markerParams = {
radius: 16,
stroke: true,
weight: 2,
opacity: 0.4,
fillOpacity: 0.9,
}
return new MarkerPin(latlng, markerParams)
}
const myOnEachFeature = (feature, layer) => {
layer.bindPopup('Clicked me!')
}
L.geoJSON(data, {
pointToLayer:myPointToLayer,
onEachFeature: myOnEachFeature,
}).addTo(map);
到现在为止还挺好。所有数据都得到正确呈现。
我的问题是:点击区域没有根据我的新形状更新,它保持像
circleMarker
的那个(因为这是我扩展来创建我的图钉),由红色圆圈表示:其他 Leaflet 元素(如多边形)的点击区域与其形状相匹配。话虽如此,是否可以更改我的
MarkerPin
的点击区域以匹配我的形状(即使我正在扩展 circleMarker
)?即使无法更改点击区域的形状,我也很高兴能够将其向上移动,如下图所示:
甚至,是否有更好的方法来使用自定义图标在 GeoJSON 中渲染多个标记并使用 Leaflet 处理它们的弹出窗口?
编辑
为了完整起见,这就是我正在使用的(感谢 https://stackoverflow.com/a/56072877/11064013 ),它使用了整个引脚区域:
const MarkerPin = L.CircleMarker.extend({
_updatePath: function() {
this._renderer._updateMarkerPin(this)
},
_containsPoint: function(p) {
let r = this._radius
let insideCircle =
p.add([0, r * 2]).distanceTo(this._point) <= r + this._clickTolerance()
let a = this._point,
b = a.subtract([0.58 * r, r]),
c = a.subtract([-0.58 * r, r])
let insideTriangle = true
let ap_x = p.x - a.x
let ap_y = p.y - a.y
let p_ab = (b.x - a.x) * ap_y - (b.y - a.y) * ap_x > 0
let p_ac = (c.x - a.x) * ap_y - (c.y - a.y) * ap_x > 0
let p_bc = (c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x) > 0
if (p_ac === p_ab) {
insideTriangle = false
}
if (p_bc !== p_ab) {
insideTriangle = false
}
return insideTriangle || insideCircle
},
})
最佳答案
通过 L.Canvas
渲染的矢量图层中的点击检测取决于每个矢量图层的 _containsPoint
私有(private)方法。请参阅 implementation on CircleMarker
或 on Polyline
。
每次 user clicks on a L.Canvas
renderer, the renderer loops through all the layers in it ,并询问他们“用户在像素 p
中做了一些事情 - 这是你的吗”?对 _containsPoint
的调用必须回答这个问题。
所以你必须为你的 _containsPoint
类实现 MarkerPin
,也许像例如
const MarkerPin = L.CircleMarker.extend({
_updatePath: function() {
this._renderer._updateMarkerPin(this)
},
_containsPoint: function(p) {
return L.CircleMarker.prototype._containsPoint.call(this, p.subtract([0, 10]));
}
})
这应该向上或向下移动点击区域。如果你想要一个更好的形状,你必须提供一个函数的正确实现,该函数返回一个点是否在形状内部。
关于javascript - 从 CircleMarker 扩展的标记 - 如何更改点击区域?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56067809/