We use Higcharts/Highstocks. (great job!)
We need to render in one chart:
one or many timelines
the chart navigator
marking facts flags
maybe other curves
So we need to use Highstocks
You can see an adaptation of the best base we found here :
http://jsfiddle.net/g4KLk/100/
customrange are representing a duration in seconds
We need to display the navigator in order to be able to zoom on specifiq a timerange
In order to get customrange detailed seconds by seconds, we've had to render a point each second on the last line int the graph.
Any solution to get what we want without having to display a "seconds line" ?
And by the way, is there a solution in order to custom the color of each customrange ?
Regards !
The based JSFidle here :
// WGV chart demo
$(function() {
$.getJSON('//www.highcharts.com/samples/data/jsonp.php?filename=aapl-ohlcv.json&callback=?', function(data) {
var inputs = [{
name: 'Bookmark',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 1, 00),
to: Date.UTC(2013, 9, 27, 9, 1, 01)
}, {
from: Date.UTC(2013, 9, 27, 9, 20),
to: Date.UTC(2013, 9, 27, 9, 21)
}]
}, {
name: 'Mic 1',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 3, 00),
to: Date.UTC(2013, 9, 27, 9, 6, 00)
}, {
from: Date.UTC(2013, 9, 27, 9, 18, 00),
to: Date.UTC(2013, 9, 27, 9, 23, 00)
}]
}, {
name: 'Mic 2',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 3, 00),
to: Date.UTC(2013, 9, 27, 9, 9, 00)
}, {
from: Date.UTC(2013, 9, 27, 9, 16, 00),
to: Date.UTC(2013, 9, 27, 9, 18, 00)
}, {
from: Date.UTC(2013, 9, 27, 9, 42, 00),
to: Date.UTC(2013, 9, 27, 9, 44, 00)
}, {
from: Date.UTC(2013, 9, 27, 9, 49, 00),
to: Date.UTC(2013, 9, 27, 10, 05, 00)
}]
}, {
name: 'Lights',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 11, 00),
to: Date.UTC(2013, 9, 27, 9, 55, 00)
}]
}, {
name: 'Brakes',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 11, 00),
to: Date.UTC(2013, 9, 27, 9, 55, 00)
}]
}, {
name: 'Siren',
intervals: [{ // From-To pairs
from: Date.UTC(2013, 9, 27, 9, 11, 00),
to: Date.UTC(2013, 9, 27, 9, 55, 00)
}]
}];
// re-structure the tasks into line seriesvar status = [];
var status = [];
$.each(inputs.reverse(), function(i, input) {
var item = {
name: input.name,
data: []
};
$.each(input.intervals, function(j, interval) {
item.data.push({
x: interval.from,
y: i,
label: interval.label,
from: interval.from,
to: interval.to
}, {
x: interval.to,
y: i,
from: interval.from,
to: interval.to
});
// add a null value between intervals
if (input.intervals[j + 1]) {
item.data.push(
[(interval.to + input.intervals[j + 1].from) / 2, null]
);
}
});
status.push(item);
});
// split the data set into ohlc and volume
var volume = [],
dataLength = data.length;
for (i = 0; i < dataLength; i++) {
volume.push([
data[i][0], // the date
data[i][5] // the volume
]);
}
// set the allowed units for data grouping
var groupingUnits = [
['millisecond', // unit name
[1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
],
[
'second', [1, 2, 5, 10, 15, 30]
],
[
'minute', [1, 2, 5, 10, 15, 30]
],
[
'hour', [1, 2, 3, 4, 6, 8, 12]
],
[
'day', [1]
]
];
// create the chart
$('#container').highcharts('StockChart', {
chart: {
renderTo: 'container',
marginTop: 40
},
credits: {
enabled: false
},
rangeSelector: {
enabled: false,
inputEnabled: false,
selected: 3,
buttons: [{
type: 'second',
count: 1,
text: '1s'
}, {
type: 'minute',
count: 1,
text: '1m'
}, {
type: 'day',
count: 1,
text: '1d'
}, {
type: 'all',
text: 'All'
}]
},
navigator: {
adaptToUpdatedData: false,
// ^-- This should be false when loading data asynchronously,
// to prevent circular loading
margin: 5,
// maskInside: false,
series: {
lineWidth: 0,
marker: {
enabled: false
}
}
},
title: {
text: '' // title above chart
},
xAxis: {
type: 'datetime',
events: {
afterSetExtremes: function(e) {},
setExtremes: function(e) {
var min = e.min,
max = e.max;
$('#report').html('Start Time: ' + min + ',<br/> Stop Time: ' + max + ',<br/> e.trigger: ' + e.trigger);
}
},
plotBands: [{ // mark the weekend
color: '#222',
from: Date.UTC(2013, 9, 27, 9, 1, 00),
to: Date.UTC(2013, 9, 27, 9, 7, 00),
label: {
text: 'Missing Video',
style: {
color: '#888'
}
}
},
{ // mark the weekend
color: '#222',
from: Date.UTC(2013, 9, 27, 9, 11, 00),
to: Date.UTC(2013, 9, 27, 9, 55, 00),
label: {
text: 'Missing Video',
style: {
color: '#888'
}
}
}, ],
},
yAxis: [{
height: '60%',
opposite: false,
tickInterval: 1,
tickWidth: 0,
labels: {
formatter: function() {
if (inputs[this.value]) {
return inputs[this.value].name;
}
},
align: 'right',
x: -20,
y: 4
},
showLastLabel: true
}, {
height: '40%',
top: '60%',
opposite: false,
offset: 60,
lineWidth: 1,
tickWidth: 0,
labels: {
align: 'right',
formatter: function() {
return this.value + ' MPH';
},
x: 52,
y: 4
},
showLastLabel: true,
title: {
text: 'Speed',
align: 'middle',
opposite: false,
style: {
color: '#fff'
}
}
}],
plotOptions: {
series: {
states: {
hover: {
lineWidth: 2
}
}
},
line: {
linecap: 'square',
marker: {
enabled: true // shows markers for all graphs points
},
point: {
events: {
click: function() {
// let's show the data value of the selected point (on click)
$('#click-value').html(Highcharts.dateFormat('%m/%d/%Y at %H:%M:%S', this.x));
}
}
}
}
},
series: [{
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[0].data,
dataGrouping: {
units: groupingUnits
}
}, {
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1,
radius: 5
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[1].data,
dataGrouping: {
units: groupingUnits
}
}, {
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1,
radius: 5
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[2].data,
dataGrouping: {
units: groupingUnits
}
}, {
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1,
radius: 5
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[3].data,
dataGrouping: {
units: groupingUnits
}
}, {
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1,
radius: 5
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[4].data,
dataGrouping: {
units: groupingUnits
}
}, {
states: {
hover: {
lineWidth: 10
}
},
lineWidth: 10,
marker: {
enabled: false, // hide markers for interval bars
lineWidth: 1,
radius: 5
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
},
name: '',
data: status[5].data,
dataGrouping: {
units: groupingUnits
}
}, {
name: 'GPS Speed',
data: [
[Date.UTC(2013, 9, 27, 9, 1, 00), 32],
[Date.UTC(2013, 9, 27, 9, 2, 33), 40],
[Date.UTC(2013, 9, 27, 9, 3, 00), 55],
[Date.UTC(2013, 9, 27, 9, 6, 00), 55],
[Date.UTC(2013, 9, 27, 9, 9, 00), 65],
[Date.UTC(2013, 9, 27, 9, 11, 00), 66],
[Date.UTC(2013, 9, 27, 9, 14, 00), 67],
[Date.UTC(2013, 9, 27, 9, 16, 00), 71],
[Date.UTC(2013, 9, 27, 9, 18, 00), 78],
[Date.UTC(2013, 9, 27, 9, 20, 00), 81],
[Date.UTC(2013, 9, 27, 9, 23, 00), 83],
[Date.UTC(2013, 9, 27, 9, 30, 00), 85],
[Date.UTC(2013, 9, 27, 9, 35, 00), 85],
[Date.UTC(2013, 9, 27, 9, 38, 00), 92],
[Date.UTC(2013, 9, 27, 9, 42, 00), 90],
[Date.UTC(2013, 9, 27, 9, 44, 00), 88],
[Date.UTC(2013, 9, 27, 9, 46, 00), 87],
[Date.UTC(2013, 9, 27, 9, 49, 00), 85],
[Date.UTC(2013, 9, 27, 9, 50, 00), 80],
[Date.UTC(2013, 9, 27, 9, 53, 00), 75],
[Date.UTC(2013, 9, 27, 9, 55, 00), 70],
[Date.UTC(2013, 9, 27, 10, 02, 00), 65],
[Date.UTC(2013, 9, 27, 10, 04, 00), 60],
[Date.UTC(2013, 9, 27, 10, 05, 00), 40],
[Date.UTC(2013, 9, 27, 10, 08, 00), 35]
],
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}, {
name: 'Patrol Speed',
data: [
[Date.UTC(2013, 9, 27, 9, 1, 00), 30],
[Date.UTC(2013, 9, 27, 9, 2, 33), 33],
[Date.UTC(2013, 9, 27, 9, 3, 00), 37],
[Date.UTC(2013, 9, 27, 9, 6, 00), 40],
[Date.UTC(2013, 9, 27, 9, 9, 00), 48],
[Date.UTC(2013, 9, 27, 9, 11, 00), 52],
[Date.UTC(2013, 9, 27, 9, 14, 00), 55],
[Date.UTC(2013, 9, 27, 9, 16, 00), 60],
[Date.UTC(2013, 9, 27, 9, 18, 00), 66],
[Date.UTC(2013, 9, 27, 9, 20, 00), 68],
[Date.UTC(2013, 9, 27, 9, 23, 00), 80],
[Date.UTC(2013, 9, 27, 9, 30, 00), 88],
[Date.UTC(2013, 9, 27, 9, 35, 00), 90],
[Date.UTC(2013, 9, 27, 9, 38, 00), 80],
[Date.UTC(2013, 9, 27, 9, 42, 00), 75],
[Date.UTC(2013, 9, 27, 9, 44, 00), 63],
[Date.UTC(2013, 9, 27, 9, 50, 00), 46],
[Date.UTC(2013, 9, 27, 9, 55, 00), 35],
[Date.UTC(2013, 9, 27, 10, 08, 00), 28]
],
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}]
});
});
});
$("#slider").slider({
value: 0,
min: Date.UTC(2013, 9, 27, 9, 1, 00),
max: Date.UTC(2013, 9, 27, 10, 08, 00),
step: 0.0001,
slide: function(event, ui) {
//$("#slider1").slider("value", ui.value);
$("#slider-value").html(ui.value);
}
}).find('.ui-slider-handle').append('<div class="line"></div>');
*, *:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
padding: 10px;
background: #323334
}
p {
font-family: Helvetica, Arial;
color: #aaa;
font-size: 14px;
}
a, a:visited, a:hover {
color: #FFDD45;
text-decoration: underline;
outline: none;
}
#container {
min-height: 400px;
min-width: 310px;
position: relative;
z-index: 1;
}
.ui-slider {
margin: 0 22px 0 110px;
}
.ui-slider .ui-slider-handle {
background: url('https://revivemarketing.github.io/images/playhead_top.png') no-repeat 50% 50% !important;
border: none !important;
width: 18px !important;
height: 20px !important;
margin-left: -.75em;
cursor: pointer;
outline: none;
}
#slider.ui-slider .ui-slider-handle {
background: url('https://revivemarketing.github.io/images/playhead_bottom.png') no-repeat 50% 50% !important;
}
.ui-slider {
position: relative;
text-align: left;
background: #6F7073 !important;
border-color: #303030 !important;
border-left: none;
border-right: none;
box-shadow: 0px 1px 1px 0px #000 inset !important;
height: .75em;
border-radius: 0;
}
.line {
width: 2px;
background: #FF2600;
border-left: #9A0900 1px solid;
bottom: 15px;
left: 8px;
height: 68px;
z-index: 100;
position: absolute;
pointer-events: none;
box-shadow: 1px 0 0 0 #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/highcharts-more.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script src="http://revivemarketing.github.io/js/highcharts-dark.js"></script>
<div id="container"></div>
<div id="slider"></div>
<p id="slider-value"></p>
<p id="click-value"></p>
<p id="report"></p>