单击时弹出 SVG 美国州要素路径

Pop Out SVG US State Feature Path On Click

我正在使用 d3-geotopojson-client 渲染 geoAlbersUSA SVG 地图 - 如下所示 - 但当用户点击路径时我想做一些奇特的事情.我想缩放和平移基本路径,在本例中为爱达荷州或弗吉尼亚州,以便该州“漂浮”在美国上方,但仍以质心为中心。每次我尝试简单地 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>

你需要先设置transform-origin style property. It determines the point relative to which the transformations are applied. If you can find the centre of the path (for example, using 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>