Маркеры расширены от CircleMarker - Как изменить область щелчка? - PullRequest
0 голосов
/ 10 мая 2019

С помощью Leaflet я пытаюсь отобразить много точек (+ 10000) как функцию GeoJSON для повышения производительности. Чтобы добиться лучших результатов, я нашел этот ответ , в котором объясняется, как расширить листлет 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.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 (потому что это то, что я расширил, чтобы создать мою булавку), показанную красным кружком:

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
    },
})

1 Ответ

1 голос
/ 10 мая 2019

Обнаружение щелчков в векторных слоях, отображаемых с помощью L.Canvas, зависит от частного метода _containsPoint каждого векторного слоя. См. Реализацию для CircleMarker или для Polyline.

Каждый раз, когда пользователь щелкает на рендере L.Canvas, он отображает все слои в нем и спрашивает их: «Пользователь сделал что-то в пикселе 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]));
    }
})

Это должно сместить область щелчка вверх или вниз. Если вы хотите получить лучшую форму, вам нужно будет обеспечить правильную реализацию функции, которая возвращает, находится ли точка внутри фигуры или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...