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

如何在D3.js中点击SVG矩形后嵌套添加另一个SVG图表?

在D3.js中点击矩形后嵌套添加子SVG图表的正确实现

我看了你的代码,发现几个关键问题导致效果不符合预期:

  • 函数语法错误:var createMap (mapData){ 这种写法不符合JS规范,应该用标准函数定义写法,而且你还混用了mapData和mapdata的拼写
  • SVG不能嵌套在<rect>元素里:矩形是SVG的基础图形元素,无法作为其他SVG的父节点,你需要在主SVG容器中添加子SVG,再把它定位到矩形的位置
  • 你把生成的子SVG放到了外部的#subnodeMap div里,而不是目标矩形所在的SVG内部

下面是修正后的完整实现,我会一步步解释关键改动:

修正后的HTML结构

我们只需要保留主SVG的容器,子SVG会直接嵌套在主SVG里,不需要额外的外部div:

<body>
  <div id="mainMap">
    <svg></svg>
  </div>
</body>

修正后的JavaScript代码

// 初始化主SVG容器
var svg = d3.select("#mainMap svg")
  .attr("width", 600)
  .attr("height", 400);

// 添加可点击的矩形
svg.append('rect')
  .attr('class', 'content shape')
  .attr("x", 50) // 给矩形设置明确的x/y位置,方便后续定位子SVG
  .attr("y", 50)
  .attr("width", 20)
  .attr("height", 20)
  .attr("stroke", "black")
  .attr("stroke-width", 1)
  .style("fill", "#fff")
  .on("click", createMap);

// 点击事件处理函数
function createMap() {
  var rect = d3.select(this);
  // 检查是否已经存在子SVG,避免重复添加,实现切换效果
  var existingSubSvg = rect.parent().select(".sub-svg");
  if (existingSubSvg.size() > 0) {
    existingSubSvg.remove();
    rect.attr("width", 20)
        .attr("height", 20)
        .style("fill", "#fff");
    return;
  }

  // 获取矩形的位置,设置子SVG的尺寸
  var x = parseFloat(rect.attr("x"));
  var y = parseFloat(rect.attr("y"));
  var subWidth = 200;
  var subHeight = 200;

  // 放大原矩形(可选,根据你的需求调整)
  rect.attr("width", subWidth)
      .attr("height", subHeight)
      .style("fill", "lightsteelblue");

  // 在主SVG中添加子SVG,定位到原矩形的位置
  var subSvg = rect.parent()
    .append("svg")
    .attr("class", "sub-svg")
    .attr("x", x)
    .attr("y", y)
    .attr("width", subWidth)
    .attr("height", subHeight);

  // 调用生成图表的函数,传入子SVG和模拟数据
  getGeneratedMap(subSvg, {
    data: [15, 30, 45, 22, 50] // 这里替换成你的真实业务数据
  });
}

// 生成子图表的函数,接收子SVG容器和数据作为参数
function getGeneratedMap(subSvg, mapData) {
  // 这里写你的图表生成逻辑,下面是一个简单的柱状图示例
  var padding = 20;
  // X轴比例尺
  var xScale = d3.scaleBand()
    .domain(d3.range(mapData.data.length))
    .range([padding, subSvg.attr("width") - padding])
    .padding(0.1);

  // Y轴比例尺
  var yScale = d3.scaleLinear()
    .domain([0, d3.max(mapData.data)])
    .range([subSvg.attr("height") - padding, padding]);

  // 添加柱状图柱子
  subSvg.selectAll("rect.bar")
    .data(mapData.data)
    .enter()
    .append("rect")
    .attr("class", "bar")
    .attr("x", function(d, i) { return xScale(i); })
    .attr("y", function(d) { return yScale(d); })
    .attr("width", xScale.bandwidth())
    .attr("height", function(d) { return subSvg.attr("height") - padding - yScale(d); })
    .style("fill", "darkorange");

  return subSvg;
}

关键改动说明

  1. 修正函数语法:把错误的变量声明式函数改成标准function定义,统一变量名拼写,避免拼写错误
  2. 正确嵌套子SVG:子SVG直接添加到主SVG容器中,通过x和y属性定位到原矩形的位置,符合SVG的嵌套规则
  3. 实现切换效果:每次点击先检查是否已有子SVG,存在则删除并恢复原矩形状态,避免重复创建
  4. 传递子SVG容器:getGeneratedMap函数直接接收子SVG作为参数,在指定容器内绘制图表,不再依赖外部DOM元素
  5. 明确位置定位:给原矩形设置明确的x/y属性,确保子SVG能精准对齐到矩形位置

这样点击矩形后,就会在它的位置展开一个包含子图表的SVG,再次点击可以收起恢复原状。

内容的提问来源于stack exchange,提问作者Vaishali Chaudhari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:14:18