highstock axis update from button - highcharts

I am trying to get a simple axis update to work through a button on highstocks, with the plan of "hiding" a data series/yaxis out of view when you hit a button, and then reducing the chart's height by that amount. For the life of me I just cannot get the button to work. If I manually put the setting of "top: -300" into the second y axis it works. Where is this going wrong?
jsfiddle:
http://jsfiddle.net/abbike18/Ww5Tg/3/
var chart = $('#container').highcharts();
$('#hide').click(function() {
chart.yAxis[1].update({
top: -300
});
chart.setSize(chartHeight = chartHeight -100);
});

First of all, you create variable chart before chart is initialized. Move that line inside the button, will be better. Second, you didn't created chartHeight variable anywhere. Last thing, is to redraw chart only once (in setChart function), so disable redraw for yAxis.update().
See working demo: http://jsfiddle.net/Ww5Tg/4/
And code:
var chartHeight = 500;
$('#hide').click(function() {
var chart = $('#container').highcharts();
chart.yAxis[1].update({
top: -300
}, false);
chartHeight -= 100;
chart.setSize(null, chartHeight);
});

Related

How to position highcharts tooltip above chart with outside:true

I have a system with lots of highcharts which can be positioned basically anywhere on the page.
Some are very small (e.g. 50px x 50px).
I see we can set tooltip.outside : true
tooltip: {
outside: true
}
This stops the tooltip taking over the whole chart container by breaking it out of the chart and into the window.
However this can cause overflow issues with the window when you're near the edge of the page and I personally prefer a static tooltip.
I'd like to always fix the tooltip to float above the chart, top left with a bit of padding, which for my application will almost always be visible and will avoid overflow issues, e.g.;
I've looked into setting a custom positioner, however, as the "outside" tooltip is now part of the window and not relative to the chart, the positioner sets a fixed position, which isn't suitable for my application.
I'd like the tooltip to always be above the chart regardless of mouse or scroll positions.
Of course I could add a custom element and position it above the chart myself, then applying the tooltip to that, but we have a lot of charts and this seems cumbersome.
Tooltip outside Fiddle
Suggestions?
Thanks
After a bit of poking around in the highstock Tooltip.prototype.getPosition code, it turns out what I needed was this.point.chart.pointer.getChartPosition();
tooltip: {
distance: 40,
outside: true,
positioner: function () {
var point = this;
var chart = point.chart;
var chartPosition = chart.pointer.getChartPosition();
var distance = point.distance;
//Position relative to renderTo container
return {
x: chartPosition.left - distance,
y: chartPosition.top - distance - (point.options.useHTML == true ? point.label.div.offsetHeight : point.label.height)
}
//Alternatively - Position relative to chart plot (ignoring legend)
var containerScaling = chart.containerScaling;
var scaleX = function (val) {
return (containerScaling ? val * containerScaling.scaleX : val);
};
var scaleY = function (val) {
return (containerScaling ? val * containerScaling.scaleY : val);
};
return {
x: chartPosition.left - distance + scaleX(chart.plotLeft),
y: chartPosition.top - distance + scaleY(chart.plotTop) - point.label.height
}
},
},
See working fiddle.
I find it odd that this method is attached to pointer, but it's what I was after.
One thing to note, in the fiddle I use point.label.height, if useHTML:true; use point.label.div.height.
What about using the positioner callback without setting the 'outside' option? It will set the wanted position inside the chart area.
Demo: https://jsfiddle.net/BlackLabel/gabjwd2e/
API: https://api.highcharts.com/highcharts/tooltip.positioner

Highcharts click function update series and cancel previous update

I built a line chart with more than 50 series: fiddle
Now I want to highlight one series by button click (opacity: 1). When I highlight another series, the first one should get its original opacity of 0.1 again.
With only two series I can achieve this by doing this:
$('#func1').click(function () {
var chart = $('#Weltweit').highcharts();
chart.series[3].update({opacity: 0.1});
chart.series[4].update({opacity: 1});
});
$('#func2').click(function () {
var chart = $('#Weltweit').highcharts();
chart.series[3].update({opacity: 1});
chart.series[4].update({opacity: 0.1});
});
But I cannot do this with 50 series because it takes too long to calculate. Is there a way to cancel the previous update before doing a new one?
Use the update method with redraw parameter set to false and redraw chart after loop:
chart.series.forEach(function(s) {
s.update({
...
}, false);
});
chart.redraw();
Live demo: http://jsfiddle.net/BlackLabel/3a9bfjgd/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.Series#update
https://api.highcharts.com/class-reference/Highcharts.Chart#redraw
You can read here, similar with your problem: https://api.highcharts.com/highcharts/series.line.point.events.select

Highcharts yAxis labels inside plot area and left padding

I have a column chart that has yAxis labels inside the plot area. DEMO: http://jsfiddle.net/o4abatfo/
This is how I have set up the labels:
yAxis: {
labels: {
align: 'left',
x: 5,
y: -3
}
}
The problem is that the leftmost column is so near the plot area edge that labels are overlapping it. Is there a way to adjust the plot area padding so that the columns would start a bit further on the right?
You can set min value as -0.49.
http://jsfiddle.net/o4abatfo/2/
One possible solution:
Keep the labels on the outside, and apply the plotBackgroundColor as the chart backgroundColor.
This means that the legend will be encased in the background color too, but, again, it's on option.
Example:
http://jsfiddle.net/jlbriggs/o4abatfo/11/
I asked the same thing in the Highcharts forum and got this solution as a reply from #paweł-fus:
var chartExtraMargin = 30;
Highcharts.wrap(Highcharts.Axis.prototype, 'setAxisSize', function (p) {
p.call(this);
if (this.isXAxis) {
this.left += chartExtraMargin;
this.width -= chartExtraMargin;
this.len = Math.max(this.horiz ? this.width : this.height, 0);
this.pos = this.horiz ? this.left : this.top;
}
});
However, adding this made the tooltips appear in the wrong position. This was fixed by overriding the Tooltip.prototype.getAnchor() method and adding the extra margin in the x coordinate:
Highcharts.wrap(Highcharts.Tooltip.prototype, 'getAnchor', function(p, points, mouseEvent) {
var anchor = p.call(this, points, mouseEvent);
anchor[0] += chartExtraMargin;
return anchor;
});

How to draw a background behind a plotLine label in a highstock chart

I want to draw a background behind a plotLine label in a highstock chart.
Using an example from the Highstock API, I came up with this code (crt is the chart object):
var textbox = crt.yAxis[ 0 ].plotLinesAndBands[ 0 ].label;
var box = textbox.getBBox();
crt.renderer.rect(box.x - 3, box.y + 1, box.width + 6, box.height, 3).attr({
fill: '#0c0',
id: 'labelBack',
opacity: .7,
'stroke-width': 0,
zIndex: 4
}).add();
This draws a semi-transparent box behind the label as intended (the label has zIndex 5). However when the chart is resized, the box maintains the same position relative to the top-left of the chart, causing misalignment with the label text (the position of the label changes because of the chart resizing).
I tried using the chart redraw event for this, but even though I can see that the event is fired, and the function is executed again, no other boxes are drawn (I was trying to get more boxes to appear on each redraw, planning to solve removing obsolete boxes in the next iteration).
How can I solve this?
It feels more like a hack than a genuine solution, but I have come up with a workaround that solves my issue for now, I have the function below:
var labelBackground = null;
function labelDrawBack(crt) {
if ( isIntraDay ) {
var textbox = crt.yAxis[ 0 ].plotLinesAndBands[ 0 ].label;
if ( !!labelBackground ) {
labelBackground.attr({ y: textbox.y - 10 });
} else {
var box = textbox.getBBox();
labelBackground = crt.renderer.rect( box.x - 3, box.y + 1, box.width + 6, box.height, 3 ).attr( {
fill: '#fff',
id: 'labelBack',
opacity: .65,
'stroke-width': 0,
zIndex: 4
}).add();
}
}
}
I make sure this function is executed immediately after the chart is initialized and additionally I attach the function to the chart object that is returned from the StockChart call:
var chartObj = new Highcharts.StockChart( chartConfig, function ( crt ) {
labelDrawBack( crt );
} );
chartObj.labelDraw = labelDrawBack;
And in the chart options I have added this to the chart.redraw event:
events: {
redraw: function() {
this.labelDraw(this);
}
}
This works as intended, moving the transparent background with the label (which is moved vertically when the chart is resized).
The reason I have redirected the call in the chart redraw event is that the labelDrawBack function is defined in another function than the one where my chart options are defined, thus the labelDrawBack function is out of scope there.

HighCharts Keep Vertical Line on Click Event

Using this example: http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/stock/demo/candlestick-and-volume/
When you hover over points on the chart, you get a nice vertical line showing you which point you're currently on. I want to modify the click event so that the vertical line stays when I hover away after a click. Changing the line color would be ideal on click, but not necessary.
If I click another point I'd want to remove any previous lines. Any ideas on how I could accomplish this?
The above solution like I said, is really cool, but is kind of a hack (getting the path of the crosshair) into the implementation details of highcharts, and may stop working in future releases, may not be totally cross browser (esp since <IE8 do not support SVG, the adding path may still work as it should be handled by highchart's add path method, but getting the crosshair's path may not work, I may be wrong, am an SVG noob). So here I give you the alternate solution of dynamically adding plotLines. PlotLines also allow some additional features like dashStyles, label etc.
get the axis and x value of point clicked (may not exactly overlap the crosshair)
var xValue = evt.xAxis[0].value;
var xAxis = evt.xAxis[0].axis;
Or
EDIT If you want to have the plotLine at the location of the crosshair and not the click position, you can use following formula (No direct API to get this, obtained from source code hence may stop working if code changes)
var chart = this;
var index = chart.inverted ? chart.plotHeight + chart.plotTop - evt.chartY : evt.chartX - chart.plotLeft;
var xValue = chart.series[0].tooltipPoints[index].x;
Add plotline
xAxis.addPlotLine({
value: xValue,
width: 1,
color: 'red',
//dashStyle: 'dash',
id: myPlotLineId
});
You can cleanup existing plotline
$.each(xAxis.plotLinesAndBands,function(){
if(this.id===myPlotLineId)
{
this.destroy();
}
});
OR
try {
xAxis.removePlotLine(myPlotLineId);
} catch (err) {}
Putting the pieces together
var myPlotLineId="myPlotLine";
...
var chart=this;
index = chart.inverted ? chart.plotHeight + chart.plotTop - evt.chartY : evt.chartX - chart.plotLeft;
var xValue = chart.series[0].tooltipPoints[index];
// var xValue = evt.xAxis[0].value; // To use mouse position and not crosshair's position
var xAxis = evt.xAxis[0].axis;
$.each(xAxis.plotLinesAndBands,function(){
if(this.id===myPlotLineId)
{
this.destroy();
}
});
xAxis.addPlotLine({
value: xValue,
width: 1,
color: 'red',
//dashStyle: 'dash',
id: myPlotLineId
});
...
Add plot lines at click position # jsFiddle
Persist crosshair/cursor as plot lines on click # jsFiddle
You can do it in several ways
Highchart has a very cool renderer that allows you to add various graphics to the chart. One of the options is to add a path I will be illustrating the same here.
We shall reuse the path of the crosshair and add the same to the chart with some additional styles like color you mentioned. The path of the crosshair can be optained as this.tooltip.crosshairs[0].d this is in string form and can be easily converted to an array using the Array.split() function
click: function() {
this.renderer.path(this.tooltip.crosshairs[0].d.split(" ")).attr({
'stroke-width': 2,
stroke: 'red'
}).add();
}
This will accomplish adding the line. You can store the returned object into a global variable and then when you are about to add another such line, you can destroy the existing one by calling Element.destroy()
var line;
...
chart:{
events: {
click: function() {
if (line) {
line.destroy();
}
line = this.renderer.path(this.tooltip.crosshairs[0].d.split(" ")).attr({
'stroke-width': 2,
stroke: 'red'
}).add();
}
}
...
Persist tooltip / crosshair on click # jsFiddle
Assuming you don't have much meta data to be shown along with the line, this is the easiest (or the coolest :) ) approach. You can also attach meta data if you want to using the renderer's text object etc.
An alternate way could be adding vertical plotLines to the xAxis
UPDATE
Refer my other solution to this question, that would work with zoom,scroll,etc

Resources