Last active
March 1, 2021 12:50
-
-
Save frboyer/c5484b23b401c33be8abaea766783402 to your computer and use it in GitHub Desktop.
This is test to see how difficult it would be to add arrows to vis.js timeline view. Can be previewed with https://gistpreview.github.io/?c5484b23b401c33be8abaea766783402
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<title>Timeline | Group example, with an arrow</title> | |
<style> | |
body, html { | |
font-family: arial, sans-serif; | |
font-size: 11pt; | |
} | |
#visualization { | |
box-sizing: border-box; | |
width: 100%; | |
height: 300px; | |
} | |
</style> | |
<!-- note: moment.js must be loaded before vis.js, else vis.js uses its embedded version of moment.js --> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"></script> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" rel="stylesheet" type="text/css" /> | |
</head> | |
<body> | |
<p> | |
This is the same example which is in "vis/examples/timeline/groups/groups.html" but with an added arrow between item 0 and item 1, to demonstrate that it is possible without | |
</p> | |
<div id="visualization"></div> | |
<script> | |
var getItemPos = function(item) { | |
left_x = item.left; | |
top_y = item.parent.top + item.parent.height - item.top - item.height; | |
return { | |
left: left_x, | |
top: top_y, | |
right: left_x + item.width, | |
bottom: top_y + item.height, | |
mid_x: left_x + item.width/2, | |
mid_y: top_y + item.height/2, | |
width: item.width, | |
height: item.height | |
}; | |
} | |
var drawArrows = function() { | |
var item0_pos = getItemPos(timeline.itemSet.items[0]); | |
var item1_pos = getItemPos(timeline.itemSet.items[1]); | |
if (item1_pos.mid_x < item0_pos.mid_x) | |
[item0_pos, item1_pos] = [item1_pos, item0_pos]; // As demo, we put an arrow between item 0 and item1, from the one that is more on left to the one more on right. | |
var curveLen = item0_pos.height*2; // Length of straight Bezier segment out of the item. | |
item1_pos.left -= 10; // Space for the arrowhead. | |
somePath.setAttribute("d", | |
"M " + item0_pos.right + " " + item0_pos.mid_y | |
+ " C " | |
+ (item0_pos.right+curveLen) + " " + item0_pos.mid_y + " " | |
+ (item1_pos.left-curveLen) + " " + item1_pos.mid_y + " " | |
+ item1_pos.left + " " + item1_pos.mid_y | |
); | |
}; | |
var options = { | |
groupOrder: 'content', // groupOrder can be a property name or a sorting function | |
onInitialDrawComplete: function() { | |
drawArrows(); | |
timeline.on('changed', drawArrows); //NOTE: We hijack the on "changed" event to draw the arrow. | |
} | |
}; | |
// Generate some | |
var now = moment().minutes(0).seconds(0).milliseconds(0); | |
var names = ['John', 'Alston', 'Lee', 'Grant']; | |
var itemCount = 20; | |
// create a data set with groups | |
var groups = new vis.DataSet(); | |
for (var g = 0; g < names.length; g++) { | |
groups.add({id: g, content: names[g]}); | |
} | |
// create a dataset with items | |
var items = new vis.DataSet(); | |
for (var i = 0; i < itemCount; i++) { | |
var start = now.clone().add(Math.random() * 200, 'hours'); | |
var group = Math.floor(Math.random() * names.length); | |
items.add({ | |
id: i, | |
group: group, | |
content: 'item ' + i + | |
' <span style="color:#97B0F8;">(' + names[group] + ')</span>', | |
start: start, | |
type: 'box' | |
}); | |
} | |
// Create visualization. | |
var container = document.getElementById('visualization'); | |
var timeline = new vis.Timeline(container, items, groups, options); | |
// Create SVG layer on top of timeline "center" div. | |
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | |
svg.style.position = "absolute"; | |
svg.style.top = '0px'; | |
svg.style.height = '100%'; | |
svg.style.width = '100%'; | |
svg.style.display = "block"; | |
svg.style.zIndex = "1"; // Should it be above or below? (1 for above, -1 for below) | |
svg.style.pointerEvents = "none"; // To click through, if we decide to put it above other elements. | |
timeline.dom.center.appendChild(this.svg); | |
// Add arrowhead definition to SVG. | |
var arrowHead = document.createElementNS('http://www.w3.org/2000/svg', 'marker'); | |
arrowHead.setAttribute("id", "arrowhead0"); | |
arrowHead.setAttribute("viewBox", "-10 -5 10 10"); | |
arrowHead.setAttribute("refX", "-7"); | |
arrowHead.setAttribute("refY", "0"); | |
arrowHead.setAttribute("markerUnits", "strokeWidth"); | |
arrowHead.setAttribute("markerWidth", "3"); | |
arrowHead.setAttribute("markerHeight", "3"); | |
arrowHead.setAttribute("orient", "auto"); | |
var arrowHeadPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |
arrowHeadPath.setAttribute("d", "M 0 0 L -10 -5 L -7.5 0 L -10 5 z"); | |
arrowHeadPath.style.fill = "#F00"; | |
arrowHead.appendChild(arrowHeadPath); | |
svg.appendChild(arrowHead); | |
// Add empty path (for now); it will be dynamically modified. | |
var somePath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |
somePath.setAttribute("d", "M 0 0"); | |
somePath.setAttribute("marker-end", "url(#arrowhead0)"); | |
somePath.style.stroke = "#F00"; | |
somePath.style.strokeWidth = "5px"; | |
somePath.style.fill = "none"; | |
svg.appendChild(somePath); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment