简体   繁体   English

在javascript中使用时间轴创建图形

[英]Creating graph with timeline in javascript

I would like to create dynamically changing graph with timeline in javascript, That would look something like this . 我想用javascript中的时间轴创建动态变化的图形,这看起来像这样 Edit: I would like to decide by myself which node should be in which time slice. 编辑:我想自己决定哪个节点应该在哪个时间片。

I wonder, is there a library that I can use to do this, or I need to create it by myself ( by simply drawing on canvas )? 我想知道,有没有我可以用来做这个的库,或者我需要自己创建它(通过简单地画在画布上)? I tried to find one, however it seems that there are many implementations of timelines and of graphs but the combination of those two is hard to find. 我试图找到一个,但似乎有很多时间轴和图形的实现,但很难找到这两者的组合。 The most suitable solution was using gojs . 最合适的解决方案是使用gojs However I can't create a node with two parents in it because it is implemented as a tree data structure. 但是我无法创建一个包含两个父节点的节点,因为它是作为树数据结构实现的。

You may have to play around with the maths, but I hope this will be useful as a starting point: 你可能不得不玩数学,但我希望这将作为一个起点有用:

DEMO : JSFiddle 演示JSFiddle

HTML HTML

<div id='board'>
 <div id='titles'></div>

</div>

CSS CSS

#board { 
  position: relative; 
  width: 500px;
  height: 600px;
  background-color:#f83213;
}
#titles {
  color: #ffffff;
  width: 100%;
  height: 18px;
  font-size: 12px;
}
#titles div {
  display:inline-block;
  margin: 10px;
}
.event{
    border: 0px;
    background-color: #3a2356;
    color: #ffffff;
    width: 18px;
    height: 18px;
    position: absolute;
    padding: 4px;
    font-size: 18px;
    z-index: 2;
}
.line{
    height: 1px;
    width: 60px;
    background-color: #3a2356;
    position: absolute;
    z-index: 1;
}

** JavaScript** ** JavaScript **

var margin = 20;
var events = {
  "A": {
    day: 0,
    indexInDay: 0,
    lineTos: ["D"]
  },
  "B": {
    day: 0,
    indexInDay: 1,
    lineTos: ["D"]
  },
  "D": {
    day: 1,
    indexInDay: 0,
    lineTos: ["E","F"]
  },
  "E": {
    day: 2,
    indexInDay: 0,
    lineTos: null
  },
  "C": {
    day: 0,
    indexInDay: 2,
    lineTos: ["F"]
  },
  "F": {
    day: 2,
    indexInDay: 2,
    lineTos: null
  },
};

drawAll(events);

function drawAll(events) {
  drawTitles(events);
  drawEvents(events);
  drawLines(events);
}

function drawTitles(events) {
  var titles = document.getElementById('titles');
  var max = 0;
  for (var name in events) {
    if (events[name].day > max)
      max = events[name].day;
  }
  for (var i = 0 ; i <= max ; i++)
    titles.innerHTML += '<div>' + 'Day' + i + '</div>';
}

function drawEvents(events) {
  var board = document.getElementById('board');
  for (var name in events) {
    var ev = events[name];
    var eventDiv = document.createElement('DIV');
    board.appendChild(eventDiv);
    eventDiv.className = 'event';
    setTopLeftEvent(ev, eventDiv);
    eventDiv.innerText = name;

  }
}

function drawLines(events) {
  var board = document.getElementById('board');
  for (var name in events) {
    var from = events[name];
    var tos = from.lineTos;
    if (!tos) continue;
    for (var j = 0 ; j < tos.length ; j++) {
      var to = events[tos[j]];
      var lineDiv = document.createElement('DIV');
      board.appendChild(lineDiv);
      lineDiv.className = 'line';
      setTopLeftLine(from, lineDiv);
      lineDiv.style.width = margin  + 1 * margin * distance(to.indexInDay,from.indexInDay,to.day, from.day) + 'px';
      var tan = (to.indexInDay - from.indexInDay) / (to.day - from.day);
      lineDiv.style.top = lineDiv.offsetTop + (tan * margin) +'px';
      var angle = Math.atan(tan) * 180/Math.PI;
      // Code for Safari
      lineDiv.style.WebkitTransform = "rotate(" + angle + "deg)"; 
      // Code for IE9
      lineDiv.style.msTransform = "rotate(" + angle + "deg)"; 
      // Standard syntax
      lineDiv.style.transform = "rotate(" + angle + "deg)"; 
    }

  }
}

function distance(x1, y1, x2, y2){
 var res = Math.sqrt((y2-y1)*(y2-y1) + (x2-x1)*(x2-x1)); 
 return res;
}

function setTopLeftEvent(event, eventDiv) {
  eventDiv.style.left = (margin + event.day * (margin * 2)) + 'px';
    eventDiv.style.top = (margin * 2 + event.indexInDay * (margin * 2)) + 'px';
}
function setTopLeftLine(event, lineDiv) {
  lineDiv.style.left = (margin + event.day * (margin * 2)) + 'px';
  lineDiv.style.top = (margin * 2.5 + event.indexInDay * (margin * 2)) + 'px';
}

As that GoJS sample mentions in the text, it is easy to replace the TreeLayout with a LayeredDigraphLayout and the TreeModel with a GraphLinksModel . 作为GoJS样品在文中提到,很容易与LayeredDigraphLayout并用GraphLinksModelTreeModel更换TreeLayout。 Here's what I just did to modify the sample. 这就是我刚刚修改样本的方法。

Replace go.TreeLayout with go.LayeredDigraphLayout , so that the custom layout no longer inherits from TreeLayout. 更换go.TreeLayoutgo.LayeredDigraphLayout ,使自定义布局不再TreeLayout继承。 Change the constructor not to bother setting TreeLayout specific properties. 更改构造函数不要打扰设置TreeLayout特定属性。 Change the diagram's layout to use LayeredDigraphLayout specific properties: 更改图表的布局以使用LayeredDigraphLayout特定属性:

            layout: $(LayeredTreeLayout,  // custom layout is defined above
                      {
                        angle: HORIZONTAL ? 0 : 90,
                        columnSpacing: 5,
                        layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
                      }),

Replace that sample's model with a GraphLinksModel holding the data that you want: 用包含所需数据的GraphLinksModel替换该样本的模型:

// define the node data
var nodearray = [
  { // this is the information needed for the headers of the bands
    key: "_BANDS",
    category: "Bands",
    itemArray: [
      { text: "Day 0" },
      { text: "Day 1" },
      { text: "Day 2" },
      { text: "Day 3" },
      { text: "Day 4" },
      { text: "Day 5" }
    ]
  }
];
var linkarray = [
  { from: "A", to: "D" },
  { from: "B", to: "D" },
  { from: "D", to: "E" },
  { from: "D", to: "F" },
  { from: "C", to: "F" }
];

myDiagram.model = $(go.GraphLinksModel,
    { // automatically create node data objects for each "from" or "to" reference
      // (set this property before setting the linkDataArray)
      archetypeNodeData: {},
      nodeDataArray: nodearray,
      linkDataArray: linkarray
    });

Without having changed any of the templates or the styling, the result is: 在没有更改任何模板或样式的情况下,结果是:

在此输入图像描述

Just to make sure it works, I also tried setting HORIZONTAL = false : 为了确保它有效,我还尝试设置HORIZONTAL = false

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM