D3.js绘制线段:一端绑定g元素另一端绑定SVG的实现方法
D3.js 线段两端绑定不同坐标系实现方案
SVG 元素本身只能继承单一父级坐标系,无法直接让单个 line 元素的两个端点绑定不同坐标系,我们可以通过坐标动态转换的方式实现需求:
实现步骤
- 调整线段挂载节点
不要将line挂载在g元素下,直接挂载到SVG根节点上。此时line的坐标默认使用SVG根坐标系,将x2/y2直接设置为指向右侧div的固定值即可,这部分坐标不会随地图拖拽变化。 - 动态计算地理端点的实时坐标
加利福尼亚等固定地理位置在g元素的原始坐标系下的坐标是固定的,只需在每次地图拖拽/缩放触发时,将这个固定坐标通过g元素当前的变换矩阵,转换为SVG根坐标系下的坐标,赋值给line的x1/y1即可。
代码示例
配合d3.zoom实现(推荐)
// 初始化线段,挂载到svg根节点 const line = svg.append('line') .style("stroke", "lightgreen") .style("stroke-width", 10) // x2、y2设为根坐标系下指向右侧div的固定值,无需后续修改 .attr("x2", 200) .attr("y2", 400); // 加州在g原始坐标系下的固定坐标,可根据你的地理投影计算得到 const caliOriginalPoint = [960, 200]; // 绑定zoom事件 svg.call(d3.zoom() .on('zoom', (event) => { // 给地图容器g应用当前的缩放平移变换 g.attr('transform', event.transform); // 将g内的地理原始坐标转换为svg根坐标系的实时坐标 const [x1, y1] = event.transform.apply(caliOriginalPoint); // 更新线段的地理端坐标 line.attr('x1', x1).attr('y1', y1); }) )
原生SVG API实现(不依赖d3.zoom)
如果没有用d3.zoom管理地图变换,可以用SVG原生的矩阵转换方法计算坐标:
// 每次地图变换完成后执行以下逻辑更新线段 const svgNode = svg.node(); const gNode = g.node(); const point = svgNode.createSVGPoint(); // 填入g坐标系下的地理固定坐标 point.x = 960; point.y = 200; // 通过g的当前变换矩阵转成根坐标系坐标 const rootPoint = point.matrixTransform(gNode.getCTM()); line.attr('x1', rootPoint.x).attr('y1', rootPoint.y);
内容的提问来源于stack exchange,提问作者thedoomer1000
相关产品推荐
相关产品推荐

