旋转的矩形与文本框不匹配
Rotated rectangle not match text bbox
我尝试旋转文本和背景矩形来注释两点。但是旋转后,背景位置与文本框不匹配。
console.clear()
var svg = d3.select('body')
.append('svg')
add_defs(svg)
var g = svg.append('g')
var data = [[0,0],[100,100]]
var nodes = g.selectAll('.circle')
.data(data)
.join('circle')
.attr('cx',d => d[0])
.attr('cy',d => d[1])
.attr('r',2)
.attr('stroke','none')
.attr('fill','red')
ann_line(svg,data[0][0],data[0][1],data[1][0],data[1][1],"hello")
adjust_view(svg)
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 a2x = ax + 2*w*dy
var a2y = ay - 2*w*dx
var b1x = bx + w*dy
var b1y = by - w*dx
var b2x = bx + 2*w*dy
var b2y = by - 2*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
var alpha = Math.atan(dx/dy)/Math.PI*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-bb.width/2},${cy-bb.height/2}) rotate(${alpha})`)
.attr('width', bb.width)
.attr('height', bb.height)
}
function renderTextInCenterOfLine(line, text) {
const from = parseInt(line.attr('x1'));
const to = parseInt(line.attr('x2'));
const y = parseInt(line.attr('y1'));
const svg = d3.select('svg');
const textBackground = svg.append('rect')
const textElement = svg.append('text')
.text(text)
.attr('x', (from + to) / 2)
.attr('y', y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'central');
const box = textElement.node().getBBox();
const width = box.width + 50; //
const height = box.height + 20;
textBackground
.attr('x', (from + to - width) / 2)
.attr('y', y - height / 2)
.attr('width', width)
.attr('height', height)
.style('fill', 'white')
}
function add_defs(svg) {
var lw = 1
var w = 6
var h = 12
var m = 2
var lc = 'black'
var path = ['M',2+w,2,'L',2+w,2+h,'M',2+m,2+h/2,'L',2,2+h/4,2+w-lw,2+h/2,2,2+3*h/4,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arrhead')
.attr('viewBox', [0, 0, w+4, h+4])
.attr('refX', w+1)
.attr('refY', 2+h/2)
.attr('markerWidth', w+4)
.attr('markerHeight', h+4)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d',path.join(' '))
.attr('stroke', lc)
.attr('stroke-width',lw)
.attr('fill',lc)
.attr('stroke-miterlimit', 10)
}
function adjust_view(svg) {
var bbox = svg.node().getBBox()//getBoundingClientRect()
svg.attr('width',600)
.attr('height',400)
.attr('viewBox',[bbox.x,bbox.y,bbox.width,bbox.height])
.style('border','2px solid red')
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
如果您想围绕其中心旋转元素,请计算该点 (x,y
) 并将这些坐标放入 rotate
方法中:
rotate(${alpha} ${bb.width/2} ${bb.height/2})`
这里是你的代码有那个变化:
console.clear()
var svg = d3.select('body')
.append('svg')
add_defs(svg)
var g = svg.append('g')
var data = [
[0, 0],
[100, 100]
]
var nodes = g.selectAll('.circle')
.data(data)
.join('circle')
.attr('cx', d => d[0])
.attr('cy', d => d[1])
.attr('r', 2)
.attr('stroke', 'none')
.attr('fill', 'red')
ann_line(svg, data[0][0], data[0][1], data[1][0], data[1][1], "hello")
adjust_view(svg)
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 a2x = ax + 2 * w * dy
var a2y = ay - 2 * w * dx
var b1x = bx + w * dy
var b1y = by - w * dx
var b2x = bx + 2 * w * dy
var b2y = by - 2 * 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
var alpha = Math.atan(dx / dy) / Math.PI * 180
const rect = svg.append('rect');
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();
rect.attr('stroke', 'none')
.style('fill', 'steelblue')
.attr('transform', `translate(${cx-bb.width/2},${cy-bb.height/2}) rotate(${alpha} ${bb.width/2} ${bb.height/2})`)
.attr('width', bb.width)
.attr('height', bb.height)
}
function renderTextInCenterOfLine(line, text) {
const from = parseInt(line.attr('x1'));
const to = parseInt(line.attr('x2'));
const y = parseInt(line.attr('y1'));
const svg = d3.select('svg');
const textBackground = svg.append('rect')
const textElement = svg.append('text')
.text(text)
.attr('x', (from + to) / 2)
.attr('y', y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'central');
const box = textElement.node().getBBox();
const width = box.width + 50; //
const height = box.height + 20;
textBackground
.attr('x', (from + to - width) / 2)
.attr('y', y - height / 2)
.attr('width', width)
.attr('height', height)
.style('fill', 'white')
}
function add_defs(svg) {
var lw = 1
var w = 6
var h = 12
var m = 2
var lc = 'black'
var path = ['M', 2 + w, 2, 'L', 2 + w, 2 + h, 'M', 2 + m, 2 + h / 2, 'L', 2, 2 + h / 4, 2 + w - lw, 2 + h / 2, 2, 2 + 3 * h / 4, 'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arrhead')
.attr('viewBox', [0, 0, w + 4, h + 4])
.attr('refX', w + 1)
.attr('refY', 2 + h / 2)
.attr('markerWidth', w + 4)
.attr('markerHeight', h + 4)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d', path.join(' '))
.attr('stroke', lc)
.attr('stroke-width', lw)
.attr('fill', lc)
.attr('stroke-miterlimit', 10)
}
function adjust_view(svg) {
var bbox = svg.node().getBBox() //getBoundingClientRect()
svg.attr('width', 600)
.attr('height', 400)
.attr('viewBox', [bbox.x, bbox.y, bbox.width, bbox.height])
.style('border', '2px solid red')
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
我尝试旋转文本和背景矩形来注释两点。但是旋转后,背景位置与文本框不匹配。
console.clear()
var svg = d3.select('body')
.append('svg')
add_defs(svg)
var g = svg.append('g')
var data = [[0,0],[100,100]]
var nodes = g.selectAll('.circle')
.data(data)
.join('circle')
.attr('cx',d => d[0])
.attr('cy',d => d[1])
.attr('r',2)
.attr('stroke','none')
.attr('fill','red')
ann_line(svg,data[0][0],data[0][1],data[1][0],data[1][1],"hello")
adjust_view(svg)
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 a2x = ax + 2*w*dy
var a2y = ay - 2*w*dx
var b1x = bx + w*dy
var b1y = by - w*dx
var b2x = bx + 2*w*dy
var b2y = by - 2*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
var alpha = Math.atan(dx/dy)/Math.PI*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-bb.width/2},${cy-bb.height/2}) rotate(${alpha})`)
.attr('width', bb.width)
.attr('height', bb.height)
}
function renderTextInCenterOfLine(line, text) {
const from = parseInt(line.attr('x1'));
const to = parseInt(line.attr('x2'));
const y = parseInt(line.attr('y1'));
const svg = d3.select('svg');
const textBackground = svg.append('rect')
const textElement = svg.append('text')
.text(text)
.attr('x', (from + to) / 2)
.attr('y', y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'central');
const box = textElement.node().getBBox();
const width = box.width + 50; //
const height = box.height + 20;
textBackground
.attr('x', (from + to - width) / 2)
.attr('y', y - height / 2)
.attr('width', width)
.attr('height', height)
.style('fill', 'white')
}
function add_defs(svg) {
var lw = 1
var w = 6
var h = 12
var m = 2
var lc = 'black'
var path = ['M',2+w,2,'L',2+w,2+h,'M',2+m,2+h/2,'L',2,2+h/4,2+w-lw,2+h/2,2,2+3*h/4,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arrhead')
.attr('viewBox', [0, 0, w+4, h+4])
.attr('refX', w+1)
.attr('refY', 2+h/2)
.attr('markerWidth', w+4)
.attr('markerHeight', h+4)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d',path.join(' '))
.attr('stroke', lc)
.attr('stroke-width',lw)
.attr('fill',lc)
.attr('stroke-miterlimit', 10)
}
function adjust_view(svg) {
var bbox = svg.node().getBBox()//getBoundingClientRect()
svg.attr('width',600)
.attr('height',400)
.attr('viewBox',[bbox.x,bbox.y,bbox.width,bbox.height])
.style('border','2px solid red')
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
如果您想围绕其中心旋转元素,请计算该点 (x,y
) 并将这些坐标放入 rotate
方法中:
rotate(${alpha} ${bb.width/2} ${bb.height/2})`
这里是你的代码有那个变化:
console.clear()
var svg = d3.select('body')
.append('svg')
add_defs(svg)
var g = svg.append('g')
var data = [
[0, 0],
[100, 100]
]
var nodes = g.selectAll('.circle')
.data(data)
.join('circle')
.attr('cx', d => d[0])
.attr('cy', d => d[1])
.attr('r', 2)
.attr('stroke', 'none')
.attr('fill', 'red')
ann_line(svg, data[0][0], data[0][1], data[1][0], data[1][1], "hello")
adjust_view(svg)
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 a2x = ax + 2 * w * dy
var a2y = ay - 2 * w * dx
var b1x = bx + w * dy
var b1y = by - w * dx
var b2x = bx + 2 * w * dy
var b2y = by - 2 * 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
var alpha = Math.atan(dx / dy) / Math.PI * 180
const rect = svg.append('rect');
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();
rect.attr('stroke', 'none')
.style('fill', 'steelblue')
.attr('transform', `translate(${cx-bb.width/2},${cy-bb.height/2}) rotate(${alpha} ${bb.width/2} ${bb.height/2})`)
.attr('width', bb.width)
.attr('height', bb.height)
}
function renderTextInCenterOfLine(line, text) {
const from = parseInt(line.attr('x1'));
const to = parseInt(line.attr('x2'));
const y = parseInt(line.attr('y1'));
const svg = d3.select('svg');
const textBackground = svg.append('rect')
const textElement = svg.append('text')
.text(text)
.attr('x', (from + to) / 2)
.attr('y', y)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'central');
const box = textElement.node().getBBox();
const width = box.width + 50; //
const height = box.height + 20;
textBackground
.attr('x', (from + to - width) / 2)
.attr('y', y - height / 2)
.attr('width', width)
.attr('height', height)
.style('fill', 'white')
}
function add_defs(svg) {
var lw = 1
var w = 6
var h = 12
var m = 2
var lc = 'black'
var path = ['M', 2 + w, 2, 'L', 2 + w, 2 + h, 'M', 2 + m, 2 + h / 2, 'L', 2, 2 + h / 4, 2 + w - lw, 2 + h / 2, 2, 2 + 3 * h / 4, 'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arrhead')
.attr('viewBox', [0, 0, w + 4, h + 4])
.attr('refX', w + 1)
.attr('refY', 2 + h / 2)
.attr('markerWidth', w + 4)
.attr('markerHeight', h + 4)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d', path.join(' '))
.attr('stroke', lc)
.attr('stroke-width', lw)
.attr('fill', lc)
.attr('stroke-miterlimit', 10)
}
function adjust_view(svg) {
var bbox = svg.node().getBBox() //getBoundingClientRect()
svg.attr('width', 600)
.attr('height', 400)
.attr('viewBox', [bbox.x, bbox.y, bbox.width, bbox.height])
.style('border', '2px solid red')
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>