d3.js 存储从力模拟中随意附加的圆的像素坐标
d3.js store pixel coordinates of circles appended haphazardly from force simulation
我有一个简化的视觉效果,我试图从一堆小圆圈(右侧)到大圆圈(左侧)绘制贝塞尔线。正在进行的片段:
var margins = {top:100, bottom:300, left:100, right:100};
var height = 600;
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 data = d3.range(200).map(function(v) {return {name: v.toString()+'_movie', top:false, link:'2019'} });
data.forEach(function(d, i) {
d.x = 900;
//d.y = 100;
d.y = 200
});
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) {
return 900;
}).strength(0.4))
.force("y", d3.forceY(function(d) {
//return 100;
return 200;
}).strength(0.1))
.force("collide", d3.forceCollide(4))
.stop();
simulation.tick(75);
console.log(data)
var circles = graphGroup.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", function(d) {
return 2;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.style('fill', "#003366")
.on('click', function(d) {
return console.log(d3.select(this).datum());
});
var topData = [
{year:'2019', top:true}
];
graphGroup.selectAll(null)
.data(topData)
.enter()
.append('circle')
.attr('cx', 200)
.attr('cy', 200)
.attr('r', 20)
.style('fill', "#003366");
var topCircles = d3.selectAll('circle').filter(function(d) {return d.top == true}).data();
var bottomCircles = d3.selectAll('circle').filter(function(d) {return d.top == false}).data();
console.log(topCircles)
var topLinks = topCircles.map(function(d,i) {
return {source: [200, 200], link:d.year}
});
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], link:d.year}
});
var multiLinkData = topLinks.map(t1 => ({...t1, ...bottomLinks.find(t2 => t2.link === t1.link)}));
console.log(multiLinkData)
var link = d3.linkHorizontal();
graphGroup.selectAll(null)
.data(multiLinkData)
.enter()
.append('path')
//.join("path")
.attr("d", link)
.attr("fill", "none")
//.style('stroke', function(d) {return colorMap[d.applied]})
.attr("stroke", "#d9d9d9");
<script src="https://d3js.org/d3.v5.min.js"></script>
因此 none 行已附加;错误读取无法读取此行未定义的 cx
:
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], series:d.name}
});
但我记得,这是检索 svgs 像素坐标的唯一方法。由于它们是从群体模拟中附加的,因此无法预先计算每个圆圈的确切位置。因此,我认为在圆附加后放置我的 source/target 贝塞尔线逻辑是合适的,然后我可以在模拟吐出它的渲染后获取实际像素坐标。
问题
我的临时坐标生成可能存在什么缺陷,或者是否有更简单的方法来引用我的代码片段中的那些圆心点?
+1 以获得有趣的可视化效果!
您的想法是正确的,但实际上,您可以更轻松地检索这些值,因为您已经将 x
和 y
设置为 forEach()
你的代码的开头。所以没有必要爬行每件事并查找个人 cx
s 和 cy
s。您所需要的只是将正确的值输入 multiLinkData
:
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d.x, d.y], link:d.link}
});
var multiLinkData = bottomLinks.map(t1 => ({...t1, ...topLinks.find(t2 => t2.link === t1.link)}));
我有一个简化的视觉效果,我试图从一堆小圆圈(右侧)到大圆圈(左侧)绘制贝塞尔线。正在进行的片段:
var margins = {top:100, bottom:300, left:100, right:100};
var height = 600;
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 data = d3.range(200).map(function(v) {return {name: v.toString()+'_movie', top:false, link:'2019'} });
data.forEach(function(d, i) {
d.x = 900;
//d.y = 100;
d.y = 200
});
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) {
return 900;
}).strength(0.4))
.force("y", d3.forceY(function(d) {
//return 100;
return 200;
}).strength(0.1))
.force("collide", d3.forceCollide(4))
.stop();
simulation.tick(75);
console.log(data)
var circles = graphGroup.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", function(d) {
return 2;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.style('fill', "#003366")
.on('click', function(d) {
return console.log(d3.select(this).datum());
});
var topData = [
{year:'2019', top:true}
];
graphGroup.selectAll(null)
.data(topData)
.enter()
.append('circle')
.attr('cx', 200)
.attr('cy', 200)
.attr('r', 20)
.style('fill', "#003366");
var topCircles = d3.selectAll('circle').filter(function(d) {return d.top == true}).data();
var bottomCircles = d3.selectAll('circle').filter(function(d) {return d.top == false}).data();
console.log(topCircles)
var topLinks = topCircles.map(function(d,i) {
return {source: [200, 200], link:d.year}
});
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], link:d.year}
});
var multiLinkData = topLinks.map(t1 => ({...t1, ...bottomLinks.find(t2 => t2.link === t1.link)}));
console.log(multiLinkData)
var link = d3.linkHorizontal();
graphGroup.selectAll(null)
.data(multiLinkData)
.enter()
.append('path')
//.join("path")
.attr("d", link)
.attr("fill", "none")
//.style('stroke', function(d) {return colorMap[d.applied]})
.attr("stroke", "#d9d9d9");
<script src="https://d3js.org/d3.v5.min.js"></script>
因此 none 行已附加;错误读取无法读取此行未定义的 cx
:
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d3.select(this).datum().cx, d3.select(this).datum().cy], series:d.name}
});
但我记得,这是检索 svgs 像素坐标的唯一方法。由于它们是从群体模拟中附加的,因此无法预先计算每个圆圈的确切位置。因此,我认为在圆附加后放置我的 source/target 贝塞尔线逻辑是合适的,然后我可以在模拟吐出它的渲染后获取实际像素坐标。
问题
我的临时坐标生成可能存在什么缺陷,或者是否有更简单的方法来引用我的代码片段中的那些圆心点?
+1 以获得有趣的可视化效果!
您的想法是正确的,但实际上,您可以更轻松地检索这些值,因为您已经将 x
和 y
设置为 forEach()
你的代码的开头。所以没有必要爬行每件事并查找个人 cx
s 和 cy
s。您所需要的只是将正确的值输入 multiLinkData
:
var bottomLinks = bottomCircles.map(function(d,i) {
return {target: [d.x, d.y], link:d.link}
});
var multiLinkData = bottomLinks.map(t1 => ({...t1, ...topLinks.find(t2 => t2.link === t1.link)}));