在d3v4中强制定向图

时间:2017-07-19 13:51:33

标签: javascript d3.js

我正在试验D3版本4力导向图,并将Jim Vallandingham的教程和代码作为起点。

http://vallandingham.me/bubble_chart_v4/

我正试图从Nathan Yau那里制作一个类似于这个例子的动画

https://flowingdata.com/2016/08/23/make-a-moving-bubbles-chart-to-show-clustering-and-distributions/

我已经将Jim Vallandingham的代码中的气泡图剥离到我认为我需要的代码,并且可以通过更改索引值来显示各个状态,但由于某种原因,代码不希望在不同状态之间设置动画。我假设重绘功能不起作用。这可能是一个明显的错误,也可能是完全无知的错误,但是如果你能提供帮助那就太棒了。

这是我的代码:

function bubbleChart() {
  var width = 940;
  var height = 600;
  var center = { x: width / 2, y: height / 3 };

  var years = ["0","2008", "2009", "2010"];

  var yearCenters = {
    2008: { x: width / 3, y: 2 * height / 3 },
    2009: { x: width / 2, y: 2 * height / 3 },
    2010: { x: 2 * width / 3, y: 2 * height / 3 }
  };

  // @v4 strength to apply to the position forces
  var forceStrength = 0.03;

  // These will be set in create_nodes and create_vis
  var svg = null;
  var bubbles = null;
  var nodes = [];
  var index= 0;

  function charge(d) {
    return -Math.pow(d.radius, 2.3) * forceStrength;
  }

  // Here we create a force layout
  var simulation = d3.forceSimulation()
    .velocityDecay(0.2)
    .force('x', d3.forceX().strength(forceStrength).x(center.x))
    .force('y', d3.forceY().strength(forceStrength).y(center.y))
    .force('charge', d3.forceManyBody().strength(charge))
    .on('tick', ticked);

  // @v4 Force starts up automatically, which we don't want as there aren't any nodes yet.
  simulation.stop();

  // Nice looking colors
  var fillColor = d3.scaleOrdinal()
    .domain(['low', 'medium', 'high'])
    .range(['#d84b2a', '#beccae', '#7aa25c']);

  function createNodes(rawData) {
    var myNodes = rawData.map(function (d) {
      return {
        id: d.id,
        radius: 5, 
        value: +d.total_amount,
        name: d.grant_title,
        org: d.organization,
        group: d.group,
        year: d.start_year,
        x: Math.random() * 900,
        y: Math.random() * 800
      };
    });

    // sort them to prevent occlusion of smaller nodes.
    myNodes.sort(function (a, b) { return b.value - a.value; });

    return myNodes;
  }

  /*
   * Main entry point to the bubble chart. 
   */
  var chart = function chart(selector, rawData) {
    // convert raw data into nodes data
    nodes = createNodes(rawData);

    // Create a SVG element inside the provided selector
    // with desired size.
    svg = d3.select(selector)
      .append('svg')
      .attr('width', width)
      .attr('height', height);

    // Bind nodes data to what will become DOM elements to represent them.
    bubbles = svg.selectAll('.bubble')
      .data(nodes, function (d) { return d.id; });

    // Create new circle elements each with class `bubble`.
    // There will be one circle.bubble for each object in the nodes array.
    // Initially, their radius (r attribute) will be 0.
    // @v4 Selections are immutable, so lets capture the
    //  enter selection to apply our transtition to below.
    var bubblesE = bubbles.enter().append('circle')
      .classed('bubble', true)
      .attr('r', 0)
      .attr('fill', function (d) { return fillColor(d.group); })
      .attr('stroke', function (d) { return d3.rgb(fillColor(d.group)).darker(); })
      .attr('stroke-width', 2)

    // @v4 Merge the original empty selection and the enter selection
    bubbles = bubbles.merge(bubblesE);

    // Fancy transition to make bubbles appear, ending with the
    // correct radius
    bubbles.transition()
      .duration(2000)
      .attr('r', function (d) { return d.radius; });

    // Set the simulation's nodes to our newly created nodes array.
    // @v4 Once we set the nodes, the simulation will start running automatically!
    simulation.nodes(nodes);

    chart.redraw();
  };

  // Callback function that is called after every tick of the force simulation.
  // These x and y values are modified by the force simulation.
  function ticked() {
    bubbles
      .attr('cx', function (d) { return d.x; })
      .attr('cy', function (d) { return d.y; });
  }

  chart.redraw = function (index){
    simulation.force('x', d3.forceX().strength(forceStrength).x(nodePosX));
    simulation.force('y', d3.forceY().strength(forceStrength).y(nodePosY));
    simulation.alpha(1).restart();
  }

  function nodePosX(d) {
    if (+d.year <= +years[index]) {
      return yearCenters[d.year].x;
    } else {
      return center.x;
    } 
  }
  function nodePosY(d) {
    if (+d.year <= +years[index]) {
      return yearCenters[d.year].y;
    } else {
      return center.y;
    } 
  }

  // return the chart function from closure.
  return chart;
}

var myBubbleChart = bubbleChart();

myBubbleChart('#vis', data);  

for (i=0;i<4;i++){
  setInterval(function(){myBubbleChart.redraw(i);}, 100);
}

1 个答案:

答案 0 :(得分:0)

我误解了如何使用setInterval重绘图表,所以应该如下:

var i = 0;
setInterval(function(){myBubbleChart.redraw(i++);}, 1000);