使用d3plus.js动态更改网络图表

Change network chart dynamically with d3plus.js

本文关键字:网络 d3plus js 动态 使用      更新时间:2023-09-26

我现在正在使用D3plus库对一些网络进行可视化。我想做的是根据对象的关键字显示不同的网络,例如年份。有一个tree_map图表的工作示例。但我无法为网络实现相同的功能。

这是我的代码:

<!doctype html>
<meta charset="utf-8">
<script src="http://www.d3plus.org/js/d3.js"></script>
<script src="http://www.d3plus.org/js/d3plus.js"></script>
<div id="viz"></div>
<script>
  var sample_data = [
    {"name": "point1", "year": 1994},
    {"name": "point2", "year": 1994},
    {"name": "point3", "year": 1994},
    {"name": "point4", "year": 1994},
    {"name": "point5", "year": 1994},
    {"name": "point6", "year": 1994},
    {"name": "point7", "year": 1994},
    {"name": "point8", "year": 1994},
    {"name": "point9", "year": 1994},
    {"name": "point10", "year": 1994},
    {"name": "point11", "year": 1994},
    {"name": "point12", "year": 1995}
  ]
  var positions = [
    {"name": "point1", "x": 3, "y": 7},
    {"name": "point2", "x": 2, "y": 6},
    {"name": "point3", "x": 4, "y": 6},
    {"name": "point4", "x": 1, "y": 5.5},
    {"name": "point5", "x": 5, "y": 5.5},
    {"name": "point6", "x": 2, "y": 4},
    {"name": "point7", "x": 4, "y": 4},
    {"name": "point8", "x": 1, "y": 3},
    {"name": "point9", "x": 5, "y": 3},
    {"name": "point10", "x": 2, "y": 1.5},
    {"name": "point11", "x": 4, "y": 1.5},
    {"name": "point12", "x": 2, "y": 7}
  ]
  var connections = []
  var visualization = d3plus.viz()
    .container("#viz")
    .type("network")
    .data(sample_data)   
    .nodes(positions)
    .edges(connections)
    .id("name")
    .time({"value": "year", "solo": 1994})
    .draw()
</script>

我需要在点击时间轴时显示不同的节点,这样通过选择1995,只应显示"point12"节点

JSBin示例

注意:我发现的也是一个悬而未决的问题,但可能从那时起就已经实现了此功能。

当年份范围发生变化时,可以监听时间线触发的事件并运行自定义代码。以下是谷歌集团对D3plus的一篇帖子的重新解读:

visualization.time({"solo": {
    "callback": function(timeline_range) {
        // update the nodes/edges
        visualization.nodes(new_nodes).edges(new_edges).draw();
    }
}});

我花了一些时间来解决这个问题,并决定将d3plus和d3组合在一起,而不是只使用d3plus。也许没有一个优雅的解决方案,它可以更简单地解决,但对我来说,它是有效的。

这里是完整的代码:

<!doctype html>
<meta charset="utf-8">
<script src="http://www.d3plus.org/js/d3.js"></script>
<script src="http://www.d3plus.org/js/d3plus.js"></script>
<style type="text/css">
  #viz {
    height: 600px;
  }
  #network-timeline {
    height: 30px;
    margin-bottom: 10px;
    text-align: center;
  }
  .time-tick {
    background-color: #6f6d6d;
    outline: 0;
    position: relative;
    cursor: pointer;
    vertical-align: middle;
    color: #FFF;
    letter-spacing: 0.5px;
    height: 28px;
    margin: 0 0 15px 5px;
    padding: 0 0.8rem;
    border-radius: 2px;
    text-transform: uppercase;
    border: none;
    -webkit-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
    -moz-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
  }
  .time-tick:hover {
    background-color: #9e9e9e;
  }
  .time-tick-selected {
    background-color: #9e9e9e; 
  }
</style>
<div class="network">
  <div id="viz"></div>
  <div id="network-timeline"></div>
</div>
<script>
  var initial_data = [
    {"name": "point1", "year": 1994, "x": 3, "y": 7},
    {"name": "point2", "year": 1994, "x": 2, "y": 6},
    {"name": "point3", "year": 1994, "x": 4, "y": 6},
    {"name": "point4", "year": 1994, "x": 1, "y": 5.5},
    {"name": "point5", "year": 1994, "x": 5, "y": 5.5},
    {"name": "point6", "year": 1994, "x": 2, "y": 4},
    {"name": "point7", "year": 1994, "x": 4, "y": 4},
    {"name": "point8", "year": 1994, "x": 1, "y": 3},
    {"name": "point9", "year": 1994, "x": 5, "y": 3},
    {"name": "point10", "year": 1994, "x": 2, "y": 1.5},
    {"name": "point11", "year": 1994, "x": 4, "y": 1.5},
    {"name": "point1", "year": 1995, "x": 3, "y": 7},
    {"name": "point2", "year": 1995, "x": 2, "y": 6},
    {"name": "point3", "year": 1995, "x": 4, "y": 6},
    {"name": "point4", "year": 1995, "x": 1, "y": 5.5},
    {"name": "point5", "year": 1995, "x": 5, "y": 5.5},
    {"name": "point6", "year": 1995, "x": 4, "y": 4.5},
    {"name": "point7", "year": 1995, "x": 1, "y": 3.5},
    {"name": "point8", "year": 1995, "x": 2, "y": 3.5},
    {"name": "point9", "year": 1995, "x": 1.5, "y": 1},
    {"name": "point10", "year": 1995, "x": 4, "y": 1.5},
    {"name": "point11", "year": 1995, "x": 5, "y": 2},
  ]
  var connections = []
  var filterData = function(data, key) {
    return data.filter(function(obj){
      if (!obj.hasOwnProperty("year")) {
        console.error("Check input data. Every object should contain 'year' property.")
      }
      return obj.year == key
    });
  }
  var timeButtonClickHandler = function() {
    selectNetwork(this);
    selectTimeButton(this);
  }
  var selectNetwork = function(el) {
    var slice = filterData(slices, el.value)[0].nodes;
    drawNetwork(slice);
  }
  var drawNetwork = function(data) {
    visualization.data(data)   
                 .nodes(data)
                 .edges(connections)
                 .id("name")
                 .draw();
  }
  var selectTimeButton = function(el) {
    var button = document.querySelector(".time-tick-selected")
    if (button){
      button.className = "time-tick"
    }
    el.className = "time-tick time-tick-selected"
  }
  var visualization = d3plus.viz()
    .container("#viz")
    .type("network");
  // Create slices of nodes by key "year" according to timeline
  var timeSteps = d3plus.util.uniques(initial_data, function(d){return d.year}).sort();
  var slices = [];
  timeSteps.forEach(function(step){
    slices.push({
      "year": step,
      "nodes": filterData(initial_data, step)
    });
  });
  // Create timeline buttons
  d3.select("#network-timeline")
    .selectAll("input")
    .data(timeSteps)
    .enter()
    .append("input")
    .attr("type","button")
    .attr("class","time-tick")
    .attr("value", function (d){return d})
    .on("click", timeButtonClickHandler);
  // Draw initial network
  if (timeSteps.length > 0) {
    var button = document.querySelector("input[value='" + timeSteps[0] + "']");
    if (button){button.click()}
  }
  else {
    console.error("Check input data. Every object should contain 'year' property.")
  } 
</script>

JSbin示例