I am building a real-time visualisation tool for some PC hosts, using the highcharts library. Using websocket, the web application receives data and update the charts (11 charts per web application, per host). The javascript code is in one single file and that causes the browser to freeze at some point, or just some considerable latency.
After googling, i read about web workers, and thought of trying it to optimize. So I came up with 02 javascript files:
The first one (Main thread) initialising UI and charts etc...
The second one (worker) supposed to listen to websocket, and update the charts.
Since the charts are created in the main thread (because that's where i can acces the DOM and choose charts' container), when i try to transfer the charts to the worker i get the DATA_CLONE_ERR error as follows:
DataCloneError: The object could not be cloned.
Below is the part of the script triggering the code, precisely at the postmessage() part:
var charts_list = []; //charts
function initAllCharts(host_i, l_id, pos){
var chart_i;
for (var i = 0; i < 11; i++) {
if (i < 4){
chart_i = new Highcharts.Chart({
chart: {
renderTo: l_id + '_graph'+i,
defaultSeriesType: 'spline',
zoomType: 'xy',
panning: true,
panKey: 'shift'
},
title: {
text: ''
},
legend: {
enabled: true
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
plotOptions: {
spline: {
marker: {
enabled: false
}
}
},
tooltip: {
valueDecimals: 2,
},
xAxis: {
title: {
text: ''
},
type: 'datetime',
tickPixelInterval: 150,
maxZoom: 20 * 1000
},
yAxis: {
title: {
text: ''
},
minPadding: 0.2,
maxPadding: 0.2,
},
series: [{
name: 'Random data',
data: []
}]
});
}else{
chart_i = new Highcharts.Chart({
chart: {
renderTo: l_id + '_histogram'+i,
type: 'column',
zoomType: 'xy',
panning: true,
panKey: 'shift'
},
title: {
text: '',
},
subtitle: {
text: '',
},
legend: {
enabled: false
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
tooltip: {},
plotOptions: {
series: {
pointPadding: 0,
groupPadding: 0,
borderWidth: 0.5,
}
},
xAxis: {
title: {
text: ''
}
},
yAxis: {
title: {
text: ''
}
},
series: [{
name: 'Random Data',
data: []
}],
});
}
charts_list.push(chart_i);
chart_i = {};
}
//Post to worker
toChartsWorker = {"charts_list":charts_list};
chartsDataWorker.postMessage(toChartsWorker);
return chart_i;
}
So far, that's the only approach i have. Could you please help me out ? Do you see another way of doing ?
Related
Anyone know how to add treemap upon click event on line chart point? Here's my JSFiddle link:
https://jsfiddle.net/ssoj_tellig/d6pfv1bg/19/
When I click on the line chart on the point 0.63 at the third week of sample5, I'd like a treemap to appear at the bottom with the values loaded in var mytreemap_data (or any other values for the demo, doesn't matter). I'd like to understand how it'd work.
Many thanks for your help!
var mytreemap_data = [1528675200000,0.1,0.2,0.3,0.15,0.25]
// How can we show a tree map at the bottom with the values above
// upon clicking on the point 0.63 for the third week of sample 5 ??
const chart_1 = new Highcharts.stockChart('mychart_1', {
chart: {
zoomType: 'x',
type: 'spline',
},
xAxis: {
type: 'datetime',
tickInterval: 86400000 * 7, //show each week
ordinal: false,
labels:{
formatter: function() {
return Highcharts.dateFormat('%d %b %Y', this.value);
},
align: 'right',
rotation: -90,
},
},
yAxis: {
opposite: false,
min: 0,
max: 1,
tickInterval: 0.1,
title: {
text: 'Score'
}
},
legend: {
enabled: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'top'
},
credits : {
enabled : false
},
navigator :{
enabled: true
},
scrollbar :{
enabled: true
},
rangeSelector: {
enabled: true,
allButtonsEnabled: true,
buttons: [{
type: 'month',
count: 1,
text: '1m'
}, {
type: 'all',
text: 'All'
}],
selected: 1
},
series: [{
name: 'sample1',
data: [[1527465600000,0.42242020440407213],[1528070400000,0.38747025807155444],[1528675200000,0.42678078180915674],[1529280000000,0.4091743882448146],
[1529884800000,0.4238743811604633],[1530489600000,0.39724984766613747],[1531094400000,0.39441610665405447],[1531699200000,0.41417484302834673],
[1532304000000,0.39208450506752085],[1532908800000,0.4026164523657783]],
}, {
name: 'sample2',
data: [[1527465600000,0.44242020440407213],[1528070400000,0.40747025807155444],[1528675200000,0.44678078180915674],[1529280000000,0.4291743882448146],
[1529884800000,0.4438743811604633],[1530489600000,0.41724984766613747],[1531094400000,0.41441610665405447],[1531699200000,0.43417484302834673],
[1532304000000,0.41208450506752085],[1532908800000,0.4226164523657783]],
}, {
name: 'sample3',
data: [[1527465600000,0.42242020440407213],[1528070400000,0.42747025807155444],[1528675200000,0.46678078180915674],[1529280000000,0.4491743882448146],
[1529884800000,0.4638743811604633],[1530489600000,0.43724984766613747],[1531094400000,0.43441610665405447],[1531699200000,0.45417484302834673],
[1532304000000,0.43208450506752085],[1532908800000,0.4426164523657783]],
}, {
name: 'sample4',
data: [[1527465600000,0.52242020440407213],[1528070400000,0.48747025807155444],[1528675200000,0.52678078180915674],[1529280000000,0.5091743882448146],
[1529884800000,0.5238743811604633],[1530489600000,0.49724984766613747],[1531094400000,0.49441610665405447],[1531699200000,0.51417484302834673],
[1532304000000,0.49208450506752085],[1532908800000,0.5026164523657783]],
}, {
name: 'sample5',
data: [[1527465600000,0.62242020440407213],[1528070400000,0.58747025807155444],[1528675200000,0.62678078180915674],[1529280000000,0.6091743882448146],
[1529884800000,0.6238743811604633],[1530489600000,0.59724984766613747],[1531094400000,0.59441610665405447],[1531699200000,0.61417484302834673],
[1532304000000,0.59208450506752085],[1532908800000,0.6026164523657783]],
}],
plotOptions: {
series: {
label: {
connectorAllowed: false,
},
pointstart: 1527465600000,
// pointInterval = 2,
tooltip: {
valueDecimals: 2
},
}
},
responsive: {
rules: [{
condition: {
maxWidth: 500
},
}]
}
});
document.getElementById('button').addEventListener('click', e => {
var series = chart_1.series[0];
var series1 = chart_1.series[1]
var series2 = chart_1.series[2];
if (series.visible & series1.visible & series2.visible) {
series.hide();
series1.hide();
series2.hide();
e.target.innerHTML = 'Show samples 1-3';
} else {
series.show();
series1.show();
series2.show();
e.target.innerHTML = 'Hide samples 1-3';
}
})
Use click event callback function for a point and create another chart with treemap series, for example:
plotOptions: {
series: {
point: {
events: {
click: function() {
Highcharts.chart('treemapContainer', {
series: [{
type: 'treemap',
data: mytreemap_data
}]
})
}
}
},
...
}
}
Live demo: https://jsfiddle.net/BlackLabel/rh7cfxLj/
API Reference: https://api.highcharts.com/highcharts/plotOptions.series.point.events.click
I am trying to create a chart like this one:
:
I have already achieved all of the features except the multi colored line of the area chart. I want to show the different gradients of the chart in different colors, thus I need multiple colors on the line.
I have already tested zones like shown here and also common plugins like this. Both do not work. The zones are applied to the area which I do not want and the plugin can only color lines OR areas but not only lines in area charts.
My current Highcharts settings look like this:
{
title: {
text: null
},
xAxis: {
crosshair: true,
labels: {
format: '{value} km'
},
title: {
text: null
},
opposite: true,
startOnTick: true,
endOnTick: false,
min: 0
},
yAxis: {
startOnTick: true,
showFirstLabel: false,
endOnTick: false,
maxPadding: 0.35,
title: {
text: null
},
min: 100,
labels: {
format: '{value} m'
}
},
plotOptions: {
dataGrouping: {
enabled: false
},
showInNavigator: true,
stacking: 'normal',
series: {
dragDrop: {
draggableY: true
},
point: {
events: {
mouseOver: (e) => {
this.chartHover.emit({
distance: e.target.x * 1000
});
},
}
},
},
area: {
dragDrop: {
draggableY: true,
dragPrecisionY: 1
}
}
},
credits: {
enabled: false
},
legend: {
enabled: false
},
chart: {
update: true,
styledMode: true,
marginBottom: 0,
marginRight: 0
},
tooltip: {
headerFormat: '',
pointFormatter: function () {
let point = this;
if (!this.series) {
return;
}
return '<span class="tooltip-area-series-' + this.series.index + '">\u25CF</span> ' + point.series.name + ': <b>' + point.y + 'm</b><br/>';
},
shared: true
},
series: [],
};
Is there an built-in solution for this?
EDIT:
I used the proposed solution by ppotaczek:
series: [{
type: 'areaspline',
id: 'areaSeries',
data: data
}, {
type: 'spline',
linkedTo: 'areaSeries',
data: data,
zoneAxis: 'x',
zones: [{
color: 'red',
value: 2
}, {
color: 'green',
value: 4
}]
}]
This works pretty good, but has some performance pitfalls when you try to add approx. more than 150 zones on desktop browsers.
There is also a small rendering issue - small gaps between the zones.
Best,
Philipp
You can add an extra spline series with zones:
series: [{
type: 'areaspline',
id: 'areaSeries',
data: data
}, {
type: 'spline',
linkedTo: 'areaSeries',
data: data,
zoneAxis: 'x',
zones: [{
color: 'red',
value: 2
}, {
color: 'green',
value: 4
}]
}]
Live demo: http://jsfiddle.net/BlackLabel/8er6y4u3/
API: https://api.highcharts.com/highcharts/series.spline.zones
I am using HighChart to draw a pie chart.Pie chart container is in an ascx control.In the page there are 5 controls other than this.Each ascx sections are loading by ajax async calls.Problem is that graph in first section is showing only after complete page page load.Please provide a solution.
$('#arrhythmiacontainer').highcharts({
chart: {
//plotBackgroundColor: null,
plotBorderWidth: 0,
plotShadow: false,
backgroundColor:'rgba(255, 255, 255, 0.1)'
},
colors: ['#F5F5F5'],
title: {
text: ''
},
exporting: {
enabled: exportingStatus
},
tooltip:{
formatter: function() {
return false;
}
},
credits: {
enabled: false
},
plotOptions: {
pie: {
size:'100%',
dataLabels: {
enabled: true,
distance: -70,
style: {fontSize: '12px',fontWeight: 'bold'}
}
}
},
legend: {
enabled: false
},
series: [{
type: 'pie',
name: 'Percentage',
data: [['NO DATA AVAILABLE', 100]]
}]
});
}
The above graph is in first control and it is binding using ajax call.all the other informations in control1 is loading after first ajax call.but graph is loading only after window stop.
I have multiple data coming on each day and I was wondering how to make a graph where I see the days and when I zoom in I should see the time in between the days. I am not able to do so resulting in a graph with days getting duplicated or triplicated as per the number of data points.
Before Zooming:-
After Zoom :-
I would like not to have duplicate Day names rather time in between them.
My Highcharts-ng configuration json object is as follows:-
{
options: {
chart: {
type: 'line',
zoomType: 'xy',
animation: true
},
colors:['#2C91DE','#165A8E'],
plotOptions: {
line:{
marker:{
symbol:'circle'
}
},
series: {
lineWidth: 3,
marker: {
fillColor: 'white',
lineWidth: 1,
lineColor: null,
enabled: true,
radius: 5
}
}
},
tooltip: {
shared: true,
crosshairs: true,
followPointer: true
}
},
title: {
text: ''
},
loading: false,
xAxis: {
type: 'datetime',
title: {
text: 'Date/Time'
},
dataTimeLabelFormats:{
day:'%a',
week:'%a',
},
labels: {
format: '{value:%a}'
}
},
series: [{
pointIntervalUnit: 'hourly'
}],
yAxis: {
title: {
text: ''
}
},
size: {
height: 500
}
}
I have a webpage with HighCharts and idTabs plugins installed. I just want to show 1 chart at time, so hi got them in multiple tabs. The html code is:
<ul class="idTabs">
<li>Points</li>
<li>Kills and deaths</li>
<li>Damage</li>
<li>Bombs</li>
</ul>
<div id="vpPointsGraphWrapper"><div id="vpPointsGraph"></div></div>
<div id="vpKillsDeathsGraphWrapper"><div id="vpKillsDeathsGraph"></div></div>
<div id="vpDamageGraphWrapper"><div id="vpDamageGraph"></div></div>
<div id="vpBombsGraphWrapper"><div id="vpBombsGraph"></div></div>
Until this point is all okey, the charts have their data, and all is okey except one thing, the width. The chart that is showed by default (vpPointsGraph) has the correct width (100% of the div that contains them), but the others take the width that correspond to the width of the monitor, overflowing out of the wrapper div. I think the problem is that they want to get the wrapper div width, but as its hidden they take the whole screen width. ¿Is there anyway to fix this?
Thanks for your answers.
Edit: I solved it, check the next answer for explanation.
Solution: http://jsfiddle.net/5kLdG/
What i have done its just getting the width of the container i want the chart to fit in, and setting it in the highcharts 'width' parameter. I don't know if its the best solution but it worked for me.
//Get wrapper width
var width = $('#wrapper').width()
//Points Graph
var pointsChart = new Highcharts.Chart({
chart: {
renderTo: 'vpPointsGraph',
type: 'line'
},
title: {
text: 'Points'
},
xAxis: {
title: {
text: 'Match'
},
categories: [1,2,3,4,5,6,7],
reversed: true
},
yAxis: {
title: {
text: 'Points'
},
},
tooltip: {
crosshairs: true,
shared: true,
valueSuffix: ''
},
plotOptions: {
line: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1
}
}
},
credits: {
enabled: false
},
series: [{
name: 'Points',
data: [5,6,7,8,3,6,8]
}]
});
//KillsDeaths Graph
var killsDeathsChart = new Highcharts.Chart({
chart: {
renderTo: 'vpKillsDeathsGraph',
type: 'line',
width: width
},
title: {
text: 'Kills and Deaths per match'
},
xAxis: {
title: {
text: 'Match'
},
categories: [1,2,3,4,5],
reversed: true
},
yAxis: {
title: {
text: 'Number'
},
},
tooltip: {
crosshairs: true,
shared: true,
valueSuffix: ''
},
plotOptions: {
line: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1
}
}
},
credits: {
enabled: false
},
series: [{
name: 'Kills',
data: [6,8,2,2,5]
}]
});