Highcharts / Highstock scroll default position - highcharts

I have a HighStock charge with a scrollbar very similar to this one
http://jsfiddle.net/gh/get/jquery/3.1.1/highslide-software/highcharts.com/tree/master/samples/stock/demo/navigator-disabled/
Highcharts.stockChart('container', {
rangeSelector: {
selected: 1
},
title: {
text: 'AAPL Stock Price'
},
navigator: {
enabled: false
},
series: [{
name: 'AAPL Stock Price',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
I want the default scroll position to be somewhere in the middle of the chart though, is there any way to do this?

You can do this with xAxis.setExtremes on the chart.events.load call. A simple example (using arbitrary 1 year range):
chart: {
events: {
load: function() {
this.xAxis[0].setExtremes(
Date.UTC(2013, 0, 1),
Date.UTC(2013, 11, 31)
);
}
}
},
Example jsFiddle.
If you need to determine what your "middle" is it can depend on your data source where you could pre-calculate it or you could do it also on the chart.events.load call.
For fun I added the mid-point calculations. This uses moment.js because it is much easier than rolling your own time methods.
minX = data[0][0];
maxX = data[data.length - 1][0];
midX = minX + ((maxX - minX) / 2);
var midDate = new Date(midX);
var startDate = moment(midDate);
var endDateMoment = moment(midDate);
startDate.subtract(1.5, 'months');
endDateMoment.add(1.5, 'months');
Note that I am addinng/subtracting 1.5 months to make your 3 month range selector valid. The moment.js library rounds those up to 2 months. You get the idea though. So your setExtremes becomes:
this.xAxis[0].setExtremes(
startDate.valueOf(), //.valueOf() in this context converts to javascript time
endDateMoment.valueOf()
);
And here is live jsFiddle.

Related

Show plotlines in highcharts with hidden axis?

Is there a way to show plotlines even when the associated axis has visible: false? Is seems that hiding the axis also hides the plotlines.
More details...
I'm drawing a diagram of a day, like this:
I simply want to add a vertical line at certain times, line the "Now" time, etc.
If I do that using a plot line, then the axis shows up too:
I definitely do not want the axis to show.
My plan now is to draw my own line on the chart using render.rect or render.path. Is there another option?
I found a relatively trivial solution... just hide it with css:
.highcharts-xaxis {
display: none;
}
and in js:
xAxis: {
type: 'datetime',
labels:{
enabled: false
}
}
You can extend Highcharts by wrapping the method responsible for redrawing an axis.
Highcharts.wrap(Highcharts.Axis.prototype, 'redraw', function(p) {
p.call(this);
console.log(this);
var axis = this,
each = Highcharts.each,
options = this.options;
// move plot lines and bands
if (!axis._addedPlotLB) { // only first time
each((options.plotLines || []), function(plotLineOptions) {
axis.addPlotBandOrLine(plotLineOptions);
});
axis._addedPlotLB = true;
}
each(this.plotLinesAndBands, function(plotLine) {
plotLine.render();
});
});
example: http://jsfiddle.net/ncs81btt/
The solution above is not very elegant, though. Much better ways to do it is using Renderer or hide particular axis elements (labels, ticks, etc.).
Depending on what you need from plot lines functionality, using renderer requires to do some calculations.
var customPlotLines = [{
value: 5,
color: 'red',
width: 3
}, {
value: 10,
color: 'yellow',
width: 3
}]
function renderPlotLines() {
var axis = this.xAxis[0],
top = axis.chart.plotTop,
bottom = top + axis.chart.plotHeight,
path = [
'M', null, top,
'L', null, bottom
];
if (!this.customPlotLines) {
this.customPlotLines = customPlotLines.map(plotLine => {
return this.renderer.path([]).add();
});
}
this.customPlotLines.forEach((plotLine, i) => {
var opt = customPlotLines[i];
path[4] = path[1] = axis.toPixels(opt.value);
plotLine.attr({
d: path.join(' '),
'stroke-width': opt.width,
stroke: opt.color
});
});
}
Hook into load/redraw event, so the elements will resize.
chart: {
zoomType: 'xy',
events: {
load: renderPlotLines,
redraw: renderPlotLines
}
},
example: http://jsfiddle.net/ncs81btt/1/

Highcharts display priority of overlapping labels

When data labels overlap in Highcharts, only one data label is displayed. This seems to be handled randomly. See fiddle:
http://jsfiddle.net/lamarant/rmxLd1d4/
$(function () {
$('#container').highcharts({
title: {
text: 'Label Test'
},
series: [{
type: 'line',
data: [ 10, 10, 10, 10, 10, 10, 50],
dataLabels: {
enabled: true,
color: 'blue',
zIndex: 10
},
zIndex: 10
},
{
type: 'line',
data: [ 11, 11, 11, 11, 11, 11, 49],
dataLabels: {
enabled: true,
color: 'red',
zIndex: 10
},
zIndex: 20
}]
});
});
Notice that the first data label displayed in the chart is from the second series while the rest are from the first series.
I tried setting the priority of the label display using zIndex in both series and series.dataLabel with no luck.
Is there any way to set it so that a designated series always takes priority when Highcharts determines which label to display?
One possible fix is supplying a labelrank for each point, which is used to evaluate their sorting order. If you supply this rank for each point in a series, that series should be considered "above" series without such a rank (or with a lower rank integer value).
In code, manually for each point:
series: [{
data: [
{ y: 11, labelrank: 1 },
{ y:11, labelrank: 1 }
// ...
],
// ...
}]
In code, using the callback function (JSFiddle):
$('#container').highcharts({
// Options ...
}, function() {
var mySeriesIndex = 1;
// For each point in the preferred series
for(i = 0; i < this.series[mySeriesIndex].points.length; i++)
// Set a labelrank
this.series[mySeriesIndex].points[i].labelrank = 1;
});
My current take on the issue itself is this:
With the current implementation of the overlap logic it seems to me that this is a bit of an unintended behavior. The source code uses Array.sort in a way that shifts the positions of the point labels, since Array.sort is not guaranteed to be stable (same-value items wont retain their original order).
If you check your example in Firefox it should work as intended (their implementation of Array.sort is different), while in Chrome it doesn't (not stable). You could hope that this little feature is fixed.

Highstock - Display last chart point in the center of the Y axis

I want to display last chart point in the center of the Y axis always. To do this I use setExtremes() function. With integer values this solution works fine. But then it comes to float values it doesn't.
https://jsfiddle.net/antongrinenko/jj33wd2p/1/
$(function () {
$('#chart').highcharts('StockChart', {
chart: {
type: 'line'
},
series: [{
name: 'SomeData',
data: [[1, 1.1111], [2, 2.2222], [3,3.3333]]
}],
yAxis: {
floor: 0
}
});
var newValue = 2.82654;
var series = $('#chart').highcharts().series[0];
series.addPoint([4, newValue]);
var extr = series.yAxis.getExtremes();
var delta = Math.max(extr.dataMax - newValue, newValue - extr.dataMin);
series.yAxis.setExtremes(newValue - delta, newValue + delta);
});
How can I fix it?
It is caused by default options yAxis.startOnTick and yAxis.endOnTick (both set to true) - Highcharts are rounding extremes to start/end on a "nice-number" tick. You can disable that by setting those option to false, see: https://jsfiddle.net/jj33wd2p/2/

How to force points above maximum to be on maximum grid line, but still show real value in tooltip

I'm drawing a really simple line chart with hours slept each day. So hours are on the y axis and dates on the x axis. The y axis goes from 0 to 23, but interesting values are usually between 3 and 12, so I only want to draw these values. This is easy, just define min and max on yaxis.
But now highcharts will still draw values above and below the min and max y valus. What I want is to have it just draw values above 12 on the 12 max grid line, and show the real value in the tooltip, and the inverse for values below 3.
Illustration of problem: https://jsfiddle.net/HhP39/10/
$(function () {
$('#container').highcharts({
chart: {},
yAxis: {
title: {
text: 'Hours'
},
min: 3,
max: 12,
tickInterval: 1
},
series: [{
data: [2,6,13,4,9,12,6,8,1,15,9,7,5,8,14,5,8,2,3]
}]
});
});
As you can see, values just out of range, such as 2, will still produce a tooltip if you hover over where they are. I want all values like these to move to be on the min and max lines.
Anybody got any ideas?
Take a look at this update to your fiddle: https://jsfiddle.net/HhP39/7/
It's creating an array of the original values and then an array of the adjusted values. The graph actually charts the adjusted values but the tooltip pulls from the original values.
data = [2,6,13,4,9,12,6,8,1,15,9,7,5,8,14,5,8,2,3];
series = [];
tooltips = [];
for (var i in data) {
tooltips.push(data[i]);
series.push( Math.max(3, Math.min(data[i], 12)) );
}
And then chart it with:
$('#container').highcharts({
chart: {},
yAxis: {
title: {
text: 'Hours'
},
min: 3,
max: 12,
tickInterval: 1
},
tooltip: {
formatter: function() {
return ('Real value: ' + data[this.x]);
}
},
series: [{
data: series
}]
});

Shared Crosshair Highlighting /w Non-sequential Series

I have two lines of date data. One line plots a point sequentially every day. The other line plots non-sequental points that fall on one of the days of the previous line.
The problem is that the crosshair functionality behaves weirdly when I do this. See the example linked below. You will notice that although the tooltip and point highlighting shows for the proper point, the crosshair gets stuck on the non-sequential point along the x-axis, even though this is not the current position of my mouse on the chart. The exception to this is when you hover your mouse directly across the line. The crosshair follows the mouse properly then.
See example here: http://jsfiddle.net/2H9m3/1/
$(function () {
$('#container').highcharts({
tooltip: {
shared: true,
crosshairs: true
},
xAxis: {
type: "datetime", maxPadding: 0, minPadding: 0
},
yAxis: {
min: 0
},
series: [{
name: 'Line',
data: GenerateData(10, 50)
}, {
name: "Events",
color: "#EF4B68",
lineWidth: 0,
marker: {
enabled: true,
symbol: "triangle",
radius: 6
},
data: [
[5 * 86400000, 0],
[21 * 86400000, 0]
]
}]
});
});
function GenerateData(min, max) {
var data = [];
for (i = 0; i < (30 * 86400000); i = i + 86400000) {
data.push([i, GetRandomInt(min, max)]);
}
return data;
}
function GetRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
I am not sure if this is a bug or something that I am doing wrong.
The issue here is subtle. It is actually caused by the fact that the tooltip is linked over the top-most series. Since you are creating your linear series first then your non-sequential series the top-most series is the 2 points. So, in order to recapture the 'tooltip` and your crosshair you have to hover closer to the series that is behind the non-sequential series.
Fixes:
Make the non-sequential series the first one you add.
Give an index value to whichever series you want on top that is larger than the least-full series.
I went with option 2:
series: [{
name: 'Line',
index: 1,
data: GenerateData(10, 50)
}, {
name: "Events",
index: 0,
color: "#EF4B68",
lineWidth: 0,
marker: {
enabled: true,
symbol: "triangle",
radius: 6
},
data: [
[5 * 86400000, 0],
[21 * 86400000, 0]
]
}]
Example here.
Looks like a bug in new crosshairs core.
Reported to devs: https://github.com/highslide-software/highcharts.com/issues/2816
Thanks!

Resources