在地球上放大D3 v4

时间:2017-08-25 15:53:39

标签: javascript d3.js zoom

我正在寻找一种在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();
                };
            })

基本上,我想要我现在拥有的东西,但我想让它放大,就像我在上面提供的Animated World Zoom示例中一样。我不是在寻找代码,我宁愿有人用一个例子或者其他东西指出我正确的方向(值得注意的是我对d3相当新,而且这个项目很大程度上是基于mbostock的World Tour,所以它使用canvas)。提前谢谢大家!

1 个答案:

答案 0 :(得分:0)

根据您的plunker和comment,在转换中的两个点之间缩小的挑战是插值器仅在两个值之间进行插值。您的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作为基础),剥去动画线和图标,我可能会把像({{3 ,以下摘录在全屏幕上最佳观看):

&#13;
&#13;
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();  })
      
      
    }
    
});
&#13;
<script src="http://d3js.org/d3.v4.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
&#13;
&#13;
&#13;