Update xAxis individual label position for printing Highcharts - highcharts

Is there a way to update specific xAxis label when a user wants to print the chart?
This is the initial chart (inverted column with custom styles). I created xAxis labels with formatter function
xAxis: {
arrowOnEnd: true,
labels: {
x: 40,
formatter: function() {
if (this.isLast) { return 'Less Likely' }
if (this.isFirst) { return 'More Likely' }
}
},
and was able to position them so it looks like inverted xAxis has values from Less likely to More likely as follows
events: {
load: function() {
// https://stackoverflow.com/questions/51656849/xaxis-point-specific-label-positions
const chart = this;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick: any) {
if (!tick.isNewLabel && tick.isFirst) { tick.label.attr({ y: 25 })}
if (!tick.isNewLabel && tick.isLast) { tick.label.attr({ y: 590 })}
});
},
The problem I have is when I want to print the chart:
xAxis labels gets back to its original location.
I tried to replicate events: { load: ... } logic in beforePrint or wrapping 'print' event to highcharts object, but that doesn't seem to take any effect
beforePrint: function() {
const chart = this;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick: any) {
if (tick.isFirst) { tick.label.attr({ y: 125 })}
if (tick.isLast) { tick.label.attr({ y: 590 })}
});
}
Highcharts.wrap(Highcharts.Chart.prototype, 'print', function (proceed) {
const chart = this;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick: any) {
if (tick.isFirst) { tick.label.attr({ y: 25 })}
if (tick.isLast) { tick.label.attr({ y: 590 })}
});
proceed.call(this)
});
I tried tickPositionier but couldn't actually work out how to make that work.
Worth to mention. that afterPrint event with the same logic resets the chart, so I don't understand why one event is working (afterPrint) but the other doesn't (print)
afterPrint: function() {
const chart = this;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick: any) {
if (tick.isFirst) { tick.label.attr({ y: 25 })}
if (tick.isLast) { tick.label.attr({ y: 590 })}
});
},
Am I missing something here? Why I can't update tick position for printing?
Sidenote - jsfiddle gives me 502 Bad Gateway so I'm unable to demo it there

Changing the load event to render should fix the issue when the chart will be initialized again before the print.
Demo: https://jsfiddle.net/BlackLabel/4qbp1w0z/
chart: {
type: 'bar',
events: {
render: function() {
// https://stackoverflow.com/questions/51656849/xaxis-point-specific-label-positions
const chart = this;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick) {
if (!tick.isNewLabel && tick.isFirst) {
tick.label.attr({
y: 20
})
}
if (!tick.isNewLabel && tick.isLast) {
tick.label.attr({
y: 350
})
}
});
},
}
},
API: https://api.highcharts.com/highcharts/chart.events.render

Related

Highcharts how do i keep space between series the same but increase space between categories?

I have a highcharts column chart, here is the jsFiddle for it. I want to keep the space between the series as it is -- really close to each other without touching. But I'd like to increase the space between the categories so that it's more distinguishable they are different categories. I've tried playing around with pointpadding and grouppadding but everything I've tried wants to increase/decrease the space between all the columns. Any ideas?
plotOptions: {
column: {
borderRadius: 5,
dataLabels: {
enabled: true,
},
groupPadding: 0,
pointWidth: 45,
},
},
In Highcharts API we can read:
pointWidth: number
A pixel value specifying a fixed width for each column or bar. When
null, the width is calculated from the pointPadding and groupPadding.
Defaults to undefined.
So in this situation pointPadding and groupPadding can be not respected but you can create your own function for positioning the columns, for example:
events: {
render: function() {
var series = this.series;
if (redrawEnabled) {
if (this.chartWidth > 600) {
if (this.options.plotOptions.column.grouping) {
redrawEnabled = false;
this.update({
plotOptions: {
column: {
grouping: false
}
}
});
redrawEnabled = true;
}
series.forEach(function(s, i) {
s.points.forEach(function(p) {
if (i === 0) {
p.graphic.attr({
translateX: 25
});
p.dataLabel.attr({
translateX: p.dataLabel.translateX + 25
});
} else {
p.graphic.attr({
translateX: -25
});
p.dataLabel.attr({
translateX: p.dataLabel.translateX - 25
});
}
});
});
} else {
if (!this.options.plotOptions.column.grouping) {
redrawEnabled = false;
this.update({
plotOptions: {
column: {
grouping: true
}
}
});
redrawEnabled = true;
}
}
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/hvqs4juy/

Can I assign a different radius when click a pie slice using Highcharts?

I am using Highcharts it is working fine but i want to change in pie slice when i click on single pie slice then that slice overlap two slice(right or left slice).
Below is the image attached tha i have done in pie chart.
Below is the image attached of the expexted pie chart result
You can add your own method, which will resize shape on click, for example: http://jsfiddle.net/BlackLabel/8vd6cod1/
function resizeSlice(point, change) {
// Original shape params are stored in shapeArgs:
var shape = point.shapeArgs;
if (point.graphic) {
point.graphic.attr({
// "r" is outer radius:
r: shape.r + change,
// "innerR" is inner radius:
innerR: shape.innerR - change
});
}
}
// Build the chart
Highcharts.chart('container', {
chart: {
type: 'pie',
events: {
// On window resize, apply change:
redraw: function() {
Highcharts.each(this.series[0].points, function(point) {
resizeSlice(point, point.customResized ? 5 : 0)
});
}
}
},
plotOptions: {
pie: {
innerSize: '90%',
cursor: 'pointer',
dataLabels: {
enabled: false
},
point: {
events: {
click: function() {
var change = 0;
// Custom param, can be called whatever we want:
this.customResized = !this.customResized;
if (this.customResized) {
// Let's resize!
change = 5;
}
resizeSlice(this, change);
}
}
}
}
},
series: [{
data: [3, 4, 5, 6]
}]
});
I have make some change to this code for re size all other pie.
: http://jsfiddle.net/8vd6cod1/2/
function resizeSlice(point, change) {
// Original shape params are stored in shapeArgs:
var shape = point.shapeArgs;
if (point.graphic) {
point.graphic.attr({
// "r" is outer radius:
r: shape.r + change,
// "innerR" is inner radius:
innerR: shape.innerR - change
});
}
}
// Build the chart
Highcharts.chart('container', {
chart: {
type: 'pie',
events: {
// On window resize, apply change:
redraw: function() {
Highcharts.each(this.series[0].points, function(point) {
resizeSlice(point, point.customResized ? 5 : 0)
});
}
}
},
plotOptions: {
pie: {
innerSize: '90%',
cursor: 'pointer',
dataLabels: {
enabled: false
},
point: {
events: {
click: function() {
Highcharts.each(this.series.points, function(point) {
resizeSlice(point, 0)
});
var change = 0;
// Custom param, can be called whatever we want:
this.customResized = !this.customResized;
if (this.customResized) {
// Let's resize!
change = 5;
}
resizeSlice(this, change);
}
}
}
}
},
series: [{
data: [3, 4, 5, 6]
}]
});

highcharts - add label for missing column

In my chart, I have a column with a value of -1. This is to indicate that the value for this series is not available.
In the chart, I would like to add a label rotated 90 degrees that says "No data" where the bar should be. Can someone provide me with an example for how to accomplish this?
If you have a column with -1 it will still be rendered. You need to map -1 values to null. After that you can use renderer.text function and render a rotated text for the null columns.
Function for rendering/redrawing labels:
function renderLabels() {
this.series[0].points.forEach((point, i) => {
if (point.isNull) {
point.noDataLabel = this.renderer.text('No data', 0, -9e9).attr({
rotation: 90,
zIndex: 99
}).add()
}
})
redrawLabels.call(this)
}
function redrawLabels() {
this.series[0].points.forEach(point => {
if (point.noDataLabel) {
point.noDataLabel.attr({
x: point.series.group.translateX + point.plotX,
y: this.plotTop + this.plotHeight - 80
})
}
})
}
Attach functions on load and redraw events, and map data:
Highcharts.chart('container', {
chart: {
type: 'column',
events: {
load: renderLabels,
redraw: redrawLabels
}
},
series: [{
data: data.map(v => v === -1 ? null : v)
}]
});
Example and output
http://jsfiddle.net/n3nuhvL7/

Highcharts piechart with slice animation and drilldown on click together throws exception in chart and breaks the pie chart

I have a pie chart here. On click event it drills down and on mouseover it does the slice animation. The slice animation is copied from an answer here from Pawel Fus
The events I have on pie chart point are as below,
mouseOut: function () {
setTranslation(this, false);
},
mouseOver: function() {
setTranslation(this, true);
},
click: function() {
var drilldown = this.drilldown;
if (drilldown) { // drill down
setChart(drilldown.name, drilldown.categories, drilldown.data, drilldown.color);
} else { // restore
setChart(name, categories, data);
}
}
and the functions used in them are
function setChart(name, categories, data, color) {
chart.xAxis[0].setCategories(categories);
chart.series[0].remove();
chart.addSeries({
name: name,
data: data,
pointPadding: -0.3,
borderWidth: 0,
pointWidth: 15,
shadow: false,
color: color || 'white'
});
}
function setTranslation(p, slice){
p.sliced = slice;
if(p.sliced){
p.graphic.animate(p.slicedTranslation);
} else {
p.graphic.animate({
translateX: 0,
translateY: 0
});
}
}
The problem I have is it throws following exception:
Uncaught TypeError: Property 'select' of object #<Object> is not a function highcharts.src.js:12364
It breaks the chart when clicking on it for drilldown.
I am not sure what I am doing wrong but I guess the mouseover event is getting messed up on drilldown.
It would be great if I can get both these features working together.
The problem is with actual running animation. I advice to not use setting translation to a pie chart until all animations for a slice are don, see: http://jsfiddle.net/5H675/5/
function setTranslation(p, slice) {
p.sliced = slice;
if (!$(p.graphic).is(':animated')) {
if (p.sliced) {
p.graphic.animate(p.slicedTranslation);
} else {
p.graphic.animate({
translateX: 0,
translateY: 0
});
}
}
}

Highcharts Pie chart return slice animation on mouseout

I am implementing an animated pie chart in Highcharts where the slices pull out on mouseover and all is good apart from a issue where the on mouseOut I want the slice to return to the 'closed' position.
This is the code for the animation and I have a clearTimeout on mouseOut however this is not returning the slice to the original position.
Is there an easy way of the chart to its original position.
I have a fiddle here...
http://jsfiddle.net/rupertito/Y3wvN/1/
pie: {
allowPointSelect: true,
stickyTracking: false,
point: {
events: {
legendItemClick: function() {
return false;
},
mouseOver: function(event) {
var point = this;
if (!point.selected) {
timeout = setTimeout(function () {
point.firePointEvent('click');
sectors.tooltip.refresh(point);
}, 20);
}
}
}
},
events: {
mouseOut: function() {
clearTimeout(timeout);
},
},
Hope this all makes sense and thanks for any help in advance.
Cheers
Rob
This is bug reported here. It's about not working slice for point. There is also workaround how avoid that issue. And simple example for you with mouseOver/mouseOut: http://jsfiddle.net/GqfU4/8/
function setTranslation(p, slice){
p.sliced = slice;
if(p.sliced){
p.graphic.animate(p.slicedTranslation);
} else {
p.graphic.animate({
translateX: 0,
translateY: 0
});
}
}
And for a pie:
point: {
events: {
mouseOut: function () {
setTranslation(this, false);
},
mouseOver: function() {
setTranslation(this, true);
}
}
},

Resources