
資料科學、物理模擬、網路及層次相關領域可能會使用到,目前僅覺得這種資料互動很有趣。
主要模擬器,可以用來監聽整體內部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)
}