通过 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
的调用必须回答这个问题。
因此,您必须尝试为您的 MarkerPin
类实现 _containsPoint
,也许像这样:
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/