在正交拖动上隐藏圈子

时间:2018-01-09 04:28:09

标签: javascript d3.js

我创造了一个有圆圈和拖动的地球仪。问题是圆圈出现在地球的远端。我希望隐藏这些圈子。

我的bl.ock可以在这里找到: 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。

我发现的只有一个类似的例子:来自Curran的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 个答案:

答案 0 :(得分:3)

有几种不同的方法可以实现这一点,但其中一种更简单的方法是计算投影质心(由旋转确定)与阻力事件中的圆心之间的角距:

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
}

总之,经过必要的修改后,您的代码可能会显示like this