如何使用D3 JS在SVG区域绘制DIV等HTML元素实现散点图
D3 实现SVG内HTML元素散点图(支持动态更新)
核心注意点:SVG本身是矢量图形命名空间,无法直接嵌套普通DIV/HTML元素,需要借助SVG原生的<foreignObject>标签作为HTML容器,它完全遵循SVG坐标系定位,内部可渲染任意标准HTML元素。
完整可运行代码
<!DOCTYPE html> <html> <head> <style> /* 散点DIV基础样式 */ .scatter-dot { width: 60px; height: 30px; border-radius: 4px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); transform: translate(-50%, -50%); /* 让DIV中心对准散点坐标,和circle定位逻辑对齐 */ } svg { border: 1px solid #eee; margin: 20px; } </style> <script src="https://d3js.org/d3.v7.min.js"></script> </head> <body> <svg id="scatter-chart" width="800" height="500"></svg> <script> // 初始化画布参数 const svg = d3.select('#scatter-chart') const width = 800, height = 500, margin = 40 // 定义坐标比例尺,把数据值映射到画布像素位置 const xScale = d3.scaleLinear().domain([0, 100]).range([margin, width - margin]) const yScale = d3.scaleLinear().domain([0, 100]).range([height - margin, margin]) // 渲染函数,接收数据完成绘制/更新 function renderScatter(data) { // 绑定数据,创建foreignObject作为HTML容器 const dots = svg.selectAll('.dot-container') .data(data, d => d.id) // 用id作为数据唯一标识,提升更新性能 .join( // 新增元素逻辑 enter => { const fo = enter.append('foreignObject') .attr('class', 'dot-container') .attr('width', 60) .attr('height', 30) // 在foreignObject内部添加DIV fo.append('xhtml:div') .attr('class', 'scatter-dot') return fo }, // 已有元素更新逻辑 update => update, // 多余元素删除逻辑 exit => exit.remove() ) // 更新所有点的位置和DIV内容 dots.attr('x', d => xScale(d.x)) .attr('y', d => yScale(d.y)) .select('.scatter-dot') .style('background', d => d.color) .text(d => d.content) } // 生成模拟数据 function generateData() { return d3.range(8).map(i => ({ id: i, x: Math.random()*100, y: Math.random()*100, content: `点${i+1}`, color: d3.schemeCategory10[i] })) } // 首次渲染 renderScatter(generateData()) // 动态更新演示:每2秒刷新数据重新渲染 setInterval(() => { const newData = generateData().map(d => ({ ...d, content: `值:${Math.round(d.x)}`, x: Math.random()*100, y: Math.random()*100 })) renderScatter(newData) }, 2000) </script> </body> </html>
关键说明
- 定位逻辑:
<foreignObject>的x/y属性和普通SVG图形(圆形、矩形)完全一致,直接传入比例尺映射后的坐标即可。CSS中给DIV加的偏移样式是为了让元素中心对准坐标点,避免出现左上角对齐坐标的偏移问题。 - 内容扩展:内部的DIV支持所有HTML/CSS能力,可以替换成图片、按钮、表单、富文本等任意内容,不受SVG原生图形元素的能力限制。
- 动态更新:使用D3标准的
data().join()模式,只要把新数据传入渲染函数,就会自动完成元素新增、位置更新、内容更新、冗余元素删除,不需要手动清空画布重绘。
踩坑提示:不要直接把DIV等HTML元素append到
<svg>标签下,SVG属于独立的XML命名空间,直接嵌套HTML元素不会被浏览器解析渲染,必须放在<foreignObject>标签内部才能正常显示。
内容的提问来源于stack exchange,提问作者Rajdip
相关产品推荐
相关产品推荐

