在 javascript 中创建带有时间线的图表
Creating graph with timeline in javascript
我想在 javascript 中创建带有时间轴的动态变化图,看起来像 this。
编辑:我想自己决定哪个节点应该在哪个时间片中。
我想知道,是否有我可以用来执行此操作的库,或者我需要自己创建它(只需在 canvas 上绘图)?我试图找到一个,但似乎有很多时间线和图表的实现,但很难找到这两者的组合。最合适的解决方案是使用 gojs。但是我不能创建一个有两个父节点的节点,因为它是作为树数据结构实现的。
您可能需要玩弄数学,但我希望这对您有所帮助:
演示:JSFiddle
HTML
<div id='board'>
<div id='titles'></div>
</div>
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**
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';
}
正如文中提到的 GoJS sample,很容易将 TreeLayout 替换为 LayeredDigraphLayout 和 TreeModel 和 GraphLinksModel。这是我刚刚对示例所做的修改。
将go.TreeLayout
替换为go.LayeredDigraphLayout
,这样自定义布局就不再继承自TreeLayout。将构造函数更改为不再设置 TreeLayout 特定属性。更改图表的布局以使用 LayeredDigraphLayout 特定属性:
layout: $(LayeredTreeLayout, // custom layout is defined above
{
angle: HORIZONTAL ? 0 : 90,
columnSpacing: 5,
layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
}),
用包含所需数据的 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
});
没有更改任何模板或样式,结果是:
为了确保它有效,我也尝试设置 HORIZONTAL = false
:
我想在 javascript 中创建带有时间轴的动态变化图,看起来像 this。 编辑:我想自己决定哪个节点应该在哪个时间片中。
我想知道,是否有我可以用来执行此操作的库,或者我需要自己创建它(只需在 canvas 上绘图)?我试图找到一个,但似乎有很多时间线和图表的实现,但很难找到这两者的组合。最合适的解决方案是使用 gojs。但是我不能创建一个有两个父节点的节点,因为它是作为树数据结构实现的。
您可能需要玩弄数学,但我希望这对您有所帮助:
演示:JSFiddle
HTML
<div id='board'>
<div id='titles'></div>
</div>
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**
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';
}
正如文中提到的 GoJS sample,很容易将 TreeLayout 替换为 LayeredDigraphLayout 和 TreeModel 和 GraphLinksModel。这是我刚刚对示例所做的修改。
将go.TreeLayout
替换为go.LayeredDigraphLayout
,这样自定义布局就不再继承自TreeLayout。将构造函数更改为不再设置 TreeLayout 特定属性。更改图表的布局以使用 LayeredDigraphLayout 特定属性:
layout: $(LayeredTreeLayout, // custom layout is defined above
{
angle: HORIZONTAL ? 0 : 90,
columnSpacing: 5,
layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
}),
用包含所需数据的 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
});
没有更改任何模板或样式,结果是:
为了确保它有效,我也尝试设置 HORIZONTAL = false
: