Hide Series without hiding y-Axis - javascript

There are plenty examples of hiding an Y-Axis without hiding the series - But i need the opposite of that.
I want to make a series invisible while still displaying the y-axis and i dont know how!
Why?
Because i have 2 diagrams which are perfectly aligned by their x-Axis:
But when i disable both Temperature fields, the axis will be lost, and the diagrams are incorrect in size:
I also don't like the idea, of disabling all and loosing whole diagram style:
There is no problem by having an empty diagram, but having a blank box isn't the style i want to reach.
I tried to manipulate the axis in within the legendItemClick event, but selecting the correct axis and set their value visible didn't work out. How can I solve this problem?

I think you have two options:
play around with margins - to make them fixed
set min and max for axis, so labels will remain on a chart: example
if you don't know min/max values at start you can change them within the legendItemClick as following:
plotOptions: {
series: {
events: {
legendItemClick: function() {
var temperatur = this.chart.series[0];
var taupunkt = this.chart.series[1];
var other = this.name=="Lufttemperatur"?taupunkt:temperatur;
var element = this;
if(this.name == "Lufttemperatur" || this.name == "Taupunkt") {
if(this.visible && !other.visible) {
//both will be invisible soon
this.chart.yAxis[0].update({
min:element.yAxis.min,
max:element.yAxis.max
});
} else {
//one will be visible
this.chart.yAxis[0].update({
min:null,
max:null
});
}
}
}
}
},
}
This will only set min/max if there is no one of your series visible, but deletes it if you have one visible

Related

Highcharts tooltip in scrollable container scrolls with the content

I have a Highcharts instance that is rendered within a scrollable container. The tooltip.outside option is also set to true so that the tooltip is always on top regardless if it fits the chart svg.
When you scroll however, you can see tooltip following the scrolling. Moreover, when you hover over the series, the tooltip renders in various positions.
Is there a way to fix it? FYI if you set tooltip.outside to false everything works just fine. I'm sure the issue revolves around the fact that when set to true, the calculation to determine where to render the tooltip is no longer correct as the position changed with the scrolling.
So to sum up the 2 issues that appear:
The tooltip follows the scrolling
On re-hovering, the position on the tooltip on the series is wrong.
See gif around the issue: https://imgur.com/a/Zj3NstL
See example: https://jsfiddle.net/tcqeo415/2/
If you comment out my CSS code in the example, you should be able to see how it should work
This answer is pretty similar to #ppotaczek one in terms of the idea just a different implementation.
When the mouse enters a chart, the chart position is cached so if you scroll but your mouse is still within the chart, it doesn't recalculate the position but due to the scrolling the position has changed.
A solution would be to use tooltip.positioner and disable the caching by nullifying the chartsPosition.
positioner: function (w, h, point) {
this.chart.pointer.chartPosition = null;
return this.getPosition(w, h, point);
},
This will force the chart to recalculate the charts position. Note that this might be DOM expensive.
Then, if you want to maintain the scrolling behaviour checkout #ppotaczeck's answer. The code below will remove any tooltips on scroll (works only for the first example)
document.body.addEventListener("scroll", function() {
Highcharts.charts[0].tooltip.hide(0);
}, true)
Example: https://jsfiddle.net/gv1m6tjy/
A chart does not recalculate it's position because it does not track the scroll event.
To fix this, you can recalculate chart.pointer.chartPosition.top. Below code works only for the first chart:
(function (H) {
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed, points) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
this.points = points;
});
}(Highcharts));
document.getElementById('container1').addEventListener('mouseenter', function(){
var chart = Highcharts.charts[0];
if (chart && chart.pointer && !chart.startChartPosY) {
chart.pointer.getChartPosition();
chart.startChartPosY = chart.pointer.chartPosition.top;
}
});
document.getElementById('outer').addEventListener('scroll', function(e){
var H = Highcharts,
chart = H.charts[H.hoverChartIndex],
tooltip = chart.tooltip;
if (chart && chart.pointer) {
chart.pointer.chartPosition.top = chart.startChartPosY - this.scrollTop;
}
if (tooltip && !tooltip.isHidden) {
tooltip.refresh(tooltip.points);
}
});
Live demo: https://jsfiddle.net/BlackLabel/ao0c21g6/3/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts

Slanted highcharts axis labels overlap with legend

I made a small fiddle based on the highcharts demos at http://jsfiddle.net/w53woene/1/
The issue I have boils down to four things:
1) I need to rotate the labels (this is based on a feature request so I can't ignore it).
labels: {
rotation: -45
}
2) The fact that the last label is really really long. This is based on data which is given for each chart so it's not always the case but it's the case around 30%-40% of the time so quite often.
3) Labels shouldn't be wrapped or shortened with an ellipsis.
4) I need to add spacing between the chart and the legend to adapt to the labels size but only when the label is going to be too long and colliding with the legend.
This only seems to happen when the chart: { inverted: true } and if it's not inverted the legend behaves normally, increasing the distance from the chart as needed.
Ideally I'd like to know if there's a specific option I'm missing that achieves this natively, i.e., I would have expected floating: false to achieve this the same way it does when the chart is not inverted, but it doesn't seem to. If this isn't possible I'd like to know how I can adjust the chart size (excluding the legend) in order to achieve this via JavaScript.
The problem is that vertical axis add space on the left size, but doesn't add on the bottom. I would wrap labels for a better readability: http://jsfiddle.net/w53woene/2/ - otherwise it may happen that you will have so long label that chart will get 0 pixels for plotting area.
If you really need non-wrapped text, then I would wrap Axis.prototype. getOffset to add extra space:
(function(H) {
H.wrap(H.Axis.prototype, 'getOffset', function(p) {
p.call(this);
if (this.isXAxis) {
var lastTick = this.tickPositions[this.tickPositions.length - 1],
lastLabel = this.ticks[lastTick].label,
height = lastLabel.getBBox(true).height;
this.labelDiff = height - this.chart.marginBottom;
if (this.labelDiff > this.chart.axisOffset[2]) {
this.chart.axisOffset[2] = this.labelDiff;
} else {
this.labelDiff = 0;
}
} else {
this.offset -= this.chart.xAxis[0].labelDiff;
}
});
})(Highcharts)
And live demo: http://jsfiddle.net/vwegeuvy/

stackLabels configuration in Highcharts

I am working with highcharts and having some problems with stackLabels configuration of highcharts. I was asked to display a bar chart with "score/full score" format, e.g. 6 out of 10 should be like
⬛︎⬛︎⬛︎⬛︎⬛︎⬛︎⬜︎⬜︎⬜︎⬜︎ 6/10
And I faked it with stacked bar chart with 6 for the first part of the bar and 4 for the second part.
[Solved] However, I don't know how to display 6/10 in stackLabels (It seems that I can only use {total} in it, while I can use {point.y}/{point.fullscore} in dataLabels).
[Unsolved] And also, when I use the basic bar chart, dataLabels automatically adjust its position (In my case, dataLabels will show on the left of the right edge of the bar). However, how should I force the stackLabels to display?
This answer points out that there is no enough space for stackLabels to display, and the solution is to make max value bigger and leave some space for it. However, the solution is not that elegant to me, and also since my bar chart is horizontal and the label should be long.
Any help will be appreciated! Thanks in advance!
To answer second question:
You can set yAxis.stackLabels.crop to false, so labels will be rendered always. Those labels won't show up inside the plotting area, but will be rendered somewhere outside. stackLabels are not dataLabels - dataLabels have option justify, which forces labels to be rendered inside the plotting area.
However, in Highcharts you can get access to those labels, and move them (that's why crop needs to be set to false - to render labels anyway), here is simple POC:
function updateStacks() {
var chart = this,
H = Highcharts,
padding = 15,
item,
bbox;
for (var stackName in chart.yAxis[0].stacks) {
for (var itemName in chart.yAxis[0].stacks[stackName]) {
item = chart.yAxis[0].stacks[stackName][itemName]; // get stack item
bbox = item.label.getBBox(true); // get label's bounding box
// if label is outside, translate it:
if (bbox.width + bbox.x > chart.plotWidth) {
// add some poding, for a better look&feel:
item.label.translate(-bbox.width - padding);
}
}
}
}
Now simply use that method in load and redraw events, here you are:
chart: {
type: 'bar',
events: {
redraw: updateStacks,
load: updateStacks
}
},
And live demo: http://jsfiddle.net/awe4abwk/ - let me know if something is not clear.
PS: Your answer with formatter for stackLabels is good!
Use formatter to change default stack label. You can access axis label with this.axis.
stackLabels: {
enabled: true,
formatter: function() {
return (this.axis.series[1].yData[this.x] / this.total * 100).toPrecision(2) + '%';
//Make your changes here to reflect your output. This is just a sample code
}
}
Now to always show stack labels you have two options which are described here.
Link
Okay, I've found the solution for the first question: How to show the specific series values in stackLabels? from this answer.
In my case, the code should be:
yAxis: {
stackLabels: {
formatter: function() {
return [this.axis.series[1].yData[this.x], '/', this.total].join('');
},
enabled: true,
}
}
If you have better solution, post it! And I still have no idea about how to find it in the docs, maybe I should dig more...

x-area labels on hover

I need add another color for xAxis labels when it's hover (like number 19 in the picture). I saw this property later but I lost it.
Need a help =)
And can I set a property (z-index) for xAxis tick? Cause its color must be white, and now I can't see this color, when its z-index less than z-index chart's area.
For your first question, I would use a shared tooltip and the point mouseOver event to change the corresponding axis label:
plotOptions: {
series: {
point: {
events: {
// on mouseOver make the xaxis label red
mouseOver: function(){
var xAxis = this.series.chart.xAxis[0];
$(xAxis.ticks[this.x].label.element).css('fill','red');
},
// on mouseOut make it gray again
mouseOut: function(){
var xAxis = this.series.chart.xAxis[0];
$(xAxis.ticks[this.x].label.element).css('fill','#606060');
}
}
}
}
},
Example here.
For your second question, z index with SVG is a little tricky. It doesn't have a true zIndex you can re-order but rather it's dictated by the order in which the elements are drawn. I can't see it matters, though, because the labels are drawn on top of the chart area already (or else you wouldn't see them at all).

HighCharts - How to reposition labels after legend is clicked

I am trying to reposition data labels in HighCharts line charts so that they don't overlap.
You can do this initially by attaching a repositioning function to the load event:
var repositionLabels = function(series) {
var s1 = series[0].data;
var s2 = series[1].data;
var i=0, l=s1.length, higher;
for(; i<l; i++) {
higher = s1[i].y > s2[i].y;
s1[i].dataLabel.attr('y', higher ? s1[i].dataLabel.y-10 : s1[i].dataLabel.y+30 );
s2[i].dataLabel.attr('y', !higher ? s2[i].dataLabel.y-10 : s2[i].dataLabel.y+30 );
}
}
For the upper line, data labels are positioned above the line; for the lower line, the data labels are positioned below. So they don't overlap.
The problem
The problem is that if you click on a legend item to show/hide a line, the data labels revert to their default (bad, overlapping) positions. Here's a demo: http://jsfiddle.net/supertrue/QbGPV/984/
I would expect that attaching the same function to the redraw event would keep new label positions intact, but it doesn't. Nor does attaching it to plotOptions.line.events.legendItemClick.
How can I keep the good label positions intact after legend items are clicked?
I don't know if this is the best solution. I delayed the positioning and then it kinda worked.
See fiddle
setTimeout(function () {
positionLabels(chart.series);
}, 500);
Edit
Updated Fiddle
It appears that the series animation is interfering with the label positioning. If you set:
chart: { renderTo: 'container', type: 'line', animation:false,
then it all works fine. I'm guessing that the animation is running after you have positioned the labels, and is re-positioning them for you.
It looks like you'll either have to turn off animation, or use the setTimeout method posted by #anpsmn.

Categories

Resources