資料科學、物理模擬、網路及層次相關領域可能會使用到,目前僅覺得這種資料互動很有趣。
主要模擬器,可以用來監聽整體內部node
變化,以及執行、暫停或重新啟動引力模擬。
範例:
const simulation = d3.forceSimulation(nodes)
.velocityDecay(0.2)
.force("x", d3.forceX().strength(0.002))
.force("y", d3.forceY().strength(0.002))
.force("collide", d3.forceCollide().radius(d => d.r + 0.5).iterations(2))
.on("tick", data => ticked(data));
const width = 800;
const height = 800;
const svg = d3.select('svg').attr('width', width).attr('height', height);
const rootLayer = svg.append('g').attr('transform', `translate(${width / 2}, ${height / 2})`);
// 將圖層置中
const radii = Array.from({length: 500}, d3.randomUniform(4, 18));
// 亂數產生數字
const nodes = radii.map(r => ({r}));
// 產生一個nodes陣列 [{r: 4.XXXXX}, {r: 5.XXXXX}, {r: 17.XXXXX} .... ]
const simulation = d3.forceSimulation(nodes)
.velocityDecay(0.2)
.force("x", d3.forceX().strength(0.01))
.force("y", d3.forceY().strength(0.01))
.force("collide", d3.forceCollide().radius(d => d.r + 0.5).iterations(2))
.on("tick", paint);
// 產生引力模擬
function dragged(d) {
// 如果被拖拉,即更新目前拖拉的元件
d.subject.x = d.x;
d.subject.y = d.y;
paint();
// 並重新繪製且引力重新計算
simulation.alphaTarget(0.3).restart();
}
// 繪製目前的資料
// tick會一直執行,直到所有資料已經到引力模擬算好的位置。
function paint() {
rootLayer
.selectAll('circle')
.data(nodes)
.enter()
.append('circle')
.attr('r', data => data.r)
.attr('cx', data => data.x)
.attr('cy', data => data.y)
.call(d3.drag().on("drag", dragged));
// 拖拉事件發生
rootLayer
.selectAll('circle')
.attr('r', data => data.r)
.attr('cx', data => data.x)
.attr('cy', data => data.y)
}