Leaflet.js:将要素属性传递给类构造函数

时间:2018-08-31 00:40:45

标签: javascript d3.js leaflet

我有很多使用过的svg标记(字形)(这要感谢名称为rioV8的SO用户在此方面的帮助-不仅是此-...),并且理想情况下,我希望这些字形能够从要素属性结构中获取形状。

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

这些用户定义的字形扩展了L.circleMarker,为简单起见,我们说它们的形状可以是正方形或菱形。当前,我正在扩展L.Class并在构造函数中传递glyphName:(随时可以批评一下,如果它对您来说看起来不太好)

        var glyph = L.Class.extend({
        initialize: function(glyphName) {
             glyphName === "square"? this.type = MarkerSquare:
             glyphName === "diamond"? this.type = MarkerDiamond:
             this.type = L.circleMarker; 
            },
        });

当我需要绘制字形时,我有类似的内容:

L.geoJson(myDots[i], {
    pointToLayer: function(feature, latlng) {
        var p = latlng;
        var myGlyph = new glyph('diamond')
        return new myGlyph.type(p, style(feature));
       },
       onEachFeature: onEachDot
   }).addTo(map);

请问我可以具有由要素属性确定的形状吗?最终,我想要实现的是合并这两行

var myGlyph = new glyph('diamond')
return new myGlyph.type(p, style(feature));

类似于

return new myGlyph.type(p, style(feature));

这将使我能够绘制不同的形状,并且这些形状将由用于填充要素属性的输入数据确定。这些属性用于颜色或尺寸的方式类似,现在可以用来设置形状。

谢谢! (下面的完整代码)

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

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

    <title>Chart</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
        }

        #map {
            width: 600px;
            height: 600px;
        }
    </style>


    <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/leaflet@1.3.3/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js"></script>
</head>

<body>
    <div id="map"></div>
    <script>
        L.Canvas.include({
            _updateMarkerDiamond: function(layer) {
                if (!this._drawing || layer._empty()) {
                    return;
                }

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

                this._drawnLayers[layer._leaflet_id] = layer;

                ctx.beginPath();
                ctx.moveTo(p.x - r, p.y);
                ctx.lineTo(p.x, p.y - r);
                ctx.lineTo(p.x + r, p.y);
                ctx.lineTo(p.x, p.y + r);
                ctx.lineTo(p.x - r, p.y);
                ctx.closePath();
                this._fillStroke(ctx, layer);
            }
        });
        var MarkerDiamond = L.CircleMarker.extend({
            _updatePath: function() {
                this._renderer._updateMarkerDiamond(this);
            }
        });


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

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

                this._drawnLayers[layer._leaflet_id] = layer;

                ctx.beginPath();
                ctx.moveTo(p.x - r, p.y - r);
                ctx.lineTo(p.x + r, p.y - r);
                ctx.lineTo(p.x + r, p.y + r);
                ctx.lineTo(p.x - r, p.y + r);
                ctx.lineTo(p.x - r, p.y - r);
                ctx.closePath();
                this._fillStroke(ctx, layer);
            }
        });
        var MarkerSquare = L.CircleMarker.extend({
            _updatePath: function() {
                this._renderer._updateMarkerSquare(this);
            }
        });

        var glyph = L.Class.extend({
            initialize: function(glyphName) {
                glyphName === "square"? this.type = MarkerSquare:
                glyphName === "diamond"? this.type = MarkerDiamond:
                this.type = L.circleMarker;
            },
        });


        var data = [];
        var NumOfPoints = 100;
        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),
                    //"glyphName": "square",
                    "size": 500 // Fixed size circle radius=~13
                };

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


        //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;
        }

        var myRenderer;

        //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.glyphName +
                '</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 renderChart(data) {


            var myDots = make_dots(data);

            var minZoom = 0,
                maxZoom = 15;

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

            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;
                        
                        var myGlyph = new glyph('diamond')
                        return new myGlyph.type(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>

1 个答案:

答案 0 :(得分:2)

您需要将标记的shape设为标记的属性,并将MarkerDiamondMarkerSquare的渲染部分合并到另一个标记中,并确定要绘制的渲染部分基于属性if的{​​{1}} 内部 _updateMarkerXX方法。

shape包含渲染例程中的形状。

或者在layer.options.shape例程中完成

Marker

修改

定时使用幻数(Enums)而不是字符串可能会很有用,因为数字的比较比字符串比较便宜。而且Aenaon大约有30万个标记,但它可以忽略不计。