如何确定一个点是否隐藏在投影上?

Cra*_*ich 6 javascript projection geo d3.js

我正在使用 D3 和 D3.geo.projection 创建一个带有数据点的旋转地球仪,这是一个相当简单的世界地球仪界面。

当我只是用圆圈绘制点时,一切都很好(即当它们在地平线后面旋转时,点“黯然失色”):

svg.append("g")
    .attr("class","points")
    .selectAll("text")
    .data(places.features)
  .enter()

  //for circle-point------------------------------
  .append("path")
  .attr("d", path.pointRadius(function(d) {
      if (d.properties)
        return 3+(4*d.properties.scalerank);
                    }))
    .attr("d", path)

    .attr("class", "point")
    .on("click",pointClick)
;
Run Code Online (Sandbox Code Playgroud)

但现在我试图绘制符号而不是圆圈:

svg.append("g")
    .attr("class","points")
    .selectAll("text")
    .data(places.features)
  .enter()
    //for image-------------------------------------
    .append("image")
    .attr("xlink:href", "img/x_symbol.png")
    .attr("x", -12)
    .attr("y", -12)
    .attr("width", 24)
    .attr("height", 24)
    .attr("transform", function(d) {
        return "translate(" + projection([
          d.properties.longitude,
          d.properties.latitude
        ]) + ")"
      })

    .attr("class", "point")
    .on("click",pointClick)
;
Run Code Online (Sandbox Code Playgroud)

虽然这是有效的,并且符号绘制在地球上的正确位置,但即使它们绕到地球的背面,它们也会持续存在。如果我有办法确定它们是否被遮蔽,我可以使用可见性属性隐藏它们,但是我在 d3.geo.projection 中没有看到这样做的方法。有任何想法吗?

Jam*_*mes 7

计算点是否可见

如果你有你的投影:

const chartProjection = d3.geo.orthographic();
Run Code Online (Sandbox Code Playgroud)

你可以把它变成一个路径函数:

const path = d3.geo.path()
  .projection(chartProjection);
Run Code Online (Sandbox Code Playgroud)

然后您可以评估每个点的可见性。path将返回undefined投影后面的值。

function getVisibility(d) {
  const visible = path(
    {type: 'Point', coordinates: [d.longitude, d.latitude]});

  return visible ? 'visible' : 'hidden';
}

// Update all text elements.
svg.selectAll('text')
  .attr('visibility', getVisibility);
Run Code Online (Sandbox Code Playgroud)

  • 这是一个更好的答案,因为它适用于任何投影。 (2认同)

Cra*_*ich 5

好的,所以我至少能够通过计算投影中心和相关点之间的大圆距离来模拟隐藏在地球背面的图像。如果距离大于 ?/2,则该点将超出地平线:

        .attr("opacity", function(d) {
            var geoangle = d3.geo.distance(
                    d.geometry.coordinates,
                    [
                        -projection.rotate()[0],
                        projection.rotate()[1]
                    ]);
            if (geoangle > 1.57079632679490)
            {
                return "0";
            } else {
                return "1.0";
            }
        })
Run Code Online (Sandbox Code Playgroud)

我相信我可以通过在它们接近边缘时淡出它们,禁用点击等来变得更漂亮,但现在我可以继续......