Highcharts 6.0 Synchronization Bug - javascript

I'm trying to use Highcharts Synchronization for a slightly complex chart. I've gotten synchronization to work just fine on graphs with just 1 series for other plots.
You can check out the example here: http://jsfiddle.net/nhng5827/o9uh2jqy/42/
I've dumbed down my complex chart to just a few points, and usually the chart has 6 lines as opposed to 4. As you can see, the tooltip only appears on the right side of the graph, and everything is delayed. I also do not want the callout box to have any numbers read out if the tooltip is not hovered the specific lines.
I've done a fair bit of research and have implemented some code I've seen that allows for charts with 2 series to be synchronized (http://jsfiddle.net/mjsdnngq/72/), however I think the biggest difference in mine is that the series only go to about half of the actual chart.
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
points,
i,
secSeriesIndex = 1;
for (i = 0; i < Highcharts.charts.length; i++) {
chart = Highcharts.charts[i];
e = chart.pointer.normalize(e); // Find coordinates within the chart
points = [chart.series[0].searchPoint(e, true), chart.series[1].searchPoint(e, true),chart.series[2].searchPoint(e, true),chart.series[3].searchPoint(e, true)]; // Get the hovered point
if (points[0] && points[1]&& points[2]&& points[3]) {
// if (!points[0].series.visible) {
// points.shift();
// secSeriesIndex = 0;
// }
// if (!points[secSeriesIndex].series.visible) {
// points.splice(secSeriesIndex,1);
// }
if (points.length) {
chart.tooltip.refresh(points); // Show the tooltip
chart.xAxis[0].drawCrosshair(e, points[0]); // Show the crosshair
chart.xAxis[0].drawCrosshair(e, points[3]); // Show the crosshair
}
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and crosshairs.
*/
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
Highcharts.Point.prototype.highlight = function (event) {
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh([points[0],points[1],points[2],points[3]]); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
/**
* Synchronize zooming through the setExtremes event handler.
*/
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function (chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, { trigger: 'syncExtremes' });
}
}
});
}
}
Any help would be immensely appreciated.

To correctly synchronize charts, you have to clear points state on every mousemove event:
Highcharts.each(chart.series, function(s) {
Highcharts.each(s.points, function(p) {
p.setState('');
});
});
Live demo: http://jsfiddle.net/BlackLabel/cvb6pwsu/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Point#setState
Also, please take a look at this example: http://jsfiddle.net/BlackLabel/6f37b42q/, it can be useful for you.

Related

How to synchronise shared tooltip and crosshair in highcharts?

I have a couple of charts, some with a single series, others with multiple series. I show shared tooltips for charts with multiple series. I show a vertical crosshair on each chart.
Now I would like to synchronise the charts. Moving the mouse in one chart should show the described features (crosshair and toolip) on the correct place in all charts, with updated data.
As you can see in fiddle, this does not work completely. The x position is synchronised correctly. Tooltips are updated. But mouseover on the second chart shows a tooltip in the first chart with only one y value instead of two. [Edit: I've found a way to update crosshairs; but it does not not work in every chart, when I set
tooltip: {
shared: true,
maybe there is a better solution?]
https://jsfiddle.net/hbaed859/1/
let highlightFunction = function (point) {
Highcharts.charts.forEach(chart => {
chart.series.forEach(s => {
if (point.series.name != s.name) {
s.points.forEach(p => {
if (p.index === point.index) {
p.setState('hover')
p.series.chart.tooltip.refresh(p)
// shows tooltip, but ignores "shared: true"
chart.xAxis[0].drawCrosshair(null, p);
...
chart = Highcharts.chart('chart1', {
series: [{
point: {
events: {
mouseOver(e) {
let point = this;
highlightFunction(point)
}
...
[edit] ... and the method is nice for small datasets, for large one it needs too long to recalculute the crossjair positions for all the charts.
You are really close to achieve the wanted result. Use the hideCrosshair method for crosshair visibility and add points from all chart's series to the tooltip.refresh method call. Optimized code below:
function setHighlightState() {
const point = this;
Highcharts.charts.forEach(chart => {
if (point.series.chart !== chart) {
const matchedPoints = [];
chart.series.forEach(s => {
const matchedPoint = s.points[point.index];
matchedPoints.push(matchedPoint);
matchedPoint.setState('hover');
});
chart.tooltip.refresh(matchedPoints)
chart.xAxis[0].drawCrosshair(null, matchedPoints[0]);
}
});
}
function hideHighlightState() {
const point = this;
Highcharts.charts.forEach(chart => {
if (point.series.chart !== chart) {
chart.series.forEach(s => {
s.points[point.index].setState('');
});
chart.tooltip.hide();
chart.xAxis[0].hideCrosshair();
}
});
}
Live demo: https://jsfiddle.net/BlackLabel/nwj3co0a/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis#hideCrosshair

React Highchart: Synchronized chart and tooltip is not highlighting the points

I am using highchart-react-official, I am using it draw two charts:
1) Line chart with multiple series
2) Column Chart.
Now I want, if I hover over a point in first chart, it should display highlight point on both lines of first chart and column chart in second chart. Like a synchronized chart: http://jsfiddle.net/doc_snyder/51zdn0jz/6/
This is my code:
((H) => {
H.Pointer.prototype.reset = () => undefined;
/**
* Highlight a point by showing tooltip, setting hover state and
draw crosshair
*/
H.Point.prototype.highlight = function highlight(event) {
event = this.series.chart.pointer.normalize(event);
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh(this); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
H.syncExtremes = function syncExtremes(e) {
const thisChart = this.chart;
if (e.trigger !== 'syncExtremes') {
// Prevent feedback loop
Highcharts.each(Highcharts.charts, (chart) => {
if (chart && chart !== thisChart) {
if (chart.xAxis[0].setExtremes) {
// It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
trigger: 'syncExtremes',
});
}
}
});
}
};
})(Highcharts);
componentDidMount() {
this.changeChart();
['mousemove', 'touchmove', 'touchstart'].forEach((eventType) => {
document
.getElementById('tab__charts')
.addEventListener(eventType, (e) => {
for (let i = 0; i < Highcharts.charts.length; i += 1) {
const chart = Highcharts.charts[i];
// let secSeriesIndex = 1;
if (chart) {
// Find coordinates within the chart
const event = chart.pointer.normalize(e);
// Get the hovered point
chart.series.forEach(series => {
const point = series.searchPoint(event, true);
if (point) {
point.highlight(e);
}
});
}
}
});
});
}
Some imporant chart config:
tooltip: {
enabled: true,
useHTML: true,
shared: true,
}
xAxis: {
events: {
setExtremes: (e) => {
Highcharts.syncExtremes(e);
},
}
}
Now this code is working perfectly by synchronizing tooltip on both charts. But the issue is in first chart, it has two lines, when I hover over first line it hightlights the point with round circle, but the second line is not getting highlighted.
And the reason I found for that is in point.highlight(e); in componendDidMount
For second series, this line giving error on hover:
More specifically, point.highligh(e) is calling top function: H.Point.prototype.highlight = (), check top of the question, in that function this function call is resulting in error
this.series.chart.tooltip.refresh(this);
Note: I'll try to reproduce and create a jsfiddle or something like that, but posting this just so if anyone can help figure this out.
And I am passing Array of Object in Series data, because I need more informative tooltip on chart point:
data: [{
"x": "2018-12-23T11:00:09.311Z",
"y": 107.54,
"data": {
"Toltip Info 1": "1,884,681,725",
"Tooltip info 2": "158,039,757.99",
"price":"107.54"
}
}]
Here is demo of the issue: https://codesandbox.io/s/pk2w85jpk0
The problem is the data format, x values should be in milliseconds:
data: [
{
x: new Date("2018-12-25T09:00:06.247Z").getTime(),
y: 6609592859.48
},
...
]
Live demo: https://codesandbox.io/s/ovk25m493q

How to synchronize the Highchart Sunburst behavior

As shown in the image, I want to show two sunbursts next to each other. I want to implement it with Highchart and react in such a way where,
If user mouse over on any data point on one sunburst, same data point should get highlighted on another chart, while other data points just goes into disabled mode or changes their color to white
In mouseOver event, by using references to the charts, you can programmatically set 'hover' state at the right point:
point: {
events: {
mouseOver: function() {
const chart1 = component.highchartsChart1.current.chart;
const chart2 = component.highchartsChart2.current.chart;
function clearState(chart) {
Highcharts.each(chart.series[0].points, function(p) {
p.setState("");
});
}
if (this.series.chart === chart1) {
clearState(chart2);
chart2.series[0].points[this.index].setState("hover");
} else {
clearState(chart1);
chart1.series[0].points[this.index].setState("hover");
}
}
}
}
Live demo: https://codesandbox.io/s/nn54z2234m
API: https://api.highcharts.com/class-reference/Highcharts.Point#setState

how to hide series data in combination high charts

I am using combine high charts. I need to hide a particular pie chart and column chart data while clicking a particular legend. If i use:
series[i].data[index].remove()
That removes the value but not able to show that value again while clicking the legend.
series[i].data[index].hide()
Refer to this JSFidddle - Example which I tried but I get an error like This is not function. How do I solve this?
You can use hide method on point SVG graphic element:
events: {
legendItemClick: function(e) {
var index = this.index;
var chart = this.series.chart;
var series = chart.series;
var len = series.length - 1;
if (this.visible) {
series[0].points[index].graphic.hide();
} else {
series[0].points[index].graphic.show();
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/d8uaxefo/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGElement#hide

highstocks - legend position and refresh legend values on mousemove of multiple charts

Here is the scenario. I've multiple highstocks say 10 charts on a single page. Currently I've written 500 lines of code to position the legend, show tooltip and refresh the legend values on mousemove.
No. of legends vary per chart. On mousemove values of all the legends are updated. I need to optimize the code I am using highstocks v1.2.2.
Above screenshot shows 2 charts. Return, Basket, vs Basket Spread are legends and it's values are updated on every mousemove.
Please find this fiddle for example. In my case legends are positioned and updated values on mouse move with hundreds of lines of code. When I move the mouse the legend values of Return and Basket of first chart and the legend values of vs Basket Spread are updated. It's working fine but with lots of javascript code. So I need to optimize it less code or with highstocks built-in feature.
Update
User #wergeld has posted new fiddle. As I've shown in screenshot when cross-hair is being moved over any chart, the legend values of all the charts should be updated.
Is there anyway to implement the same functionality with less code or is there built-in feature available in highstocks ???
Using this as a reference.
Basic example would be to use the events.mouseover methods:
plotOptions: {
series: {
point: {
events: {
mouseOver: function () {
var theLegendList = $('#legend');
var theSeriesName = this.series.name;
var theYValue = this.y;
$('li', theLegendList).each(function (l) {
if (this.innerText.split(':')[0] == theSeriesName) {
this.innerText = theSeriesName + ': ' + theYValue;
}
});
}
}
}
}
}
This is assuming I have modded the <li> to be:
$('<li>')
.css('color', serie.color)
.text(serie.name + ': NA')
.click(function () {
toggleSeries(i);
})
.appendTo($legend);
You would then need to handle the mouseout event but I do not know what you want to do there.
Working example.
EDIT:
Here is a version using your reference OHLC chart to put the values in a different legend location when any point in the chart is hovered.
plotOptions: {
series: {
point: {
events: {
mouseOver: function () {
//using the ohlc and volumn data sets created at runtime.
var stockVal = ohlc[this.index][4]; // show close value
var stockVolume = volume[this.index][1];
var theChart = $('#container').highcharts();
var theLegendList = $('#legend');
$('li', theLegendList).each(function (l) {
var legendTitle = theChart.series[l].name;
if (l === 0) {
this.innerText = legendTitle + ': ' + stockVal;
}
if (l === 1) {
this.innerText = legendTitle + ': ' + stockVolume;
}
});
}
}
}
}
}

Categories

Resources