javascript - d3 美国 map 缩放加载至标记状态

标签 javascript angularjs d3.js

使用 Mike Bostock 示例的 d3.v3 的美国 map :

US map with d3.v3 using mike bostock's example

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

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)

我有使用上面粘贴的滚动放大的代码,但我希望它能够放大加载到这些特定位置。我想要的样子:

How i want it to be

最佳答案

在 d3 中缩放 map 有两种主要方法:

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

在 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 容器的宽度上拉伸(stretch)差异的比例值的 1 倍。

(这样写可能更有意义:var scale = 0.9 * Math.min(w/dx,h/dy); - 我们希望通过最低比例值并将其乘以某个百分比以给出边距。但另一种表示形式在在线示例中普遍存在)

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

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

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

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

但是,您可能希望在页面加载时更新缩放参数以反射(reflect)初始缩放和平移:

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

这样,当您放大或缩小初始 View 时,变化是相对于您的初始缩放而言的。

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

关于javascript - d3 美国 map 缩放加载至标记状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47750168/

相关文章:

javascript - 下拉列表多次保持上下滑动

javascript - 未定义从渲染过程中要求 Electron 对话

javascript - 如何使用 Jasmine 为 Angular.js 的服务和 Controller 创建测试?

javascript - 使用 javascript 实现下拉菜单更改时的重绘功能

javascript - D3 强制布局图从文件加载数据

javascript - 如何在 Angular js 的新选项卡上显示图像或 pdf 文件?

javascript - 如何使用 jquery 动态插入 css vendor 前缀

javascript - 如何在 AngularJS 中设置范围验证

angularjs - AngularJS 中的嵌套和开槽 Transclude

javascript - 在 javascript 中向 CanvasRenderingContext2D 添加标记