我正在尝试使用贝塞尔线将堆叠在一列中的大圆圈连接到附加到线性刻度上的较小圆圈。这是我的片段:
var margins = {top:100, bottom:300, left:100, right:100};
var height = 1300;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
var yScale = d3.scaleLinear()
.range([450,0])
.domain([-4,4]);
graphGroup.append('g')
.call(d3.axisRight(yScale).ticks(5))
.attr("transform", "translate(350,0)");
var circData = [
{'type':'bonds','growth':3.3},
{'type':'bond funds','growth':0},
{'type':'pstock','growth':-.4},
{'type':'pbonds','growth':.9},
{'type':'ploans','growth':0},
{'type':'debt','growth':.2},
{'type':'other','growth':-2.5},
];
var yScale2 = d3.scaleLinear()
.domain([0,6])
.range([420,30]);
graphGroup.selectAll(null)
.data(circData)
.enter()
.append('circle')
.attr('cx',250)
.attr('cy', function(d,i) {return yScale2(i)})
.attr('r', 20)
.on('click', function(d) {return console.log(this)})
.style('fill',"#003366");
var multiLinkData = [
{source: [250,30], target: [350,39.4]},
{source: [250,95], target: [350,225]},
{source: [250,160], target: [350,248]},
{source: [250,225], target: [350,174]},
{source: [250,290], target: [350,225]},
{source: [250,355], target: [350,213]},
{source: [250,420], target: [350,366]},
];
var link = d3.linkHorizontal();
graphGroup.selectAll(null)
.data(circData)
.enter()
.append('circle')
.attr('cx',350)
.attr('cy', function(d,i) {return yScale(d.growth)})
.attr('r', 7)
.on('click', function(d) {return console.log(this)})
.style('fill',"#003366");
d3.select(null)
.selectAll("path")
.data(multiLinkData)
.join("path")
.attr("d", link)
.attr("fill", "none")
.attr("stroke", "#d9d9d9");
<script src="https://d3js.org/d3.v5.min.js"></script>
正如我们所看到的,大圆圈和小圆圈是根据需要附加的,但是我尝试连接的贝塞尔线没有绘制。错误内容:
<块引用>未捕获的类型错误:.selectAll().data().join() 不是函数
然而,这几乎正是 this tutorial 安排流程的方式。
如何根据需要绘制贝塞尔线?作为奖励,我如何动态附加它们? (注意我硬编码了 multiLinkData
并煞费苦心地点击并在控制台日志中记录 x/y 位置)。
答案 0 :(得分:1)
您没有路径的容器:使用 d3.select(null).selectAll("path")
,您是在告诉 D3 将路径附加到 d3.select(null)
选择的元素,这毫无意义。
应该是:
graphGroup.selectAll("path")
//etc...
这是您的更改代码:
var margins = {top:100, bottom:300, left:100, right:100};
var height = 1300;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
var yScale = d3.scaleLinear()
.range([450,0])
.domain([-4,4]);
graphGroup.append('g')
.call(d3.axisRight(yScale).ticks(5))
.attr("transform", "translate(350,0)");
var circData = [
{'type':'bonds','growth':3.3},
{'type':'bond funds','growth':0},
{'type':'pstock','growth':-.4},
{'type':'pbonds','growth':.9},
{'type':'ploans','growth':0},
{'type':'debt','growth':.2},
{'type':'other','growth':-2.5},
];
var yScale2 = d3.scaleLinear()
.domain([0,6])
.range([420,30]);
graphGroup.selectAll(null)
.data(circData)
.enter()
.append('circle')
.attr('cx',250)
.attr('cy', function(d,i) {return yScale2(i)})
.attr('r', 20)
.on('click', function(d) {return console.log(this)})
.style('fill',"#003366");
var multiLinkData = [
{source: [250,30], target: [350,39.4]},
{source: [250,95], target: [350,225]},
{source: [250,160], target: [350,248]},
{source: [250,225], target: [350,174]},
{source: [250,290], target: [350,225]},
{source: [250,355], target: [350,213]},
{source: [250,420], target: [350,366]},
];
var link = d3.linkHorizontal();
graphGroup.selectAll(null)
.data(circData)
.enter()
.append('circle')
.attr('cx',350)
.attr('cy', function(d,i) {return yScale(d.growth)})
.attr('r', 7)
.on('click', function(d) {return console.log(this)})
.style('fill',"#003366");
graphGroup.selectAll("path")
.data(multiLinkData)
.join("path")
.attr("d", link)
.attr("fill", "none")
.attr("stroke", "#d9d9d9");
<script src="https://d3js.org/d3.v5.min.js"></script>