【问题标题】:How can I make my lines spin with the globe?我怎样才能让我的线条随着地球旋转?
【发布时间】:2020-11-11 04:33:22
【问题描述】:

我已修改this d3 example 以在绘制地球后动态添加地点/点和红线。 (本质上,我想动态添加数据,而不是像示例那样从一组固定的点开始)。绘制了红色虚线,但是随着地球的旋转,这些线保持在相同的位置。我如何让我的线条像示例中那样随着地球旋转?我的小提琴:https://jsfiddle.net/6qhvt8aL/2/

  var width = 960,
    height = 500;
  var proj = d3.geoOrthographic().scale(230).translate([width / 2, height / 2]).clipAngle(90);
  var path = d3.geoPath().projection(proj).pointRadius(1.5);
  var graticule = d3.geoGraticule();
  var london = [-0.118667702475932, 51.5019405883275];
  var time = Date.now();
  var rotate = [39.666666666666664, -30];
  var velocity = [.015, -0];
  var lineToLondon = function(d) {
    return path({
      "type": "LineString",
      "coordinates": [london, d.geometry.coordinates]
    });
  }

  function stripWhitespace(str) {
    if (!str) {
      return "";
    }
    return str.replace(" ", "");
  }

  var svg = d3.select("body").append("svg").attr("width", width).attr("height", height)
  svg.call(d3.drag().on("start", dragstarted).on("drag", dragged));
  queue().defer(d3.json, "https://openlayers.org/en/latest/examples/data/topojson/world-110m.json").defer(d3.json, "/static/destinations.json").await(ready);
  var places = {
    "type": "FeatureCollection",
    "features": [{
      "type": "Feature",
      "properties": {
        "name": "San Francisco"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-122.417168773552248, 37.769195629687431]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Chicago"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-87.752000832709314, 41.831936519278429]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Los Angeles"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-118.243683, 34.052235]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Vancouver"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-123.116226, 49.246292]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Calgary"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-114.062019, 51.044270]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Barcelona"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [2.154007, 41.390205]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Berlin"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [13.404954, 52.520008]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Paris"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [2.349014, 48.864716]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Cologne"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [6.953101, 50.935173]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Geneva"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [6.143158, 46.204391]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Fethiye"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [29.1263, 36.6592]
      }
    }, {
      "type": "Feature",
      "properties": {
        "name": "Edinburgh"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-3.188267, 55.953251]
      }
    }]
  };

  addLocations(places);

  function addLocations(places) {
    svg.append("g").attr("class", "points")
      .selectAll("text").data(places.features)
      .enter().append("path")
      .attr("class", "point")
      .attr("d", path);
    svg.append("g").attr("class", "lines")
      .selectAll(".lines").data(places.features)
      .enter().append("path")
      .attr("class", "lines")
      .attr("id", d => stripWhitespace(d.properties.name))
      .attr("d", d => lineToLondon(d));

    refresh();
    svg.selectAll(".lines").attr("d", (d) => {
      if (d) {
        return lineToLondon(d);
      }
    });
  }

  function ready(error, world, places) {
    $.getJSON("https://openlayers.org/en/latest/examples/data/topojson/world-110m.json", function(world) {
      svg.append("circle").attr("cx", width / 2).attr("cy", height / 2).attr("r", proj.scale()).attr("class", "noclicks").attr("fill", "none");
      svg.append("path").datum(topojson.object(world, world.objects.land)).attr("class", "land").attr("d", path);
      svg.append("path").datum(graticule).attr("class", "graticule noclicks").attr("d", path);
      svg.append("g").attr("class", "countries").selectAll("path").data(topojson.object(world, world.objects.countries).geometries).enter().append("path").attr("d", path);
      refresh();
      spin();
    });
  }

  function refresh() {
    svg.selectAll(".land").attr("d", path);
    svg.selectAll(".countries path").attr("d", path);
    svg.selectAll(".graticule").attr("d", path);
    svg.selectAll(".point").attr("d", path);
  }

  var timer;

  function spin() {
    timer = d3.timer(function() {
      var dt = Date.now() - time;
      proj.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);
      refresh();
    });
  }

  function dragstarted() {
    timer.stop();
    v0 = versor.cartesian(proj.invert(d3.mouse(this)));
    r0 = proj.rotate();
    q0 = versor(r0);
  }

  function dragged() {
    var v1 = versor.cartesian(proj.rotate(r0).invert(d3.mouse(this))),
      q1 = versor.multiply(q0, versor.delta(v0, v1)),
      r1 = versor.rotation(q1);
    proj.rotate(r1);
    refresh();
  }

【问题讨论】:

  • 为什么不每次更新刷新功能中的所有其他功能时都更新行路径:svg.selectAll("path.lines").attr("d",lineToLondon);

标签: javascript html jquery d3.js


【解决方案1】:

您在刷新函数中更新除行之外的所有内容,您只需要更新这些。

您不能使用svg.selectAll(".lines").attr("d", lineToLondon),因为您有一个g 和一个类lines,其中包含该类的所有路径。相反,您可以使用:

 svg.selectAll("path.lines").attr("d", lineToLondon);

需要注意的是,您的代码中不需要这些行:

svg.selectAll(".lines").attr("d", (d) => {
  if (d) {
    return lineToLondon(d);
  }
});

这里是更新后的 fiddle,其中包含这些更改。

【讨论】:

  • 哦,酷!最后一个问题:我将如何做到lineToLondon 接受 2 个参数:源和目标。现在它接受一个参数d,但来源并不总是伦敦……它可能是巴黎、德克萨斯或其他地方。再次感谢!
  • 您是否会以不同的方式构建数据,例如两点而不是一个点?你将如何确定另一点?这是一个不同的问题 - 根据您的数据结构,您的方法会有所不同,如果您发布有关此主题的新问题,我会添加一个答案(除非有人以一个好的答案击败我)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2011-01-10
  • 2017-11-23
相关资源
最近更新 更多