Shared tooltip positioner point.plotY is always 0 in Highcharts Stacked columns - highcharts

I have this kind of graphics : https://www.highcharts.com/demo/column-stacked-percent
My problem is that, like in the example, the tooltip lies on the top of each bar. Using the positioner property of the tooltip gives me the possibility of placing it somewhere, however the point.plotY property is always 0. I think that this comes from the fact that tooltip is shared.
I need to place the tooltip on bottom when i'm hovering the top series, because I have some information between bars hidden by the tooltip.
How can I get this point.plotY "real" value or overcome the problem ?

When you have a stacked column, you can get the hover points via this.chart.hoverPoints (this is the tooltip) and choose the point from the stacked column.
If want a specific point which is not part of the hovered column - you can access series object and its via this.chart.series[seriesIndex].data[pointIndex].
Positioner for the tooltip which appears in the bottom point:
positioner: function (w, h, p) {
const chart = this.chart
const points = chart.hoverPoints
if (points && points.length) {
const i = points.length - 1
return { x: points[i].plotX + chart.plotLeft - w / 2, y: points[i].plotY + chart.plotTop}
}
return { x: 0, y: -9e7 }
}
example: http://jsfiddle.net/8acems26/

Related

How to position Highcharts tooltip on top of bar or at 0 line of Y-axis for negative value

Highcharts tooltip is shown at bottom of the column bar for negative values but i want it to show on top or at 0 axis level. Please help.
Present tooltip position as per highcharts:
Reference image of how i want to position:
You can set the positioner of tooltip like this
tooltip: {
positioner: function(__, __, point) {
return {
x: point.plotX,
y: point.negative ? point.plotY - point.h : point.plotY
}
}
}

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

Position shared tooltip above the stacked columns

When using stacked columns, I would like the tooltip to be positioned above the stacked columns. Right now, the tooltip will appear above the hovered part of the column, like this:
I would like the tooltip to always appear above the stacked columns regardless of the hovered part, like this:
(source: i.ibb.co)
I know about the positioner method, but this function doesn't seem to receive the proper parameters for me to position the tooltip above the stacked columns. In particular I don't know how to properly get the coordinates of the hovered column, all I get is the global position of the cursor.
You can use the shared parameter for a tooltip:
tooltip: {
shared: true
}
Live demo: http://jsfiddle.net/BlackLabel/us4h659d/
API Reference: https://api.highcharts.com/highcharts/tooltip.shared
So I finally managed to do it using Axis.toValue() and Axis.toPixels() values:
https://api.highcharts.com/class-reference/Highcharts.Axis
For my solution to work you need to have a way to get the total value of a stacked column. There may be a way to do it using only the Highcharts object, but I don't like messing too much with the internals of Highcharts for compatibility reasons.
Here's what the positioner method could look like:
function positioner(labelWidth, labelHeight, point)
{
// Default position, assuming mChart is the Highcharts object
var chartY = point.plotY + mChart.plotTop;
var chartX = point.plotX + mChart.plotLeft;
// Move chartY above the stacked column, assuming getTotalColumnValue() exists
var category = Math.round(mChart.xAxis[0].toValue(point.plotX, true));
if(category in mChart.xAxis[0]['categories'])
chartY = mChart.yAxis[0].toPixels(getTotalColumnValue(category), false);
// Move tooltip above the point, centered horizontally
return {
x: chartX - labelWidth / 2,
y: chartY - labelHeight - 10,
};
}

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.

Resources