【问题标题】:d3 US Map zoom on load to marked stated3 美国地图在加载到标记状态时缩放
【发布时间】:2018-05-24 19:31:05
【问题描述】:

美国地图与 d3.v3 使用 Mike Bostock 的示例:

我希望地图在页面加载时最初放大标记的位置,但应该呈现整个地图,以便用户可以根据需要缩小。

var w = 300;
var h = 280;
//Define map projection
var projection = d3.geo.albersUsa()
                   .translate([w/2, h/2])
                   .scale([300]);

//Define path generator
var path = d3.geo.path()
             .projection(projection);



//Create SVG element
var svg = d3.select("#map1").append("svg")
                        .attr("width", w)
                        .attr("height", h)
var g = svg.append("g");

var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "1000")
.style('opacity', 0)
.style("font-family", "sans-serif")
.style("background-color", "white")
.style("border-radius", "5px")
.style("padding", "10px")
.style('color', '#000')
.style("font-size", "12px");

//Load in GeoJSON data
d3.json("us-states.json", function(json) {
        d3.csv("cities.csv", function(error, data) {    
            g.selectAll("circle")
                .data(data)
                .enter()
               .append("circle")
                .attr("cx", function(d) {
                    return projection([d.longi, d.lati])[0];
                })
                .attr("cy", function(d) {
                    return projection([d.longi, d.lati])[1];
                })
                .attr("r", 4)
                .style("fill", "#4F6D88")
                .on("mouseover", function(d){
                    tooltip.transition().style("opacity", 0.9)
                    .style('left', (d3.event.pageX) + 'px')
                    .style('top', (d3.event.pageY) + 'px')
                    .text(d.city)
                })
                .on("mousemove", function(event){
                    tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");
                })
                .on("mouseout", function(){
                    tooltip.transition().delay(500).style("opacity", 0);
                });
        });

        //Bind data and create one path per GeoJSON feature
        g.selectAll("path")
           .data(json.features)
           .enter()
           .append("path")
           .attr("d", path);

});
    var zoom = d3.behavior.zoom()
    .scaleExtent([1, 50])
    .on("zoom", function() {
      var e = d3.event,
          tx = Math.min(0, Math.max(e.translate[0], w - w * e.scale)),
          ty = Math.min(0, Math.max(e.translate[1], h - h * e.scale));
      zoom.translate([tx, ty]);
      g.attr("transform", [
        "translate(" + [tx, ty] + ")",
        "scale(" + e.scale + ")"
      ].join(" "));
    });
svg.call(zoom)

我有使用上面粘贴的滚动放大的代码,但我希望它在加载到这些特定位置时放大。我希望它是怎样的:

【问题讨论】:

    标签: javascript angularjs d3.js


    【解决方案1】:

    在 d3 中放大地图有两种主要方法:

    • 修改将重新绘制路径的投影,或
    • 使用缩放和变换修改绘制的路径。

    在 d3v4 中使用 fitSize 或 fitExtent 修改投影最容易 - 尽管您需要将点转换为 geojson。您还可以手动计算平移和缩放值以更新投影(请参阅 Mike Bostock 的 this answer,其中解释了这种常见的 d3v3 方法)。

    或者,您可以通过调用缩放功能来修改绘制的路径 - this question 昨天问有一个很好的例子(在 d3v4 中)。或者您可以手动计算和应用缩放,然后更新缩放以指示当前比例和平移。我将使用上面提到的修改 d3v3 投影的常用方法(使用 Mike 的回答)并将其应用于路径上的变换 - 而不是修改投影。 虽然不难看出如何更改我的答案来修改投影。


    首先,您需要确定点的 x 和 y 坐标之间的最大差异。如果处理两点,这将相当容易:

    var data = [[-100,45],[-110,45]];
    var p1 = projection(data[0]);
    var p2 = projection(data[1]);
    
    var dx = Math.abs(p1[0] - p2[0]);
    var dy = Math.abs(p1[1] - p2[1]);
    

    为了更简短的回答,我假设使用简单的数据格式。此外,如果处理很多点,这会有点复杂。一种可能的选择是将您的点放在 geojson 中并获取点的边界框。

    现在我们需要找出点的质心——在两个点的情况下,这只是 x 和 y 值的平均值:

    var x = (p1[0] + p2[0])/2;
    var y = (p1[1] + p2[1])/2;
    

    接下来我们需要计算一个新的比例尺,同时还要判断这个比例尺是受限于坐标x值的差异还是坐标y值的差异:

    var scale = 0.9 / Math.max( dx/w , dy/h );
    

    0.9 略微缩小了比例,它与0.9 * scale 相同,并允许可变的边距。 dx/w 返回的值是我们需要在 svg 容器宽度上拉伸差异的比例值的 1。

    (写成这样可能更有意义:var scale = 0.9 * Math.min(w/dx,h/dy); - 我们希望将缩放限制为最低比例值并将其乘以某个百分比以给出边距。但其他表示在在线示例中无处不在)

    现在我们有了一个比例,我们只需要确定一个翻译。为此,我们找出需要将 xy 变量中保存的值重新定位到多远,以使这些值居中:

    var translate = [w/2 - scale * x, h/2-scale*y];
    

    现在您可以设置地图的初始比例和平移:

    g.attr("transform", "translate("+translate+")scale("+scale+")");
    

    但是,您可能希望在页面加载时更新缩放参数以反映初始缩放和翻译:

    zoom.translate(translate);
    zoom.scale(scale);
    

    这样,当您从初始视图放大或缩小时,更改与您的初始缩放相关。

    现在您所要做的就是在添加点时包含上面的代码。请注意,如果您想返回初始位置,此技术可能需要进行一些修改。

    【讨论】:

      猜你喜欢
      • 2016-03-23
      • 2017-07-11
      • 1970-01-01
      • 2020-01-21
      • 2018-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多