I have this Jscharting script which loads data from a csv file. It works great, but unfortunately it doesn't load at all if there is any empty data in the source. How would you add handling empty data into following script?
JSC.fetch(
'./js/data.csv'
).then(function(response) {
response.text().then(function(t) {
var jsonData = JSC.csv2Json(t,{coerce:function(d){
return {
Date: d.date,
s1: parseFloat(d.s1),
s2: parseFloat(d.s2),
}
}});
var s1Points = JSC.nest()
.key('Date')
.rollup('s1')
.points(jsonData);
var s2Points = JSC.nest()
.key('Date')
.rollup('s2')
.points(jsonData);
var chart = JSC.chart('chartDiv', {
debug: true,
type: 'line',
legend_visible: false,
defaultCultureName: "hu-SK",
xAxis: {
crosshair_enabled: true,
scale: {
type: 'time',
time: {
parser: 'YYYY-MM-DD',
}
},
formatString: 'd',
},
yAxis: {
orientation: 'opposite',
formatString: 'c'
},
defaultSeries: {
firstPoint_label_text: '<b>%seriesName</b>',
defaultPoint_marker: {
type: 'circle',
fill: 'white',
outline: { width: 2, color: 'currentColor' }
}
},
series: [
{
name: 's1',
points: s1Points
},
{
name: 's2',
points: s2Points
}
]
});
});
});
I tried simple thing as:
s1: (parseFloat(d.s1) || '0'),
s2: (parseFloat(d.s2) || '0'),
...but the result is quite unreadable:
I would like to have in this case break the continuous line instead of zero value, if it's possible.
Use regular Javascript to filter out the bad data.
To remove entries/rows where s1 or s2 is null or undefined:
jsonData = jsonData.filter( ({s1, s2}) => s1 != null && s2 != null);
I think you need to use parseFloat(d.s1) || null.
And, on series, set emptyPointMode to default, ignore, or treatAsZero.
Demo JsFiddle
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Empty point mode</title>
</head>
<body>
<script src="https://code.jscharting.com/latest/jscharting.js"></script>
<div id="chartDiv" style="width: 100%; height: 400px;"></div>
<script>
function showData(t) {
var jsonData = JSC.csv2Json(t, {
coerce: function (d) {
return {
Date: d.date,
s1: (parseFloat(d.s1) || null),
s2: (parseFloat(d.s2) || null),
s3: (parseFloat(d.s3) || null),
}
}
});
var s1Points = JSC.nest()
.key('Date')
.rollup('s1')
.points(jsonData);
var s2Points = JSC.nest()
.key('Date')
.rollup('s2')
.points(jsonData);
var s3Points = JSC.nest()
.key('Date')
.rollup('s3')
.points(jsonData);
var chart = JSC.chart('chartDiv', {
debug: true,
type: 'line',
legend_visible: true,
title: {
position: 'top',
padding: 7,
fill: ['orange', 'orange', 0],
opacity: 0.4,
boxVisible: true,
label: {
text: 'emptyPointMode: default / ignore / treatAsZero',
align: 'left'
}
},
legend: {
position: 'inside right top',
defaultEntry_value: '%value'
},
defaultCultureName: "hu-SK",
xAxis: {
crosshair_enabled: true,
scale: {
type: 'time',
time: {
parser: 'YYYY-MM-DD',
}
},
formatString: 'dd',
},
yAxis: {
orientation: 'opposite',
formatString: 'c'
},
defaultSeries: {
firstPoint_label_text: '<b>%seriesName</b>',
defaultPoint_marker: {
type: 'circle',
fill: 'white',
outline: { width: 2, color: 'currentColor' }
}
},
series: [
{
name: 'default',
points: s1Points,
emptyPointMode: 'default'
},
{
name: 'ignore',
points: s2Points,
emptyPointMode: 'ignore'
},
{
name: 'treatAsZero',
points: s3Points,
emptyPointMode: 'treatAsZero'
}
]
});
}
const data = `date,s1,s2,s3
2022-01-1,22.2,33,15
2022-01-2,25.2,30,17
2022-01-3,30.1.2,35,13
2022-01-4,20.2,25,15
2022-01-5,,,
2022-01-6,22.2,30,15
2022-01-7,23.2,31,15,
2022-01-8,23.2,31.5,16
`;
showData(data);
</script>
</body>
</html>
In above demo 5th day has no data.
The demo may not run on Stackoverflow. Use the JsFiddle link.
Related
I am trying to customize a Chart JS element from a template (Front Dashboard)
In the template the example is set up from the HTML as follows
<canvas class="js-chart"
data-hs-chartjs-options='{
"type": "line",
"data": {
"labels": ["1 May","2 May","3 May","4 May","5 May","6 May","7 May","8 May","9 May","10 May","11 May","12 May","13 May","14 May","15 May","16 May","17 May","18 May","19 May","20 May","21 May","22 May","23 May","24 May","25 May","26 May","27 May","28 May","29 May","30 May","31 May"],
"datasets": [{
"data": [25,18,30,31,35,35,60,60,60,75,21,20,24,20,18,17,15,17,30,120,120,120,100,90,75,90,90,90,75,70,60],
"backgroundColor": ["rgba(55, 125, 255, 0)", "rgba(255, 255, 255, 0)"],
"borderColor": "#377dff",
"borderWidth": 2,
"pointRadius": 0,
"pointHoverRadius": 0
}]
},
"options": {
"scales": {
"yAxes": [{
"display": false
}],
"xAxes": [{
"display": false
}]
},
"hover": {
"mode": "nearest",
"intersect": false
},
"tooltips": {
"postfix": "%",
"hasIndicator": true,
"intersect": false
}
}
}'>
</canvas>
This displays a nicely formatted Tooltip
but when I setup the chart from script with the same structure/config, the tooltip formatting changes and it also is clipped inside the bounds of the chart.
var myData = [];
var myLabels = [];
var myOccupancy;
function showChart() {
myData = myOccupancy.DataList;
myLabels = myOccupancy.LabelList;
console.log(myData);
console.log(myLabels);
let popCanvasName = document.getElementById("occChart");
let barChartName = new Chart(popCanvasName, {
type: 'line',
data: {
labels: myLabels,
datasets: [
{
data: myData,
backgroundColor: ['rgba(55, 125, 255, 0)', 'rgba(255, 255, 255, 0)'],
borderColor: '#377dff',
borderWidth: 2,
pointRadius: 0,
pointHoverRadius: 0
}
]
},
options: {
scales: {
yAxes: [
{
display: false
}
],
xAxes: [
{
display: false
}
]
},
hover: {
mode: 'nearest',
intersect: false
},
tooltips: {
postfix: '%',
hasIndicator: false,
intersect: false
},
legend: {
display: false
}
}
});
}
function getChartData() {
return fetch('./Index?handler=OccupancyChartData', {
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
.then(function(response) {
console.log(response);
if (response.ok) {
return response.text();
} else {
throw Error('Response Not OK');
}
})
.then(function(text) {
try {
return JSON.parse(text);
} catch (err) {
throw Error('Method Not Found');
}
})
.then(function(responseJSON) {
myOccupancy = responseJSON;
showChart();
});
};
$(document).on('ready', function() {
getChartData();
// initialization of circles
$('.js-circle').each(function() {
var circle = $.HSCore.components.HSCircles.init($(this));
});
$('.js-chart').each(function () {
var chart = $.HSCore.components.HSChartJS.init($(this));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4"></script>
<!-- as you are using v2.x of chart.js -->
<canvas id="occChart" width="640" height="480"></canvas>
The reason the formatting is different is because chart.js does not support the options postfix and hasIndicator, seems like your wrapper is styling the tooltip and taking those extra options and transforms the tooltip itself. If you want to make your chart via script you need to follow the normal documentation.
About the tooltip getting cut off guess its somewhere else that it might go wrong because standard behaviour it adjusts the tooltip placement so that it is in the chart area:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: '# of Votes',
data: [12, 19, 2, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
}
};
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
canvas {
background-color : #eee;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4"></script>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
Your code in your question is for ..... chart.js v2.xx
v3.xx is not backwards compatible with v2.xx
v3.xx has better performance, hence you might consider migrating
Anyhow, I offer you 2 solutions for both versions:
code for chart.js v2.9.4 (latest for v2.x)
code for chart.js v3.5.1 (latest for v3.x)
I migrated your code to v3.x
I used some sample data (as I cannot fetch your data from here).
v2.x
Replacing postfix: '%' with following callback function:
options: {
...
tooltips: {
usePointStyle: true,
// postfix: '%',
callbacks: { // <-- to replace 'postfix:'
label: function(context) {
return context.yLabel + '%' || '';
}
}
...
}
See following complete code for v2.x and Run code snippet to see result:
const popCanvasName = document.getElementById('occChart').getContext('2d');
let myData = [];
let myLabels = [];
const myOccupancy = { // <-- let's use sample data meanwhile
"LabelList" : ["2021-08-02","2021-08-03","2021-08-04","2021-08-05","2021-08-06"],
"DataList" : [39,41,42,30,21]
};
function showChart() {
myData = myOccupancy.DataList;
myLabels = myOccupancy.LabelList;
// console.log(myData);
// console.log(myLabels);
const barChartName = new Chart(popCanvasName, {
type: 'line',
data: {
labels: myLabels,
datasets: [{
data: myData,
backgroundColor: ['rgba(55, 125, 255, 0.5)', 'rgba(255, 255, 255, 0.5)'],
fill: true, // <-- to show backgroundColor
borderColor: '#377dff',
borderWidth: 2,
pointRadius: 0,
pointHoverRadius: 0
}]
},
options: {
aspectRatio: 5,
responsive: true,
interaction: {
intersect: false,
mode: 'nearest'
},
scales: {
yAxes: [{
display: false
}],
xAxes: [{
type: 'time', // load moment.js and adapter for this to work
display: true,
time: {
unit: 'week',
displayFormats: {
hour: 'h:mm a',
day: 'ddd',
week: 'dddd',
month: 'MMM'
},
tooltipFormat: 'dddd, MMM DD, YYYY' // modify format string to your needs
}
}]
},
tooltips: {
usePointStyle: true,
// postfix: '%',
callbacks: { // you can use this callback
label: function(context) {
return context.yLabel + '%' || '';
}
},
// hasIndicator: true,
intersect: false
},
legend: {
display: false
}
}
});
};
function getChartData() {
return fetch('./Index?handler=OccupancyChartData', {
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
.then(function(response) {
console.log(response);
if (response.ok) {
return response.text();
} else {
throw Error('Response Not OK');
}
})
.then(function(text) {
try {
return JSON.parse(text);
} catch (err) {
throw Error('Method Not Found');
}
})
.then(function(responseJSON) {
myOccupancy = responseJSON;
showChart();
});
};
showChart();
/* We use sample data meanwhile
$(document).on('ready', function() {
// getChartData(); <-- we use sample data meanwhile
// initialization of circles
$('.js-circle').each(function() {
var circle = $.HSCore.components.HSCircles.init($(this));
});
$('.js-chart').each(function () {
var chart = $.HSCore.components.HSChartJS.init($(this));
});
});
*/
<!-- get latest version of Chart.js v2.x -->
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4"></script>
<!-- You need moment.js and adapter for time to work at x-Axis -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
<canvas id="occChart" width="320"></canvas>
v3.x
Replacing postfix: '%' with following callback function:
options: {
...
plugins: { // toolip within plugin now
tooltip: { // before tooltips --> now toolip (singular)
usePointStyle: true,
// postfix: '%',
callbacks: { // <-- replacing 'postfix:'
label: function(context) {
return context.parsed.y + '%' || '';
}
}
}
...
}
See following complete code for v3.x and Run code snippet to see result:
const popCanvasName = document.getElementById('occChart').getContext('2d');
let myData = [];
let myLabels = [];
const myOccupancy = { // <-- let's use sample data meanwhile
"LabelList" : ["2021-08-02","2021-08-03","2021-08-04","2021-08-05","2021-08-06"],
"DataList" : [39,41,42,30,21]
};
function showChart() {
myData = myOccupancy.DataList;
myLabels = myOccupancy.LabelList;
// console.log(myData);
// console.log(myLabels);
const barChartName = new Chart(popCanvasName, {
type: 'line',
data: {
labels: myLabels,
datasets: [{
data: myData,
backgroundColor: ['rgba(55, 125, 255, 0.5)', 'rgba(255, 255, 255, 0.5)'],
fill: true, // <-- to show backgroundColor
borderColor: '#377dff',
borderWidth: 2,
pointRadius: 0,
pointHoverRadius: 0
}]
},
options: {
aspectRatio: 5,
responsive: true,
interaction: { // before hover --> now 'interaction'
intersect: false,
mode: 'nearest'
},
scales: {
yAxes: { // before '[{' now '{' (not an array anymore)
display: false
},
xAxes: { // before '[{' --> now '{' (not an array anymore)
type: 'time', // load moment.js and adapter for this to work
display: false,
time: {
unit: 'week',
displayFormats: {
hour: 'h:mm a',
day: 'ddd',
week: 'dddd',
month: 'MMM'
},
tooltipFormat: 'dddd, MMM DD, YYYY' // modify format string to your needs
}
}
},
plugins: {
tooltip: { // before tooltips --> now toolip (singular) within plugin
usePointStyle: true,
// postfix: '%',
callbacks: { // <-- replacing 'postfix:'
label: function(context) {
return context.parsed.y + '%' || '';
}
},
hasIndicator: true,
intersect: false
},
legend: { // --> now within plugin
display: false
}
}
}
});
};
function getChartData() {
return fetch('./Index?handler=OccupancyChartData', {
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
.then(function(response) {
console.log(response);
if (response.ok) {
return response.text();
} else {
throw Error('Response Not OK');
}
})
.then(function(text) {
try {
return JSON.parse(text);
} catch (err) {
throw Error('Method Not Found');
}
})
.then(function(responseJSON) {
myOccupancy = responseJSON;
showChart();
});
};
showChart();
/* We use sample data meanwhile
$(document).on('ready', function() {
// getChartData(); <-- we use sample data meanwhile
// initialization of circles
$('.js-circle').each(function() {
var circle = $.HSCore.components.HSCircles.init($(this));
});
$('.js-chart').each(function () {
var chart = $.HSCore.components.HSChartJS.init($(this));
});
});
*/
<!-- get latest version of Chart.js, now at v3.5.1 -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- You need moment.js and adapter for time to work at x-Axis -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
<canvas id="occChart" width="320"></canvas>
What is the most up to date (ES6) and minimal way to use Chart.js with time series data (requiring an adapter like moment.js) and zoom/pan capabilities (chartjs-plugin-zoom) using only CDN? Do you have to use require or import?
The code below will throw errors relating to missing functions that are coming from the other adapters and plugins.
var default_series = [1, 2, 3, 4, 5];
var default_time_series = [new Date()];
for (let i = 1; i < 5; i++)
{
var tempDay = new Date(default_time_series[i - 1]);
tempDay.setDate(tempDay.getDate() + 1);
default_time_series.push(new Date(tempDay.valueOf()));
}
const default_chart_dataset = {
data: [],
label: 'Default',
borderColor: '#000000',
fill: false,
hidden: false,
spanGaps: false,
pointRadius: 0
};
var chart_data = {
type: 'line',
data: {
labels: [],
datasets: []
},
options: {
title: {
display: true,
text: "A Chart"
},
scales: {
x: {
type: "time",
time: {
// unit: 'day',
// tooltipFormat: 'MMM DD',
displayFormats: {
day: 'MMM DD YY'
}
}
}
},
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'x'
},
zoom: {
wheel: {
enabled: true
},
pinch: {
enabled: true
},
mode: 'x'
}
}
}
}
};
var main_chart = new Chart(document.getElementById('a-chart').getContext('2d'), chart_data);
main_chart.data.datasets.push({...default_chart_dataset});
main_chart.data.datasets[0].data = [...default_series];
main_chart.data.labels = [...default_time_series];
main_chart.update();
<html lang="en">
<body>
<canvas id="a-chart" class="a-graph" width="850" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.5.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom#1.1.1/dist/chartjs-plugin-zoom.min.js"></script>
</body>
</html>
As stated in the documentation and migration guide since chart.js version 3 you will need to include a date adapter yourself.
Example:
var default_series = [1, 2, 3, 4, 5];
var default_time_series = [new Date()];
for (let i = 1; i < 5; i++) {
var tempDay = new Date(default_time_series[i - 1]);
tempDay.setDate(tempDay.getDate() + 1);
default_time_series.push(new Date(tempDay.valueOf()));
}
const default_chart_dataset = {
data: [],
label: 'Default',
borderColor: '#000000',
fill: false,
hidden: false,
spanGaps: false,
pointRadius: 0
};
var chart_data = {
type: 'line',
data: {
labels: [],
datasets: []
},
options: {
title: {
display: true,
text: "A Chart"
},
scales: {
x: {
type: "time",
time: {
// unit: 'day',
// tooltipFormat: 'MMM DD',
displayFormats: {
day: 'MMM DD YY'
}
}
}
},
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'x'
},
zoom: {
wheel: {
enabled: true
},
pinch: {
enabled: true
},
mode: 'x'
}
}
}
}
};
var main_chart = new Chart(document.getElementById('a-chart').getContext('2d'), chart_data);
main_chart.data.datasets.push({ ...default_chart_dataset
});
main_chart.data.datasets[0].data = [...default_series];
main_chart.data.labels = [...default_time_series];
main_chart.update();
<html lang="en">
<body>
<canvas id="a-chart" class="a-graph" width="850" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.5.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom#1.1.1/dist/chartjs-plugin-zoom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.0/chartjs-adapter-moment.js"></script>
</body>
</html>
I'm looking to simplify this code. Any way to it so? Spring MVC + Apex Charts
var d = /*[[${s0}]]*/ null`; <-- It is sent via the Spring Framework. Basically represents datetime(in millis) at `d[0]`, `d[3]`,... Temperature at `d[1]`, `d[4]`,... and Humidity at `d[2]`, `d[5]`,...
<script type="text/javascript" th:inline="javascript">
var d = /*[[${s0}]]*/ null;
var options = {
chart: {
type: 'area',
height: 300
},
series: [
{
name: 'Temperature',
data: [
[d[0], d[1]],
[d[3], d[4]],
[d[6], d[7]],
[d[9], d[10]],
[d[12], d[13]],
[d[15], d[16]],
[d[18], d[19]],
[d[21], d[22]],
[d[24], d[25]],
[d[27], d[28]],
[d[30], d[31]],
[d[33], d[34]],
[d[36], d[37]],
[d[39], d[40]],
[d[42], d[43]],
[d[45], d[46]],
[d[48], d[49]],
[d[51], d[52]],
[d[54], d[55]],
[d[57], d[58]],
[d[60], d[61]],
[d[63], d[64]],
[d[66], d[67]],
[d[69], d[70]]
]
},
{
name: "Humidity",
data: [
[d[0], d[2]],
[d[3], d[5]],
[d[6], d[8]],
[d[9], d[11]],
[d[12], d[14]],
[d[15], d[17]],
[d[18], d[20]],
[d[21], d[23]],
[d[24], d[26]],
[d[27], d[29]],
[d[30], d[32]],
[d[33], d[35]],
[d[36], d[38]],
[d[39], d[41]],
[d[42], d[44]],
[d[45], d[47]],
[d[48], d[50]],
[d[51], d[53]],
[d[54], d[56]],
[d[57], d[59]],
[d[60], d[62]],
[d[63], d[65]],
[d[66], d[68]],
[d[69], d[71]]
]
}
],
xaxis: {
type: 'datetime'
},
yaxis: [
{
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Temperature"
}
}, {
min: 0,
max: 100,
opposite: true,
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Humidity"
}
}
],
legend: {
position: 'top',
horizontalAlign: 'center'
},
tooltip: {
x: {
format: 'HH:mm dd/MM/yy'
},
}
}
var chart = new ApexCharts(document.querySelector("#chart0"), options);
chart.render();
</script>
I just need to simplify sending data via d[0], d[1] etc. Is there any kind of loop or anything else I can use?
You could take a function which takes the data and a pattern for the wanted elements and an offset for increment for the next row.
function mapByPattern(data, pattern, offset) {
var result = [], i = 0;
while (i < data.length) {
result.push(pattern.map(j => data[i + j]));
i += offset;
}
return result;
}
var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
result = { series: [
{ name: 'Temperature', data: mapByPattern(data, [0, 1], 3) },
{ name: "Humidity", data: mapByPattern(data, [0, 2], 3) }
]};
console.log(result);
Thank You, Nina. Code code didn't work exactly as i wanted but was so helpful to fix my own. Thanks alot! Here's some fixed code :)
var data = /*[[${s0}]]*/ null;
function mapByPattern(data, pattern, offset) {
var result = [], i = 0;
while (i < data.length) {
result.push(pattern.map(j => data[i + j]));
i += offset;
}
return result;
}
var options = {
chart: {
type: 'area',
height: 300
},
series: [
{
name: 'Temperature',
data: mapByPattern(data, [0, 1], 3)
},
{
name: "Humidity",
data: mapByPattern(data, [0, 2], 3)
}
],
xaxis: {
type: 'datetime'
},
yaxis: [
{
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Temperature"
}
}, {
min: 0,
max: 100,
opposite: true,
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Humidity"
}
}
],
legend: {
position: 'top',
horizontalAlign: 'center'
},
tooltip: {
x: {
format: 'HH:mm dd/MM/yy'
},
}
}
var chart = new ApexCharts(document.querySelector("#chart0"), options);
chart.render();
I am facing an issue with exporting a column chart with scroll bar enabled which is not exporting a full chart after a scroll. It works for the first time, but when I scroll to the right or left and then when I export, the export is not happening completely.
Here is the sample.
var processedDataArray = [
{"Series_1_Value":1054237.31,"Series_2_Value":297367.88,"Series_3_Value":955472.31, "other":123450.45, "category":"CATEGORY-1"},
{"Series_1_Value":1914955.84,"Series_2_Value":472603.94,"Series_3_Value":1717425.84,"other":234560.45, "category":"CATEGORY-2"},
{"Series_1_Value":1172527.75,"Series_2_Value":368143.09,"Series_3_Value":1073762.75,"other":345670.45, "category":"CATEGORY-3"},
{"Series_1_Value":908568.43,"Series_2_Value":309490.05,"Series_3_Value":809803.43,"other":789010.45, "category":"CATEGORY-4"},
{"Series_1_Value":8001718.08,"Series_2_Value":5983055.85,"Series_3_Value":7112833.08,"other":890102.45, "category":"CATEGORY-5"},
{"Series_1_Value":1060572.17,"Series_2_Value":317503.11,"Series_3_Value":961807.17,"other":901230.45, "category":"CATEGORY-6"},
{"Series_1_Value":2484203.07,"Series_2_Value":1189924.57,"Series_3_Value":2187908.07,"other":435260.45, "category":"CATEGORY-7"},
{"Series_1_Value":6070895.44,"Series_2_Value":2722014.27,"Series_3_Value":5379540.44,"other":678900.45, "category":"CATEGORY-8"}
];
var series1DataArray = [];
var series2DataArray = [];
var series3DataArray = [];
var series4DataArray = [];
var categories = [];
var seriesNms = ['Series 1', 'Series 2', 'Series 3', 'Other'];
var _colors = ['#2F7ED8', '#915612', '#8BBC21', '#AA86F2', '#9054B6', '#76F0A3', '#A98835', '#09ACB6'];
for (i = 0; i < processedDataArray.length; i++) {
var dataObject = processedDataArray[i];
categories.push(dataObject['category']);
series1DataArray.push({
name: dataObject['category'],
y: parseInt(dataObject['Series_1_Value'])
});
series2DataArray.push({
name: dataObject['category'],
y: parseInt(dataObject['Series_2_Value'])
});
series3DataArray.push({
name: dataObject['category'],
y: parseInt(dataObject['Series_3_Value'])
});
series4DataArray.push({
name: dataObject['category'],
y: parseInt(dataObject['other'])
});
}
$(function() {
new Highcharts.Chart({
chart: {
type: 'column',
renderTo: 'colChart',
borderColor: '#000000',
borderWidth: 2,
plotBackgroundColor: 'rgba(255, 255, 255, .1)',
plotBorderColor: '#CCCCCC',
plotBorderWidth: 1,
zoomType: 'xy',
width: 960,
events: {
load: function() {
alert('Chart has loaded with exporting option ' + this.options.exporting.enabled + ", min:" + this.xAxis[0].min + ", max:" + this.xAxis[0].max + ", categories.length=" + categories.length);
}
}
},
scrollbar: {
enabled: true
},
colors: _colors,
exporting: {
enabled: true,
sourceWidth: 960,
sourceHeight: 400,
chartOptions: {
xAxis: [{
categories: categories,
max: categories.length - 1
}],
scrollbar: {
enabled: false
}
}
},
yAxis: {
title: {
text: 'Value($)'
}
},
xAxis: {
categories: categories,
max: categories.length > 5 ? 5 : categories.length - 1
},
plotOptions: {
series: {
pointPadding: 0.05,
groupPadding: 0.15
}
},
title: {
text: 'Column Chart',
align: 'center'
},
series: [{
name: seriesNms[0],
data: series1DataArray
}, {
name: seriesNms[1],
data: series2DataArray
}, {
name: seriesNms[2],
data: series3DataArray
}, {
name: seriesNms[3],
data: series4DataArray
}],
credits: {
enabled: false
}
}); //end of Chart const
}); //end of function...
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
<title>Highcharts</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.highcharts.com/stock/highstock.js"></script>
<script type="text/javascript" src="http://code.highcharts.com/highcharts.js"></script>
<script type="text/javascript" src="http://code.highcharts.com/modules/exporting.js"></script>
</head>
<body>
<div id="colChart"></div>
</body>
</html>
How to resolve the issue?. If you see the pop-up dialog it is not displaying the same "export enabled" boolean value.
Adding min and minRange to your exporting.chartOptions.xAxis seems to yield positive results. This does require max to still be there, and seemingly it gives varying results if any of those three are missing.
For example (updated JSFiddle):
exporting:{
enabled: true,
sourceWidth: 960,
sourceHeight: 400,
chartOptions: {
xAxis: [{
categories: categories,
min: 0, // Added for fix
minRange: categories.length-1, // Added for fix
max: categories.length-1
}],
scrollbar:{
enabled: false
}
}
}
Hopefully this resolves your issue. As to why, I do not know.
Can I apply theme without reloading the whole chart. Can I push the themes settings within the chart code? In highcharts site all examples are single theme based. Here is my code
$(function() {
$.getJSON('http://api-sandbox.oanda.com/v1/candles?instrument=EUR_USD&candleFormat=midpoint&granularity=W', function(data) {
// create the chart
var onadata =[];
var yData=[];
var type='line';
var datalen=data.candles.length;
var all_points= [];
var all_str="";
for(var i=0; i<datalen;i++)
{
var each=[Date._parse(data.candles[i].time), data.candles[i].openMid, data.candles[i].highMid, data.candles[i].lowMid, data.candles[i].closeMid]
onadata.push(each);
yData.push(data.candles[i].closeMid);
}
$( "#change_theme" ).on("change", function() {
var optionSelected = $("option:selected", this);
var valueSelected = this.value;
//alert(valueSelected);
if(valueSelected=='default.js')
{
location.reload();
}
else{ $.getScript('js/themes/'+valueSelected, function() {
//alert('Load was performed.');
chart();
});
}
});
chart();
function chart()
{
$('#container').highcharts('StockChart', {
credits: {
enabled : 0
},
rangeSelector : {
buttons: [{
type: 'month',
count: 1,
text: '1M'
}, {
type: 'month',
count: 3,
text: '3M'
},{
type: 'month',
count: 6,
text: '6M'
},{
type: 'all',
text: 'All'
}],
selected:3
},
legend: {
enabled: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
title : {
text : 'Stock Price'
},
xAxis :{
minRange : 3600000
},
yAxis : [{
offset: 0,
ordinal: false,
height:280,
labels: {
format: '{value:.5f}'
}
}],
chart: {
events: {
click: function(event) {
var x1=event.xAxis[0].value;
var x2 =this.xAxis[0].toPixels(x1);
var y1=event.yAxis[0].value;
var y2 =this.yAxis[0].toPixels(y1);
selected_point='['+x1+','+y1+']';
all_points.push(selected_point);
all_str=all_points.toString();
if(all_points.length>1)
{
this.addSeries({
type : 'line',
name : 'Trendline',
id: 'trend',
data: JSON.parse("[" + all_str + "]"),
color:'#'+(Math.random()*0xEEEEEE<<0).toString(16),
marker:{enabled:true}
});
}
if(all_points.length==2)
{
all_points=[];
}
}
}
},
series : [{
//allowPointSelect : true,
type : type,
name : 'Stock Price',
id: 'primary',
data : onadata,
tooltip: {
valueDecimals: 5,
crosshairs: true,
shared: true
},
dataGrouping : {
units : [
[
'hour',
[1, 2, 3, 4, 6, 8, 12]
], [
'day',
[1]
], [
'week',
[1]
], [
'month',
[1, 3, 6]
], [
'year',
[1]
]
]
}
},
]
});
}
});
});
and this is my js fiddle
Please help. Thanks in advance.
This is possible if you're using modern browsers that support CSS variables.
Highcharts.theme = {
colors: [
'var(--color1)',
'var(--color2)',
'var(--color3)',
'var(--color4)',
'var(--color5)',
'var(--color6)',
]
}
Highcharts.setOptions(Highcharts.theme);
function setTheme(themeName) {
// remove theme-* classes from body
removeClasses = Array.from(document.body.classList).filter(s => s.startsWith('theme-'));
document.body.classList.remove(...removeClasses)
if (themeName) {
document.body.classList.add('theme-' + themeName);
}
}
CSS
body {
--color1: #e00;
--color2: #b00;
--color3: #900;
--color4: #600;
--color5: #300;
--color6: #000;
}
body.theme-dark {
--color1: #555;
--color2: #444;
--color3: #333;
--color4: #222;
--color5: #111;
--color6: #000;
}
body.theme-retro {
--color1: #0f0;
--color2: #ff0;
--color3: #0ff;
--color4: #0a0;
--color5: #aa0;
--color6: #00a;
}
Unfortunately it is not possible, so you need to destroy and create new chart.