D3 js正字法标记旋转

D3 js orthographic markers rotation

本文关键字:旋转 js D3      更新时间:2023-09-26

目前我用D3制作的半功能正字法地球仪。这是一张有记号的地图。所有"陆地"区域都可以通过拖拽旋转显示,但svg标记不能。下面是我当前的测试代码:

var width = 960,
    height = 500,
    sens = 0.25;
var proj = d3.geo.orthographic()
    .scale(220)
    .translate([width / 2, height / 2])
    .clipAngle(90);
var path = d3.geo.path().projection(proj).pointRadius(function(d) { return 6 });
var svg = d3.select('body').append('svg')
            .attr('width', width)
            .attr('height', height);
var g = svg.append('g');
queue()
    .defer(d3.json, 'data/world-110m.json')
    .defer(d3.json, 'data/generated.json')
    .await(ready);
function ready(error, world, locations) {
    g.append('path')
      .datum({type: 'Sphere'})
      .attr('class', 'water')
      .attr('d', path);
    g.selectAll('g.land')
      .data(topojson.feature(world, world.objects.countries).features)
      .enter().append('path')
      .attr('class', 'land')
      .attr('d', path)
      .call(d3.behavior.drag()
        .origin(function() {
          var r = proj.rotate();
          return {x: r[0] / sens, y: -r[1] / sens}; })
        .on('drag', function(d) {
            var rotate = proj.rotate();
            proj.rotate([d3.event.x * sens, -d3.event.y * sens, rotate[2]]);
            g.selectAll('.land').attr('d', path);
          }));
    var nodes = g.selectAll('g.node')
      .data(locations)
      .enter().append('g').attr('class', 'node')
      .attr('transform', function(d) {
        var proj_pos = proj([d.lon, d.lat]);
        return 'translate(' + proj_pos[0] + ',' + proj_pos[1] + ')';
      })
      .attr('style', 'cursor: pointer')
      .attr("d", path);
    nodes.append("svg:image")
      .attr('transform', 'translate(-24, -20)')
      .attr('width', 20)
      .attr('height', 24)
      .classed('white',true)
      .attr("href","data/marker.svg");
    console.log(g.selectAll('g.node'));
}

在尝试以某种方式工作之后,我只能在地球仪上剪辑"点",但没有svg。似乎svg必须进入"g"标签,结果我的"节点"在"d"标签中没有路径。

我需要:整个地图必须旋转拖动动作,与svg剪辑到位置,指定在'generated.json'

[
  {
    "lat": 62.782176,
    "lon": 54.3214
  },
  {
    "lat": -61.007975,
    "lon": -5.05281
  },
  {
    "lat": -78.166262,
    "lon": 45.320536
  }
]

这有点令人沮丧,如果有人能帮助我,我将非常感激。

更新节点的位置非常简单。然而,这里的技巧是确定何时标记已经"旋转"出地球仪(在地图的后面)。我能想到的唯一方法是生成一个点路径,看看它是否未定义:

.on('drag', function(d) {
  //update land like you've been doing
  var rotate = proj.rotate();
  proj.rotate([d3.event.x * sens, -d3.event.y * sens, rotate[2]]);
  g.selectAll('.land').attr('d', path);
  // for each node
  nodes.each(function(d, i) {
    var self = d3.select(this),
      lon_lat = [d.lon, d.lat];
      proj_pos = proj(lon_lat);
    // check to see if it's still visible
    var hasPath = path({
      type: "Point",
      coordinates: lon_lat
    }) != undefined;
    // if it is show it and update position
    if (hasPath) {
      self.style("display","inline");
      self.attr("transform", 'translate(' + proj_pos[0] + ',' + proj_pos[1] + ')');
    }
    // otherwise hide it
    else {
      self.style("display","none")
    }
  });
}));

完整运行代码