d3.js - 了解将元素附加到 g 的箭头函数
d3.js - understand arrow function to append element to g
这个例子工作正常,但如果我将下面的行更改为箭头函数,它将不再工作:
好的版本:
.each(function() {g.append(() => this)})
错误箭头函数版本:
.each(d => {g.append(() => this)})
如何理解这两条线的区别?
tree_demo()
function tree_demo() {
var root = {
name: '/',
contents: [
{
name: 'AAAA',
contents: [
{ name: 'BBBB' },
{ name: 'CCCCCCCCCCCC' },
{ name: 'DDDD' },
{ name: 'EEEE' },
],
},
],
};
var width = 300
var height = 200
var margin = 20
var radius = 5
var treemap = d3.tree().size([height-margin*2,width-margin*2-70])
var nodes = treemap(d3.hierarchy(root,d => d.contents))
var links = treemap(nodes).links();
var layoutRoot = d3
.select("body")
.append('svg:svg')
.attr('width', width)
.attr('height', height)
.append('svg:g')
.attr('class', 'container')
.attr('transform', 'translate(' + margin + ',' + margin+')');
var diagonal = function link(d) {
var sx = d.source.y
var sy = d.source.x
var tx = d.target.y
var ty = d.target.x
return ['M',sx,sy,'C',(sx+tx)/2,sy,
(sx+tx)/2,ty,tx,ty].join(' ')
};
layoutRoot
.selectAll('path.link')
.data(links)
.enter()
.append('path')
.attr('class', 'link')
.attr('d', diagonal)
.attr('fill','none')
.attr('stroke','black')
var nodeGroup = layoutRoot
.selectAll('g.node')
.data(nodes)
.enter()
.append('g')
.attr('class', 'node')
.attr('transform', function(d) {
return 'translate(' + d.y + ',' + d.x + ')';
});
nodeGroup
.append('circle')
.attr('class', 'node-dot')
.attr('r', radius)
.attr('stroke','steelblue')
.attr('stroke-width',2)
.attr('fill','none')
nodeGroup
.append('text')
.attr('text-anchor', function(d) {
return d.children ? 'end' : 'start';
})
.attr('dx', function(d) {
var gap = 2 * radius;
return d.children ? -gap : gap;
})
.attr('dy', 3)
.text(function(d) {
return d.data.name;
});
var g = layoutRoot.append('g')
nodeGroup.filter((d,i) => i == 2 || i==3)
.each(function() {g.append(() => this)}) //work version
//.each(d => {g.append(() => this)}) //won't work
var border = 5
var bbox = g.node().getBBox()
layoutRoot.insert('rect','path.link')
.attr('stroke','black')
.attr('fill','steelblue')
.attr('fill-opacity',0.2)
.attr('x',bbox.x-border)
.attr('y',bbox.y-border)
.attr('rx',8)
.attr('ry',8)
.attr('width',bbox.width + 2*border)
.attr('height',bbox.height + 2*border)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
一般来说,你可以用 ES6 箭头函数 () =>
代替匿名 function() {...}
除了 你正在使用 this
.
第一个版本
.each(function() {g.append(() => this)})
this
指的是当前的 DOM 元素。
而在箭头函数中
.each(d => {g.append(() => this)})
this
引用封闭上下文。
如果您想在箭头函数中引用当前 DOM 元素,您必须执行以下操作:
.each((d, i, nodes) => {g.append(() => nodes[i])})
完整代码如下:
tree_demo()
function tree_demo() {
var root = {
name: '/',
contents: [
{
name: 'AAAA',
contents: [
{ name: 'BBBB' },
{ name: 'CCCCCCCCCCCC' },
{ name: 'DDDD' },
{ name: 'EEEE' },
],
},
],
};
var width = 300
var height = 200
var margin = 20
var radius = 5
var treemap = d3.tree().size([height-margin*2,width-margin*2-70])
var nodes = treemap(d3.hierarchy(root,d => d.contents))
var links = treemap(nodes).links();
var layoutRoot = d3
.select("body")
.append('svg:svg')
.attr('width', width)
.attr('height', height)
.append('svg:g')
.attr('class', 'container')
.attr('transform', 'translate(' + margin + ',' + margin+')');
var diagonal = function link(d) {
var sx = d.source.y
var sy = d.source.x
var tx = d.target.y
var ty = d.target.x
return ['M',sx,sy,'C',(sx+tx)/2,sy,
(sx+tx)/2,ty,tx,ty].join(' ')
};
layoutRoot
.selectAll('path.link')
.data(links)
.enter()
.append('path')
.attr('class', 'link')
.attr('d', diagonal)
.attr('fill','none')
.attr('stroke','black')
var nodeGroup = layoutRoot
.selectAll('g.node')
.data(nodes)
.enter()
.append('g')
.attr('class', 'node')
.attr('transform', function(d) {
return 'translate(' + d.y + ',' + d.x + ')';
});
nodeGroup
.append('circle')
.attr('class', 'node-dot')
.attr('r', radius)
.attr('stroke','steelblue')
.attr('stroke-width',2)
.attr('fill','none')
nodeGroup
.append('text')
.attr('text-anchor', function(d) {
return d.children ? 'end' : 'start';
})
.attr('dx', function(d) {
var gap = 2 * radius;
return d.children ? -gap : gap;
})
.attr('dy', 3)
.text(function(d) {
return d.data.name;
});
var g = layoutRoot.append('g')
nodeGroup.filter((d,i) => i == 2 || i==3)
// .each(function() {g.append(() => this)}) //work version
// .each(d => {g.append(() => this)}) //won't work
.each((d, i, nodes) => {g.append(() => nodes[i])}) //works
var border = 5
var bbox = g.node().getBBox()
layoutRoot.insert('rect','path.link')
.attr('stroke','black')
.attr('fill','steelblue')
.attr('fill-opacity',0.2)
.attr('x',bbox.x-border)
.attr('y',bbox.y-border)
.attr('rx',8)
.attr('ry',8)
.attr('width',bbox.width + 2*border)
.attr('height',bbox.height + 2*border)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
这个例子工作正常,但如果我将下面的行更改为箭头函数,它将不再工作:
好的版本:
.each(function() {g.append(() => this)})
错误箭头函数版本:
.each(d => {g.append(() => this)})
如何理解这两条线的区别?
tree_demo()
function tree_demo() {
var root = {
name: '/',
contents: [
{
name: 'AAAA',
contents: [
{ name: 'BBBB' },
{ name: 'CCCCCCCCCCCC' },
{ name: 'DDDD' },
{ name: 'EEEE' },
],
},
],
};
var width = 300
var height = 200
var margin = 20
var radius = 5
var treemap = d3.tree().size([height-margin*2,width-margin*2-70])
var nodes = treemap(d3.hierarchy(root,d => d.contents))
var links = treemap(nodes).links();
var layoutRoot = d3
.select("body")
.append('svg:svg')
.attr('width', width)
.attr('height', height)
.append('svg:g')
.attr('class', 'container')
.attr('transform', 'translate(' + margin + ',' + margin+')');
var diagonal = function link(d) {
var sx = d.source.y
var sy = d.source.x
var tx = d.target.y
var ty = d.target.x
return ['M',sx,sy,'C',(sx+tx)/2,sy,
(sx+tx)/2,ty,tx,ty].join(' ')
};
layoutRoot
.selectAll('path.link')
.data(links)
.enter()
.append('path')
.attr('class', 'link')
.attr('d', diagonal)
.attr('fill','none')
.attr('stroke','black')
var nodeGroup = layoutRoot
.selectAll('g.node')
.data(nodes)
.enter()
.append('g')
.attr('class', 'node')
.attr('transform', function(d) {
return 'translate(' + d.y + ',' + d.x + ')';
});
nodeGroup
.append('circle')
.attr('class', 'node-dot')
.attr('r', radius)
.attr('stroke','steelblue')
.attr('stroke-width',2)
.attr('fill','none')
nodeGroup
.append('text')
.attr('text-anchor', function(d) {
return d.children ? 'end' : 'start';
})
.attr('dx', function(d) {
var gap = 2 * radius;
return d.children ? -gap : gap;
})
.attr('dy', 3)
.text(function(d) {
return d.data.name;
});
var g = layoutRoot.append('g')
nodeGroup.filter((d,i) => i == 2 || i==3)
.each(function() {g.append(() => this)}) //work version
//.each(d => {g.append(() => this)}) //won't work
var border = 5
var bbox = g.node().getBBox()
layoutRoot.insert('rect','path.link')
.attr('stroke','black')
.attr('fill','steelblue')
.attr('fill-opacity',0.2)
.attr('x',bbox.x-border)
.attr('y',bbox.y-border)
.attr('rx',8)
.attr('ry',8)
.attr('width',bbox.width + 2*border)
.attr('height',bbox.height + 2*border)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
一般来说,你可以用 ES6 箭头函数 () =>
代替匿名 function() {...}
除了 你正在使用 this
.
第一个版本
.each(function() {g.append(() => this)})
this
指的是当前的 DOM 元素。
而在箭头函数中
.each(d => {g.append(() => this)})
this
引用封闭上下文。
如果您想在箭头函数中引用当前 DOM 元素,您必须执行以下操作:
.each((d, i, nodes) => {g.append(() => nodes[i])})
完整代码如下:
tree_demo()
function tree_demo() {
var root = {
name: '/',
contents: [
{
name: 'AAAA',
contents: [
{ name: 'BBBB' },
{ name: 'CCCCCCCCCCCC' },
{ name: 'DDDD' },
{ name: 'EEEE' },
],
},
],
};
var width = 300
var height = 200
var margin = 20
var radius = 5
var treemap = d3.tree().size([height-margin*2,width-margin*2-70])
var nodes = treemap(d3.hierarchy(root,d => d.contents))
var links = treemap(nodes).links();
var layoutRoot = d3
.select("body")
.append('svg:svg')
.attr('width', width)
.attr('height', height)
.append('svg:g')
.attr('class', 'container')
.attr('transform', 'translate(' + margin + ',' + margin+')');
var diagonal = function link(d) {
var sx = d.source.y
var sy = d.source.x
var tx = d.target.y
var ty = d.target.x
return ['M',sx,sy,'C',(sx+tx)/2,sy,
(sx+tx)/2,ty,tx,ty].join(' ')
};
layoutRoot
.selectAll('path.link')
.data(links)
.enter()
.append('path')
.attr('class', 'link')
.attr('d', diagonal)
.attr('fill','none')
.attr('stroke','black')
var nodeGroup = layoutRoot
.selectAll('g.node')
.data(nodes)
.enter()
.append('g')
.attr('class', 'node')
.attr('transform', function(d) {
return 'translate(' + d.y + ',' + d.x + ')';
});
nodeGroup
.append('circle')
.attr('class', 'node-dot')
.attr('r', radius)
.attr('stroke','steelblue')
.attr('stroke-width',2)
.attr('fill','none')
nodeGroup
.append('text')
.attr('text-anchor', function(d) {
return d.children ? 'end' : 'start';
})
.attr('dx', function(d) {
var gap = 2 * radius;
return d.children ? -gap : gap;
})
.attr('dy', 3)
.text(function(d) {
return d.data.name;
});
var g = layoutRoot.append('g')
nodeGroup.filter((d,i) => i == 2 || i==3)
// .each(function() {g.append(() => this)}) //work version
// .each(d => {g.append(() => this)}) //won't work
.each((d, i, nodes) => {g.append(() => nodes[i])}) //works
var border = 5
var bbox = g.node().getBBox()
layoutRoot.insert('rect','path.link')
.attr('stroke','black')
.attr('fill','steelblue')
.attr('fill-opacity',0.2)
.attr('x',bbox.x-border)
.attr('y',bbox.y-border)
.attr('rx',8)
.attr('ry',8)
.attr('width',bbox.width + 2*border)
.attr('height',bbox.height + 2*border)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>