Leaflet.js: слишком медленно с пользовательскими маркерами svg (и много очков)

Я пытаюсь использовать определенные пользователем значки svg для маркеров на листовке, но я думаю, что вся задача становится слишком сложной для моего браузера.

До сих пор я использовал L.circleMarker, но теперь мне нужно использовать маркеры, такие как звездочки, стрелки, звезды и т. д., Поэтому я решил сделать их как путь svg, а затем подключить их вместо моих круговых маркеров. Чтобы усложнить задачу, у меня более 300 тысяч баллов. С помощью circleMarkers я смог создать работоспособную диаграмму, не молниеносно, но вполне приемлемо, особенно когда использовался довольно глубокий зум, чтобы можно было различать отдельные точки (в противном случае все было похоже на большую каплю и бесполезно для изучения).

Однако с маркерами svg диаграмма становится настолько тяжелой с точки зрения вычислений, что браузер просто зависает. Я играл со 100, 1000 и 10000 очков, и даже с 1000 очков разница становится очевидной. Есть ли какое-то решение для этого, пожалуйста, кто-нибудь использовал маркеры svg с большим количеством точек данных? Я думаю, что холст правильно используется в моем коде, особенно для circleMarkers, но я могу ошибаться. Любая помощь очень ценится. Код во фрагменте, прокомментируйте / раскомментируйте несколько строк внизу:

return L.circleMarker(p, style(feature));

или

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

переключиться с маркеров circleMarkers на svg. Большое спасибо!

PS. С маркерами svg код прерывается событием выделения, но я вполне понял, что не так ... он отлично работает с circleMarkers

<!DOCTYPE html>
<html lang = "en">

<head>
<meta charset = "utf-8">

<title>Chart</title>
    <style>
        #tooltip {
          position:absolute;
          background-color: #2B292E;
          color: white;
          font-family: sans-serif;
          font-size: 15px;
          pointer-events: none; /*dont trigger events on the tooltip*/
          padding: 15px 20px 10px 20px;
          text-align: center;
          opacity: 0;
          border-radius: 4px;
        }

		html, body {
			height: 100%;
			margin: 0;
		}
		#map {
			width: 600px;
			height: 600px;
		}
    </style>

<!-- Reference style.css -->
<!--    <link rel = "stylesheet" type = "text/css" href = "style.css">-->

<!-- Reference minified version of D3 -->
    <script src='https://d3js.org/d3.v4.min.js' type='text/javascript'></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
    <link rel = "stylesheet" href = "https://unpkg.com/[email protected]/dist/leaflet.css" />
    <script src = "https://unpkg.com/[email protected]/dist/leaflet.js"></script>
</head>

<body>



<div id = "map"></div>


<script>
    var data = [];
    var NumOfPoints = 100
    for (let i = 0; i < NumOfPoints; i++) {
        data.push({
            num: i,
            x: Math.random(),
            y: Math.random(),
            year: Math.floor(100*Math.random())
        })
    }
    
    renderChart(data);


    function make_dots(data) {
        var arr = [];
        var nest = d3.nest()
            .key(function (d) {
                return Math.floor(d.year / 10);;
            })
            .entries(data);

        for (var k = 0; k < nest.length; ++k) {
            arr[k] = helper(nest[k].values);
        }
        return arr;
    }

    function helper(data) {
        dots = {
            type: "FeatureCollection",
            features: []
        };
        for (var i = 0; i < data.length; ++i) {
            x = data[i].x;
            y = data[i].y;
            var g = {
                "type": "Point",
                "coordinates": [x, y]
            };

            //create feature properties
            var p = {
                "id": i,
                "popup": "Dot_" + i,
                "year": parseInt(data[i].year),
                "size": 30 // Fixed size
            };

            //create features with proper geojson structure
            dots.features.push({
                "geometry": g,
                "type": "Feature",
                "properties": p
            });
        }
        return dots;
    }


    //////////////////////////////////////////////////////////////////////////////////////////////
    //styling and displaying the data as circle markers//
    //////////////////////////////////////////////////////////////////////////////////////////////

    //create color ramp
    function getColor(y) {
        return y > 90 ? '#6068F0' :
            y > 80 ? '#6B64DC' :
            y > 70 ? '#7660C9' :
            y > 60 ? '#815CB6' :
            y > 50 ? '#8C58A3' :
            y > 40 ? '#985490' :
            y > 30 ? '#A3507C' :
            y > 20 ? '#AE4C69' :
            y > 10 ? '#B94856' :
            y > 0 ? '#C44443' :
            '#D04030';
    }

    //calculate radius so that resulting circles will be proportional by area
    function getRadius(y) {
        r = Math.sqrt(y / Math.PI)
        return r;
    }

    // This is very important! Use a canvas otherwise the chart is too heavy for the browser when
    // the number of points is too high, as in this case where we have around 300K points to plot
    var myRenderer = L.canvas({
        padding: 0.5
    });

    //create style, with fillColor picked from color ramp
    function style(feature) {
        return {
            radius: getRadius(feature.properties.size),
            fillColor: getColor(feature.properties.year),
            color: "#000",
            weight: 0,
            opacity: 1,
            fillOpacity: 0.9,
            renderer: myRenderer
        };
    }

    //create highlight style, with darker color and larger radius
    function highlightStyle(feature) {
        return {
            radius: getRadius(feature.properties.size) + 1.5,
            fillColor: "#FFCE00",
            color: "#FFCE00",
            weight: 1,
            opacity: 1,
            fillOpacity: 0.9
        };
    }

    //attach styles and popups to the marker layer
    function highlightDot(e) {
        var layer = e.target;
        dotStyleHighlight = highlightStyle(layer.feature);
        layer.setStyle(dotStyleHighlight);
        if (!L.Browser.ie && !L.Browser.opera) {
            layer.bringToFront();
        }
    }

    function resetDotHighlight(e) {
        var layer = e.target;
        dotStyleDefault = style(layer.feature);
        layer.setStyle(dotStyleDefault);
    }

    function onEachDot(feature, layer) {
        layer.on({
            mouseover: highlightDot,
            mouseout: resetDotHighlight
        });
        var popup = '<table style = "width:110px"><tbody><tr><td><div><b>Marker:</b></div></td><td><div>' + feature.properties.popup +
            '</div></td></tr><tr class><td><div><b>Group:</b></div></td><td><div>' + feature.properties.year +
            '</div></td></tr><tr><td><div><b>X:</b></div></td><td><div>' + feature.geometry.coordinates[0] +
            '</div></td></tr><tr><td><div><b>Y:</b></div></td><td><div>' + feature.geometry.coordinates[1] +
            '</div></td></tr></tbody></table>'

        layer.bindPopup(popup);
    }
    
    function makeIcon(name, color) {

    if (name == "diamond") {
        // here's the SVG for the marker
        var icon = "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='20' height='20'> " +
            "<path stroke = " + "'" + color + "'" + " stroke-width='3' fill='none' " +
            " d='M10,1 5,10 10,19, 15,10Z'/></svg>";
    }


    // Based on http://www.smiffysplace.com/stars.html
    if (name == "6-pointed-star") {
        // here's the SVG for the marker
        var icon = "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='28' height='28'> " +
            "<path stroke = " + "'" + color + "'" + " stroke-width='3' fill='none' " +
            " d='m13 13m0 5l5 3.6599999999999966l-0.6700000000000017 -6.159999999999997l5.670000000000002 -2.5l-5.670000000000002 -2.5l0.6700000000000017 -6.159999999999997l-5 3.6599999999999966l-5 -3.6599999999999966l0.6700000000000017 6.159999999999997l-5.670000000000002 2.5l5.670000000000002 2.5l-0.6700000000000017 6.159999999999997z'/></svg>";

    }


    // here's the trick, base64 encode the URL
    var svgURL = "data:image/svg+xml;base64," + btoa(icon);

    // create icon
    var svgIcon = L.icon({
        iconUrl: svgURL,
        iconSize: [20, 20],
        shadowSize: [12, 10],
        iconAnchor: [5, 5],
        popupAnchor: [5, -5]
    });

    return svgIcon
}
    

    function renderChart(data) {
        var myDots = make_dots(data);

        var minZoom = 0,
            maxZoom = 15;

        var map = L.map('map', {
            minZoom: minZoom,
            maxZoom: maxZoom
        }).setView([0.5, 0.5], 10);

        L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
            continuousWorld: false,
            minZoom: 0,
            noWrap: true
        }).addTo(map);

        var myRenderer = L.canvas({
            padding: 0.5
        });

        // Define an array to keep layerGroups
        var dotlayer = [];

        //create marker layer and display it on the map
        for (var i = 0; i < myDots.length; i += 1) {
            dotlayer[i] = L.geoJson(myDots[i], {
                pointToLayer: function (feature, latlng) {
                    var p = latlng;
//                    return L.circleMarker(p, style(feature));
                    console.info("Starting markers.")
                    return L.marker(p, {
                        renderer: myRenderer,
                        icon: makeIcon('6-pointed-star', style(feature).color),
                    });
                },
                onEachFeature: onEachDot
            }).addTo(map);
        }


        var cl = L.control.layers(null, {}).addTo(map);
        for (j = 0; j < dotlayer.length; j += 1) {
            var name = "Group " + j + "0-" + j + "9";
            cl.addOverlay(dotlayer[j], name);
        }

    }


</script>
</body>

</html>

Используйте меньше точек или переходите на холст в качестве технологии рендеринга.

Robert Longson 15.08.2018 00:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
1
4 480
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваши шеститочечные маркеры svg не отображаются холстом. Взгляните на DevTools, и вы увидите, что это теги img с svg в кодировке base-64 в качестве источника. Если у вас много маркеров, это замедлит работу средства визуализации HTML.

Метки CircleMarkers отображаются на холсте.

Создав новый подкласс L.Path, вы можете нарисовать любой маркер на холсте и позволить листовке делать то, что у нее получается лучше всего. Внесите эти изменения в буклет перед любым другим кодом 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);
    }
});

Вы используете его так же, как и для circleMarker.

return new Marker6Point(p, style(feature));

В коде 2 экземпляра L.canvas и 2 переменные myRenderer. Я сохранил глобальную переменную, но назначаю ее только тогда, когда в функции renderChart() создается L.map ().

Для демонстрации я использовал большую область с маркерами и использовал 10000 маркеров. У моего браузера с этим нет проблем. Я увеличил size в свойствах до 500, чтобы мы получили маркер с радиусом 13 пикселей, чтобы вы могли четко видеть звезду.

Я использовал последнюю версию листовки 1.3.3.

<!DOCTYPE html>
<html lang = "en">

<head>
<meta charset = "utf-8">

<title>Chart</title>
<style>
#tooltip {
    position:absolute;
    background-color: #2B292E;
    color: white;
    font-family: sans-serif;
    font-size: 15px;
    pointer-events: none; /*dont trigger events on the tooltip*/
    padding: 15px 20px 10px 20px;
    text-align: center;
    opacity: 0;
    border-radius: 4px;
}

html, body {
    height: 100%;
    margin: 0;
}
#map {
    width: 600px;
    height: 600px;
}
</style>

<!-- Reference style.css -->
<!--    <link rel = "stylesheet" type = "text/css" href = "style.css">-->

<!-- Reference minified version of D3 -->
<script src='https://d3js.org/d3.v4.min.js' type='text/javascript'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
<link rel = "stylesheet" href = "https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src = "https://unpkg.com/[email protected]/dist/leaflet.js"></script>
</head>

<body>
<div id = "map"></div>
<script>
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);
    }
});

var data = [];
var NumOfPoints = 10000;
for (let i = 0; i < NumOfPoints; i++) {
    data.push({
        num: i,
        x: Math.random()*60,
        y: Math.random()*60,
        year: Math.floor(100*Math.random())
    })
}

renderChart(data);

function make_dots(data) {
    var arr = [];
    var nest = d3.nest()
        .key(function (d) {
            return Math.floor(d.year / 10);
        })
        .entries(data);

    for (var k = 0; k < nest.length; ++k) {
        arr[k] = helper(nest[k].values);
    }
    return arr;
}

function helper(data) {
    dots = {
        type: "FeatureCollection",
        features: []
    };
    for (var i = 0; i < data.length; ++i) {
        x = data[i].x;
        y = data[i].y;
        var g = {
            "type": "Point",
            "coordinates": [x, y]
        };

        //create feature properties
        var p = {
            "id": i,
            "popup": "Dot_" + i,
            "year": parseInt(data[i].year),
            "size": 500 // Fixed size circle radius=~13
        };

        //create features with proper geojson structure
        dots.features.push({
            "geometry": g,
            "type": "Feature",
            "properties": p
        });
    }
    return dots;
}

//////////////////////////////////////////////////////////////////////////////////////////////
//styling and displaying the data as circle markers//
//////////////////////////////////////////////////////////////////////////////////////////////

//create color ramp
function getColor(y) {
    return y > 90 ? '#6068F0' :
        y > 80 ? '#6B64DC' :
        y > 70 ? '#7660C9' :
        y > 60 ? '#815CB6' :
        y > 50 ? '#8C58A3' :
        y > 40 ? '#985490' :
        y > 30 ? '#A3507C' :
        y > 20 ? '#AE4C69' :
        y > 10 ? '#B94856' :
        y > 0 ? '#C44443' :
        '#D04030';
}

//calculate radius so that resulting circles will be proportional by area
function getRadius(y) {
    r = Math.sqrt(y / Math.PI)
    return r;
}

// This is very important! Use a canvas otherwise the chart is too heavy for the browser when
// the number of points is too high, as in this case where we have around 300K points to plot
var myRenderer;
//  = L.canvas({
//     padding: 0.5
// });

//create style, with fillColor picked from color ramp
function style(feature) {
    return {
        radius: getRadius(feature.properties.size),
        fillColor: getColor(feature.properties.year),
        color: "#000",
        weight: 0,
        opacity: 1,
        fillOpacity: 0.9,
        renderer: myRenderer
    };
}

//create highlight style, with darker color and larger radius
function highlightStyle(feature) {
    return {
        radius: getRadius(feature.properties.size) + 1.5,
        fillColor: "#FFCE00",
        color: "#FFCE00",
        weight: 1,
        opacity: 1,
        fillOpacity: 0.9
    };
}

//attach styles and popups to the marker layer
function highlightDot(e) {
    var layer = e.target;
    dotStyleHighlight = highlightStyle(layer.feature);
    layer.setStyle(dotStyleHighlight);
    if (!L.Browser.ie && !L.Browser.opera) {
        layer.bringToFront();
    }
}

function resetDotHighlight(e) {
    var layer = e.target;
    dotStyleDefault = style(layer.feature);
    layer.setStyle(dotStyleDefault);
}

function onEachDot(feature, layer) {
    layer.on({
        mouseover: highlightDot,
        mouseout: resetDotHighlight
    });
    var popup = '<table style = "width:110px"><tbody><tr><td><div><b>Marker:</b></div></td><td><div>' + feature.properties.popup +
        '</div></td></tr><tr class><td><div><b>Group:</b></div></td><td><div>' + feature.properties.year +
        '</div></td></tr><tr><td><div><b>X:</b></div></td><td><div>' + feature.geometry.coordinates[0] +
        '</div></td></tr><tr><td><div><b>Y:</b></div></td><td><div>' + feature.geometry.coordinates[1] +
        '</div></td></tr></tbody></table>'

    layer.bindPopup(popup);
}

function makeIcon(name, color) {

    if (name == "diamond") {
        // here's the SVG for the marker
        var icon = "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='20' height='20'> " +
            "<path stroke = " + "'" + color + "'" + " stroke-width='3' fill='none' " +
            " d='M10,1 5,10 10,19, 15,10Z'/></svg>";
    }

    // Based on http://www.smiffysplace.com/stars.html
    if (name == "6-pointed-star") {
        // here's the SVG for the marker
        var icon = "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='28' height='28'> " +
            "<path stroke = " + "'" + color + "'" + " stroke-width='3' fill='none' " +
            " d='m13 13m0 5l5 3.66l-0.67 -6.16l5.67 -2.5l-5.67 -2.5l0.67 -6.16l-5 3.66l-5 -3.66l0.67 6.16l-5.67 2.5l5.67 2.5l-0.67 6.16z'/></svg>";
    }

    // here's the trick, base64 encode the URL
    var svgURL = "data:image/svg+xml;base64," + btoa(icon);

    // create icon
    var svgIcon = L.icon({
        iconUrl: svgURL,
        iconSize: [20, 20],
        shadowSize: [12, 10],
        iconAnchor: [5, 5],
        popupAnchor: [5, -5]
    });

    return svgIcon
}

function renderChart(data) {
    var myDots = make_dots(data);

    var minZoom = 0,
        maxZoom = 15;

    var map = L.map('map', {
        minZoom: minZoom,
        maxZoom: maxZoom
    }).setView([0.5, 0.5], 5);

    L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
        continuousWorld: false,
        minZoom: 0,
        noWrap: true
    }).addTo(map);

    myRenderer = L.canvas({ padding: 0.5 });

    // Define an array to keep layerGroups
    var dotlayer = [];

    //create marker layer and display it on the map
    for (var i = 0; i < myDots.length; i += 1) {
        dotlayer[i] = L.geoJson(myDots[i], {
            pointToLayer: function (feature, latlng) {
                var p = latlng;
                // return L.circleMarker(p, style(feature));

                // console.info("Starting markers.")
                // return L.marker(p, {
                //     renderer: myRenderer,
                //     icon: makeIcon('6-pointed-star', style(feature).color),
                // });

                return new Marker6Point(p, style(feature));
            },
            onEachFeature: onEachDot
        }).addTo(map);
    }
    var cl = L.control.layers(null, {}).addTo(map);
    for (j = 0; j < dotlayer.length; j += 1) {
        var name = "Group " + j + "0-" + j + "9";
        cl.addOverlay(dotlayer[j], name);
    }
}
</script>
</body>

</html>

Если этого недостаточно быстро, вы всегда можете настроить свой собственный сервер плиток и запечь маркеры на плитках с разными уровнями масштабирования (в прозрачных файлах PNG). И используйте его как отдельный слой плитки поверх плиток ландшафта. У вас нет простых всплывающих окон, но рендеринг 300K маркеров выполняется довольно быстро. Вы можете наложить плитку для каждого слоя / группы, которую хотите показать. Все обслуживаются с одного тайлового сервера.

rioV8, это просто потрясающе. У меня работает нормально, хотя и несколько медленнее, чем у CircleMarkers в листовке (на 300К баллов). Возможно, мне это сойдет с рук. Что касается другого подхода, у вас есть указатель (пожалуйста, не просите вас писать его, просто если вы где-то его видели, чтобы я мог увидеть, как это делается). Кроме того, как вы сделали путь svg для 6-конечной звезды, мне нужно будет сделать еще несколько фигур. Я могу понять типичные пути svg, но для меня это в новинку. Layer._radius, пожалуйста, откуда это взялось? Мне нужно сделать маркеры больше, и я думаю, это то, что я должен установить.

Aenaon 15.08.2018 23:38

@Aenaon: он использует те же свойства, что и CircleMarker. Вы устанавливаете radius в методах style и highlight, он сохраняется в layer._radius конструктором circleMarker. Поскольку у нас больше вызовов ctx и нам нужно заполнить более сложную форму по сравнению с кругом, это занимает немного больше времени. Найдите web map tile service wmts или WMS. Посмотрите примеры листовок для облицовки плиткой. Относительные координаты в пути svg не имели для меня значения (goto-relative 13,13 | goto-relative 0,5 [где эта точка ??]), поэтому я пересчитал их все относительно средней точки.

rioV8 16.08.2018 00:34

Отличный ответ - возможно, это мои версии листовки v1.5.1, но мне пришлось заменить this._drawnLayers[layer._leaflet_id] = layer; на this._layers[layer._leaflet_id] = layer;. _drawnLayers был undefined

walking_the_cow 11.10.2019 19:17

@walking_the_cow: Понятия не имею, какую версию я использовал для ответа, и, возможно, они изменили этот внутренний API. '_' означает непубличный материал

rioV8 11.10.2019 21:37

@walking_the_cow: Я использую v1.3.1 и отлично работает. Не пробовал обновляться и не планирую, так как не вижу причин для этого. Еще раз большое спасибо rioV8!

Aenaon 04.11.2019 13:19

@ rioV8: Если вы это видите, что касается ваших комментариев в последнем абзаце вашего ответа еще в августе 2018 года о предварительном преобразовании маркеров в плитки в виде прозрачных PNG-файлов, есть ли у вас какие-либо указатели, которые я мог бы прочитать и посмотреть, как это делается?

Aenaon 05.11.2019 12:22

@Aenaon. Вам необходимо реализовать веб-сервер, как вы используете для тайлов ландшафта. Подавать изображение на основе веб-запроса, содержащего x, y, масштабирование. Это определенно больше работы, чем SO-ответ.

rioV8 09.11.2019 23:58

@ rioV8, да, конечно, я не ожидаю, что вы напишете код для этого здесь (или где-нибудь еще). На всякий случай, если вы наткнулись на какой-то материал (блоги, книги, действительно что-нибудь), обсуждающий этот подход, чтобы увидеть, как это делается. Я думаю, что мне не хватает того, как сделать эти прозрачные плитки с маркерами, уже предварительно отрендеренными на них как png. Думаю, мне нужно еще много чего, чего я не знаю. Еще раз большое спасибо

Aenaon 10.11.2019 00:17

@Aenaon: веб-сервер использует некоторую проекцию, это может быть всемирный WGS84 или местный, например, UK-grid. Затем спроецируйте свои местоположения на используемые координаты проекции и нарисуйте маркер на плитках, помните, что маркер перекрывает несколько плиток (до 4), если ваш маркер меньше плитки. Сделайте это для каждого уровня масштабирования, поддерживаемого сервером листов. Вы можете делать "на лету" или предварительно запечь плитки для статических наборов данных. Может быть, делать ежедневную предварительную выпечку.

rioV8 10.11.2019 00:55

Другие вопросы по теме