单击弹出 SVG 美国州特征路径

IT技术 reactjs d3.js gis
2021-05-12 11:42:38

我正在geoAlbersUSA使用d3-geoand渲染SVG 地图topojson-client- 如下所示 - 但是当用户单击路径时,我试图做一些花哨的事情。我想缩放和转换底层路径,在这种情况下是爱达荷州或弗吉尼亚州,以便该州“漂浮”在美国上方,但仍以质心为中心。每次我试图简单地scale<path/>它结束了许多像素的位置元素; 有没有办法计算translate()对应于您缩放元素的程度?

const states = topojson.feature(us, us.objects.states as GeometryObject) as ExtendedFeatureCollection;

const path = geoPath()
    .projection(geoAlbersUsa()
      .fitSize([innerWidth as number, innerHeight as number], states)
    );

<svg>
  {
    states.features.map(feature => {
      return <path key={`state-path-${feature.id}`} d={path(feature) as string} onClick={() => updateScaleAndTranslate(feature)} />
    }
  }
</svg>

爱达荷州和弗吉尼亚州在鼠标点击时浮动

1个回答

您需要设置transform-origin样式属性。它确定相对于应用变换的点。如果可以找到路径的中心(例如,使用getBBox()),然后设置

.style("transform-origin", `${myCenter.x}px ${myCenter.y}px`)

这应该会改变应用转换的方式。

我为你做了一个小例子,使用 d3 v6。请注意,随着状态被“扩展”,它们现在可能开始重叠,因此在功能上,我建议只允许像这样扩展一个或几个状态。

const svg = d3.select('body')
  .append("svg")
  .attr("viewBox", [0, 0, 975, 610]);

d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3/states-albers-10m.json").then((us) => {
  const path = d3.geoPath()
  const color = d3.scaleQuantize([1, 10], d3.schemeBlues[9]);

  const statesContainer = svg.append("g");
  const states = statesContainer
    .selectAll("path")
    .data(topojson.feature(us, us.objects.states).features)
    .join("path")
    .attr("class", "state")
    .attr("fill", () => color(Math.random() * 10))
    .attr("d", path)
    .on("click", function(event, d) {
      const {
        x,
        y,
        width,
        height
      } = this.getBBox();

      // First, move the state to the front so it's in front of others
      const state = d3.select(this)
        .attr("transform-origin", `${x + width / 2}px ${y + height / 2}px`).remove();
      statesContainer.append(() => state.node());

      d.properties.expanded = !d.properties.expanded;

      state
        .transition()
        .duration(500)
        .attr("transform", d.properties.expanded ? "scale(1.25)" : "scale(1)")
    });

  states
    .append("title")
    .text(d => d.properties.name)
});
.state {
  stroke: #fff;
  stroke-linejoin: round;
  stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>
<script src="https://d3js.org/topojson.v3.js"></script>