隐藏正交拖动时的圆形

3
我创建了一个带有圆和拖动功能的地球仪。问题是这些圆出现在地球仪的远侧,我想让这些圆被隐藏起来。
我的代码可以在这里找到: http://bl.ocks.org/anonymous/dc2d4fc810550586d40d4b1ce9088422/40c6e199a5be4e152c0bd94a13ea94eba41f004b 例如,我希望我的地球仪像这个一样工作: https://bl.ocks.org/larsvers/f8efeabf480244d59001310f70815b4e 我看到了一些解决方案,例如这个: How to move points in an orthogonal map? 但对我来说并不完全适用。点只是消失了,因为d[0]和d[1]似乎未定义。
我还尝试过使用类似于这个方法: http://blockbuilder.org/tlfrd/df1f1f705c7940a6a7c0dca47041fec8 但那似乎也不起作用。问题在于他使用json作为数据,而我的圆数据与json独立。
我找到的唯一类似的例子是这个: https://bl.ocks.org/curran/115407b42ef85b0758595d05c825b346 但我并不真正理解他的代码。他的方法与我的有很大不同。
以下是我的JavaScript代码:
(function(){
 var h = 600;
   var w = 900;
   var i = 0;
   var map = void 0;
  var world = void 0;
  var US = void 0;


    var margin = {
          top: 10,
          bottom: 40,
          left: 0,
          right: 30
        };


      var circleScale = d3.scaleSqrt()
        .domain([0, 4445])
        .range([0.5, 10])


    var width = w - margin.left - margin.right;
    var height = h - margin.top - margin.bottom;

  var dragging = function(d){
    var c = projection.rotate();
    projection.rotate([c[0] + d3.event.dx/6, c[1] - d3.event.dy/6])
    map.selectAll('path').attr('d', path);
    map.selectAll(".circles").attr("cx", function(d){
                var coords = projection([d.Longitude_imp, d.Latitude_imp])
                return coords[0];
              })
              .attr("cy", function(d){
                var coords = projection([d.Longitude_imp, d.Latitude_imp])
                return coords[1];
              })
   }

   var drag = d3.drag()
    .on("drag", dragging)


   var projection = d3.geoOrthographic().clipAngle(90); 
   var path = d3.geoPath().projection(projection);

   var svg = d3.select("body")
        .append("svg")
        .attr("id", "chart")
        .attr("width", w)
        .attr("height", h)

   d3.json("world.json", function(json){ 
     d3.csv("arms_transfer_2012_2016_top - arms_transfer_2012_2016_top.csv", function(error, data){


    var countries = topojson.feature(json, json.objects.countries).features
    var US = countries[168]


    map = svg.append('g').attr('class', 'boundary');
    world = map.selectAll('path').data(countries);
    US = map.selectAll('.US').data([US]);
    Circles = map.selectAll(".circles").data(data)

    console.log(countries[168])


    world.enter()
    .append("path")
    .attr("class", "boundary")
    .attr("d", path)


    US.enter()
      .append("path")
      .attr("class", "US")
      .attr("d", path)
      .style("fill", "lightyellow")
      .style("stroke", "orange")




          Circles.enter()
              .append("circle")
              .attr("class", "circles")
              .attr("r", function(d){
                return circleScale(d.Millions)
              })
              .attr("cx", function(d){
                var coords = projection([d.Longitude_imp, d.Latitude_imp])
                return coords[0];
              })
              .attr("cy", function(d){
                var coords = projection([d.Longitude_imp, d.Latitude_imp])
                return coords[1];
              })
              .style("fill", "#cd0d0e")

    svg.append("rect")
      .attr("class", "overlay")
      .attr("width", w)
      .attr("height", h)
      .call(drag)

      })

   })

  })();
1个回答

2
有几种不同的方法可以实现这一点,但其中一种更容易的方法是在拖动事件中计算投影质心(由旋转确定)与圆心之间的角距离:
map.selectAll("circle")
  .style("display", function(d) {

  var circle = [d.Longitude_imp, d.Latitude_imp];
  var rotate = projection.rotate(); // antipode of actual rotational center.

  var center = [-rotate[0], -rotate[1]]

  var distance = d3.geoDistance(circle,center);
    return (distance > Math.PI/2 ) ? 'none' : 'inline';
})

获取每个点的中心,并使用 projection.rotate() 获取旋转中心 - 注意旋转值是居中点的反向。一个 [10,-20] 的旋转将地图居中于 [-10,20],你可以在地图上移动。有了这两个点,我们可以使用 d3.geoDistance() 计算两个点之间的弧度距离,因此使用 Math.PI/2 - 这使得我们得到了90度以外的点,对于这些点,我们隐藏,对于其余的点,我们显示。
这可以更好地融入您的代码中,但我在这里将其分开以更清楚地展示正在发生的事情。
这里有一个示例block - 拖动以触发,我还没有将逻辑应用到初始加载中。
一种替代方法,正如Gerardo Furtado所指出的那样,是使用路径来显示圆圈 - 使用path.pointRadius来设置每个点的圆圈大小。您可以附加以下格式的路径,而不是附加圆圈:
Circles.enter()
    .append("path")
          .attr("class", "circles")
          .attr("d",createGeojsonPoint)

这句话的意思不太清楚,可以提供更多上下文吗?
map.selectAll('.circles').attr('d',createGeojsonPoint);

这种方法使用了正交投影的剪切角度,以在特征离投影中心超过90度时隐藏它们(根据旋转确定)。您的createGeojsonPoint函数需要设置半径并返回有效的geojson对象:
var createGeojsonPoint = function(d) {
    console.log(d);
    path.pointRadius(circleScale(d.Millions));                                      // set point radius
    return path({"type":"Point","coordinates":[d.Longitude_imp,d.Latitude_imp]})    // create geojson point, return path data
}

总的来说,经过必要的修改,你的代码可能看起来像这样 (链接)

使用path怎么样,就像我的链接答案中的最后一个bl.ocks一样?那不是更容易吗? - Gerardo Furtado
嗯,这个方法是可行的,我曾经想过一下,不确定为什么我从未在答案中使用过这种方法。但是,您可能并不总是处理圆形,您可能有符号或小图表,在这种情况下,这种方法仍然有效,而路径方法则不行。 - Andrew Reid
另外,我正要去睡觉了。路径方法需要修改代码,而不是简单地插入新代码,我会尝试在明天更新,因为你的建议很好。 - Andrew Reid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接