chart.js bar chart datalabel vanishes on hovering over chart - javascript

I have a bar chart that has a label over each bar.
The problem is that when I hover on the chart, all of the labels disappear.
Before hovering:
After hovering:
and here's my code:
let barChartData = {
labels:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
datasets: [{
label: 'Sessions',
backgroundColor: 'rgba(0,163,224, 0.7)',
borderColor: 'rgba(0,163,224, 1)',
borderWidth: 1,
data:[81, 69, 60, 51, 37, 35, 45, 65, 86, 58, 64, 39, 48, 29, 69, 80, 52, 61, 56, 40, 51, 31, 70, 51, 32, 51, 27, 30, 44, 59, 46]
}]
};
let ctx = document.getElementById(id).getContext("2d");
let chart = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
responsive: true,
"animation": {
"duration": 1,
"onComplete": function () {
let chartInstance = this.chart, ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fontColor = 'black'
this.data.datasets.forEach(function (dataset, i) {
let meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
let data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
plugins: {
datalabels: {
color: '#000000'
}
},
legend: {
display: false
},
tooltips: {
enabled: true,
mode: 'label'
},
}
});
I removed the animation field but didn't work.
the chartjs version I'm using is 2.7.3

You can fix the problem with an update to Chart.js 2.9.3 and passing an empty hover function:
<html>
<head>
</head>
<body>
<canvas id="container"></canvas>
<script src="https://pagecdn.io/lib/chart/2.9.3/Chart.bundle.min.js"></script>
</body>
</html>
let barChartData = {
labels:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
datasets: [{
label: 'Sessions',
backgroundColor: 'rgba(0,163,224, 0.7)',
borderColor: 'rgba(0,163,224, 1)',
borderWidth: 1,
data:[81, 69, 60, 51, 37, 35, 45, 65, 86, 58, 64, 39, 48, 29, 69, 80, 52, 61, 56, 40, 51, 31, 70, 51, 32, 51, 27, 30, 44, 59, 46]
}]
};
const id = 'container';
let ctx = document.getElementById(id).getContext("2d");
let chart = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
responsive: true,
"animation": {
"duration": 1,
"onComplete": function () {
let chartInstance = this.chart, ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fontColor = 'black'
this.data.datasets.forEach(function (dataset, i) {
let meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
let data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
hover: () => {},
plugins: {
datalabels: {
color: '#000000'
}
},
legend: {
display: false
},
tooltips: {
enabled: true,
mode: 'label'
},
}
});
This fix doesn't work with Chart.js 2.7.3. I don't know if it's a bug or a different behavior on purpose.
Live example

Related

Trying to change background color in chart js filter

I am new to development and trying to do a project where I creating a webpage which have price range filter and there is a chart linked to that price range filter. What I am trying to do is change the background color of my labels of chartJs according to ranger filter. I want only labels in given range to show orange color and other labels should show light pink color, but here when I change background color after giving a condition all the labels' color get changed but i want only labels falling under filter range change the color.
trying to achieve range filter in this
let canvasElement = document.getElementById("productChart");
const dataPoints = [21, 0, 19, 3, 5, 0, 2, 3, 10, 4, 6, 7, 2, 0, 0, 0, 24, 30, 32, 45, 44, 22,
21, 10, 7, 5, 4, 3, 1, 0, 0];
const labels = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31]
const backgroundColor = 'rgba(255, 99, 71, 0.3)';
const newBackgroundColor = 'rgba(255, 99, 71, 1)';
let config =
{
type: 'bar',
data: {
labels: labels,
datasets: [{
barPercentage: 0.5,
barThickness: 5,
maxBarThickness: 12,
minBarLength: 2,
// label: 'Number of Phones',
data: dataPoints, //price
backgroundColor: backgroundColor,
borderColor: [
'rgba(255, 99, 71, 0.2)',
],
borderWidth: 1,
borderRadius: 5,
// borderSkipped: false,
}]
},
options: {
responsive: true,
scales: {
x: {
ticks: {
display: false, //this will remove only the label
},
grid: {
display:false,
borderColor: 'black', // <-- this line is answer to initial question
borderWidth:2,
}
},
y: {
display: false, //this will remove only the label
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
displayColors: false,
padding: 10,
yAlign: 'top',
},
},
}
}
let productChart = new Chart(canvasElement, config)
const start = document.getElementById('start')
const end = document.getElementById('end')
function updateMin(range) {
const minValue = labels.slice(range.value - 1, end.value);
let newLabels = productChart.config.data.labels
for(let i = 0; i < newLabels.length; i++){
value = newLabels[i];
if (minValue.includes(value)){
productChart.config.data.datasets[0].backgroundColor=newBackgroundColor;
}
}
end.min = range.value
productChart.update();
}
You could use a scriptable options for backgroundColor options. Based on the argument, context.index (see here the doc: https://www.chartjs.org/docs/latest/general/options.html#scriptable-options) you can decide at runtime which color to use.
In the below snippet, changing the stepper values, the chart will change the background colors.
I have used part of your code. Instead of using the stepper, you can use your slider or what you are using.
const dataPoints = [21, 0, 19, 3, 5, 0, 2, 3, 10, 4, 6, 7, 2, 0, 0, 0, 24, 30, 32, 45, 44, 22,
21, 10, 7, 5, 4, 3, 1, 0, 0];
const labels = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31]
const backgroundColor = 'rgba(255, 99, 71, 0.3)';
const newBackgroundColor = 'rgba(255, 99, 71, 1)';
const from = document.getElementById("from");
const to = document.getElementById("to");
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
//barPercentage: 0.5,
//barThickness: 5,
//maxBarThickness: 12,
//minBarLength: 2,
data: dataPoints,
backgroundColor(ctx) {
const fromValue = parseFloat(from.value);
const toValue = parseFloat(to.value);
const value = ctx.index + 1;
if (value >= fromValue && value <= toValue) {
return newBackgroundColor;
}
return backgroundColor;
},
borderColor: 'rgba(255, 99, 71, 0.2)',
borderWidth: 1,
borderRadius: 5,
}]
},
options: {
responsive: true,
scales: {
x: {
ticks: {
display: false,
},
grid: {
display:false,
}
},
y: {
display: false,
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
},
},
}
});
from.addEventListener('click', function() {
myChart.update();
});
to.addEventListener('click', function() {
myChart.update();
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.9.1/dist/chart.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"/>
</div>
From:
<input type="number" id="from" min="1" max="31" value="1"/>
To:
<input type="number" id="to" min="1" max="31" value="31"/>
</body>
</html>

SVG to Image export performance issues (using canvg / XMLSerializer / getComputedStyle)

I am using canvg to convert a chart svg to an image. We have the issue that by default not all CSS attributes are applied to the image so we ended up using getComputedStyle in a loop.
This is a total mess under performance aspects if we have 10 or even 20 charts to be exported at once.
var labels = ['2018-10-01', '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08', '2018-10-09', '2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15', '2018-10-16', '2018-10-17', '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22', '2018-10-23', '2018-10-24', '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29', '2018-10-30', '2018-10-31', '2018-11-01', '2018-11-02', '2018-11-03', '2018-11-04', '2018-11-05', '2018-11-06', '2018-11-07', '2018-11-08', '2018-11-09', '2018-11-10', '2018-11-11', '2018-11-12', '2018-11-13', '2018-11-14', '2018-11-15', '2018-11-16', '2018-11-17', '2018-11-18', '2018-11-19', '2018-11-20', '2018-11-21', '2018-11-22', '2018-11-23', '2018-11-24', '2018-11-25', '2018-11-26', '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03', '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08', '2018-12-09', '2018-12-10', '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15', '2018-12-16', '2018-12-17', '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08', '2019-01-09', '2019-01-10', '2019-01-11', '2019-01-12', '2019-01-13', '2019-01-14', '2019-01-15', '2019-01-16', '2019-01-17', '2019-01-18', '2019-01-19', '2019-01-20', '2019-01-21', '2019-01-22', '2019-01-23', '2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27', '2019-01-28', '2019-01-29', '2019-01-30', '2019-01-31', '2019-02-01', '2019-02-02', '2019-02-03', '2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07', '2019-02-08', '2019-02-09', '2019-02-10', '2019-02-11', '2019-02-12', '2019-02-13', '2019-02-14', '2019-02-15', '2019-02-16', '2019-02-17', '2019-02-18', '2019-02-19', '2019-02-20', '2019-02-21', '2019-02-22', '2019-02-23', '2019-02-24', '2019-02-25', '2019-02-26', '2019-02-27', '2019-02-28'];
var columns = ['data101', 'data2', 'data347'];
var data = [
[0, 0, 2, 2, 1, 2, 7, 3, 1, 7, 5, 5, 5, 5, 6, 6, 11, 7, 2, 7, 16, 7, 3, 5, 10, 9, 11, 7, 3, 7, 7, 10, 10, 9, 18, 10, 20, 13, 9, 19, 16, 13, 20, 18, 14, 15, 18, 20, 19, 11, 13, 13, 12, 16, 11, 12, 21, 20, 23, 19, 19, 23, 23, 24, 23, 25, 21, 23, 20, 22, 21, 23, 24, 25, 27, 29, 28, 25, 24, 17, 20, 24, 22, 27, 21, 27, 19, 26, 31, 27, 28, 27, 21, 20, 27, 22, 22, 19, 17, 21, 23, 19, 22, 20, 21, 25, 15, 19, 20, 19, 21, 28, 17, 20, 14, 18, 17, 20, 27, 21, 18, 18, 20, 16, 27, 16, 16, 9, 18, 8, 19, 13, 8, 16, 15, 16, 9, 15, 10, 13, 10, 11, 10, 13, 12, 7, 14, 16, 13, 14, 8],
[0, 0, 338, 1201, 1268, 1371, 1286, 1148, 446, 288, 228, 253, 193, 201, 283, 393, 436, 379, 421, 444, 444, 417, 513, 353, 364, 399, 238, 191, 305, 337, 365, 349, 365, 244, 101, 39, 55, 72, 151, 98, 31, 127, 114, 92, 104, 196, 307, 245, 84, 168, 41, 38, 292, 488, 536, 569, 495, 448, 408, 358, 344, 380, 328, 334, 332, 330, 345, 312, 369, 377, 356, 301, 226, 273, 237, 116, 178, 133, 114, 138, 95, 143, 74, 74, 83, 47, 75, 101, 96, 59, 46, 128, 70, 57, 93, 80, 94, 93, 63, 86, 81, 63, 70, 102, 91, 67, 69, 68, 88, 76, 79, 70, 119, 88, 74, 94, 76, 54, 82, 90, 75, 130, 67, 78, 106, 91, 81, 27, 77, 21, 104, 83, 55, 60, 62, 304, 393, 191, 292, 77, 76, 55, 125, 89, 99, 127, 60, 75, 99, 120, 56],
[0, 0, 0, 1419, 7454, 12638, 10944, 7652, 4272, 11219, 9071, 7207, 7929, 8373, 9566, 6310, 7406, 9286, 8415, 7659, 6457, 3380, 10902, 10952, 10508, 7219, 4625, 4484, 4396, 5178, 5991, 7927, 14132, 14307, 5094, 10011, 6257, 9184, 18574, 12597, 11415, 7118, 9991, 10225, 14337, 4417, 12701, 17833, 23553, 10037, 4833, 5894, 19421, 14735, 12597, 8730, 5888, 11836, 13143, 17219, 10492, 10528, 8649, 11868, 10502, 6758, 7672, 8479, 11142, 22330, 26595, 4423, 17434, 8709, 9657, 7823, 9135, 19765, 18016, 16010, 8419, 7300, 8877, 9611, 9050, 8680, 8211, 6635, 3069, 10739, 6288, 6761, 7807, 16243, 20415, 23051, 19727, 8721, 6445, 8585, 13688, 14728, 17113, 16255, 3898, 4622, 3869, 3774, 4190, 3461, 4824, 4608, 4613, 3677, 3648, 3575, 3556, 4036, 3732, 2517, 4676, 4129, 3250, 4142, 3987, 4396, 3362, 2964, 1849, 2609, 2851, 3003, 3583, 3473, 3190, 2658, 4363, 3959, 4588, 3771, 4315, 3178, 3354, 3159, 2695, 4114, 4292, 3322, 1218, 3526, 3717]
];
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
//prepare chart data
var columnData = [];
var chartDataColumns = [];
var chartData = [];
chartData.push([columns[0]].concat(data[0]));
chartDataColumns = [
['x'].concat(labels)
].concat(chartData);
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
x: 'x',
columns: [['x'].concat(labels)].concat(chartData),
type: 'line',
onmouseover: function(d) {
chart1.focus(d.id);
chart2.focus(d.id);
},
onmouseout: function() {
chart1.revert();
chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
type: 'timeseries',
tick: {
rotate: 90,
format: '%Y-%m-%d'
}
},
y: {
label: 'sample-data',
tick: {
format: d3.format(",")
}
}
},
color: {
pattern: colors
}
});
var chart2 = c3.generate({
bindto: d3.select('#chart2'),
data: {
columns: [[columns[0]].concat(data[0])],
type: 'pie',
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
color: {
pattern: colors
},
});
for (var i = 1; i < columns.length; i++) {
setTimeout(function(column) {
chart1.load({
columns: [
[columns[column]].concat(data[column])
]
});
chart2.load({
columns: [[columns[column]].concat(data[column])]
});
}, (i * 5000 / columns.length), i);
}
document.getElementById("exportButton").onclick = function() {
exportChartToImage();
};
function exportChartToImage() {
var createImagePromise = new Promise(function(resolve, reject) {
var images = [];
d3.selectAll('svg').each(function() {
if (this.parentNode) {
images.push(getSvgImage(this.parentNode, true));
}
});
if (images.length > 0)
resolve(images);
else
reject(images);
});
createImagePromise.then(function(images) {
images.forEach(function(img, n) {
img.toBlob(function(blob) {
saveAs(blob, "image_" + (n + 1) + ".png");
});
});
})
.catch(function(error) {
throw error;
});
};
/**
* Converts a SVG-Chart to a canvas and returns it.
*/
function getSvgImage(svgContainer, png) {
var svgEl = d3.select(svgContainer).select('svg').node();
var svgCopyEl = svgEl.cloneNode(true);
if (!svgCopyEl)
return;
//remove elements not for printing
lensObject = d3.selectAll(".hidden-print").remove().exit();
//add temp document objects
var emptySvgEl = d3.select(document.createElementNS("http://www.w3.org/2000/svg", "svg")).attr("id", "emptysvg")
.attr("version", 1.1)
.attr("height", 2)
.node();
var canvasComputed = d3.select(document.createElement("canvas")).attr("id", "canvasComputed").node();
var container = d3.select(document.createElement("div")).attr("style", "display: none;")
.attr("class", "c3").node();
svgContainer.append(container);
container.append(svgCopyEl);
container.append(emptySvgEl);
container.append(canvasComputed);
//apply all CSS styles to SVG
exportStyles(svgCopyEl, emptySvgEl);
// transform SVG to canvas using external canvg
canvg(canvasComputed, new XMLSerializer().serializeToString(svgCopyEl));
//remove temp document objects
canvasComputed.remove();
emptySvgEl.remove();
svgCopyEl.remove();
container.remove();
return canvasComputed;
}
function exportStyles(svg, emptySvg) {
var tree = [];
var emptySvgDeclarationComputed = getComputedStyle(emptySvg);
//d3.select(svg).selectAll().each(function() {
$(svg).find("*").each(function() {
explicitlySetStyle(this, emptySvgDeclarationComputed);
});
}
function traverse(obj, tree) {
tree.push(obj);
if (obj.hasChildNodes()) {
var child = obj.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName != 'SCRIPT') {
traverse(child, tree);
}
child = child.nextSibling;
}
}
return tree;
}
function explicitlySetStyle(element, emptySvgDeclarationComputed) {
var cSSStyleDeclarationComputed = getComputedStyle(element);
var i, len, key, value;
var computedStyleStr = "";
for (i = 0, len = cSSStyleDeclarationComputed.length; i < len; i++) {
key = cSSStyleDeclarationComputed[i];
value = cSSStyleDeclarationComputed.getPropertyValue(key);
if (value !== emptySvgDeclarationComputed.getPropertyValue(key)) {
if (key == 'visibility' && value == 'hidden') {
computedStyleStr += 'display: none;';
} else {
computedStyleStr += key + ":" + value + ";";
}
}
}
element.setAttribute('style', computedStyleStr);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.js"></script>
<!-- Required to convert named colors to RGB -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.4/rgbcolor.min.js"></script>
<!-- Optional if you want blur -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/stackblur-canvas/1.4.1/stackblur.min.js"></script>
<!-- Main canvg code -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.js"></script>
<script src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart1" class "c3">
</div>
<div id="chart2" class="c3">
</div>
<button type="button" id="exportButton">
export to SVG
</button>
=> http://jsfiddle.net/gothmogg/jLt3yq75/
This sample shows exemplary how we apply the CSS styles to the SVG. If we use normal canvg without getComputedStyle the x and y axes of the c3 chart look like a total mess...
Do you know faster way to get valid images?
Is there a way to filter the CSS-styles? Maybe use "c3" styles only?
I have managed to solve the performance problems of exporting C3 SVG charts to PNG by avoiding to use getComputedStyle.
Browsing the issues in C3 I found issue #313
https://github.com/c3js/c3/issues/313
For others http://www.nihilogic.dk/labs/canvas2image/ might also be a good place to look at but I found a solution at https://gist.github.com/aendrew/1ad2eed6afa29e30d52e#file-exportchart-js-L29.
I have changed the code from using angular to d3 and now it works (for me).
Hopefully this might help others having the same issue.
Here the working code. Please note: the css styles are only examined and inlined once.
var labels = ['2018-10-01', '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08', '2018-10-09', '2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15', '2018-10-16', '2018-10-17', '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22', '2018-10-23', '2018-10-24', '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29', '2018-10-30', '2018-10-31', '2018-11-01', '2018-11-02', '2018-11-03', '2018-11-04', '2018-11-05', '2018-11-06', '2018-11-07', '2018-11-08', '2018-11-09', '2018-11-10', '2018-11-11', '2018-11-12', '2018-11-13', '2018-11-14', '2018-11-15', '2018-11-16', '2018-11-17', '2018-11-18', '2018-11-19', '2018-11-20', '2018-11-21', '2018-11-22', '2018-11-23', '2018-11-24', '2018-11-25', '2018-11-26', '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03', '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08', '2018-12-09', '2018-12-10', '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15', '2018-12-16', '2018-12-17', '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08', '2019-01-09', '2019-01-10', '2019-01-11', '2019-01-12', '2019-01-13', '2019-01-14', '2019-01-15', '2019-01-16', '2019-01-17', '2019-01-18', '2019-01-19', '2019-01-20', '2019-01-21', '2019-01-22', '2019-01-23', '2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27', '2019-01-28', '2019-01-29', '2019-01-30', '2019-01-31', '2019-02-01', '2019-02-02', '2019-02-03', '2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07', '2019-02-08', '2019-02-09', '2019-02-10', '2019-02-11', '2019-02-12', '2019-02-13', '2019-02-14', '2019-02-15', '2019-02-16', '2019-02-17', '2019-02-18', '2019-02-19', '2019-02-20', '2019-02-21', '2019-02-22', '2019-02-23', '2019-02-24', '2019-02-25', '2019-02-26', '2019-02-27', '2019-02-28'];
var columns = ['data101', 'data2', 'data347'];
var data = [
[0, 0, 2, 2, 1, 2, 7, 3, 1, 7, 5, 5, 5, 5, 6, 6, 11, 7, 2, 7, 16, 7, 3, 5, 10, 9, 11, 7, 3, 7, 7, 10, 10, 9, 18, 10, 20, 13, 9, 19, 16, 13, 20, 18, 14, 15, 18, 20, 19, 11, 13, 13, 12, 16, 11, 12, 21, 20, 23, 19, 19, 23, 23, 24, 23, 25, 21, 23, 20, 22, 21, 23, 24, 25, 27, 29, 28, 25, 24, 17, 20, 24, 22, 27, 21, 27, 19, 26, 31, 27, 28, 27, 21, 20, 27, 22, 22, 19, 17, 21, 23, 19, 22, 20, 21, 25, 15, 19, 20, 19, 21, 28, 17, 20, 14, 18, 17, 20, 27, 21, 18, 18, 20, 16, 27, 16, 16, 9, 18, 8, 19, 13, 8, 16, 15, 16, 9, 15, 10, 13, 10, 11, 10, 13, 12, 7, 14, 16, 13, 14, 8],
[0, 0, 338, 1201, 1268, 1371, 1286, 1148, 446, 288, 228, 253, 193, 201, 283, 393, 436, 379, 421, 444, 444, 417, 513, 353, 364, 399, 238, 191, 305, 337, 365, 349, 365, 244, 101, 39, 55, 72, 151, 98, 31, 127, 114, 92, 104, 196, 307, 245, 84, 168, 41, 38, 292, 488, 536, 569, 495, 448, 408, 358, 344, 380, 328, 334, 332, 330, 345, 312, 369, 377, 356, 301, 226, 273, 237, 116, 178, 133, 114, 138, 95, 143, 74, 74, 83, 47, 75, 101, 96, 59, 46, 128, 70, 57, 93, 80, 94, 93, 63, 86, 81, 63, 70, 102, 91, 67, 69, 68, 88, 76, 79, 70, 119, 88, 74, 94, 76, 54, 82, 90, 75, 130, 67, 78, 106, 91, 81, 27, 77, 21, 104, 83, 55, 60, 62, 304, 393, 191, 292, 77, 76, 55, 125, 89, 99, 127, 60, 75, 99, 120, 56],
[0, 0, 0, 1419, 7454, 12638, 10944, 7652, 4272, 11219, 9071, 7207, 7929, 8373, 9566, 6310, 7406, 9286, 8415, 7659, 6457, 3380, 10902, 10952, 10508, 7219, 4625, 4484, 4396, 5178, 5991, 7927, 14132, 14307, 5094, 10011, 6257, 9184, 18574, 12597, 11415, 7118, 9991, 10225, 14337, 4417, 12701, 17833, 23553, 10037, 4833, 5894, 19421, 14735, 12597, 8730, 5888, 11836, 13143, 17219, 10492, 10528, 8649, 11868, 10502, 6758, 7672, 8479, 11142, 22330, 26595, 4423, 17434, 8709, 9657, 7823, 9135, 19765, 18016, 16010, 8419, 7300, 8877, 9611, 9050, 8680, 8211, 6635, 3069, 10739, 6288, 6761, 7807, 16243, 20415, 23051, 19727, 8721, 6445, 8585, 13688, 14728, 17113, 16255, 3898, 4622, 3869, 3774, 4190, 3461, 4824, 4608, 4613, 3677, 3648, 3575, 3556, 4036, 3732, 2517, 4676, 4129, 3250, 4142, 3987, 4396, 3362, 2964, 1849, 2609, 2851, 3003, 3583, 3473, 3190, 2658, 4363, 3959, 4588, 3771, 4315, 3178, 3354, 3159, 2695, 4114, 4292, 3322, 1218, 3526, 3717]
];
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
//prepare chart data
var columnData = [];
var chartDataColumns = [];
var chartData = [];
var C3Styles = null;
chartData.push([columns[0]].concat(data[0]));
chartDataColumns = [
['x'].concat(labels)
].concat(chartData);
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
x: 'x',
columns: [
['x'].concat(labels)
].concat(chartData),
type: 'line',
onmouseover: function(d) {
chart1.focus(d.id);
chart2.focus(d.id);
},
onmouseout: function() {
chart1.revert();
chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
type: 'timeseries',
tick: {
rotate: 90,
format: '%Y-%m-%d'
}
},
y: {
label: 'sample-data',
tick: {
format: d3.format(",")
}
}
},
color: {
pattern: colors
}
});
var chart2 = c3.generate({
bindto: d3.select('#chart2'),
data: {
columns: [
[columns[0]].concat(data[0])
],
type: 'pie',
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
},
legend: {
position: 'right',
show: true,
item: {
onclick: function(id) {
if (chart1) chart1.toggle(id);
if (chart2) chart2.toogle(id);
},
onmouseover: function(id) {
if (chart1) chart1.focus(id);
if (chart2) chart2.focus(id);
},
onmouseout: function(id) {
if (chart1) chart1.revert();
if (chart2) chart2.revert();
}
}
},
color: {
pattern: colors
},
});
for (var i = 1; i < columns.length; i++) {
setTimeout(function(column) {
chart1.load({
columns: [
[columns[column]].concat(data[column])
]
});
chart2.load({
columns: [
[columns[column]].concat(data[column])
]
});
}, (i * 5000 / columns.length), i);
}
document.getElementById("exportButton").onclick = function() {
exportChartToImage();
};
function exportChartToImage() {
var createImagePromise = new Promise(function(resolve, reject) {
var images = [];
d3.selectAll('svg').each(function() {
if (this.parentNode) {
images.push(getSvgImage(this.parentNode, true));
}
});
if (images.length > 0)
resolve(images);
else
reject(images);
});
createImagePromise.then(function(images) {
images.forEach(function(img, n) {
img.toBlob(function(blob) {
saveAs(blob, "image_" + (n + 1) + ".png");
});
});
})
.catch(function(error) {
throw error;
});
};
/**
* Converts a SVG-Chart to a canvas and returns it.
*/
function getSvgImage(svgContainer, png) {
var svgEl = d3.select(svgContainer).select('svg').node();
var svgCopyEl = svgEl.cloneNode(true);
if (!svgCopyEl)
return;
//remove elements not for printing
lensObject = d3.selectAll(".hidden-print").remove().exit();
//add temp document objects
var canvasComputed = d3.select(document.createElement("canvas")).attr("id", "canvasComputed").node();
var container = d3.select(document.createElement("div")).attr("style", "display: none;")
.attr("class", "c3").node();
svgContainer.append(container);
container.append(svgCopyEl);
container.append(canvasComputed);
/* taken from https://gist.github.com/aendrew/1ad2eed6afa29e30d52e#file-exportchart-js
and changed from, angular to D3 functions
*/
/* Take styles from CSS and put as inline SVG attributes so that Canvg
can properly parse them. */
var chartStyle;
if (!C3Styles) {
// Get rules from c3.css
var styleSheets = document.styleSheets;
for (var i = 0; i <= styleSheets.length - 1; i++) {
if (styleSheets[i].href && (styleSheets[i].href.indexOf('c3.min.css') !== -1 || styleSheets[i].href.indexOf('c3.css') !== -1)) {
try {
if (styleSheets[i].rules !== undefined) {
chartStyle = styleSheets[i].rules;
} else {
chartStyle = styleSheets[i].cssRules;
}
break;
}
//Note that SecurityError exception is specific to Firefox.
catch (e) {
if (e.name == 'SecurityError') {
console.log("SecurityError. Cant read: " + styleSheets[i].href);
continue;
}
}
}
if (chartStyle !== null && chartStyle !== undefined) {
C3Styles = {};
var selector;
// Inline apply all the CSS rules as inline
for (i = 0; i < chartStyle.length; i++) {
if (chartStyle[i].type === 1) {
selector = chartStyle[i].selectorText;
var styleDec = chartStyle[i].style;
for (var s = 0; s < styleDec.length; s++) {
C3Styles[styleDec[s]] = styleDec[styleDec[s]];
}
}
}
}
}
}
if (C3Styles)
d3.select(svgCopyEl).selectAll('.c3:not(.c3-chart):not(path)').style(C3Styles);
// SVG doesn't use CSS visibility and opacity is an attribute, not a style property. Change hidden stuff to "display: none"
d3.select(svgCopyEl).selectAll('*')
.filter(function(d) {
return d && d.style && (d.style('visibility') === 'hidden' || d.style('opacity') === '0');
})
.style('display', 'none');
//fix weird back fill
d3.select(svgCopyEl).selectAll("path").attr("fill", "none");
//fix no axes
d3.select(svgCopyEl).selectAll("path.domain").attr("stroke", "black");
//fix no tick
d3.select(svgCopyEl).selectAll(".tick line").attr("stroke", "black");
// transform SVG to canvas using external canvg
canvg(canvasComputed, new XMLSerializer().serializeToString(svgCopyEl));
//remove temp document objects
canvasComputed.remove();
svgCopyEl.remove();
container.remove();
return canvasComputed;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.min.js"></script>
<!-- Required to convert named colors to RGB -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.4/rgbcolor.min.js"></script>
<!-- Optional if you want blur -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/stackblur-canvas/1.4.1/stackblur.min.js"></script>
<!-- Main canvg code -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.js"></script>
<script src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>
<div id="chart1" class "c3">
</div>
<div id="chart2" class="c3">
</div>
<button type="button" id="exportButton">
export to SVG
</button>
Unfortunately
document.styleSheets[i].rules
can't be accessed in the script here. It worked in my environment though.
Any idea why this does not work here?

Issues with series.data in highcharts

I'm using a column chart with a slider that redraws the chart after slide operation is invoked. I'm storing each data array in a javascript object and the chart renders according to the slider option. After assigning the initial values for the first slider option, the chart renders correctly but when I slide back to the first position, the chart won't render. And the weird part is when I assign the initial values to a separate variable and the data option is assigned with this variable, the chart renders correctly at every position.
Here's the code:
var data = {
"jan": [0, 10, 25, 30, 25, 10, 0,30, 25, 10, 0],
"feb": [0, 5, 25, 35, 30, 10, 0, 10, 25, 30, 25],
"mar": [0, 30, 18, 4, 18, 30, 0, 20, 30, 25, 15],
"apr": [0, 20, 30, 25, 15, 10, 0, 10, 15, 25, 30],
"may": [0, 10, 15, 25, 30, 20, 0, 35, 123, 978, 43],
"jun": [54, 5, 546, 77, 34, 3, 2, 567, 567, 7, 57],
"jul": [56, 324, 768, 578, 124, 154, 90, 150, 125, 258, 312],
"aug": [67, 76, 4, 76, 23, 2, 24, 10, 15, 546, 30],
"sep": [6, 5, 35, 123, 978, 4, 32, 10, 15, 546, 30],
"oct": [97, 56, 7, 567, 567, 7, 57, 10, 15, 25, 30],
"nov": [56, 4, 65, 25, 6, 565, 56, 10, 15, 546, 30],
"dec": [0, 10, 15, 546, 30, 33, 0, 10, 15, 546, 30]
};
var someData = [0, 10, 25, 30, 25, 10, 0,30, 25, 10, 0];
var chart = new Highcharts.chart({
chart: {
renderTo: 'container',
type: 'column',
marginTop: 50,
marginLeft: 100,
marginBottom: 50
},
title: false,
exporting: {enabled: false},
xAxis: {
crosshair: true,
tickColor: '#7F7F7F',
lineColor: '#7F7F7F',
tickWidth: 0,
labels: {
step: 5
},
title: {
text: 'x-axis',
align: "left",
x: -10,
rotation: 0,
style: {
"font-size" : "15px"
}
}
},
yAxis: {
min: 0,
title: {
text: 'y-axis',
align: 'high',
rotation: 0,
y: -10,
offset: 0,
style: {
"font-size" : "15px"
}
},
gridLineColor: 'transparent',
lineColor: '#7F7F7F',
lineWidth: 1,
tickWidth: 1,
tickColor: '#7F7F7F',
gridLineWidth: 0,
minorGridLineWidth: 0,
labels: {
step: 2,
formatter: function(){
if(this.value > 999)
return Math.round(this.value/1000) + 'k';
return this.value;
}
}
},
tooltip: {
enabled: false
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
},
series: {
colorByPoint: true
}
},
series: [{
showInLegend: false,
data: someData
}],
credits: false
});
$('#slider_bar').on("slide", function () {
chart.series[0].setData(data[document.getElementById('value').innerHTML]);
});
The initial position of the slider is at jan and the chart renders correctly when I slide back to jan. I'd like to know why the chart won't render when I assign series.data as:
data: data.jan
Any suggestions?
Highchart series.data expects a key value pair, or an array of arrays like
[[x1,y1],[x2,y2]]
or
{
y: [x1,x2]
}
now when you do data = data.jan Highchart is not able to find the Y value because data.jan is a simple array
Found the solution:
instead of writing
data: data.jan
write
data: data.jan.slice()
The slice function does not directly returns the reference of the array, instead it returns a copy of the array. I still wonder why we need to use the slice function in the first place, for this particular situation but it works.

Apply pagination on column chart using Highcharts

I am drawing a column chart (see image below) using Highcharts.
So far, I am successfully able to draw the chart, but I'm facing issues with pagination (next-previous buttons).
One idea would be to use a separate <div> element just below my chart and write a logic to show buttons, but in my requirements, I need to show the next and previous buttons in the chart area itself.
<div id="chart-2" class="graph"></div>
<div id="buttons"></div>
The following is the code to draw a chart - I have 12 categories (Jan - Dec), I want to display (Jan - Jun) on one page and (Aug - Dec) on another page.
$('#chart-2').highcharts({
chart :{
backgroundColor: '#3f3b53',
type:'column'
},
legend : {
symbolHeight : 8,
symbolWidth : 8,
symbolRadius : 4,
margin: 15,
backgroundColor: '#FFFFFF',
layout:'horizontal',
itemDistance:25,
symbolMargin:10,
itemStyle: {
color: 'black',
fontWeight: 'normal'
}
},
title: {
text: ''
},
xAxis: {
categories: [
'JAN',
'FEB',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC'
],
labels: {
style: {
color: '#FFFFFF'
}
}
},
yAxis: {
min: 0,
title: {
text: ''
}
},
tooltip: {
backgroundColor: '#FFFFFF',
borderColor: '#FFFFFF',
borderRadius: 0,
borderWidth: 5,
formatter: function() {
return ' <b>' + this.y + '</b><br><b>'+this.series.name+'</b>';
}
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'Physical Medicine',
color: '#0099ff',
data: [90, 80, 85, 70, 80, 50, 88, 85, 20, 30, 40, 50]
},{
name: 'Phychiatry',
color: '#ff3399',
data: [80, 70, 85, 60, 50, 70, 38, 89, 70, 40, 20, 50]
},{
name: 'Otrhopedic Surgery',
color: '#cc0000',
data: [88, 79, 81, 50, 40, 76, 31, 81, 65, 30, 29, 59]
},{
name: 'Nephrology',
color: '#ff5c33',
data: [88, 89, 61, 60, 70, 36, 21, 51, 69, 39, 21, 51]
},{
name: 'Cardiology',
color: '#ffa64d',
data: [18, 29, 31, 50, 40, 46, 81, 31, 89, 39, 81, 31]
},{
name: 'General Surgery',
color: '#ffe066',
data: [28, 59, 61, 59, 49, 41, 31, 41, 81, 31, 87, 38]
},{
name: 'General Practise',
color: '#a64dff',
data: [78, 69, 41, 89, 29, 81, 21, 11, 41, 35, 92, 89]
},{
name: 'Pulmanory Diesease',
color: '#0066ff',
data: [58, 39, 49, 89, 39, 61, 25, 45, 23, 76, 42, 89]
}]
}, function(chart) { // on complete
//chart.renderer.button("abc", 100, 100, function() {}, {}, {}, {}).add();
chart.renderer.button('Reset zoom', null, null, chart.resetZoom, {
zIndex: 20
}).attr({
align: 'right',
title: 'Reset zoom level 1:1'
}).add(chart.zoomGroupButton).align({
align: 'right',
x: -10,
y: 10
}, false, null);
});
If I understand you correctly, you can use chart.renderer.button for adding new buttons to your chart, that will change the extremes of your xAxis.
function(chart) { // on complete
chart.renderer.button('<', chart.plotLeft - 60, chart.plotHeight + chart.plotTop).addClass('left').add();
chart.renderer.button('>', chart.plotLeft + chart.plotWidth + 30, chart.plotHeight + chart.plotTop).addClass('right').add();
$('.left').click(function() {
chart.xAxis[0].setExtremes(0, 5);
});
$('.right').click(function() {
chart.xAxis[0].setExtremes(6, 11);
})
}
When you will change you xAxis extremes you will be able to show the half of your points on left button click, and the second half on right button click.
You can find options I have used in Highcharts API:
http://api.highcharts.com/highcharts
And here you can find an example how it can work:
http://jsfiddle.net/1dtt1Lph/2/
However, The Accepted Answer is true for Jan to Dec. If there are some different cases then above code will get only two screen. I have made a some customization to the accepted answer hope it will surely help others for different scenerio.
function (chart) {
var x=6;
var max_plot=12;
chart.renderer.button('<', chart.plotLeft - 60, chart.plotHeight + chart.plotTop).addClass('left').add();
chart.renderer.button('>', chart.plotLeft + chart.plotWidth + 30, chart.plotHeight + chart.plotTop).addClass('right').add();
$('.left').click(function() {
if (x < 0) {
x = 0;
} else {
console.log('fsafg');
chart.xAxis[0].setExtremes(x-6, x-1);
x=x-6;
}
});
$('.right').click(function() {
if (x > max_plot) {
x = max_plot;
} else {
chart.xAxis[0].setExtremes(x+1, x+6);
x=x+6;
}
});
}

JqPlot Bar and Line Chart combine

I have situation where i have to combine bar and line chart I have the below data please check if have any solution of this:
$(document).ready(function () {
var s1 = [ 59, 175, 148, 213, 19, 213, 144, 64, 229, 89, 59, 363, 5, 71, 31];//bar chart
var s2 = [66, 220, 87, 59, 15, 227, 134, 46, 139, 30, 18, 71, 2, 17, 2];
//bar chart
var line1= [98.81, 98.90, 99.00, 99.17, 99.35, 99.36, 99.46, 99.56, 99.71, 99.82, 99.87, 99.89, 99.92, 99.95,99.98];//data for line chart
var line2 = [ 99.52, 99.52, 99.52, 99.52, 99.52,99.52,99.52,99.52, 99.52, 99.52, 99.52, 99.52, 99.52, 99.52];//data for line chart
var ticks = ['Rakhine', 'Ayeyarwady', 'Magway', 'Bago', 'Kayah', 'Sagaing', 'Shan', 'Kachin', 'Yangon', 'Mon', 'Kayin', 'Mandalay',
'Chin', 'Tanintharyi', 'Naypyitaw' ];
//now i need to combine bar and line with the same plot
plot2 = $.jqplot('chart2', [s1, s2], {
seriesDefaults: {
renderer: $.jqplot.BarRenderer,show: true,
pointLabels: { show: true }
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
}
});
});
Description:

Categories