I am using Synchronized chart of Highcharts to demonstrate the statistics.
For reference : http://www.highcharts.com/demo/synchronized-charts.
Here, when the chart is getting plotted for the first time, no data points is selected. As, the cursor enters into the chart area, the tooltip, crosshairs and data points get highlighted. It works as expected.
The modification I need is, when the user comes out of the chart, the chart should look like as it was in the loading stage.
i.e. If the cursor is not on any of the chart,then no data points should remain selected. In other words, the tooltip, crosshair and the highlighted shadow on data point should get removed.
Thanks in advance for any help or suggestion.
use mouseleave to detect when the mouse is out of the container:
$('#container').bind('mouseleave', function(e) {
use hide method to hide the tooltip and hide Crosshair method to hide the crosshair:
chart.tooltip.hide(point);
chart.xAxis[0].hideCrosshair();
Check the example (jsfiddle):
$(function() {
$('#container').bind('mouseleave', function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
point.onMouseOut();
chart.tooltip.hide(point);
chart.xAxis[0].hideCrosshair();
}
});
$('#container').bind('mousemove touchmove touchstart', function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent); // Find coordinates within the chart
point = chart.series[0].searchPoint(event, true); // Get the hovered point
if (point) {
point.onMouseOver(); // Show the hover marker
chart.tooltip.refresh(point); // Show the tooltip
chart.xAxis[0].drawCrosshair(event, point); // Show the crosshair
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and crosshairs.
*/
Highcharts.Pointer.prototype.reset = function() {
return undefined;
};
/**
* 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'
});
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
// https://github.com/highcharts/highcharts/blob/master/samples/data/activity.json
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=activity.json&callback=?', function(activity) {
$.each(activity.datasets, function(i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function(val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function() {
return {
x: this.chart.chartWidth - this.label.width, // right aligned
y: -1 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
});
});
Related
I'm using Highcharts series line charts in React. The config is below. Everything is working fine except on mobile browser like Safari, when I move my finger across the line chart (horizontally) to 'hover' over each data point in a series, it also moves the page vertically ever so slightly. I presume each time I pan my finger horizontally, there's also some vertical movement (it's impossible to move in a perfectly horizontal line with your finger).
Question is: is it possible to "lock" the page from scrolling up and down while I pan horizontally on Highcharts?
const
createLineChartOptions = (series, categories, height) => ({
series,
xAxis: {
categories,
title: { text: null },
labels: {
step: 2,
},
crosshair: {
width: 1,
color: GRID_LINE_COLOR
}
},
yAxis: {
title: { text: null },
tickAmount: 3,
gridLineColor: GRID_LINE_COLOR,
gridLineWidth: 0.5,
labels: {
formatter: function () {
return parseFloat(this.value).abbreviatedDollars()
}
}
},
title: { text: null },
chart: {
type: 'line',
height
},
tooltip: {
shared: true,
useHTML: true,
borderColor: 'transparent',
formatter: function () {
const series = this.points
.map(({ x, y, color, series }) => `<tr><td><b><span style="color:${color}">• ${series.name}</b></td><td>${Math.abs(y).toDollars()}</td></tr>`)
.join('');
return `${this.x}<table>${series}</table>`;
},
positioner: function (labelWidth, labelHeight, point) {
const chart = this.chart, plotTop = chart.plotTop;
return { x: chart.plotLeft + 10, y: plotTop };
},
shape: 'rect',
},
plotOptions: {
series: {
cursor: 'crosshair',
marker: {
enabled: false,
symbol: 'circle',
lineColor: GRID_LINE_COLOR,
states: {
hover: {
radius: 2,
radiusPlus: 0
}
}
}
},
},
legend: { enabled: false },
});
Edit: try opening this on an iPhone Simulator or on your phone and try going through each point: https://react-1afped.stackblitz.io
Video: https://ibb.co/37rhgv0
You can use the code below in conjunction with hovering the cursor over your chart.
if (elem.addEventListener) {
// IE9+, Opera, Chrome/Safari
elem.addEventListener ("mousewheel", onMouseWheel, false);
// Firefox
elem.addEventListener ("DOMMouseScroll", onMouseWheel, false);
} else { // IE<9
elem.attachEvent ("onmousewheel", onMouseWheel);
}
function onMouseWheel(e) {
e = e || event;
e.preventDefault ? e.preventDefault() : (e.returnValue = false);
}
I recently came across this really nice example: https://jsfiddle.net/BlackLabel/7t59w4po/
Basically, what it does is that it synchronizes the drag of a line in one graph in all the other graphs.
I was wondering if someone could help me out to reproduce the same example, but instead of one vertical line, I would like to have two. Is this possible?
Thank you!
JS Code:
/*
The purpose of this demo is to demonstrate how multiple charts on the same page
can be linked through DOM and Highcharts events and API methods. It takes a
standard Highcharts config with a small variation for each data set, and a
mouse/touch event handler to bind the charts together.
*/
/**
* In order to synchronize tooltips and crosshairs, override the
* built-in events with handlers defined on the parent element.
*/
['mousemove', 'touchmove', 'touchstart'].forEach(function(eventType) {
document.getElementById('container').addEventListener(
eventType,
function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
// Find coordinates within the chart
event = chart.pointer.normalize(e);
// Get the hovered point
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
}
);
});
/**
* Override the reset function, we don't need to hide the tooltips and
* crosshairs.
*/
Highcharts.Pointer.prototype.reset = function() {
return undefined;
};
/**
* Highlight a point by showing tooltip, setting hover state and draw crosshair
*/
Highcharts.Point.prototype.highlight = function(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
};
/**
* 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'
}
);
}
}
});
}
}
/**
* Synchronize annotations drag&drop
*/
function syncAnnotations(e) {
var thisChart = this.chart;
var newX = this.options.shapes[0].points[0].x
if (e.type !== 'afterUpdate') {
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
chart.annotations[0].update({
labels: [{
point: {
x: newX
}
}],
shapes: [{
points: [{
x: newX,
xAxis: 0,
y: 0
}, {
x: newX,
xAxis: 0,
y: 1000
}]
}]
});
}
});
}
}
// Get the data. The contents of the data file can be viewed at
Highcharts.ajax({
url: 'https://cdn.jsdelivr.net/gh/highcharts/highcharts#v7.0.0/samples/data/activity.json',
dataType: 'text',
success: function(activity) {
activity = JSON.parse(activity);
activity.datasets.forEach(function(dataset, i) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function(val, j) {
return [activity.xData[j], val];
});
var chartDiv = document.createElement('div');
chartDiv.className = 'chart';
document.getElementById('container').appendChild(chartDiv);
Highcharts.chart(chartDiv, {
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
annotations: [{
draggable: 'x',
animation: {
defer: false
},
events: {
drag: syncAnnotations,
afterUpdate: syncAnnotations
},
shapes: [{
strokeWidth: 3,
type: 'path',
points: [{
x: 3,
y: 0,
xAxis: 0
}, {
x: 3,
y: 1000,
xAxis: 0
}]
}],
labels: [{
point: {
x: 3,
y: 30,
xAxis: 0
},
shape: 'rect',
formatter: function(e) {
// Use shape options because value is available there. Label use translation only
return this.target.annotation.shapes[0].options.points[0].x.toFixed(3);
}
}]
}],
tooltip: {
positioner: function() {
return {
// right aligned
x: this.chart.chartWidth - this.label.width,
y: 10 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
}
});
You only need to add another annotation:
annotations: [{
...,
{
...
}],
And improve the syncAnnotations function a little bit:
function syncAnnotations(e) {
var thisChart = this.chart;
var newX = this.options.shapes[0].points[0].x
var index = this.chart.annotations.indexOf(this);
if (e.type !== 'afterUpdate') {
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
chart.annotations[index].update({
...
});
}
});
}
}
Live demo: https://jsfiddle.net/BlackLabel/jwtLc379/
API Reference: https://api.highcharts.com/highcharts/annotations
How to enforce that the tooltip show up only when mouse pointer is inside the chart area and not when on navigator scrollbar or on time range selectors in the top?
http://jsfiddle.net/1p4f5kny/
/*
The purpose of this demo is to demonstrate how multiple charts on the same page can be linked
through DOM and Highcharts events and API methods. It takes a standard Highcharts config with a
small variation for each data set, and a mouse/touch event handler to bind the charts together.
*/
$(function () {
/**
* In order to synchronize tooltips and crosshairs, override the
* built-in events with handlers defined on the parent element.
*/
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent); // Find coordinates within the chart
point = chart.series[0].searchPoint(event, true); // Get the hovered point
if (point) {
point.highlight(e);
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and crosshairs.
*/
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
/**
* Highlight a point by showing tooltip, setting hover state and draw crosshair
*/
Highcharts.Point.prototype.highlight = function (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
};
/**
* 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' });
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
// https://github.com/highcharts/highcharts/blob/master/samples/data/activity.json
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=activity.json&callback=?', function (activity) {
$.each(activity.datasets, function (i, dataset) {
// Add X values
/*dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});*/
$('<div class="chart">')
.appendTo('#container')
.highcharts('StockChart', {
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function () {
return {
x: this.chart.chartWidth - this.label.width, // right aligned
y: -1 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
shared: false,
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
});
});
Insted of binding events on the container, you can use point mouseOver event to synchronize tooltips:
series: [{
point: {
events: {
mouseOver: function(e) {
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
if (chart !== this.series.chart) {
point = chart.series[0].points[this.index];
chart.tooltip.refresh([point]);
}
}
}
}
},
...
}]
Live demo: http://jsfiddle.net/BlackLabel/g0brx52d/
API Reference: https://api.highcharts.com/highcharts/series.line.point.events.mouseOver
I have create a highstock chart with two serieses, when mouse over marker and tooltip will display, don't move the mouse and you can see one of the markers don't follow the series when chart is scrolling.this is a screenshot How to fix it?
This is my code: https://jsfiddle.net/sylaince/fz7cv853/3/
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart = Highcharts.stockChart('container', {
chart: {
type: 'line',
events: {
load: function() {
setInterval(updateData, 1000);
}
}
},
title: {
text: 'test chart'
},
legend: {
enabled: true
},
series: [{
name: 'CH1',
data: []
}, {
name: 'CH2',
data: []
}]
});
function updateData() {
t = new Date().getTime();
for (i = 0; i < 2; i++) {
chart.series[i].addPoint([t, Math.random() * 41 - 10], false);
}
chart.redraw();
}
put your mouse over the top right or bottom right area of the chart would help reproducte the problem.
I have a div (overflow: auto) to which I dynamically add inner divs after a certain period. When a new one is added, it is added to the beginning. Each one of the inner divs have a jqPlot chart, and as long as there is just one it works fine, but as soon as another div is added two things happen with the old one(s):
The chart is moved further down in the div.
The chart has no plots or background (although it has axes marks).
According to the developer tools, all canvases are positioned correctly, but they are empty. This is the code used to add new charts (chart_div_? exists):
$.jqplot('chart_div_' + chartCounter, sold_plot, {
seriesColors: [ "#30D2FF", "BFFFCB", "BFFFCB", "BFFFCB" ],
seriesDefaults: {
showMarker: false,
markerOptions: {
show: false,
}
},
axes: {
xaxis: {
renderer: $.jqplot.DateAxisRenderer,
min: plot_min,
max: plot_max,
}
},
grid: {
background: '#444444',
},
});
chartCounter++;
Could it be something to do with moving a canvas? I tried redrawing it, but it did not work.
here is the example which can help you: Jsfiddle Link
HTML:
<div id="main">
<div id="chart1" style="margin-top:20px; margin-left:20px;"></div>
</div>
Click Here Trigger
Javascript:
$(document).ready(function () {
$.jqplot.config.enablePlugins = true;
var chartData = [
["19-Jan-2012", 2.61],
["20-Jan-2012", 5.00],
["21-Jan-2012", 6.00]
];
var cnt = 1;
// add a custom tick formatter, so that you don't have to include the entire date renderer library.
$.jqplot.DateTickFormatter = function (format, val) {
// for some reason, format isn't being passed through properly, so just going to hard code for purpose of this jsfiddle
val = (new Date(val)).getTime();
format = '%b %#d'
return $.jsDate.strftime(val, format);
};
function PlotChart(chartData, extraDays, elem) {
var plot2 = $.jqplot(elem, [chartData], {
title: 'Mouse Cursor Tracking',
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barPadding: 1,
barWidth: 50
},
pointLabels: {
show: true
}
},
axes: {
xaxis: {
pad: 1,
// a factor multiplied by the data range on the axis to give the
renderer: $.jqplot.CategoryAxisRenderer,
// renderer to use to draw the axis,
tickOptions: {
formatString: '%b %#d',
formatter: $.jqplot.DateTickFormatter
}
},
yaxis: {
tickOptions: {
formatString: '$%.2f'
}
}
},
highlighter: {
sizeAdjust: 7.5
},
cursor: {
show: true
}
});
}
PlotChart(chartData, 3, "chart1");
$("a.topopup").click(function () {
loading();
return false;
});
function loading() {
var div = $("#main");
cnt = cnt + 1;
var elemId = "chart" + cnt;
div.prepend("<div id='" + elemId + "'></div>");
PlotChart(chartData, 3, elemId);
}
});