Custom SVGElement labels loose positioning on zoom - highcharts

I create some custom SVGElement labels in my chart.. but they loose positioning on zooming the chart.. See this fiddle https://jsfiddle.net/bz6vyedL/
chart:{zoomType: 'xy'},
Labels should not remain stuck when zooming in and behave appropriately

You need to reposition the label after every zoom, for example by using render event function:
chart: {
zoomType: 'xy',
events: {
render: function() {
var chart = this,
point = chart.series[0].points[8],
label = this.customLabel,
xPos,
labelWidth,
newLabelPos;
if (!label) {
this.customLabel = label = chart.renderer.label(
'Label',
null,
null,
'callout',
null,
null,
true, false, 'my-label'
)
.attr({
padding: 0,
zIndex: 10
})
.add();
}
label.attr({
x: point.plotX + chart.plotLeft,
y: point.plotY + chart.plotTop
});
xPos = label.x;
labelWidth = label.width;
newLabelPos = xPos - labelWidth;
label.attr('x', newLabelPos);
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/5v7xo2ky/
API Reference: https://api.highcharts.com/highcharts/chart.events.render

Related

yAxis resizer to change svgrenderer position also highcharts

I have a chart with some indicators below it. Each indicator area consists
of a svg renderer button. so when I use resize property to drag and resize
the panes, the series resized perfectly but the button remains in its same
position, Can we move the button with the resizer?
Here I created a sample link to regenerate
https://jsfiddle.net/q0ybpnvx/2/
Any help will be appreciated. I am having great trouble. Thank you
You can add and position the custom button in render event:
chart: {
events: {
render: function() {
var chart = this;
if (chart.customBtn) {
chart.customBtn.attr({
y: chart.yAxis[1].top,
});
} else {
chart.customBtn = chart.renderer.button(
'sometext',
5,
chart.yAxis[1].top,
function() {
console.log('some task')
}).add()
}
}
}
},
Live demo: https://jsfiddle.net/BlackLabel/b7vq4ecy/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr
I was able to do something by manually changing the x/y attributes of my svgRenderer label, the same should apply to buttons.
I'm in angular and have a listener for screen resizing:
Also Note that you can change the entire SVGRenderer label with the attr.text property.
this.chart = Highcharts.chart(.....);
// I used a helper method to create the label
this.chart.myLabel = this.labelCreationHelperMethod(this.chart, data);
this.windowEventService.resize$.subscribe(dimensions => {
if(dimensions.x < 500) { //this would be your charts resize breakpoint
// here I was using a specific chart series property to tell where to put my x coordinate,
// you can traverse through the chart object to find a similar number,
// or just use a hardcoded number
this.chart.myLabel.attr({ y: 15, x: this.chart.series[0].points[0].plotX + 20 });
} else {
this.chart.myLabel.attr({ y: 100, x: this.chart.series[0].points[0].plotX + 50 });
}
}
//Returns the label object that we keep a reference to in the chart object.
labelCreationHelperMethod() {
const y = screen.width > 500 ? 100 : 15; 
const x = screen.width > 500 ? this.chart.series[0].points[0].plotX + 50 :
this.chart.series[0].points[0].plotX + 20
// your label
const label = `<div style="color: blue"...> My Label Stuff</div>`
return chart.renderer.label(label, x, y, 'callout', offset + chart.plotLeft, chart.plotTop + 80, true)
.attr({
fill: '#e8e8e8',
padding: 15,
r: 5,
zIndex: 6
})
.add();
}

How can i create Highchart xAxis labels centered and enclosed?

I'm trying to replicate the effect on the image but with no luck. On another post someone answered on how to achieve multiple axis lines (see link at the end), but I am unable to achieve the style (labels to maximum width inside the gray and blue boxes).
Previous post: Highcharts: How can I achiveve multiple rows on chart labels?
I would use Highcharts.SVGRenderer to draw rect elements, based on the ticks from the second xAxis and translate the labels. Please check the example below:
chart: {
events: {
render: function() {
var ticks = this.xAxis[1].ticks,
x = this.plotLeft,
y = 378,
width,
color = 'blue',
textColor = 'yellow',
height = 28;
if (!this.customTicks) {
this.customTicks = [];
} else {
this.customTicks.forEach(function(cTick) {
cTick.destroy();
});
this.customTicks.length = 0;
}
Highcharts.objectEach(ticks, function(tick) {
if (tick.mark) {
width = tick.mark.getBBox().x - x;
tick.label.element.children[0].setAttribute('fill', textColor);
tick.label.attr({
translateX: -width / 2
});
this.customTicks.push(
this.renderer.rect(
x,
y,
width,
height
).attr({
fill: color
}).add()
)
x = tick.mark.getBBox().x;
if (color === 'blue') {
color = 'gray';
textColor = 'white';
} else {
color = 'blue';
textColor = 'yellow';
}
}
}, this)
this.customTicks.push(
this.renderer.rect(
x,
y,
this.xAxis[1].width + this.plotLeft - x,
height
).attr({
fill: color
}).add()
)
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/s7vfkgzt/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#rect

Highcarts bar legend symbol alignment to the label

If I modify the symbol Width/Height in a bar-chart the symbol is "bottom" aligned with the legend text. Is there a way to "middle - align" them?
http://jsfiddle.net/klodoma/h8j0kL1e/
legend: {
...
symbolHeight: 5,
symbolWidth: 5,
symbolRadius: 0,
...
},
You can calculate and set translateY attribute for legend symbol SVG elements:
events: {
load: function() {
var legendItems = this.legend.allItems,
textBbox,
symbolBbox;
legendItems.forEach(function(item) {
textBbox = item.legendItem.getBBox();
symbolBbox = item.legendSymbol.getBBox();
item.legendSymbol.attr({
translateY: symbolBbox.height - textBbox.height / 2
});
});
}
}
Live demo: http://jsfiddle.net/BlackLabel/a0ye5tuw/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr
The only way I know is to use CSS "it's dirty but it works"
.highcharts-point{
transform: translate(0, -10px)
}
Fiddle
http://jsfiddle.net/klodoma/p5mdy19u/
Based on the answer from #ppotaczek I've aligned the Y so that it's always middle aligned, no matter what the symbol size is.
events: {
load: function() {
var legendItems = this.legend.allItems,
textBbox,
symbolBbox;
legendItems.forEach(function(item) {
textBbox = item.legendItem.getBBox();
symbolBbox = item.legendSymbol.getBBox();
item.legendSymbol.attr({
y: textBbox.y + (textBbox.height - symbolBbox.height) / 2
});
});
}
}

Find special chart on highcharts

I would like to build a chart like this
enter image description here
Drag the red point or two blue lines on the left chart, then the chart will generate the second one on the right.
Please advice me how to do with highcharts or other chart library. Thank you very much!
There is no such feature in Highcharts, and implementation will be not so easy, but I'm not saying it's not possible. In order to achieve the similar effect, you can use renderer feature, generate the circle and lines. Then change their attributes (position and dimensions), when dragging the circle. For example:
chart: {
events: {
load() {
var chart = this,
circleWidth = 5,
circleInitPos = {
x: 100,
y: 100
},
lineWidth = 2,
indicator = chart.renderer.g('indicator').attr('zIndex', 5).add(),
leftLine = chart.renderer.rect(0, circleInitPos.y, circleInitPos.x, lineWidth)
.attr({
fill: 'blue'
})
.add(indicator),
bottomLine = chart.renderer.rect(circleInitPos.x, circleInitPos.y, lineWidth, chart.containerHeight - circleInitPos.y)
.attr({
fill: 'blue'
})
.add(indicator),
circle = chart.renderer.circle(100, 100, circleWidth)
.attr({
fill: 'red'
}).add(indicator);
circle.drag = false;
chart.container.onmousemove = function(e) {
if (circle.drag) {
let normalizedEvent = chart.pointer.normalize(e),
groupPos = indicator.getBBox(),
leftLineLen = chart.plotWidth - e.chartX,
bottomLineLen = chart.plotHeight - e.chartY;
// Recalculate dimensions
leftLine.attr({
width: e.chartX,
y: e.chartY
})
bottomLine.attr({
height: chart.containerHeight - e.chartY,
y: e.chartY,
x: e.chartX
})
circle.attr({
x: e.chartX,
y: e.chartY
})
}
}
circle.element.onmousedown = function() {
circle.drag = true
}
circle.element.onmouseup = function() {
circle.drag = false
}
}
}
},
I prepared the example which shows how to do it, so here it is: https://jsfiddle.net/rgs4v5az/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer

xAxis - point specific label positions

Is there a way to have a point specific positionning of the xAxis labels ?
I am using a waterfall chart and for some bars I would like the label to appear directly under the bar like below :
I have found the following code in the xAxis plotOptions but at this point I don't see how I can acces the info on the bottom of the chart.
xAxis: {
labels: {
y:-100 //label's y position
}
},
You can use point dataLabels to achieve such result:
dataLabels: {
crop: false,
overflow: 'none',
verticalAlign: 'bottom',
format: 'label1',
y: 20
}
Live demo: https://jsfiddle.net/BlackLabel/71jtp5mf/
API Reference: https://api.highcharts.com/highcharts/series.waterfall.dataLabels
Another way is to create your own custom function to position the xAxis labels, for example:
events: {
load: function() {
var chart = this,
point;
Highcharts.objectEach(chart.xAxis[0].ticks, function(tick) {
if (!tick.isNewLabel) {
point = chart.series[0].points[tick.pos];
tick.label.attr({
y: point.plotY + chart.plotTop + point.shapeArgs.height + 15
})
}
});
}
}
Live demo: https://jsfiddle.net/BlackLabel/oaj9bgt4/

Resources