UNPKG

vis-timeline

Version:

Create a fully customizable, interactive timeline with items and ranges.

247 lines (207 loc) 7.03 kB
<!DOCTYPE HTML> <html> <head> <title>Timeline | Clustering example</title> <style> body, html { font-family: arial, sans-serif; font-size: 11pt; } #visualization { box-sizing: border-box; width: 100%; height: 300px; } .vis-cluster{ min-width: 145px; } .cluster-header{ display: block; font-weight: 600; } .slider-value { border: 0; background: transparent; } </style> <!-- note: moment.js must be loaded before vis-timeline-graph2d or the embedded version of moment.js is used --> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script> <script src="../../../dist/vis-timeline-graph2d.min.js"></script> <link href="../../../dist/vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css" /> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" /> </head> <body> <p> This example demonstrate using clustering. </p> <button class="zoom" data-dir="1">Zoom in</button> <button class="zoom" data-dir="-1">Zoom out</button> </br> <input type="checkbox" id="clusterCheckbox">Enable clustering</button> </br> <input type="checkbox" id="groupItemsCheckBox">Enable grouping</button> </br> </br> <div> <label for="total-days-number">Days number:</label> <input class="slider-value" type="text" id="total-days-number" readonly/> <div class="slider" id="total-days-slider"></div> </div> <div> <label for="orders-per-day-number">Orders per day number:</label> <input class="slider-value" type="text" id="orders-per-day-number" readonly/> <div class="slider" id="orders-per-day-slider"></div> </div> </br> <div> <label for="total-orders-count">Total orders:</label> <input class="slider-value" type="text" id="total-orders-count" readonly/> </div> </br> <div id="visualization"></div> <script> function getRandomArbitrary(min, max) { return Math.round(Math.random() * (max - min) + min); } function getRandomSignum() { return Math.round(Math.random()) ? 1 : -1; } var names = ['Group 1', 'Group 2', 'Group 3', 'Group 4']; var groups = new vis.DataSet(); var groupsCount = 0; for (var i in names) { var name = names[i]; groups.add({id: name, content: name}); } function getTimelineData() { const offsets = []; const totalDaysCount = $( "#total-days-slider" ).slider( "value"); const itemsInClusterCount = $( "#orders-per-day-slider" ).slider( "value"); const before = [Array.from(new Array(Math.round(totalDaysCount / 2)),function (val,index) {return index - totalDaysCount + 1;})]; const after = [Array.from(new Array(Math.round(totalDaysCount / 2)),function(val,index) {return index + 1;})]; for (var i in before) { var offset = before[i]; offsets.push(...offset); } for (var i in after) { var offset = after[i]; offsets.push(...offset); } const clusterCenters = []; for (let offset of offsets) { const date = moment().add('days', offset); clusterCenters.push(date); } const timeLineData = []; let nodeIndex = 0; for (var i in clusterCenters) { let clusterCenter= clusterCenters[i]; for (let clusterNodeIdx = 0; clusterNodeIdx < itemsInClusterCount; ++clusterNodeIdx) { const minutesShift = getRandomArbitrary(1, 60)*getRandomSignum(); const hoursShift = getRandomArbitrary(1, 5)*getRandomSignum(); const secondsShift = getRandomArbitrary(1, 60)*getRandomSignum(); const start = clusterCenter.clone() .add(+minutesShift, 'm') .add(+hoursShift, 'h') .add(+secondsShift, 's'); const end = start.clone().add(60, 'm'); ++nodeIndex; const currentGroup = names[getRandomArbitrary(0, names.length - 1)]; timeLineData.push({ id: nodeIndex, content: "Order: " + nodeIndex, start: start.format('YYYY/MM/DD HH:mm:ss'), end: end.format('YYYY/MM/DD HH:mm:ss'), width: 50, group: currentGroup }); } } return timeLineData; } $('#groupItemsCheckBox').change(function() { if(this.checked) { timeline.setGroups(groups); } else { timeline.setGroups(null); } }); $( "#orders-per-day-slider" ).slider({ value: 10, min: 1, max: 1000, slide: function( event, ui ) { setTimeout(() => { $( "#orders-per-day-number").val( ui.value ); timeLineData = getTimelineData(); $( "#total-orders-count" ).val(timeLineData.length); timeline.setItems(timeLineData); }); } }); $( "#total-days-slider" ).slider({ value: 1, min: 2, max: 10, step: 2, slide: function( event, ui ) { setTimeout(() => { $( "#total-days-number").val( ui.value ); timeLineData = getTimelineData(); $( "#total-orders-count" ).val(timeLineData.length); timeline.setItems(timeLineData); }); } }); $( "#total-days-number" ).val($( "#total-days-slider" ).slider( "value" ) ); $( "#orders-per-day-number" ).val( $( "#orders-per-day-slider" ).slider( "value" ) ); // create visualization var container = document.getElementById('visualization'); var defaultOptions = { stack: true, maxHeight: 800, height: 600, groupOrder: 'content', // groupOrder can be a property name or a sorting function, template: (itemData, element, data) => { if (data.isCluster) { return `<span class="cluster-header">Cluster</span><div>containg ${data.items.length} items </div>`; } else { return `<div>${data.content}</div>`; } }, }; var timeline = new vis.Timeline(container); timeline.setOptions(defaultOptions); var timeLineData = getTimelineData(); $( "#total-orders-count" ).val(timeLineData.length); timeline.setItems(timeLineData); timeline.fit(); $(".zoom").on("click", function(){ var dir = $(this).data('dir'); var range = timeline.getWindow(); var interval = range.end - range.start; timeline.setWindow({ start: range.start.valueOf() - interval * dir * 0.2, end: range.end.valueOf() + interval * dir * 0.2 }); }); $('#clusterCheckbox').change(function() { var options = {}; if(this.checked) { var clusterOpts = { cluster: { titleTemplate: "Cluster containing {count} events. Zoom in to see the individual events.", showStipes: true, } }; Object.assign(options, defaultOptions, clusterOpts); } else { Object.assign(options, defaultOptions); } timeline.setOptions(options); }); </script> </body> </html>