d3.js - 将背景矩形添加到元素组
d3.js - add background rect to elements group
下面的代码绘制了 4 个组元素,我想根据组的 bbox 大小在每个组上绘制背景矩形。我尝试了下面的代码但没有用!
var margin = {top:40,left:10,bottom:10,right:10}
var svg = d3.select('body').append('svg')
.attr('width',600)
.attr('height',600)
.attr('viewBox',[0,0,300,300])
.attr('transform',`translate(${margin.left},${margin.top})`)
add_defs(svg)
var color = d3.scaleOrdinal(d3.schemeCategory10);
var data = [
{name:'data1',
x:20,
y:40,
contents:[
{name:'Group 1'},
{name:'AAAA'},
{name:'BBBB'},
{name:'CCCC'},
{name:'DDDD'},
{name:'EEEE'},
{name:'FFFF'}
]
},
{name:'data2',
x:110,
y:10,
contents:[
{name:'Group2'},
{name:'GGGG'},
{name:'HHHH'}
]
},
{name:'data3',
x:110,
y:50,
contents:[
{name:'Group3'},
{name:'IIII'},
{name:'JJJJ'}
]
},
{name:'data4',
x:110,
y:90,
contents:[
{name:'Group4'},
{name:'KKKK'},
{name:'LLLL'},
{name:'MMMM'},
{name:'NNNN'},
]
},
]
add_box(data)
function add_box(data) {
var groups = svg.selectAll('.groups')
.data(data).enter()
.append('g')
var g1 = groups.selectAll('nodes')
.data(d => d.contents)
.enter().append('g')
var w = 70
var fontsize = 5
var text = g1.append('text')
.attr('class','modname')
.attr('text-anchor','start')
.attr('font-size',fontsize)
.attr("dominant-baseline", "central")
.attr('x',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return p.x
})
.attr('y',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return i*10 + p.y
})
.text(d => d.name)
.each( (d,i,n) => {
if (n[i] instanceof SVGGraphicsElement) {
var bbox = n[i].getBBox();
bbox.x -= 5
bbox.width += 12
bbox.height += 2
if (bbox.width < w) bbox.width = w
d.bbox = bbox
d.xs = d.bbox.x
d.ys = d.bbox.y + d.bbox.height/2
d.xe = d.xs + d.bbox.width;
d.ye = d.ys
}
})
var rects = g1.insert('rect','text')
.attr('id','modrect')
.attr('x',(d,i) => {
return d.bbox.x
})
.attr('y',(d,i) => {
return d.bbox.y
})
.attr('width',(d,i) => {
return d.bbox.width
})
.attr('height',(d,i) => {
return d.bbox.height
})
.attr('fill',(d,i) => {
if (i == 0) return 'none'
return color(i)})
.attr('fill-opacity',.3)
var e = 2
var g1bbox = g1.node().getBBox()
g1bbox.x -= e
g1bbox.y -= e
g1bbox.width += 2*e
g1bbox.height += 2*e
g1.insert('rect','rect')
.attr('x',g1bbox.x)
.attr('y',g1bbox.y)
.attr('width',g1bbox.width)
.attr('height',g1bbox.height)
.attr('fill',color(0))
.attr('fill-opacity',.3)
.attr('stroke','grey')
return
}
function add_defs(svg) {
var w = 3
var h = 2
var m = 0
var lc = 'black'
var path = ['M',2+m,2+h/2,'L',2,2,2+w,2+h/2,2,2+h,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arr1')
.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('fill',lc)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
将矩形添加到组中!
groups.each(function(d) {
var bbox = d3.select(this).node().getBBox()
var m = 4
bbox.x -= m
bbox.y -= m
bbox.width += 2*m
bbox.height += 2*m
d.bbox = bbox
})
.append('rect').lower()
.attr('stroke','grey')
.attr('fill',color(0))
.attr('fill-opacity',0.3)
.attr('x',d => d.bbox.x)
.attr('y',d => d.bbox.y)
.attr('width',d => d.bbox.width)
.attr('height',d => d.bbox.height)
console.clear()
var margin = {top:40,left:10,bottom:10,right:10}
var svg = d3.select('body').append('svg')
.attr('width',600)
.attr('height',600)
.attr('viewBox',[0,0,300,300])
.attr('transform',`translate(${margin.left},${margin.top})`)
add_defs(svg)
var color = d3.scaleOrdinal(d3.schemeCategory10);
var data = [
{name:'data1',
x:20,
y:40,
contents:[
{name:'Group 1',group:1},
{name:'AAAA'},
{name:'BBBB'},
{name:'CCCC'},
{name:'DDDD'},
{name:'EEEE'},
{name:'FFFF'}
]
},
{name:'data2',
x:110,
y:10,
contents:[
{name:'Group2'},
{name:'GGGG'},
{name:'HHHH'}
]
},
{name:'data3',
x:110,
y:50,
contents:[
{name:'Group3'},
{name:'IIII'},
{name:'JJJJ'}
]
},
{name:'data4',
x:110,
y:90,
contents:[
{name:'Group4'},
{name:'KKKK'},
{name:'LLLL'},
{name:'MMMM'},
{name:'NNNN'},
]
},
]
add_box(data)
function add_box(data) {
var groups = svg.selectAll('.groups')
.data(data).enter()
.append('g')
var g1 = groups.selectAll('nodes')
.data(d => d.contents)
.enter().append('g')
var w = 70
var fontsize = 5
var text = g1.append('text')
.attr('class','modname')
.attr('text-anchor','start')
.attr('font-size',fontsize)
.attr("dominant-baseline", "central")
.attr('x',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return p.x
})
.attr('y',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return i*10 + p.y
})
.text(d => d.name)
.each( (d,i,n) => {
if (n[i] instanceof SVGGraphicsElement) {
var bbox = n[i].getBBox();
bbox.x -= 5
bbox.width += 12
bbox.height += 2
if (bbox.width < w) bbox.width = w
d.bbox = bbox
d.xs = d.bbox.x
d.ys = d.bbox.y + d.bbox.height/2
d.xe = d.xs + d.bbox.width;
d.ye = d.ys
}
})
var rects = g1.insert('rect','text')
.attr('id','modrect')
.attr('x',(d,i) => {
return d.bbox.x
})
.attr('y',(d,i) => {
return d.bbox.y
})
.attr('width',(d,i) => {
return d.bbox.width
})
.attr('height',(d,i) => {
return d.bbox.height
})
.attr('fill',(d,i) => {
if (i == 0) return 'none'
return color(i)})
.attr('fill-opacity',.3)
groups.each(function(d) {
var bbox = d3.select(this).node().getBBox()
var m = 4
bbox.x -= m
bbox.y -= m
bbox.width += 2*m
bbox.height += 2*m
d.bbox = bbox
})
.append('rect').lower()
.attr('stroke','grey')
.attr('fill',color(0))
.attr('fill-opacity',0.3)
.attr('x',d => d.bbox.x)
.attr('y',d => d.bbox.y)
.attr('width',d => d.bbox.width)
.attr('height',d => d.bbox.height)
return
}
function add_defs(svg) {
var w = 3
var h = 2
var m = 0
var lc = 'black'
var path = ['M',2+m,2+h/2,'L',2,2,2+w,2+h/2,2,2+h,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arr1')
.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('fill',lc)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
下面的代码绘制了 4 个组元素,我想根据组的 bbox 大小在每个组上绘制背景矩形。我尝试了下面的代码但没有用!
var margin = {top:40,left:10,bottom:10,right:10}
var svg = d3.select('body').append('svg')
.attr('width',600)
.attr('height',600)
.attr('viewBox',[0,0,300,300])
.attr('transform',`translate(${margin.left},${margin.top})`)
add_defs(svg)
var color = d3.scaleOrdinal(d3.schemeCategory10);
var data = [
{name:'data1',
x:20,
y:40,
contents:[
{name:'Group 1'},
{name:'AAAA'},
{name:'BBBB'},
{name:'CCCC'},
{name:'DDDD'},
{name:'EEEE'},
{name:'FFFF'}
]
},
{name:'data2',
x:110,
y:10,
contents:[
{name:'Group2'},
{name:'GGGG'},
{name:'HHHH'}
]
},
{name:'data3',
x:110,
y:50,
contents:[
{name:'Group3'},
{name:'IIII'},
{name:'JJJJ'}
]
},
{name:'data4',
x:110,
y:90,
contents:[
{name:'Group4'},
{name:'KKKK'},
{name:'LLLL'},
{name:'MMMM'},
{name:'NNNN'},
]
},
]
add_box(data)
function add_box(data) {
var groups = svg.selectAll('.groups')
.data(data).enter()
.append('g')
var g1 = groups.selectAll('nodes')
.data(d => d.contents)
.enter().append('g')
var w = 70
var fontsize = 5
var text = g1.append('text')
.attr('class','modname')
.attr('text-anchor','start')
.attr('font-size',fontsize)
.attr("dominant-baseline", "central")
.attr('x',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return p.x
})
.attr('y',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return i*10 + p.y
})
.text(d => d.name)
.each( (d,i,n) => {
if (n[i] instanceof SVGGraphicsElement) {
var bbox = n[i].getBBox();
bbox.x -= 5
bbox.width += 12
bbox.height += 2
if (bbox.width < w) bbox.width = w
d.bbox = bbox
d.xs = d.bbox.x
d.ys = d.bbox.y + d.bbox.height/2
d.xe = d.xs + d.bbox.width;
d.ye = d.ys
}
})
var rects = g1.insert('rect','text')
.attr('id','modrect')
.attr('x',(d,i) => {
return d.bbox.x
})
.attr('y',(d,i) => {
return d.bbox.y
})
.attr('width',(d,i) => {
return d.bbox.width
})
.attr('height',(d,i) => {
return d.bbox.height
})
.attr('fill',(d,i) => {
if (i == 0) return 'none'
return color(i)})
.attr('fill-opacity',.3)
var e = 2
var g1bbox = g1.node().getBBox()
g1bbox.x -= e
g1bbox.y -= e
g1bbox.width += 2*e
g1bbox.height += 2*e
g1.insert('rect','rect')
.attr('x',g1bbox.x)
.attr('y',g1bbox.y)
.attr('width',g1bbox.width)
.attr('height',g1bbox.height)
.attr('fill',color(0))
.attr('fill-opacity',.3)
.attr('stroke','grey')
return
}
function add_defs(svg) {
var w = 3
var h = 2
var m = 0
var lc = 'black'
var path = ['M',2+m,2+h/2,'L',2,2,2+w,2+h/2,2,2+h,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arr1')
.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('fill',lc)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
将矩形添加到组中!
groups.each(function(d) {
var bbox = d3.select(this).node().getBBox()
var m = 4
bbox.x -= m
bbox.y -= m
bbox.width += 2*m
bbox.height += 2*m
d.bbox = bbox
})
.append('rect').lower()
.attr('stroke','grey')
.attr('fill',color(0))
.attr('fill-opacity',0.3)
.attr('x',d => d.bbox.x)
.attr('y',d => d.bbox.y)
.attr('width',d => d.bbox.width)
.attr('height',d => d.bbox.height)
console.clear()
var margin = {top:40,left:10,bottom:10,right:10}
var svg = d3.select('body').append('svg')
.attr('width',600)
.attr('height',600)
.attr('viewBox',[0,0,300,300])
.attr('transform',`translate(${margin.left},${margin.top})`)
add_defs(svg)
var color = d3.scaleOrdinal(d3.schemeCategory10);
var data = [
{name:'data1',
x:20,
y:40,
contents:[
{name:'Group 1',group:1},
{name:'AAAA'},
{name:'BBBB'},
{name:'CCCC'},
{name:'DDDD'},
{name:'EEEE'},
{name:'FFFF'}
]
},
{name:'data2',
x:110,
y:10,
contents:[
{name:'Group2'},
{name:'GGGG'},
{name:'HHHH'}
]
},
{name:'data3',
x:110,
y:50,
contents:[
{name:'Group3'},
{name:'IIII'},
{name:'JJJJ'}
]
},
{name:'data4',
x:110,
y:90,
contents:[
{name:'Group4'},
{name:'KKKK'},
{name:'LLLL'},
{name:'MMMM'},
{name:'NNNN'},
]
},
]
add_box(data)
function add_box(data) {
var groups = svg.selectAll('.groups')
.data(data).enter()
.append('g')
var g1 = groups.selectAll('nodes')
.data(d => d.contents)
.enter().append('g')
var w = 70
var fontsize = 5
var text = g1.append('text')
.attr('class','modname')
.attr('text-anchor','start')
.attr('font-size',fontsize)
.attr("dominant-baseline", "central")
.attr('x',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return p.x
})
.attr('y',(d,i,n) => {
var p = d3.select(n[i].parentNode.parentNode).datum()
return i*10 + p.y
})
.text(d => d.name)
.each( (d,i,n) => {
if (n[i] instanceof SVGGraphicsElement) {
var bbox = n[i].getBBox();
bbox.x -= 5
bbox.width += 12
bbox.height += 2
if (bbox.width < w) bbox.width = w
d.bbox = bbox
d.xs = d.bbox.x
d.ys = d.bbox.y + d.bbox.height/2
d.xe = d.xs + d.bbox.width;
d.ye = d.ys
}
})
var rects = g1.insert('rect','text')
.attr('id','modrect')
.attr('x',(d,i) => {
return d.bbox.x
})
.attr('y',(d,i) => {
return d.bbox.y
})
.attr('width',(d,i) => {
return d.bbox.width
})
.attr('height',(d,i) => {
return d.bbox.height
})
.attr('fill',(d,i) => {
if (i == 0) return 'none'
return color(i)})
.attr('fill-opacity',.3)
groups.each(function(d) {
var bbox = d3.select(this).node().getBBox()
var m = 4
bbox.x -= m
bbox.y -= m
bbox.width += 2*m
bbox.height += 2*m
d.bbox = bbox
})
.append('rect').lower()
.attr('stroke','grey')
.attr('fill',color(0))
.attr('fill-opacity',0.3)
.attr('x',d => d.bbox.x)
.attr('y',d => d.bbox.y)
.attr('width',d => d.bbox.width)
.attr('height',d => d.bbox.height)
return
}
function add_defs(svg) {
var w = 3
var h = 2
var m = 0
var lc = 'black'
var path = ['M',2+m,2+h/2,'L',2,2,2+w,2+h/2,2,2+h,'z']
svg
.append('defs')
.append('marker')
.attr('id', 'arr1')
.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('fill',lc)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>