leaflet.js:使用自定义svg标记太慢了(还有很多要点)

Aen*_*aon 4 svg canvas d3.js leaflet mapbox

我正在尝试使用一些用户定义的svg图标作为传单上的标记,但是我认为整个任务对于我的浏览器来说太繁重了。

到目前为止,我一直在使用,L.circleMarker但是现在我不得不使用星号,箭头,星星等标记,因此我决定将它们作为svg路径,然后将其插入而不是我的circleMarkers。为了使事情更复杂,我获得了超过30万的积分。使用circleMarkers,我可以制作一个可行的图表,虽然速度不快,但可以接受,尤其是当使用相当深的缩放来区分各个点时(否则,一切就像一个大斑点,没有用处)。

但是,使用svg标记时,图表的计算量变得很大,以至于浏览器只能挂起。我玩过100、1000和10000分,即使有1000分,差异也很明显。请问对此有什么解决方案,有人使用带有大量数据点的svg标记吗?我认为我的代码中正确使用了canvas,尤其是对于canvas,circleMarkers但我可能会误会。任何帮助,高度赞赏。摘录中的代码,对底部的几行进行注释/取消注释:

return L.circleMarker(p, style(feature));
Run Code Online (Sandbox Code Playgroud)

要么

console.log("Starting markers.")
return L.marker(p, {
    renderer: myRenderer,
    icon: makeIcon('6-pointed-star', style(feature).color),
    });
Run Code Online (Sandbox Code Playgroud)

从切换circleMarkerssvg标记。非常感谢!

PS。使用svg标记,代码会因Highlight事件而中断,但是我已经很了解发生了什么错误。circleMarkers

return L.circleMarker(p, style(feature));
Run Code Online (Sandbox Code Playgroud)

rio*_*oV8 8

您的SVG 6点标记不会由“画布”渲染。看一下DevTools,您会看到它们是img带有base-64编码的svg作为源的标签。如果您有大量的标记,这将减慢HTML渲染器的速度。

CircleMarkers在画布上渲染。

通过创建一个新的L.Path子类,您可以在画布上绘制所需的任何标记,并让Leaflet发挥其最大作用。在任何其他JS代码之前进行这些传单的修改,否则它将抱怨它不是构造函数。

L.Canvas.include({
    _updateMarker6Point: function (layer) {
        if (!this._drawing || layer._empty()) { return; }

        var p = layer._point,
            ctx = this._ctx,
            r = Math.max(Math.round(layer._radius), 1);

        this._drawnLayers[layer._leaflet_id] = layer;

        ctx.beginPath();
        ctx.moveTo(p.x + r     , p.y );
        ctx.lineTo(p.x + 0.43*r, p.y + 0.25 * r);
        ctx.lineTo(p.x + 0.50*r, p.y + 0.87 * r);
        ctx.lineTo(p.x         , p.y + 0.50 * r);
        ctx.lineTo(p.x - 0.50*r, p.y + 0.87 * r);
        ctx.lineTo(p.x - 0.43*r, p.y + 0.25 * r);
        ctx.lineTo(p.x -      r, p.y );
        ctx.lineTo(p.x - 0.43*r, p.y - 0.25 * r);
        ctx.lineTo(p.x - 0.50*r, p.y - 0.87 * r);
        ctx.lineTo(p.x         , p.y - 0.50 * r);
        ctx.lineTo(p.x + 0.50*r, p.y - 0.87 * r);
        ctx.lineTo(p.x + 0.43*r, p.y - 0.25 * r);
        ctx.closePath();
        this._fillStroke(ctx, layer);
    }
});

var Marker6Point = L.CircleMarker.extend({
    _updatePath: function () {
        this._renderer._updateMarker6Point(this);
    }
});
Run Code Online (Sandbox Code Playgroud)

您使用的方法与circleMarker相同

return new Marker6Point(p, style(feature));
Run Code Online (Sandbox Code Playgroud)

在代码中,有2个L.canvas实例和2个变量myRenderer。我保留了全局变量,但仅在renderChart()函数中构造了L.map()时才分配它。

对于演示,我使用了较大的标记区域并使用了10000个标记。我的浏览器没有任何问题。我size将属性的值增加到500,这样我们得到了一个半径13像素的标记,因此您可以清楚地看到星星。

我使用了最新的传单版本1.3.3。

L.Canvas.include({
    _updateMarker6Point: function (layer) {
        if (!this._drawing || layer._empty()) { return; }

        var p = layer._point,
            ctx = this._ctx,
            r = Math.max(Math.round(layer._radius), 1);

        this._drawnLayers[layer._leaflet_id] = layer;

        ctx.beginPath();
        ctx.moveTo(p.x + r     , p.y );
        ctx.lineTo(p.x + 0.43*r, p.y + 0.25 * r);
        ctx.lineTo(p.x + 0.50*r, p.y + 0.87 * r);
        ctx.lineTo(p.x         , p.y + 0.50 * r);
        ctx.lineTo(p.x - 0.50*r, p.y + 0.87 * r);
        ctx.lineTo(p.x - 0.43*r, p.y + 0.25 * r);
        ctx.lineTo(p.x -      r, p.y );
        ctx.lineTo(p.x - 0.43*r, p.y - 0.25 * r);
        ctx.lineTo(p.x - 0.50*r, p.y - 0.87 * r);
        ctx.lineTo(p.x         , p.y - 0.50 * r);
        ctx.lineTo(p.x + 0.50*r, p.y - 0.87 * r);
        ctx.lineTo(p.x + 0.43*r, p.y - 0.25 * r);
        ctx.closePath();
        this._fillStroke(ctx, layer);
    }
});

var Marker6Point = L.CircleMarker.extend({
    _updatePath: function () {
        this._renderer._updateMarker6Point(this);
    }
});
Run Code Online (Sandbox Code Playgroud)

如果速度不够快,您始终可以设置自己的图块服务器,并以不同的缩放级别(在透明的PNG文件中)将标记烘烤到图块中。并将其用作地形图块上方的单独图块层。您没有简单的弹出窗口,但是300K标记的渲染非常快。您可以为要显示的每个图层/组制作一个瓷砖叠加层。所有服务均来自同一图块服务器。

  • 很好的答案——也许这是我的传单 v1.5.1 版本,但我必须将 `this._drawnLayers[layer._leaflet_id] = layer;` 替换为 `this._layers[layer._leaflet_id] = layer;`。“_drawnLayers”为“未定义” (3认同)