D3.js SVG标注旋转时背景矩形与文本bbox位置不匹配问题
问题根因
- 旋转中心不匹配:你给文本设置的变换规则是
先平移到标注中心点(cx, cy),再以该点为中心旋转alpha度,但给矩形设置的变换规则是先平移到(cx - 宽度/2, cy - 高度/2)再旋转,此时旋转中心是SVG坐标系原点(0,0),和文本的旋转中心不一致,导致错位。 - 角度计算错误:使用
Math.atan(dx/dy)计算角度时无法处理四个象限的方向,且会出现文本倒置的问题,应该使用Math.atan2(dy, dx)计算角度,再根据方向微调避免文本倒转。
修复后的ann_line函数代码
function ann_line(svg,ax,ay,bx,by,text) { var w = 10 var dx = bx - ax var dy = by - ay var l = Math.sqrt(dx*dx+dy*dy) dx /= l dy /= l var a1x = ax + w*dy var a1y = ay - w*dx var b1x = bx + w*dy var b1y = by - w*dx var path = ['M',a1x,a1y,'L',b1x,b1y] var line = svg.append('path') .attr('d',path.join(' ')) .attr('stroke','black') .attr('marker-start', 'url(#arrhead)') .attr('marker-end', 'url(#arrhead)'); var cx = (a1x + b1x)/2 var cy = (a1y + b1y)/2 // 修复角度计算:用atan2处理全象限,调整角度避免文本倒置 var alpha = Math.atan2(dy, dx) * 180 / Math.PI; if (alpha > 90 || alpha < -90) { alpha += 180; } const label = svg.append('text') .text(text) .attr('text-anchor', 'middle') .attr('alignment-baseline', 'middle') .attr('transform',`translate(${cx},${cy}) rotate(${alpha})`) const bb = label.node().getBBox(); svg.append('rect').lower() .attr('stroke','none') .style('fill', 'steelblue') // 修复变换规则:和文本保持一致先移到中心点,旋转后再偏移矩形到文本下方 .attr('transform',`translate(${cx},${cy}) rotate(${alpha}) translate(${-bb.width/2}, ${-bb.height/2})`) .attr('width', bb.width) .attr('height', bb.height) }
直接替换原有ann_line函数即可生效,修改后矩形会完美贴合文本边界框,不会出现错位问题,同时文本始终保持正向可读,不会出现倒置情况。
内容的提问来源于stack exchange,提问作者lucky1928
相关产品推荐
相关产品推荐

