d3js不同层的投影

时间:2018-10-03 06:01:03

标签: d3.js leaflet mapping map-projections

我制作了一张地图,其中显示了一些圆圈,单击时会显示线条。该地图叠加在传单底图上。 地图工作正常。这是我投影地图的方式:

d3.csv("going.csv", function(data) {
      going = data;

    d3.json("lor_migration.geojson", function(json) {

        //Projection
        transform = d3.geo.transform({
            point: projectPoint
        });
        path = d3.geo.path().projection(transform);

        function projectPoint(x, y) {
            var point = map.latLngToLayerPoint(new L.LatLng(y, x));
                this.stream.point(point.x, point.y);
        }
        //Bind data and create one path per GeoJSON feature
        var feature = g.selectAll("path")
            .data(json.features)
            .enter()
            .append("path")
            .attr("id", function(d) {
                return d.properties.state;
            })
            .attr("d", path)
            .attr("stroke-width", 0.5)
            .attr("fill-opacity", "0.5")
            .style("stroke", "#666")
            .style("fill", "#fff");

map.on("viewreset", reset);
        reset();

        //Reset function
        function reset() {
            var bounds = path.bounds(json);
                topLeft = bounds[0],
                bottomRight = bounds[1];
            svg.attr("width", bottomRight[0] - topLeft[0])
                .attr("height", bottomRight[1] - topLeft[1])
                .style("left", topLeft[0] + "px")
                .style("top", topLeft[1] + "px");
            g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
                feature.attr("d", path);
            }

以下是在地图上绘制圆圈的方式:

 //Create circles for net migration
        var circles = g.selectAll("circle")
            .data(json.features)
            .enter().append("circle")
            .attr("cx", function(d) {
                d.centroid = path.centroid(d);
                return d.centroid[0];
            })
            .attr("cy", function(d) {
                return d.centroid[1];
            })
            .attr("r", function(d) {  //circle size
                console.log("Value: " + value);
                var diff = d.properties.total_imm - d.properties.total_emm; 
                    return circleSize((Math.abs(diff)/Math.PI));
            })
            .attr("class", "circ")
            .attr("id", function(d) {
                return d.abbrev;
            })
            .attr("fill", function(d) { //circle color
                var diff = d.properties.total_imm - d.properties.total_emm; 
                if (diff > 0) {
                    return "#65a89d";
                } 
                else {
                    return "#a96a46";
                }
            })
            .attr("fill-opacity", "0.5")
            .attr("stroke", "#fff")
            .attr("stroke-weight", "0.5")
            .on("mouseover", function(d) {
                return toolOver(d, this);
            })
            .on("mousemove", function(d) {
                var m = d3.mouse(this);
                mx = m[0];
                my = m[1];
                return toolMove(mx, my, d);
            })
            .on("mouseout", function(d) {
                return toolOut(d, this);
            })
            .on("click", function(d) {
                clicked(d)
            });

这是各行的onclick函数:

function clicked(selected) {
    var selname = selected.id;  
    var homex = selected.centroid[0];
    var homey = selected.centroid[1];
    g.selectAll(".goingline")
        .attr("stroke-dasharray", 0)
        .remove()
    g.selectAll(".goingline")
        .data(going)
        .enter().append("path")
        .attr("class", "goingline")
        .attr("d", function(d, i) { 
            var finalval = coming[i][selname] - going[i][selname]; 
            come = coming[i][selname];
            go  = going[i][selname];   
                try {
                    var theState = d3.select("#" + d.abbrev).datum();
                    if (!isNaN(finalval)) {
                        var startx = theState.centroid[0];
                        var starty = theState.centroid[1];
                        if (finalval > 0)  
                            return "M" + startx + "," + starty + " Q" + (startx + homex) / 2 + " " + (starty + homey) / 1.5 + " " + homex + " " + homey;
                        else 
                            return "M" + homex + "," + homey + " Q" + (startx + homex) / 2 + " " + (starty + homey) / 5 + " " + startx + " " + starty;
                    }
                }
                catch (err) {
                    console.log(err)
                    console.log('No datum found for ' + d.abbrev)
                }
        })
        .call(transition)
        .attr("stroke-width", function(d, i) {
            var finalval = coming[i][selname] - going[i][selname]; 
                return 0.75//(Math.abs(finalval));
        })
        .attr("stroke", function(d, i) {
            var finalval = coming[i][selname] - going[i][selname];
            if (finalval > 0) {
                return "#65a89d";
            }
            else {
                return "#a96a46";
            }
        })
        .attr("fill", "none")
        .attr("opacity", 0.5)
        .attr("stroke-linecap", "round")
        .on("mouseover", function(d) {
            return toolOver2(d, this);
        })
        .on("mousemove", function(d, i) {
            var m = d3.mouse(this);
            mx = m[0];
            my = m[1];
            return toolMove2(mx, my, selname, d.state, coming[i][selname], going[i][selname]);
        })
        .on("mouseout", function(d) {
            return toolOut2(d, this);
        });
}

问题是投影不适用于圆和直线。您能提出一个解决方案吗? 谢谢

已编辑

所以这是我尝试解决的问题:还有一些问题

//Create SVG element
var svg = d3.select(map.getPanes().overlayPane)
    .append("svg")

var g = svg.append("g").attr("class", "leaflet-zoom-hide");
var svgCircles = svg.append("g").attr("class", "leaflet-zoom-hide");

var coming, going;
var by_name = {};

//Define the coming and going of csv
d3.csv("coming.csv", function(data) {
    coming = data;
});

d3.csv("going.csv", function(data) {
    going = data;

    d3.json("lor_migration.geojson", function(json) {

        //Projection
        transform = d3.geo.transform({
            point: projectPoint
        });
        path = d3.geo.path().projection(transform);

    /*  json.features.forEach(function(d) {
            d.LatLng = new L.LatLng(d.geometry.coordinates[1], d.geometry.coordinates[0]);
        });*/

        function projectPoint(x, y) {
            var point = map.latLngToLayerPoint(new L.LatLng(y, x)); 
                this.stream.point(point.x, point.y);
        }

        for (var i = 0; i < data.length; i++) {
            by_name[ data[i].state ] = {}; 
            for (var propt in data[i]) {
                by_name[ data[i].state ][propt] = +data[i][propt];
            }
            by_name[ data[i].state ].abbrev = data[i].abbrev;
            by_name[ data[i].state ].state = data[i].state;  
        }

        //Find the corresponding state inside the GeoJSON
        json.features.forEach( function (j) {
            var jsonState = j.properties.name; 
            if ( by_name[jsonState] ) { 
                j.properties.state = by_name[jsonState].state;
                j.id = by_name[jsonState].state;
                j.abbrev = by_name[jsonState].abbrev;
                j.properties.total_imm = by_name[jsonState].total_imm;
                j.properties.total_emm = by_name[jsonState].total_emm;   
            }
            else {
                console.log('No data for ' + jsonState)
            }
        })

        //Bind data and create one path per GeoJSON feature
        var feature = g.selectAll("path")
            .data(json.features)
            .enter()
            .append("path")
            .attr("id", function(d) {
                return d.properties.state;
            })
            .attr("d", path)
            .attr("stroke-width", 0.5)
            .attr("fill-opacity", "0.5")
            .style("stroke", "#666")
            .style("fill", "#fff");

        //Net migration circles
        var circles = svgCircles.selectAll("circle")
        .data(json.features)
        .enter().append("circle")
        .attr("cx", function(d) {
            d.centroid = path.centroid(d);
            return d.centroid[0];
        })
        .attr("cy", function(d) {
            return d.centroid[1];
        })
        .attr("r", function(d) {  //circle size
            console.log("Value: " + value);
            var diff = d.properties.total_imm - d.properties.total_emm; 
        //  if (diff > 200){
                return circleSize((Math.abs(diff)/Math.PI));
        //  }
        })
        .attr("class", "circ")
        .attr("id", function(d) {
            return d.abbrev;
        })
        .attr("fill", function(d) { //circle color
            var diff = d.properties.total_imm - d.properties.total_emm; 
            if (diff > 0) {
                return "#65a89d";
            } 
            else {
                return "#a96a46";
            }
        })
        .attr("fill-opacity", "0.5")
        .attr("stroke", "#fff")
        .attr("stroke-weight", "0.5")
        .on("mouseover", function(d) {
            return toolOver(d, this);
        })
        .on("mousemove", function(d) {
            var m = d3.mouse(this);
            mx = m[0];
            my = m[1];
            return toolMove(mx, my, d);
        })
        .on("mouseout", function(d) {
            return toolOut(d, this);
        })
        .on("click", function(d) {
            clicked(d)
        });

        map.on("viewreset", reset);
        reset();

        //Reset function
        function reset() {
            var bounds = path.bounds(json);
                topLeft = bounds[0],
                bottomRight = bounds[1];
            svg.attr("width", bottomRight[0] - topLeft[0])
                .attr("height", bottomRight[1] - topLeft[1])
                .style("left", topLeft[0] + "px")
                .style("top", topLeft[1] + "px");
            g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
                feature.attr("d", path);

            circles.attr("cx", function(d) {
                return map.latLngToLayerPoint(d.LatLng).x;
            });
            circles.attr("cy", function(d) {
                return map.latLngToLayerPoint(d.LatLng).y;
            });
            svgCircles.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
        }
    });
});

问题是,如果我尝试使用此功能,则什么也没有显示:

    json.features.forEach(function(d) {
            d.LatLng = new L.LatLng(d.geometry.coordinates[1], 
                       d.geometry.coordinates[0]);
        });

我也收到错误消息:

 TypeError: t is undefined, can't access property "lat" of it

请帮助

1 个答案:

答案 0 :(得分:0)

所以我至少固定了圆圈。问题是我没有返回正确的属性。应该退还质心而不记录纬度。这是我的重置功能的更新版本:

  //Reset function
        function reset() {

        //Defining Bounds
        var bounds = path.bounds(json);
            topLeft = bounds[0],
            bottomRight = bounds[1];
        svg.attr("width", bottomRight[0] - topLeft[0])
            .attr("height", bottomRight[1] - topLeft[1])
            .style("left", topLeft[0] + "px")
            .style("top", topLeft[1] + "px");

        //Recalculating Projections for Json map        
        g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
            feature.attr("d", path);

        //Recalculating Projections for Circles 
        circles.attr("cx", function(d) { 
            d.centroid = path.centroid(d);
            return d.centroid[0];
        });
        circles.attr("cy", function(d) {
            return d.centroid[1];
        });
        g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
            circles.attr("d", path);
        }

我仍然需要弄清楚线条的投影。有什么建议吗?