You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在D3.js中垂直翻转可缩放SVG并保留交互功能?

解决方案:通过嵌套组翻转Y轴并调整初始缩放

最简洁的方案是通过嵌套一个带Y轴翻转变换的外层组,同时调整初始缩放的Y轴偏移量,无需修改任何数据处理逻辑,也不会影响平移和缩放功能。

修改步骤:

  1. 添加外层翻转组:创建一个外层<g>元素,应用scale(1, -1)实现Y轴翻转,所有可视化内容放在内层组中。
  2. 调整初始缩放的Y偏移:由于Y轴翻转后坐标系统倒置,需要将初始缩放中的Y轴偏移量取反,确保内容正确居中。

修改后的完整代码:

const svg = d3.select<SVGSVGElement, unknown>(d3Container.current);
// 新增外层翻转组,应用Y轴翻转
const flipGroup = svg.append("g").attr("transform", "scale(1, -1)");
const g = flipGroup.append("g"); // 原内层组,用于缩放和平移

const zoom = d3.zoom<SVGSVGElement, unknown>().on("zoom", (event) => {
  const { transform } = event;
  g.attr("transform", transform); // 缩放仍作用于内层组
});

const filledRegions = g.selectAll(".filledRegions");
filledRegions.data(data).join(
  (enter) =>
    enter
      .append("path")
      .attr("class", "filledRegions")
      .attr("d", (d) => datumToPath(d))
      .attr("fill", (d) => d.fill.color)
);

svg.call(zoom);

const boundingBox = g?.node()?.getBBox();

if (boundingBox) {
  const { x: x0, y: y0, width: bbWidth, height: bbHeight } = boundingBox;
  const x1 = x0 + bbWidth;
  const y1 = y0 + bbHeight;

  const { clientHeight: frameHeight, clientWidth: frameWidth } =
    d3Container.current;

  svg.call(
    zoom.transform,
    d3.zoomIdentity
      .translate(frameWidth / 2, frameHeight / 2)
      .scale(
        Math.min(
          8,
          0.9 / Math.max((x1 - x0) / frameWidth, (y1 - y0) / frameHeight)
        )
      )
      // 将Y轴偏移量取反,适配翻转后的坐标系统
      .translate(-(x0 + x1) / 2, (y0 + y1) / 2)
  );
}

原理说明:

  • 外层翻转组:scale(1, -1)会将内层所有内容的Y轴坐标倒置,实现数据Y轴向上到SVG Y轴向下的转换。
  • 初始缩放调整:由于Y轴翻转后,内容的中心Y坐标变为原中心的相反数,因此将初始缩放的Y偏移从-(y0+y1)/2改为(y0+y1)/2,确保内容在SVG画布中居中显示。
  • 平移缩放兼容性:所有平移和缩放操作仍作用于内层组,外层翻转组的变换会自动适配这些操作,无需额外修改交互逻辑。

内容的提问来源于stack exchange,提问作者Jim P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 15:45:26