JSFiddle becomes unresponsive after continuous zooming in the chart - highcharts

When we continuously zoom in the chart around after 8 or 10 times, the JSFiddle becomes unresponsive.
JSFiddle
HTML
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<div id="container"></div>
CSS
#container {
max-width: 800px;
height: 400px;
margin: 1em auto;
}
JavaScript + jQuery 1.7.2
$(function () {
/**
* Experimental Highcharts plugin to implement chart.alignThreshold option. This primary axis
* will be computed first, then all following axes will be aligned to the threshold.
* Author: Torstein Hønsi
* Last revision: 2015-05-18
*/
(function (H) {
var Axis = H.Axis,
inArray = H.inArray,
wrap = H.wrap;
wrap(Axis.prototype, 'adjustTickAmount', function (proceed) {
var chart = this.chart,
primaryAxis,
primaryThreshold,
primaryIndex,
index,
newTickPosLow,
threshold,
newTickPositionsHigh,
max,
nextStep;
// Find the index and return boolean result
function isAligned(axis) {
index = inArray(threshold, axis.tickPositions); // used in while-loop
return axis.tickPositions.length === axis.tickAmount && index === primaryIndex;
}
for(var i = chart[this.coll].length - 1; i >= 0; i--){
chart[this.coll][i].removePlotLine('zero-point-plotline');
if(chart[this.coll][i].hasVisibleSeries){
primaryAxis = chart[this.coll][i];
}
}
primaryThreshold = (primaryAxis.series[0] && primaryAxis.series[0].options.threshold) || 0;
threshold = 0;
for(var i = 0; i < this.series.length; i++){
if(this.series[i].visible){
threshold = this.series[i].options.threshold;
break;
}
}
primaryIndex = primaryAxis.tickPositions && inArray(primaryThreshold, primaryAxis.tickPositions);
if(primaryIndex > 0 && primaryIndex < primaryAxis.tickPositions.length - 1){
primaryAxis.addPlotLine({
color: 'black',
value: 0,
width: 0,
id: 'zero-point-plotline',
zIndex: 3
})
}
if (chart.options.chart.alignThresholds && primaryAxis && this !== primaryAxis && this.hasVisibleSeries) {
if (this.tickPositions && primaryIndex >= 0 && primaryIndex <= primaryAxis.tickPositions.length - 1) {
if (this.tickAmount) {
while (!isAligned(this)) {
if (index < primaryIndex) {
// fill up the tick positions, so that we can calculate the new interval-steps
while (this.tickPositions.length < primaryAxis.tickPositions.length) {
var nextStep = Math.abs(Math.abs(this.tickPositions[this.tickPositions.length - 1]) - Math.abs(this.tickPositions[this.tickPositions.length - 2]));
this.tickPositions.push(this.tickPositions[this.tickPositions.length - 1] + nextStep);
}
newTickPositionsHigh = [];
for(var i = 0; i < primaryAxis.tickPositions.length; i++){
max = this.tickPositions[this.tickPositions.length - 1];
nextStep = max / (primaryAxis.tickPositions.length - 1 - primaryIndex);
newTickPositionsHigh.push(max - i * nextStep);
}
this.tickPositions = newTickPositionsHigh.reverse();
this.max = this.tickPositions[this.tickPositions.length - 1];
this.min = this.tickPositions[0];
} else {
newTickPosLow = this.tickPositions[this.tickPositions.length - 1] + this.tickInterval;
this.tickPositions.push(newTickPosLow);
this.max = newTickPosLow;
}
proceed.call(this);
}
}
}
} else {
proceed.call(this);
}
});
}(Highcharts));
$('#container').highcharts({
chart: {
alignThresholds: true,
type: 'area',
zoomType:'xy'
},
title: {
text: 'The <em>alignThreshold</em> option is true'
},
xAxis: {
categories: ['Flags(1)','Flags(2)','Flags(3)','Shopping (4)','Shopping(5)','Shopping(6)','Shopping(7)','Town(8)','Town(9)','Town(10)','Town(11)','Town(12)','Town(14)','Town(15)','Town(16)','Town(17)','Small(18)','Small(19)','Small(20)','Town(13)'],
scrollbar:
{
enabled:true
}
},
yAxis: [{
title: {
text: 'Traffic',
},
}, {
title: {
text: 'Conversion Rate'
},
opposite: true
},
{
title: {
text: 'ATV'
},
opposite: true
},
{
title: {
text: 'TotalTransaction'
},
opposite: true
},
{
title: {
text: 'Sta'
},
opposite: true
}],
series: [{
data: [8.16,7.6,2.86,2.02,-1.98,-2.83,4.53,-63.35,0],
type: 'spline',
yAxis: 0
}, {
data: [0.9,0.4,-0.4,-2.2,-0.3,0.0,-0.5,1.1,-0.4,3.4,0.8,1.4,2.4,-1.2,3.2,1.7,-0.5,-0.3,2.3,2.8],
type: 'column',
yAxis: 1,
visible: false
}, {
data: [-6.44,6.56,-9.94,35.70,58.07,0.00,103.36,91.03,-84.11,-41.35,25.15,-6.32,4.66,2.93,59.47,-6.39,22.44,17.30,46.46,-14.18],
type: 'column',
yAxis: 2,
visible: false
}]
});
});

Related

Leaflet use popup not display

I use highchart chart to present in popup.
It can be presented when the marker is clicked for the first time.
But opening another popup cannot display the chart.
If I close the original one and open a new one, it can be displayed.
What is the problem?
Turn on for the first time
When opening another
Code:
function onEachFeature(feature, layer) {
var popupContent = '<p style="font-size:130%;">' + feature.properties.id + "<br>PM2.5: " + air + '</p><div class="d-flex"> <button class="day-button">24 hr</button> <button class="week-button">7 Days</button> <button class="mon-button ">30 Days</button></div>' + '</p><div id="container" style="min-width: 350px; height: 190px; margin: 0 auto"></div> <p> ';
if (feature.properties && feature.properties.popupContent) {
popupContent += feature.properties.popupContent;
}
layer.bindPopup(popupContent, { minWidth: 370 }).on("popupopen", function(e) {
var id1 = feature.properties.id;
Highcharts.setOptions({ global: { useUTC: false } });
var chart = null;
test(id1);
}
}
Highchart:
function test (station){
var ob = [];
var json_hour ="data.csv";
var count_nul = 0;
d3.csv(json_hour, function (error, result) {
function date_to_epoch(key) {
var epoch_seconds = new Date(key).getTime();
return Math.floor(epoch_seconds);
}
for (var i = 0; i < result.length; i++) {
var apoche = date_to_epoch(result[i]['date']).toString();
apoche = parseFloat(apoche);
if (parseFloat(result[i]['pm25']).toString() == 'NaN') {
count_nul++;
} else {
var miles = parseFloat(result[i]['pm25']);
}
ob.push([apoche, miles]);
}
if (count_nul >= 24) {
$("#con").text("no data");
}
else {
$("#con").empty();
console.log((ob));
new Highcharts.Chart({
chart: {
renderTo: 'con',
type: 'line'
},
title: { text: '' },
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
minute: '%H:%M',
hour: '%H:%M',
day: '%Y<br/>%m%d',
week: '%Y<br/>%m-%d',
month: '%Y<br/>%m',
year: '%Y'
}
, crosshair: true,
},
tooltip: {
split: false,
shared: true,
animation: true,
xDateFormat: '%Y-%m-%d %H:%M',
valueSuffix: ' µm'
},
series: [{
name: "PM2.5",
data: ob,
showInLegend: true
}
],
credits: {
enabled: false
},
exporting: {
enabled: false
},
plotOptions: {
line: {
connectNulls: true,
}
},
responsive: {
rules: [{
condition: {
maxWidth: 330
},
}]
}
});
}
});
}
Change your code to:
function onEachFeature(feature, layer) {
var popupContent = '<p style="font-size:130%;">' + feature.properties.id + "<br>PM2.5: " + air + '</p><div class="d-flex"> <button class="day-button">24 hr</button> <button class="week-button">7 Days</button> <button class="mon-button ">30 Days</button></div>' + '</p><div id="container" style="min-width: 350px; height: 190px; margin: 0 auto"></div> <p> ';
if (feature.properties && feature.properties.popupContent) {
popupContent += feature.properties.popupContent;
}
layer.bindPopup(popupContent, { minWidth: 370 }).on("popupopen", function(e) {
var id1 = e.popup._source.feature.properties.id;
Highcharts.setOptions({ global: { useUTC: false } });
var chart = null;
test(id1);
}
}
With e.popup._source.feature.properties.id you are sure that the id is from the current open layer

Is there a way to update the legend to the value of a variable within the chart.events?

I am plotting a 3D line chart over time. Each time the count changes at the end of the loop, a new point is plotted for each series. Is there a way to set the value of the legend as the value of count in my example code? The count represents hours since the start of an experiment, so being able to display this is necessary. Thanks!
events: {
load: function() {
var thischart = this;
for (i = 0; i < allpoints.length; i++) {
thischart.addSeries({
enableMouseTracking: false,
lineWidth: 1,
marker: {
enabled: false
},
data: [0, 0, 0]
}, false)
thischart.redraw(false);
}
setInterval(function() {
if (count >= max_data_length) {
if (!pause_at_end) {
for (i = 0; i < allpoints.length; i++) {
thischart.series[i + marker_series_length].setData([0, 0, 0], false);
}
thischart.redraw(false);
count = 1;
} else {
is_paused = true;
document.getElementById('pauseit').value = "Unpause";
}
}
if (!is_paused) {
for (i = 0; i < allpoints.length; i++) {
if (allpoints[i].length > count) {
thischart.series[i + marker_series_length].addPoint([
allpoints[i][count][0], allpoints[i][count][2], allpoints[i][count][1]
], false);
}
}
thischart.redraw(false);
count = count + 4;
}
}, 10)
}
}
You can use series.update method to set new data and change the series name in legend:
chart: {
...,
events: {
load: function() {
var counter = 0,
series = this.series[0];
setInterval(function() {
counter++;
series.update({
data: getRandomData(),
name: 'Name ' + counter
});
}, 1000);
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/7bq21tak/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#update
Thanks ppotaczek! This pointed me in the right direction. I used chart.update instead to update the subtitle. Here is the code I used:
chart.update({
chart: {
inverted: false,
polar: false
},
subtitle: {
style: {
fontSize: '20px'
},
text:'Day:'+ countdays
}
});

Highstock dual x-axis with scrollbar

I have a chart with the dual x-axis and grouped categories as labels and I need a working scrollbar. I have tried multiple ways of how to achieve that but I am not successful so far... This is the nearest I have gone, there are 10 "rows" from which I have displayed 5, there is a scrollbar, but I cannot move the scrollbar.
var count = 10;
var dataArray = [];
for (var i = 0; i < count; i++) {
dataArray[i] = [i + 1, i + 2, i + 3, i + 4, i + 5];
}
var categories1Array = [];
for (var i = 0; i < count; i++) {
categories1Array[i] = i + 1;
}
var categories2Array = [];
for (var i = 0; i < count; i++) {
categories2Array[i] = {
name: "3rd",
categories: [{
name: "2nd",
categories: ['1st']
}]
};
}
Highcharts.chart('container', {
chart: {
inverted: true
},
series: [{
type: 'boxplot',
data: dataArray,
showInLegend: false
}],
xAxis: [{
categories: categories1Array,
max: 4,
gridLineWidth: 1
},
{
opposite: true,
linkedTo: 0,
categories: categories2Array,
max: 9,
scrollbar: {
enabled: true
},
labels: {
formatter: function() {
return `<div style="width:30px">${this.value}</div>`;
},
useHTML: true
}
},
],
credits: {
enabled: false
},
title: {
text: null
},
yAxis: {
title: {
text: null
}
}
});
#container {
min-width: 310px;
max-width: 800px;
height: 300px;
margin: 0 auto
}
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://blacklabel.github.io/grouped_categories/grouped-categories.js"></script>
<div id="container"></div>
Any ideas?
You need to add a scrollbar to the first xAxis. See: https://jsfiddle.net/wchmiel/vrheuwqc/
xAxis: [{
categories: categories1Array,
max: 4,
gridLineWidth: 1,
scrollbar: {
enabled: true
}
}, {
opposite: true,
linkedTo: 0,
categories: categories2Array,
min: 0,
max: 9,
labels: {
formatter: function() {
return `<div style="width:30px">${this.value}</div>`;
},
useHTML: true
}
}]
To align scrollbar to the right side of the chart overwrite H.Scrollbar.prototype.position function and add there an additional offset:
(function(H) {
H.Scrollbar.prototype.position = function(x, y, width, height) {
var scroller = this,
options = scroller.options,
vertical = options.vertical,
xOffset = height,
yOffset = 0,
method = scroller.rendered ? 'animate' : 'attr',
customOffset = 133;
scroller.x = x;
scroller.y = y + this.trackBorderWidth;
scroller.width = width; // width with buttons
scroller.height = height;
scroller.xOffset = xOffset;
scroller.yOffset = yOffset;
// If Scrollbar is a vertical type, swap options:
if (vertical) {
scroller.width = scroller.yOffset = width = yOffset = scroller.size;
scroller.xOffset = xOffset = 0;
scroller.barWidth = height - width * 2; // width without buttons
scroller.x = x = x + scroller.options.margin;
} else {
scroller.height = scroller.xOffset = height = xOffset =
scroller.size;
scroller.barWidth = width - height * 2; // width without buttons
scroller.y = scroller.y + scroller.options.margin;
}
// Set general position for a group:
scroller.group[method]({
translateX: x + customOffset, // add additional offset here
translateY: scroller.y
});
// Resize background/track:
scroller.track[method]({
width: width,
height: height
});
// Move right/bottom button ot it's place:
scroller.scrollbarButtons[1][method]({
translateX: vertical ? 0 : width - xOffset,
translateY: vertical ? height - yOffset : 0
});
}
})(Highcharts);
Demo:
https://jsfiddle.net/wchmiel/9yf58pd6/

How to display extra data in highcharts bubble chart tooltip with datetime x-axis

I am trying to display some more data in highcharts bubble chart tooltip with no success. How can I access this.point.comments inside the tooltip formatter?
The bubble chart I am using has datetime as x-axis.
$('#chart-bubble').highcharts({
chart: {
type: 'bubble',
zoomType: 'xy',
plotBorderWidth: 1
},
title: {
text: 'Risk & Profit Vs Date'
},
tooltip: {
useHTML: true,
formatter: function(){
var expectedProfit = '';
if( this.point.z !== 'none' )
{
expectedProfit = formatExpectedProfit(this.point.z);
}
var tooltip = '<table class="table table-bordered" style="width: 300px;"><tbody><tr><td colspan="2"><h5>'+this.series.name.substr(0,75)+'...</h5></td></tr>' +
'<tr><td>Risk:</td><td>'+this.y+'</td></tr>';
if( expectedProfit !== '' )
{
tooltip += '<tr><td>Profit:</td><td>'+expectedProfit+'</td></tr>';
}
else
{
tooltip += '<tr><td>Comments:</td><td>'+this.point.comments+'</td></tr>';
}
tooltip += '</tbody></table>';
return tooltip;
},
followPointer: false
},
rangeSelector: {
enabled:true
},
xAxis:{
type: 'datetime',
dateTimeLabelFormats: {
day: '%e of %b'
}
},
yAxis: {
title: {
text: 'Ri'
}
},
series: prepareData(res.bubble)
});
Here is the prepareData function:
function prepareData(data)
{
for( var i in data )
{
var item = data[i];
for( var k in item.data )
{
var itemData = item.data[k];
if( itemData[0] )
{
var split = itemData[0].split("-");
var y = split[0];
var m = split[1]-1;
var d = split[2];
itemData[0] = Date.UTC(y,m,d);
item.data[k] = itemData;
}
}
data[i] = item;
}
return data;
}
And the res.bubble json returned from PHP:
$list = array();
$list[] = array('name'=>'project 1','color'=>'#FF0000','data'=>array(new \DateTime(),20,'none'),'pointInterval'=>86400000,'comments'=>'this is a comment');
//.... repeating by adding some more elements to this array
You can access all additional properties via point.options[/* property */.
Highcharts.chart('container', {
chart: {
type: 'bubble',
},
tooltip: {
formatter: function () {
return this.point.options.comments[0];
}
},
series: [{
data: [
{ x: 95, y: 95, z: 13.8, name: 'BE', comments: ['this is a comment'] },
]
}]
});
example: http://jsfiddle.net/yd1vjfmp/

Highcharts pie graph with two rings filtering

I have a pie chart here that I'm working on that has two "rings" in it. The inner ring is just a summation of the outer ring for that given category.
Here is the fiddle: http://jsfiddle.net/jeffvan576/a50859s7/1/
(Apologies for the code - it's a bit of a mess right now)
I've been messing around with the showInLegend functionality but that will (as it's intended) only pull out the given piece of the pie chart. So, for instance, if you click google, it pulls out that piece of the pie chart but leaves the outer ring. To completely eliminate google you need to click "google", "match", "funds added" and "organic" for google.
My question is, is there a way to remove the entire slice (google and all it's children) from the chart at once?
The issue is that in order to get the functionality / layout on the chart that I need, this pie chart is actually built out of two series.
ShowInLegend code:
pie: {
shadow: false,
center: ['50%', '50%'],
showInLegend: true
}
I started building a custom visibility function at the bottom of the fiddle but dialed it back until I understood showInLegend a little better.
Thanks in advance!
you can achieve this by getting name of series on which clicked by using http://api.highcharts.com/highcharts#plotOptions.pie.events.click of plotoptions -> pie.
after that calling visibility function to hide Channel series along with its children to hide/show.
Event:
plotOptions: {
pie: {
shadow: false,
center: ['50%', '50%'],
showInLegend: true,
point: {
events: {
}
}
}
}
also static line put into visibility function to hide/show need to remove.
// chart.series[0].data[0].visible = false;
http://jsfiddle.net/a50859s7/27/
Full code:
$(function () {
var dataObject = {
facebook: {
'organic': 10.85,
'match': 7.35,
'fundsadded': 33.06,
'total': 0,
'status': 'disabled'
},
google: {
'organic': 10.85,
'match': 7.35,
'fundsadded': 33.06,
'total': 0,
'status': 'disabled'
},
email: {
'organic': 10.85,
'match': 7.35,
'fundsadded': 33.06,
'total': 0,
'status': 'enabled'
},
colorSelections: {
'facebook': '#3b5998',
'google': '#dd4b39',
'disabled': '#c6c6c6'
}
}
var sumObjects = function () {
for (var channel in dataObject) {
if (channel === 'colorSelections') continue;
var sum = 0;
for (var key in dataObject[channel]) {
if (key === 'status') continue;
sum += dataObject[channel][key];
}
dataObject[channel].total = sum;
}
}
sumObjects();
var colors = Highcharts.getOptions().colors,
categories = ['Facebook', 'Google', 'Email'],
data = [{
y: dataObject.facebook.total + 1,
//color: dataObject.facebook.status === 'disabled' ? dataObject.colorSelections.disabled : dataObject.colorSelections.facebook,
color: 'rgba(59, 89, 152, 0.3)',
drilldown: {
name: 'Facebook',
categories: ['organic', 'match', 'funds added'],
data: [
dataObject.facebook.organic,
dataObject.facebook.match,
dataObject.facebook.fundsadded],
color: 'rgba(59, 89, 152, 0.3)'
},
}, {
y: dataObject.google.total + 1,
color: '#dd4b39',
drilldown: {
name: 'Google',
categories: ['organic', 'match', 'funds added'],
data: [
dataObject.google.organic,
dataObject.google.match,
dataObject.google.fundsadded],
color: '#e46f61'
}
}, {
y: dataObject.email.total + 1,
color: colors[2],
drilldown: {
name: 'Email',
categories: ['organic', 'match', 'funds added'],
data: [
dataObject.email.organic,
dataObject.email.match,
dataObject.email.fundsadded],
color: colors[2]
}
}],
browserData = [],
versionsData = [],
i,
j,
dataLen = data.length,
drillDataLen,
brightness;
// Build the data arrays
for (i = 0; i < dataLen; i += 1) {
// add browser data
browserData.push({
name: categories[i],
y: data[i].y,
color: data[i].color
});
// add version data
drillDataLen = data[i].drilldown.data.length;
for (j = 0; j < drillDataLen; j += 1) {
brightness = 0.2 - (j / drillDataLen) / 5;
versionsData.push({
name: data[i].drilldown.categories[j],
y: ((data[i].drilldown.data[j] / browserData[0].y) * 100),
color: Highcharts.Color(data[i].color).brighten(brightness).get()
});
}
}
// Create the chart
$('#container').highcharts({
chart: {
type: 'pie'
},
title: {
text: 'Browser market share, April, 2011'
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
plotOptions: {
pie: {
shadow: false,
center: ['50%', '50%'],
showInLegend: true,
point: {
events: {
click: function (event) {
var seriesIndex;
var secondarySeriesIndex;
if (this.name == 'Facebook') {
seriesIndex = 0;
secondarySeriesIndex = 0;
} else if (this.name == 'Google') {
seriesIndex = 1;
secondarySeriesIndex = 3;
} else if (this.name == 'Email') {
seriesIndex = 2;
secondarySeriesIndex = 6;
}
var chart = $('#container').highcharts();
visibility(chart.series[0].data[seriesIndex]);
visibility(chart.series[1].data[secondarySeriesIndex]);
visibility(chart.series[1].data[secondarySeriesIndex + 1]);
visibility(chart.series[1].data[secondarySeriesIndex + 2]);
}
}
}
}
},
tooltip: {
valueSuffix: '%'
},
series: [{
name: 'Channel',
type: 'pie',
data: browserData,
size: '120%',
dataLabels: {
formatter: function () {
return this.y > 5 ? this.point.name : null;
},
color: 'white',
distance: -30
}
}, {
name: 'Added',
type: 'pie',
data: versionsData,
size: '120%',
innerSize: '80%',
dataLabels: {
formatter: function () {
// display only if larger than 1
return this.y > 1 ? '<b>' + this.point.name + ':</b> ' + this.y + '%' : null;
}
}
}]
});
var visibility = function (series) {
series.visible ? series.graphic.hide() : series.graphic.show();
// chart.series[0].data[0].visible = false;
}
var chart = $('#container').highcharts();
$('.update').click(function () {
visibility(chart.series[0].data[0]);
visibility(chart.series[1].data[0]);
visibility(chart.series[1].data[1]);
visibility(chart.series[1].data[2]);
chart.redraw();
});
function synchronizePieSeries(event, slice) {
debugger;
$(chart.series[1].data).each(function (i, e) {
if (slice.name === e.name) {
slice.visible ? e.graphic.hide() : e.graphic.show();
}
});
}
//$('.update').click(function (event) {
// synchronizePieSeries(event, this);
//});
});

Resources