javascript - 从 CircleMarker 扩展的标记 - 如何更改点击区域?

标签 javascript leaflet

通过 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

MarkerPin 然后在 L.GeoJSONpointToLayer 选项中使用,如下所示:

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 的区域一样(因为这是我用来创建图钉的扩展区域),如红色圆圈所示:

MarkerPin click area

其他 Leaflet 元素(例如多边形)的点击区域与其形状相匹配。话虽这么说,是否可以更改我的 MarkerPin 的点击区域以匹配我的形状(即使我正在扩展 circleMarker)?

即使无法更改点击区域的形状,我也会很满意能够将其向上移动一点,如下图所示:

MarkerPin recentered click area

或者甚至,是否有更好的方法来使用自定义图标渲染 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 CircleMarkeron 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/

相关文章:

javascript - 在 JavaScript 中使用位移或数学创建通用数据溢出函数

javascript - 从 Leaflet 中的图例中删除 ""

javascript - 如何在传单 map 上绘制标记

javascript - 使用带有 $GetJson 函数的传单搜索插件

javascript - 使用 ES6 解构简化 javascript 对象的创建

javascript - 从嵌套函数返回 getJSON 结果

javascript - 将行为附加到由knockoutjs创建的元素

javascript - Leaflet JS - 居中和缩放功能组

javascript - 将鼠标悬停在标记上时不要更改鼠标图标

javascript - 如何在复选框选中时启用文本框