Highcharts | Line height control for plot band labels in styled mode - highcharts

I am looking to find a way to control line height for plot band labels in styled mode. The useHTML property doesn't work in my case as I need styles to persist in the downloaded PNG. I was looking for a solution similar to this.
I've tried adding something similar, but it completely broke my chart.
function (p) {
p.call(this);
const plotLine = this;
plotLine.label?.css(merge(this.options.label.style));
Here's a simple fiddle describing the issue, seems like no matter what is the font size the dy prop stays 15.
Appreciate if someone can help.

In this case, you need to wrap Highcharts.PlotLineOrBand.prototype render function. Check the following code and demo:
(function(H) {
H.wrap(H.PlotLineOrBand.prototype, 'render', function(proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, ));
const label = this.label;
if (label) {
label.css({
lineHeight: label.alignOptions.style.lineHeight
})
}
});
}(Highcharts));
More about Extending Highcharts:
https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
Demo:
https://jsfiddle.net/BlackLabel/nsg5abhq/

Related

Highchart datetime-XAxis export is different from the page

I use reflow = true to make sure my chart fit the width of the container div on resizing the window, so the XAxis will also change.
But when export, different size charts exported as the same size, and the XAxis are not as same as shown.
demo: https://jsfiddle.net/8zb9k5j6/
Is there any way to solve this? Thanks for your help
For example:
Full-screen, my XAxis is (4.Dec, 20.Dec, 3.Jan, 31.Jan, 14.Feb, 28.Feb)
Full-screen
When export as PNG(or whatever), my XAxis is (4.Dec, 20.Dec, 3.Jan, 31.Jan, 14.Feb, 28.Feb), that's what I want.
Full-screen-export
When I zoom out of the browser, the size of the chart will also decrease, my XAxis is (Dec'21, Jan'22, Feb'22)
small-size
When export as PNG(or whatever), my XAxis is (4.Dec, 20.Dec, 3.Jan, 31.Jan, 14.Feb, 28.Feb), that's not what I want, I want (Dec'21, Jan'22, Feb'22).
small-size-export
The chart export function renders the chart from initial - any changes, like zoom, extremes changes are not applied to the chart config. If you want to apply those changes you will need to add custom logic in the load event, like:
chart: {
events: {
load() {
const chart = this;
if (chart.renderer.forExport) {
console.log('aaply custom changes')
}
}
}
},
Demo: https://jsfiddle.net/BlackLabel/wfua8rye/
API: https://api.highcharts.com/highcharts/chart.events.load

Is there a way of dynamically toggling the Highstock navigator to regain vertical space for the chart?

I'd like to be able to be able to dynamically toggle the presence of the Highstock navigator and allow the chart to expand into the vertical space it occupied.
I've tried simply toggling chart.userOptions.navigator.enabled but it has no effect.
This thread explains how to use .hide() and .show() methods to conceal the individual components of the navigator and scrollbar, but these use visibility:hidden so the space does not become available for the chart. However, using .css({display: 'none'}) works, but the series itself has no .css() method, and I've been unable to find a way of removing the series from just the navigator.
Does anyone know a method to achieve what I want?
Thanks.
In short: it's not supported to hide navigator in real time. The best way would be to destroy chart and create new one with disabled navigator.
Other solution is to use workaround provided by Sebastian Bochan. Then you will need to update manually yAxis.height, for example: http://jsfiddle.net/dJbZT/91/
$('#btn').toggle(function () {
chart.yAxis[0].defaultHeight = chart.yAxis[0].height;
chart.xAxis[0].defaultHeight = chart.xAxis[0].height;
chart.yAxis[0].update({
height: 500 - chart.plotTop - 35
}, false);
chart.xAxis[0].update({
height: 500 - chart.plotTop - 35
});
chart.scroller.xAxis.labelGroup.hide();
chart.scroller.xAxis.gridGroup.hide();
chart.scroller.series.hide();
chart.scroller.scrollbar.hide();
chart.scroller.scrollbarGroup.hide();
chart.scroller.navigatorGroup.hide();
$.each(chart.scroller.elementsToDestroy, function (i, elem) {
elem.hide();
})
}, function () {
chart.yAxis[0].update({
height: chart.yAxis[0].defaultHeight
}, false);
chart.xAxis[0].update({
height: chart.xAxis[0].defaultHeight
});
chart.scroller.xAxis.labelGroup.show();
chart.scroller.xAxis.gridGroup.show();
chart.scroller.series.show();
chart.scroller.navigatorGroup.show();
chart.scroller.scrollbar.show();
chart.scroller.scrollbarGroup.show();
$.each(chart.scroller.elementsToDestroy, function (i, elem) {
elem.show();
})
});
There's another way to do this: reduce the chart height by the navigator's height, and set chart.reflow to false to prevent the Y-axis from adapting to the new chart height (try setting it to true in the fiddle -- notice the flicker when you show / hide the navigator?).
I've added this answer to the other thread, and the demo is here: http://jsfiddle.net/dJbZT/148/ (credits to Sebastian Bochan for the original answer).
I'm not sure when highcharts added this ability via options, but this worked for me:
var chart = $('#graphContainer').highcharts();
chart.options.navigator.enabled = !chart.options.navigator.enabled;
$('#graphContainer').highcharts(chart.options);

Highcharts - resize legend on chart resize?

Is there anyway to dynamically set a specific width of legend items when resizing the chart? I have some really long item names possible in the legend so I need to specify a width to force the text to wrap, but I would like to change the width when the width the chart changes. Thanks.
I found a better work around for this:
chart.legend.options.width = newwidth;
chart.legend.itemStyle.width = newwidth;
for(var index in this.chart.series) {
chart.legend.destroyItem(chart.series[index]);
}
chart.legend.render()
Generally it is not possible, but you can disable highcharts legend, and prepare your own div (positioned absolutely) which will include list of all series and click event. Simple example is available here
$legend = $('#customLegend');
$.each(chart.series[0].data, function (j, data) {
$legend.append('<div class="item"><div class="symbol" style="background-color:'+data.color+'"></div><div class="serieName" id="">' + data.name + '</div></div>');
});
$('#customLegend .item').click(function(){
var inx = $(this).index(),
point = chart.series[0].data[inx];
if(point.visible)
point.setVisible(false);
else
point.setVisible(true);
});
http://jsfiddle.net/N3KAC/10/
Than only what you need is adapt this to your chart by catching $(window).resize() function and resize element.

HighCharts: Positioning label on chart agnostic of legend size

I am building a pie chart where the labels for the data points can very greatly in length, the legend is configured to be vertical and positioned on the left side.
I have added a label element to the bottom of the chart that shows the total of all data points.
The problem I am facing is that the positioning of this label (via the style element) is based on how wide the legend is, which occasionally if the legend is wide enough will be pushed off the right side of the chart.
Does anyone know of a way that I can style this label so that is positioned based solely on the width of the entire chart.
Here is the styling applied to the label (I tried adding the position value but this didn't appear to do anything):
style: {
top: '325px',
position: 'absolute',
left: '-160px',
'font-size': '175%'
}
Here is an example of the chart that I'm working with, you can see that the value for the total has bee cut off.
EDIT:
As per Sebastian's comment I was able to effectively solve the issue by using the legend label formatter to limit the length of the series names. Here is the code:
labelFormatter: function () {
var formattedName = this.name;
if (formattedName.length > 17) {
formattedName = formattedName.substr(0, 14) + '...';
}
return formattedName;
}
Have you tried to use labelFormatter http://api.highcharts.com/highcharts#legend.labelFormatter ?

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