I made a radial progress bar using the nested doughnut chart, the object works fine.
I wanted to show the progress on a label, but the label became visible in the data I used as the background.
q1:How can i hide the label i just use as background?
q2:Do you think it is good to make progress bar using chartjs? (real time) I would be very happy if you could provide information about another alternative library.
My code:
var _gaugeValue = 5;
var _gaugeValue2 = 43;
var _gagueMaxVal = 100;
var _gagueMaxVal2 = 150;
var ctxGauge = document.getElementById("myCanvasGauge");
var myGauge = new Chart(ctxGauge, {
type: "doughnut",
data: {
datasets: [
{
data: [_gaugeValue2, _gagueMaxVal2 - _gaugeValue2],
backgroundColor: ["rgba(255,0,0,1)", "rgba(220,220,220,1)"],
hoverOffset: 4,
cutout: "80%",
},
{
data: [_gaugeValue, _gagueMaxVal - _gaugeValue],
backgroundColor: ["rgba(71,148,218,1)", "rgba(220,220,220,1)"],
hoverOffset: 4,
cutout: "70%",
options: {
plugins: {
datalabels: {
display: false,
},
},
},
},
],
},
options: {
response: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
enabled: false,
},
datalabels: {
backgroundColor: function (context) {
return context.dataset.backgroundColor;
},
borderColor: "white",
borderRadius: 25,
borderWidth: 2,
color: "white",
display: function (context) {
var dataset = context.dataset;
var count = 2;
var value = dataset.data[1];
return value > count * 1.5;
},
font: {
weight: "bold",
},
padding: 6,
formatter: Math.round,
},
},
},
plugins: [ChartDataLabels],
});
function changeData() {
_gaugeValue = Math.floor(Math.random() * 100) - 1;
myGauge.data.datasets[1].data = [
_gaugeValue,
_gagueMaxVal - _gaugeValue,
];
myGauge.update();
}
function changeData2() {
_gaugeValue2 = Math.floor(Math.random() * 100) - 1;
myGauge.data.datasets[0].data = [
_gaugeValue2,
_gagueMaxVal2 - _gaugeValue2,
];
myGauge.update();
}
.gauge-container {
margin: auto;
}
.button-container {
margin: auto;
padding: 10px;
}
<script
src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"
integrity="sha512-TW5s0IT/IppJtu76UbysrBH9Hy/5X41OTAbQuffZFU6lQ1rdcLHzpU5BzVvr/YFykoiMYZVWlr/PX1mDcfM9Qg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.min.js"
integrity="sha512-R/QOHLpV1Ggq22vfDAWYOaMd5RopHrJNMxi8/lJu8Oihwi4Ho4BRFeiMiCefn9rasajKjnx9/fTQ/xkWnkDACg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<div class="gauge-container">
<canvas id="myCanvasGauge"></canvas>
</div>
<div class="button-container">
<button onclick="changeData()">Change Data 1</button>
</div>
<div class="button-container">
<button onclick="changeData2()">Change Data 2</button>
</div>
you can use the display callback to determine which labels are displayed
if I follow correctly, you do not want labels to appear on the gray portion of the chart...?
if so, only display the first value...
display: function (context) {
return context.dataIndex === 0;
},
see following working snippet...
var _gaugeValue = 5;
var _gaugeValue2 = 43;
var _gagueMaxVal = 100;
var _gagueMaxVal2 = 150;
var ctxGauge = document.getElementById("myCanvasGauge");
var myGauge = new Chart(ctxGauge, {
type: "doughnut",
data: {
datasets: [
{
data: [_gaugeValue2, _gagueMaxVal2 - _gaugeValue2],
backgroundColor: ["rgba(255,0,0,1)", "rgba(220,220,220,1)"],
hoverOffset: 4,
cutout: "80%",
},
{
data: [_gaugeValue, _gagueMaxVal - _gaugeValue],
backgroundColor: ["rgba(71,148,218,1)", "rgba(220,220,220,1)"],
hoverOffset: 4,
cutout: "70%",
options: {
plugins: {
datalabels: {
display: false,
},
},
},
},
],
},
options: {
response: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
enabled: false,
},
datalabels: {
backgroundColor: function (context) {
return context.dataset.backgroundColor;
},
borderColor: "white",
borderRadius: 25,
borderWidth: 2,
color: "white",
display: function (context) {
return context.dataIndex === 0;
},
font: {
weight: "bold",
},
padding: 6,
formatter: Math.round,
},
},
},
plugins: [ChartDataLabels],
});
function changeData() {
_gaugeValue = Math.floor(Math.random() * 100) - 1;
myGauge.data.datasets[1].data = [
_gaugeValue,
_gagueMaxVal - _gaugeValue,
];
myGauge.update();
}
function changeData2() {
_gaugeValue2 = Math.floor(Math.random() * 100) - 1;
myGauge.data.datasets[0].data = [
_gaugeValue2,
_gagueMaxVal2 - _gaugeValue2,
];
myGauge.update();
}
.gauge-container {
margin: auto;
}
.button-container {
margin: auto;
padding: 10px;
}
<script
src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"
integrity="sha512-TW5s0IT/IppJtu76UbysrBH9Hy/5X41OTAbQuffZFU6lQ1rdcLHzpU5BzVvr/YFykoiMYZVWlr/PX1mDcfM9Qg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.min.js"
integrity="sha512-R/QOHLpV1Ggq22vfDAWYOaMd5RopHrJNMxi8/lJu8Oihwi4Ho4BRFeiMiCefn9rasajKjnx9/fTQ/xkWnkDACg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<div class="gauge-container">
<canvas id="myCanvasGauge"></canvas>
</div>
<div class="button-container">
<button onclick="changeData()">Change Data 1</button>
</div>
<div class="button-container">
<button onclick="changeData2()">Change Data 2</button>
</div>
Related
I want to make a pie chart like the image below, using chart.js however, cannot seem to get there.
this is what i wanna make
I have seen some d3.js plugins that helps with this however, I cannot learn that in time so whatever i can do with chart.js.
can i get some help please. i am struggling with this, not sure if this should be simple or i am just over complicating thing. as for as i am aware i am taking the logical approach
below is my code.
<script>
const documentType = [];
const documentRevision = [];
const docTypeRev = [];
const docTypeTotal = [];
const percentage = [];
showDoughnutChart();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// START OF DOUGHNUT CHART
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
async function showDoughnutChart() {
await getDataDoughnutGraph();
const doughnutChart = document
.getElementById("myChart")
.getContext("2d");
let chart3a = new Chart(doughnutChart, {
type: "doughnut",
data: {
labels: documentType,
datasets: [
{
label: "Some metric",
backgroundColor: [
"#619E98",
"#4164BE",
"#7D35CA",
"#B2A44D",
"#946B76",
"#6C9D62",
"#C6B139",
"#2688D9",
"#D62963",
"#CCBF33",
"#adff2f",
"#B6495D",
],
borderWidth: 1,
borderRadius: 5,
offset: [0, 0, 0, 0, 0, 0, 0],
cutout: "50%",
data: docTypeRev,
},
{
label: "Some metric",
backgroundColor: [
"#619E98",
"#4164BE",
"#7D35CA",
"#B2A44D",
"#946B76",
"#6C9D62",
"#C6B139",
"#2688D9",
"#D62963",
"#CCBF33",
"#adff2f",
"#B6495D",
],
borderWidth: 1,
borderRadius: 5,
offset: [0, 0, 0, 0, 0, 0, 0],
cutout: "50%",
data: [1, 1, 1],
},
],
},
options: {
plugins: {
legend: {
display: true,
position: "right",
},
title: {
display: true,
text: "Tag Distrubution by Class",
color: "black",
},
},
layout: {
padding: 10,
},
maintainAspectRatio: true,
responsive: true,
},
});
}
async function getDataDoughnutGraph() {
const responseLine = await fetch("stats_doc_type_Rev.csv");
const chart3el = document.getElementById("myChart").getContext("2d");
const data = await responseLine.text();
const table = data.split("\n").slice(1);
table.forEach((row) => {
//split by line
const columns = row.split(",");
// split by column
const documentTypeEX = columns[0];
const documentRevisionEX = columns[1];
const docTypeRevEX = columns[2];
const docTypeTotalEX = columns[3];
const percentage_EX = columns[4];
//pushing into global variables
documentType.push(documentTypeEX);
documentRevision.push(documentRevisionEX);
docTypeRev.push(docTypeRevEX);
docTypeTotal.push(docTypeTotalEX);
percentage.push(percentage_EX);
// console.log(percentage_EX);
});
}
</script>
</body>
</html>
<style>
* {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.chartMenu {
width: 100vw;
height: 40px;
background: #1a1a1a;
color: rgba(255, 26, 104, 1);
}
.chartMenu p {
padding: 10px;
font-size: 20px;
}
.chartCard {
width: 100vw;
height: calc(100vh - 40px);
background: rgba(255, 26, 104, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.chartBox {
width: 700px;
padding: 20px;
border-radius: 20px;
border: solid 3px rgba(255, 26, 104, 1);
background: white;
}
</style>
<div class="chartMenu">
<p></p>
</div>
<div class="chartCard">
<div class="chartBox">
<canvas id="myChart"></canvas>
</div>
</div>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/chart.js"
></script>
I think you could add 2 datasets, 1 grouped and 1 with all values.
To show the labels, you can use https://github.com/chartjs/chartjs-plugin-datalabels/.
const multiLeveData = {
firstLevel: {
data: [15, 10]
},
secondLevel: {
data: [20, 30]
},
};
const dataForDataset = function(grouped) {
const result = [];
for (const key of Object.keys(multiLeveData)) {
if (grouped) {
result.push(multiLeveData[key].data.reduce(function(a, b) { return a + b; }, 0));
} else {
multiLeveData[key].data.forEach(function(item){
result.push(item);
})
}
}
return result;
}
const ctx = document.getElementById("myChart");
Chart.register(ChartDataLabels);
const myChart = new Chart(ctx, {
type: "doughnut",
data: {
datasets: [
{
label: "Some metric",
backgroundColor: [
"#619E98",
"#619E98",
"#7D35CA",
"#7D35CA"
],
borderWidth: 1,
borderRadius: 5,
offset: [0, 0, 0, 0, 0, 0, 0],
cutout: "50%",
data: dataForDataset(),
},
{
label: "Some metric",
backgroundColor: "#4164BE",
borderWidth: 1,
borderRadius: 5,
offset: [0, 0, 0, 0, 0, 0, 0],
cutout: "50%",
data: dataForDataset(true),
},
],
},
options: {
plugins: {
legend: {
display: false,
},
tooltip: {
display: false,
},
title: {
display: true,
text: "Tag Distrubution by Class",
color: "black",
},
datalabels: {
color: 'white',
font: {
size: 16
}
}
},
layout: {
padding: 10,
},
maintainAspectRatio: true,
responsive: true,
},
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.9.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.1.0/dist/chartjs-plugin-datalabels.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400" tabindex="1"/>
</div>
</body>
</html>
I am facing an issue in adjusting the width of each container in chartjs.
Please have a look into this and provide your input to fix this issue.
I am using a single <div> in a loop to print 3 types of data in different divs.
Here in the screenshot, first chart is proper. But in the 2nd and 3rd one there are spaces between the BARs. So please help me to remove those spaces.
Please have a look into this attached picture for better clarity.
Source code :
<body>
<div>
<div id="barChartContainer" class="chartAreaWrapper" style="display: inline-block">
<canvas id="barChart"></canvas>
</div>
</div>
</div>
</body>
<!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>CHART PROBLEM</title>
<style>
.chartAreaWrapper {
height: 300px;
margin:0!important;
padding:0!important;
/* overflow-x: scroll; */
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0-rc.1/chartjs-plugin-datalabels.min.js" integrity="sha512-+UYTD5L/bU1sgAfWA0ELK5RlQ811q8wZIocqI7+K0Lhh8yVdIoAMEs96wJAIbgFvzynPm36ZCXtkydxu1cs27w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div>
<div id="barChartContainer" class="chartAreaWrapper" style="display: inline-block">
<canvas id="barChart"></canvas>
</div>
</div>
</div>
</body>
<script>
let myChart = undefined;
function random_rgba() {
let r = Math.round, g = Math.random, b = 255;
return 'rgba(' + r(g() * b) + ',' + r(g() * b) + ',' + r(g() * b) + ', 0.7)';
}
let jsonData = { "xAsix": ["Skipped", "Passed", "Failed"], "dataSet": [{"data": [0, 28, 12], "label": "test" }, { "data": [3, 0, 0], "label": "dit2" }, { "data": [6, 0, 0], "label": "Xerces_JavaDriversHP" }, { "data": [12, 0, 0], "label": "Sun_Xerces" }, { "data": [1, 0, 0], "label": "Sun_Dad" }, { "data": [1, 0, 0], "label": "JavaConn-LnxDIT" }, { "data": [0, 31, 1], "label": "HP_Xerces" }, { "data": [6, 0, 0], "label": "HP_JavaDrivers" }, { "data": [0, 30, 2], "label": "HP" }, { "data": [2, 0, 0], "label": "DIT-JavaConn" }, { "data": [4, 0, 0], "label": "DIT" }, { "data": [1, 0, 0], "label": "DAD_Sun" }, { "data": [0, 1, 0], "label": "DADDrivers_HP" }, { "data": [6, 0, 0], "label": "Auto" }] }
console.log("jsonData--->", jsonData);
const label = jsonData.xAsix;
console.log(label);
const dataset = jsonData.dataSet;
console.log("dataset len::" + dataset.length);
if (dataset.length > 0) {
let maxEle = 0;
dataset.forEach((e, i) => {
let positiveValue = 0;
e.data = e.data.map(value => {
positiveValue += !value && 1;
return value || undefined
});
maxEle = maxEle < positiveValue ? positiveValue : maxEle;
e.skipNull = true;
e.backgroundColor = [random_rgba(i)];
e.borderColor = ["rgba(255,159,64,0.2)"];
e.barPercentage = 0.9;
//e.barThickness = 50;
//e.barThickness = 'flex';
e.categoryThickness = 'flex';
e.maxBarThickness= 50;
e.minBarLength= 30;
e.categoryPercentage = 1;
});
const Containerwidth = dataset.length * dataset[0].data.length * 50 + 250;
document.getElementById('barChartContainer').style.width = Containerwidth + 100 + 'px'
console.log(dataset);
if (myChart) {
myChart.destroy();
console.log(myChart);
}
var element = $('#barChart');
document.getElementById("barChart").style.display = "block";
myChart = new Chart(element, {
type: 'bar',
exportEnabled: true,
//animationEnabled: true,
categoryThickness: 'flex',
maintainAspectRatio: false,
responsive: true,
data: {
labels: label,
datasets: dataset,
},
plugins: [ChartDataLabels],
options: {
skipNull: true,
maintainAspectRatio: false,
animation: {
onComplete: function () {
var sourceCanvas = myChart.canvas;
var copyWidth = myChart.scales['y'].width - 10;
var copyHeight = myChart.scales['y'].height + myChart.scales['y'].top + 10;
//var targetCtx = document.getElementById("axis-FuelSpend").getContext("2d");
//targetCtx.canvas.width = copyWidth;
//targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
}
},
scales: {
x: {
/*ticks:{
autoSkip:false,
maxRotation: 90,
minRotation: 90
},
gridLines: {
offsetGridLines: false
},
stacked: true,*/
},
y: {
beginAtZero: true,
grid: {
display: false
}
},
},
plugins: {
datalabels: {
display: function (context) {
return context.dataset.data[context.dataIndex] > 0;
},
color: 'black',
anchor: 'end',
align: 'top',
font: {
size: 10,
}
},
legend: {
display: true,
position: "right",
fontSize: '8px',
boxWidth: 60,
},
layout: {
padding: {
right: 10
}
}
}
}
});
myChart.render();
}
</script>
</html>
I am creating 5 sections of gauge using chartjs-gauge. I am using the following data.
[150,200,250,300,400]
From this data, I want to display the circumference until 300. But the angle should calculated by including the last section value too. I had custom the text showing in section by setting it to empty string if more than 300. For section colour, I set 4 colours["green", "yellow", "orange", "red"]. Now, last section showing as silver colour which is default background of gauge. I have add rgba(0,0,0,0) to colour array ["green", "yellow", "orange", "red","rgba(0,0,0,0)"] which will show transparent colour for last section. But, when hover on section, it is responsive showing border. I would like to know if have other way to show the circumference until certain value from our data ,but calculating section area in chart using all value from data.
var data = [150, 200, 250, 300, 400];
var config = {
type: "gauge",
data: {
labels: ['Success', 'Warning', 'Warning', 'Error'],
datasets: [{
data: data,
value: 300,
backgroundColor: ["green", "yellow", "orange", "red"],
borderWidth: 2
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Gauge chart with datalabels plugin"
},
layout: {
padding: {
bottom: 30
}
},
needle: {
// Needle circle radius as the percentage of the chart area width
radiusPercentage: 2,
// Needle width as the percentage of the chart area width
widthPercentage: 3.2,
// Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
lengthPercentage: 80,
// The color of the needle
color: "rgba(0, 0, 0, 1)"
},
valueLabel: {
formatter: Math.round
},
plugins: {
datalabels: {
display: true,
formatter: function(value, context) {
//return '>'+value;
if (value <= 300) {
return value;
} else {
return '';
}
},
color: function(context) {
//return context.dataset.backgroundColor;
return 'black';
},
//color: 'rgba(255, 255, 255, 1.0)',
/*backgroundColor: "rgba(0, 0, 0, 1.0)",*/
borderWidth: 0,
borderRadius: 5,
font: {
weight: "bold"
}
}
}
}
};
window.onload = function() {
var ctx = document.getElementById("chart").getContext("2d");
window.myGauge = new Chart(ctx, config);
};
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="jQuery/jquery-3.4.1.min.js"></script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Gauge Chart with datalabels plugin</title>
<script src="https://unpkg.com/chart.js#2.8.0/dist/Chart.bundle.js"></script>
<script src="https://unpkg.com/chartjs-gauge#0.3.0/dist/chartjs-gauge.js"></script>
<script src="https://unpkg.com/chartjs-plugin-datalabels#0.7.0/dist/chartjs-plugin-datalabels.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:100%">
<canvas id="chart"></canvas>
</div>
</body>
</html>
var data = [150, 200, 250, 300, 400];
colour_array = ["#11d8ee", "#3cc457", "#f12b0e", "#dda522", "#808080"];
let sum = data.reduce(function(a, b) {
return a + b;
}, 0);
var perc = 0;
perc_array = [];
for (i = 0; i < data.length; i++) {
perc = (data[i] / sum * 100).toFixed(2);
perc_array.push(perc);
}
Chart.plugins.register({ //increase distance between legend and chart
id: 'paddingBelowLegends',
beforeInit: function(chart, options) {
chart.legend.afterFit = function() {
this.height = this.height + 50; //custom 50 to value you wish
};
}
});
//when want to disable this plugin in other chart, paddingBelowLegends: false in plugin{}
var config = {
type: "doughnut",
data: {
labels: ['A', 'B', 'C', 'D', 'Others'],
datasets: [{
data: data,
value: data[(colour_array.length - 1)], //300
backgroundColor: colour_array,
borderWidth: 2
}]
},
options: {
responsive: true,
cutoutPercentage: 60,//thickness of chart
title: {
display: true,
text: "Gauge chart with datalabels plugin"
},
layout: {
padding: {
bottom: 30
}
},
valueLabel: {
formatter: Math.round,
display: false // hide the label in center of gauge
},
plugins: {
beforeInit: function(chart, options) {
chart.legend.afterFit = function() {
this.height = this.height + 50;
};
},
outlabels: {
display: true,
//text: '%l %v %p',//(label value percentage)the percentage automatically roundoff
//hide chart text label for last section-https://github.com/Neckster/chartjs-plugin-piechart-outlabels/issues/10#issuecomment-716606369
text: function(label) {
console.log(label);
highest_index = label['labels'].length - 1; //get highest index from the labels array
current_index = label['dataIndex']; //current index
value = label['dataset']['data'][label['dataIndex']]; //value of current index
const v = parseFloat(label['percent']) * 100;
if (current_index != highest_index) //to hide last section text label on chart.
{
//return value + ' , ' + `${v.toFixed(2)}%`;
return value+',\n'+`${v.toFixed(2)}%`;
} else {
return false;
}
},
color: 'white',
stretch: 12, //length of stretching
font: {
resizable: true,
minSize: 10,
maxSize: 14
},
padding: {
/*left:25,
right: 0
top:0,
bottom:0*/
}
},
//inner label:
datalabels: { //label on arc section
display: false,
formatter: function(value, context) {
if (value <= data[(colour_array.length - 2)]) //hide datalabel for last section
{
id = data.indexOf(value);
perc = perc_array[id];
return value + ' , ' + perc + '%';
} else {
return '';
}
},
color: function(context) {
return 'black';
},
borderWidth: 0,
borderRadius: 10,
font: {
weight: "bold",
},
anchor: "end" //'center' (default): element center, 'start': lowest element boundary, 'end': highest element boundary
}
},
legend: { //filter last section from legend chart labels
display: true,
//position: 'right',
labels: {
filter: function(legendItem, data) {
//ori-return legendItem !=1;
return !legendItem.text.includes('Others');
},
boxWidth: 20
}
},
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
tooltips: {
enabled: true,
mode: 'single',
filter: function(tooltipItem, data) { //disable display tooltip in last section
var label = data.labels[tooltipItem.index];
if (label == "Others") {
return false;
} else {
return true;
}
},
callbacks: { //custom tooltip text to show percentage amount (by default,showing real amount)
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
hovered_index = tooltipItem.index;
data_length = data.datasets[0].data.length;
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
var currentValue = dataset.data[tooltipItem.index];
var percentage = (currentValue / total * 100).toFixed(2);
return currentValue + ' , ' + percentage + "%";
}
}
}
}
};
window.onload = function() {
var ctx = document.getElementById("chartJSContainer").getContext("2d");
window.myGauge = new Chart(ctx, config);
};
<html>
<head>
<script src="https://unpkg.com/chart.js#2.8.0/dist/Chart.bundle.js"></script>
<script src="https://unpkg.com/chartjs-gauge#0.3.0/dist/chartjs-gauge.js"></script>
<script src="https://unpkg.com/chartjs-plugin-datalabels#0.7.0/dist/chartjs-plugin-datalabels.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-piechart-outlabels"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:50% align:center">
<canvas id="chartJSContainer"></canvas>
</div>
</body>
</html>
This is my first Django project, and I am working on a Django html template that should contain a Chart.JS bar graph (https://www.chartjs.org/docs/latest/charts/bar.html) alongside a Highcharts drilldown map of the US (https://www.highcharts.com/demo/maps/map-drilldown).
I've successfully implemented my Chart.JS bar graph and passed data to it from our AWS RDS. But now when I try to implement even just the stock Highcharts code from their website, the map fails to render at all. After trying to isolate the problem, I've found that the map does render if I simply delete "context" from the return statement in my view (i.e. delete "context" from the final line in my first block of code below). But this obviously then inhibits my bar graph from rendering. I think I must be missing something with how the highcharts data is loaded in the presence of other context data, but I've been unable to fix it such that both the graph and map render. Any help would be greatly appreciated!
My Django View:
def index(request):
mydb = mysql.connector.connect(
host=xxxx,
user=xxxx,
password=xxxx,
database=xxxx
)
mycursor = mydb.cursor()
mycursor.execute("WITH CS1 AS (SELECT cts.Name, cts.State, m.Frequently, m.Always FROM Masks m JOIN Counties cts ON (m.FIPS = cts.FIPS)) SELECT CS1.State, AVG((CS1.Frequently+CS1.Always)*100) AS Perc_High_Frequency FROM CS1 WHERE CS1.State<>'Puerto Rico' GROUP BY CS1.State ORDER BY Perc_High_Frequency DESC")
tempList = mycursor.fetchall()
statesMaskName = [item[0] for item in tempList]
statesMaskPerc = [item[1] for item in tempList]
context={'statesMaskName':statesMaskName, 'statesMaskPerc':statesMaskPerc}
return render(request,'index.html', context)
The relevant HTML/JS:
<html lang="en" dir="ltr">
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div class="fixed-header">
<h1>COVID-19 Sentiment and Mask Practices</h1>
</div>
<div>
<div class="col-lg-3" style="float: left; max-height: 6500px;max-width:400px;overflow: scroll; overflow-x:hidden;">
<div style="background-color: #17202A;">
<span style="color: #F7F9F9; text-align: center;"><h4>% Population Who "Frequently" or "Always" Wear Masks When In Public Within 6" of Others (as of July 2-14, 2020)</h4></span>
</div>
<div class="col-lg-12">
<form method="post" enctype="multipart/form-data" action="selectState">
{% csrf_token %}
<div class="col-lg-4" style="float: left; max-height: 3000px;">
<br><br style="line-height: 15px"/>
{% for state in statesMaskName %}
<table style="border-width: 2px; border: #333;">
<tr>
<input type="submit" value="{{state}}" name="statesMaskName" style="width:130px;">
</tr>
</table>
{% endfor%}
</div>
<div style="float: left;">
<canvas id="myChart" height="1360" width="250"></canvas>
</div>
</form>
</div>
</div>
<div class="col-lg-6">
</div>
<div class="col-lg-3">
</div>
</div>
<br>
</body>
<!--my updated code for chartjs graph-->
<script>
const labels = {{statesMaskName|safe}};
const data = {
labels: labels,
datasets: [{
label: '% Population',
color: 'orange',
backgroundColor: 'orange',
borderColor: 'orange',
data: {{statesMaskPerc|safe}},
}]
};
const config = {
type: 'bar',
data,
options: {
indexAxis: 'y',
color: 'white',
scales: {
y: {
grid: {
color: '#b3b1ad',
},
ticks: {
color: 'white',
},
display: false
},
x: {
grid: {
color: '#b3b1ad',
},
ticks: {
color: 'white',
// Include a % sign in the ticks
callback: function(value, index, values) {
return value + '%';
}
}
}
}
}
};
var myChart = new Chart(
document.getElementById('myChart'),
config
);
</script>
<!--stock code for highcharts map-->
<div id="usMap" style="height: 500px; min-width: 310px; max-width: 800px; margin: 0 auto"></div>
<script src="https://code.highcharts.com/maps/highmaps.js"></script>
<script src="https://code.highcharts.com/maps/modules/data.js"></script>
<script src="https://code.highcharts.com/maps/modules/drilldown.js"></script>
<script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
<script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
<script src="https://code.highcharts.com/mapdata/countries/us/us-all.js"></script>
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<script type="text/javascript">
/*
TODO:
- Check data labels after drilling. Label rank? New positions?
*/
let data = Highcharts.geojson(Highcharts.maps['countries/us/us-all']);
const separators = Highcharts.geojson(Highcharts.maps['countries/us/us-all'], 'mapline');
// Set drilldown pointers
data.forEach((d, i) => {
d.drilldown = d.properties['hc-key'];
d.value = i; // Non-random bogus data
});
function getScript(url, cb) {
const script = document.createElement('script');
script.src = url;
script.onload = cb;
document.head.appendChild(script);
}
// Instantiate the map
Highcharts.mapChart('usMap', {
chart: {
events: {
drilldown: function (e) {
if (!e.seriesOptions) {
const chart = this,
mapKey = 'countries/us/' + e.point.drilldown + '-all';
// Handle error, the timeout is cleared on success
let fail = setTimeout(() => {
if (!Highcharts.maps[mapKey]) {
chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
fail = setTimeout(() => {
chart.hideLoading();
}, 1000);
}
}, 3000);
// Show the spinner
chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
// Load the drilldown map
getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', () => {
data = Highcharts.geojson(Highcharts.maps[mapKey]);
// Set a non-random bogus value
data.forEach((d, i) => {
d.value = i;
});
// Hide loading and add series
chart.hideLoading();
clearTimeout(fail);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
});
}
this.setTitle(null, { text: e.point.name });
},
drillup: function () {
this.setTitle(null, { text: '' });
}
}
},
title: {
text: 'Highcharts Map Drilldown'
},
subtitle: {
text: '',
floating: true,
align: 'right',
y: 50,
style: {
fontSize: '16px'
}
},
colorAxis: {
min: 0,
minColor: '#E6E7E8',
maxColor: '#005645'
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
plotOptions: {
map: {
states: {
hover: {
color: '#EEDD66'
}
}
}
},
series: [{
data: data,
name: 'USA',
dataLabels: {
enabled: true,
format: '{point.properties.postal-code}'
}
}, {
type: 'mapline',
data: separators,
color: 'silver',
enableMouseTracking: false,
animation: {
duration: 500
}
}],
drilldown: {
activeDataLabelStyle: {
color: '#FFFFFF',
textDecoration: 'none',
textOutline: '1px #000000'
},
drillUpButton: {
relativeTo: 'spacingBox',
position: {
x: 0,
y: 60
}
}
}
});
</script>
</html>
Right now I'm using onHover into each pie to add some scale/zoom, but I want to use mouseenter and mouseleave. So on mouseenter on each pie it will add some scale/zoom, and on mouseleave, I want it back to its original state.
either mouseenter-mouseleave or mouseover-mouseout is fine.
here is the codepen:
https://codepen.io/graydirt/pen/NWNZNyQ
Thanks guys!
var ctx = document.getElementById('chartPie').getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Red', 'Blue', 'Green'],
datasets: [{
label: '# of Votes',
data: [12, 19, 20],
backgroundColor: [
'red',
'blue',
'green'
],
datalabels: {
color: '#000'
}
}]
},
options: {
legend: {
display: false
},
layout: {
padding: 5
},
onHover: function (evt, elements) {
let segment;
if (elements && elements.length) {
segment = elements[0];
this.chart.update();
selectedIndex = segment["_index"];
segment._model.outerRadius += 5;
} else {
if (segment) {
segment._model.outerRadius -= 5;
}
segment = null;
}
}
}
});
.chart-pie {
width: 400px;
height: 400px;
margin: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<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.8.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<div class="container p-4">
<div class="chart-pie position-relative">
<canvas id="chartPie"></canvas>
</div>
</div>
Your code is already designed to return to the original size on mouseout, but you have a subtle bug.
You need to define the segment variable outside the chart. With a saved reference to the segment, the mouseout event will fire and the onHover handler will return the pie to its original size.
Please see the attached example below:
let segment;
var ctx = document.getElementById('chartPie').getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Red', 'Blue', 'Green'],
datasets: [{
label: '# of Votes',
data: [12, 19, 20],
backgroundColor: [
'red',
'blue',
'green'
],
datalabels: {
color: '#000'
}
}]
},
options: {
legend: {
display: false
},
layout: {
padding: 5
},
onHover: function(evt, elements) {
if (elements && elements.length) {
segment = elements[0];
this.chart.update();
selectedIndex = segment["_index"];
segment._model.outerRadius += 5;
} else {
if (segment) {
segment._model.outerRadius -= 5;
}
segment = null;
}
}
}
});
.chart-pie {
width: 400px;
height: 400px;
margin: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
<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.8.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<div class="container p-4">
<div class="chart-pie position-relative">
<canvas id="chartPie"></canvas>
</div>
</div>