【问题标题】:Zooming in D3 v4 on a globe在地球上放大 D3 v4
【发布时间】:2018-02-03 17:31:26
【问题描述】:

我正在寻找一种在 D3 v4 中从一个地方缩放到另一个地方的方法(v4 很重要)。我正在寻找的基本上就是这样:https://www.jasondavies.com/maps/zoom/我的问题是 Jason Davies 混淆了他的代码,所以我无法阅读它,而且我找不到包含该项目或任何类似内容的 bl.ock .我将提供一个链接到我在这里得到的东西:http://plnkr.co/edit/0mjyR3ovTfkDXB8FTG0j?p=preview 相关的大概在.tween()里面:

.tween("rotate", function () {
                var p = d3.geoCentroid(points[i]),
                    r = d3.geoInterpolate(projection.rotate(), [-p[0], -p[1]]);

                return function (t) {
                    projection.rotate(r(t));
                    convertedLongLats = [projection(points[0].coordinates), projection(points[1].coordinates)]
                    c.clearRect(0, 0, width, height);
                    c.fillStyle = colorGlobe, c.beginPath(), path(sphere), c.fill();
                    c.fillStyle = colorLand, c.beginPath(), path(land), c.fill();
                    for (var j = 0; j < points.length; j++) {
                        var textCoords = projection(points[j].coordinates);
                        c.fillStyle = textColors, c.textAlign = "center", c.font = "18px FontAwesome", c.fillText(points[j].icon, textCoords[0], textCoords[1]);
                        textCoords[0] += 15;
                        c.textAlign = "left", c.font = " 12px Roboto", c.fillText(points[j].location, textCoords[0], textCoords[1]);
                    }
                    c.strokeStyle = textColors, c.lineWidth = 4, c.setLineDash([10, 10]), c.beginPath(), c.moveTo(convertedLongLats[0][0], convertedLongLats[0][1]), c.lineTo(convertedLongLats[1][0], convertedLongLats[1][1]), c.stroke();
                };
            })

基本上,我想要我现在拥有的东西,但我想要它放大,几乎就像我在上面提供的动画世界缩放示例中一样。我并不是真的在寻找代码,我宁愿有人用一个例子或其他东西指出我正确的方向(值得注意的是,我对 d3 还很陌生,而且这个项目很大程度上基于 mbostock 的 World Tour,所以它使用画布)。提前谢谢大家!

【问题讨论】:

  • 你想放大一个正交投影,试试this question & answer,它实现了你例子中的效果,或者这个block(点击放大)。
  • @AndrewReid 该示例使用边界框,我的代码的问题是我需要放大点,所以解决方案可能是找到一种方法在点周围制作人工边界框,但那是仅凭我有限的 d3 知识。
  • 边界框仅用于获取比例,如果您使用点,您可以手动将其设置为某个固定数字,但旋转的质心只是一个点。如果您只使用点,所有位置的比例应该相同,您是否希望从初始状态(全球?)和/或过渡期间(点之间缩小)有任何比例变化?
  • @AndrewReid 我似乎已经解决了边界框和缩放的问题,我现在唯一的问题是我想在tween() 中间缩小到整个地球然后再缩小在tween() 的末尾再次指出这一点。我用我更新的代码创建了一个新的 plunk:plnkr.co/edit/y4vn3L8QV0fwyCBBmgIM?p=preview 当前的问题是,当它达到我希望它切换的级别时,它会跳到 2000 的规模,但我觉得我要去这完全是错误的。

标签: javascript d3.js zooming


【解决方案1】:

根据您的 plunker 和评论,在过渡中缩小两点之间的挑战是插值器只会在两个值之间插值。 plunker 中的解决方案依赖于两个插值器,一个用于放大和缩小。正如您所注意到的,这种方法增加了不必要的复杂性,并且沿线某处,它跳到了不正确的比例。你可以简化一下:

取一个在-1到1之间进行插值的插值器,根据插值器的绝对值对每个尺度进行加权。在零时,缩放应该一直向外,而在 -1,1 时,您应该放大:

var s = d3.interpolate(-1,1);

// get the appropriate scale:
scale = Math.abs(0-s(t))*startEndScale + (1-Mat.abs(0-s(t)))*middleScale

这有点笨拙,因为它从缩小到突然放大,所以你可以用正弦缓动来缓和它:

var s = d3.interpolate(0.0000001,Math.PI);

// get the appropriate scale:    
scale = (1-Math.abs(Math.sin(s(t))))*startEndScale + Math.abs(Math.sin(s(t)))*middleScale

我已将此应用到您的plunker here

对于一个使用我建议的示例以及您的两个点和路径(并使用您的 plunkr 作为基础)的简单且最小的示例,去掉动画线和图标,我可能会将类似 (plunker , sn-p 下面最好全屏查看):

var width = 600,
    height = 600;

var points = [{
    type: "Point",
    coordinates: [-74.2582011, 40.7058316],
    location: "Your Location",
    icon: "\uF015"
}, {
    type: "Point",
    coordinates: [34.8887969, 32.4406351],
    location: "Caribe Royale Orlando",
    icon: "\uF236"
}];

var canvas = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height);

var c = canvas.node().getContext("2d");

var point = points[0].coordinates;

var projection = d3.geoOrthographic()
    .translate([width / 2, height / 2])
    .scale(width / 2)
    .clipAngle(90)
    .precision(0.6)
    .rotate([-point[0], -point[1]]);

var path = d3.geoPath()
    .projection(projection)
    .context(c);

var colorLand = "#4d4f51",
    colorGlobe = "#2e3133",
    textColors = "#fff";

d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function (error, world) {
    if (error) throw error;

    var sphere = { type: "Sphere" };
    var land = topojson.feature(world, world.objects.land);
    var i = 0;
    
    var scaleMiddle = width/2;
    var scaleStartEnd = width * 2;
    
    loop();
    
    function loop() {
      d3.transition()
        .tween("rotate",function() {
            var flightPath = {
                type: 'Feature',
                geometry: {
                    type: "LineString",
                    coordinates: [points[i++%2].coordinates, points[i%2].coordinates]
                }
            };

          // next point:
          var p = points[i%2].coordinates;
          // current rotation:
          var currentRotation = projection.rotate();  
          // next rotation:
          var nextRotation = projection.rotate([-p[0],-p[1]]).rotate();
          
          // Interpolaters:
          var r = d3.geoInterpolate(currentRotation,nextRotation);
          var s = d3.interpolate(0.0000001,Math.PI);
          
          return function(t) {
            // apply interpolated values
            projection.rotate(r(t))
              .scale(  (1-Math.abs(Math.sin(s(t))))*scaleStartEnd + Math.abs(Math.sin(s(t)))*scaleMiddle  ) ;          

            c.clearRect(0, 0, width, height);
            c.fillStyle = colorGlobe, c.beginPath(), path(sphere), c.fill();
            c.fillStyle = colorLand, c.beginPath(), path(land), c.fill();
            c.beginPath(), path(flightPath), c.globalAlpha = 0.5, c.shadowColor = "#fff", c.shadowBlur = 5, c.lineWidth = 0.5, c.strokeStyle = "#fff", c.stroke(), c.shadowBlur = 0, c.globalAlpha = 1;

          }
        })
        .duration(3000)
        .on("end", function() {  loop();  })
      
      
    }
    
});
<script src="http://d3js.org/d3.v4.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>

【讨论】:

  • 谢谢,这太完美了!
猜你喜欢
  • 2018-12-08
  • 2016-11-18
  • 1970-01-01
  • 2018-12-18
  • 1970-01-01
  • 2020-01-21
  • 2011-01-10
  • 2017-10-15
  • 1970-01-01
相关资源
最近更新 更多