Update chart.js with dynamic data from a file - javascript

I am reading a text file and put the data from the text file into arrays and I pass the arrays as data in the Chart.js dataset field but the data is not plotted. I have tried to use the update function but I am not winning. The arrays are populated when I log them to the console.
Here's my JS and HTML:
/// <reference path="../scripts/angular.js" />
/// <reference path="angular-chart.min.js" />
/// <reference path="Chart.min.js" />
var app;
//Start of File Reader
var currentArray = new Array();
var voltageArray = new Array();
document.getElementById('inputFile').onchange = function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function (progressEvent) {
var lines = this.result.split('\n');
for (var line = 4; line < lines.length - 2; line++) {
var pair = lines[line].split('\t');
if (!pair[0].includes(".") || !pair[1].includes(".")) {
voltageArray.push(parseFloat(pair[0].replace(' ', '.')));
currentArray.push(parseFloat(pair[1].replace(' ', '.')));
}
else {
voltageArray.push(parseFloat(pair[0]));
currentArray.push(parseFloat(pair[1]));
}
}
};
reader.readAsText(file);
};
//End of File Reader
console.log(voltageArray);
console.log(currentArray);
//Module
(function () {
app = angular.module("app", ['chart.js']);
})();
app.controller("lineCtrl_Voltage", function ($scope) {
let lineV = new Chart(document.getElementById("voltage"), {
type: 'line',
data: {
labels: [0.00018,
0.00036,
0.00054,
0.00072,
0.0009,
0.00108,
0.00126,
0.00144,
0.00162,
0.0018,
0.00198,
0.00216,
0.00234,
0.00252,
0.0027,
0.00288,
0.00306,
0.00324,
0.00342,
0.0036,
0.00378,
0.00396,
0.00414,
0.00432,
0.0045,
0.00468,
0.00486,
0.00504,
0.00522,
0.0054,
0.00558,
0.00576,
0.00594,
0.00612,
0.0063,
0.00648,
0.00666,
0.00684,
0.00702,
0.0072,
0.00738,
0.00756,
0.00774,
0.00792,
0.0081,
0.00828,
0.00846,
0.00864,
0.00882,
0.009,
0.00918,
0.00936],
datasets: [{
data: [0, 0, 0, 0],
label: "Voltage",
borderColor: "#8e5ea2",
fill: false
}]
},
options: {
title: {
display: true,
text: ''
},
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 0, // minimum will be 0, unless there is a lower value.
},
scaleLabel: {
display: true,
labelString: 'Voltage (V)'
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Time (ms)'
}
}],
}
}
});
lineV.update();
});
app.controller("lineCtrl_Current", function ($scope) {
new Chart(document.getElementById("current"), {
type: 'line',
data: {
labels:
[0.00018,
0.00036,
0.00054,
0.00072,
0.0009,
0.00108,
0.00126,
0.00144,
0.00162,
0.0018,
0.00198,
0.00216,
0.00234,
0.00252,
0.0027,
0.00288,
0.00306,
0.00324,
0.00342,
0.0036,
0.00378,
0.00396,
0.00414,
0.00432,
0.0045,
0.00468,
0.00486,
0.00504,
0.00522,
0.0054,
0.00558,
0.00576,
0.00594,
0.00612,
0.0063,
0.00648,
0.00666,
0.00684,
0.00702,
0.0072,
0.00738,
0.00756,
0.00774,
0.00792,
0.0081,
0.00828,
0.00846,
0.00864,
0.00882,
0.009,
0.00918,
0.00936],
datasets: [{
data: [0, 0, 0, 0, 0, 0, 0, 0, 0],
label: "Current",
borderColor: "#3e95cd",
fill: false
}]
},
options: {
title: {
display: true,
text: ''
},
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 0, // minimum will be 0, unless there is a lower value.
},
scaleLabel: {
display: true,
labelString: 'Current (A)',
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Time (ms)'
}
}],
}
}
});
});
function addData(chart, data) {
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
<div class="row" ng-app="app">
<div class="col-md-1"></div>
<div class="col-md-5">
<div class="x_panel">
<div class="x_title">
<h2 style="text-align: -webkit-center;">Voltage vs Time </h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div ng-controller="lineCtrl_Voltage">
<canvas id="voltage"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-5">
<div class="x_panel">
<div class="x_title">
<h2 style="text-align: -webkit-center;">Current vs Time</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div ng-controller="lineCtrl_Current">
<canvas id="current"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-1"></div>
</div>

Related

problem when i add data on datasets to line chart (chatjs with vue-chatjs)

I have a problem with vue-chartjs.
I have updated vuejs v2 to v3 and vue-chartjs v3 to v5
Error is: InternalError: too much recursion
I have tried to add computed, modify many line of code, i don't remember all my modify, but that don't work.
I have found this topic: Adding data to line chart (chart.js with Vue.js) results in 'too much recursion' error but, He used composition api and me option api, but I have to make ref and shallowRef that make no difference.
My component actual code:
<template>
<div>
<div class="row">
<div class="col-lg-6 col-md-6">
<div class="d-new-flex m-b-10 no-block">
<h5 class="card-title m-b-0 align-self-center text-uppercase">Statistiques</h5>
</div>
<ul class="list-inline m-b-10 text-uppercase lp-5 font-medium font-12">
<li #click="hide('CPU')" id="cpu-stats" :style="'text-decoration: ' + this.style['CPU']"><i class="fa fa-square m-r-5 text-warning"></i> CPU (en %)</li>
<li #click="hide('RAM')" id="ram-stats" :style="'text-decoration: ' + this.style['RAM']"><i class="fa fa-square m-r-5 text-danger"></i> RAM (en Mo)</li>
<li #click="hide('DISK')" id="disk-stats" :style="'text-decoration: ' + this.style['DISK']"><i class="fa fa-square m-r-5"
style="color: #03e5fa;"></i> Disque (en Mo)
</li>
</ul>
</div>
</div>
<div class="clearfix"></div>
<div style="height: 400px; width: 100%">
<Line :data="chartData"
:options="options" ref="stats"/>
<div class="clearfix"></div>
</div>
</div>
</template>
<script>
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip,
Legend,
TimeSeriesScale
} from 'chart.js';
import { Line } from 'vue-chartjs';
import 'chartjs-adapter-moment';
ChartJS.register(
CategoryScale,
LinearScale,
TimeSeriesScale,
LineElement,
PointElement,
Title,
Tooltip,
Legend
);
export default {
name: 'Chart',
props: ["optionsAdd"],
components: { Line },
data() {
return {
style: {
RAM: "none",
DISK: "none",
CPU: "none"
},
options: {
responsive: true,
maintainAspectRatio: false,
hoverMode: 'index',
plugins: {
legend: {
display: false
}
},
scales: {
x: {
display: true,
type: 'timeseries',
bounds: 'data',
time: {
unit: 'second',
displayFormats: {
second: "hh:mm:ss"
}
},
grid: {
display: false,
drawTicks: false,
},
ticks: {
source: "labels"
}
},
yRD: {
type: 'linear',
ticks: {
beginAtZero: true
},
position: 'left',
min: 0,
title: {
display: true,
labelString: 'RAM (en Mo) et Disque (Mo)'
}
},
yCPU: {
type: 'linear',
ticks: {
beginAtZero: true
},
max: 100,
min: 0,
position: 'right',
grid: {
drawOnChartArea: false
},
title: {
display: true,
labelString: 'CPU (en %)'
}
}
}
},
cData: {
labels: [new Date(Date.now() - 30000), new Date(Date.now() - 60000), new Date(Date.now() - 90000)],
datasets: [
{
backgroundColor: "#FF484C",
borderColor: "#FF484C",
fill: false,
label: "RAM",
data: [0,0,0],
yAxisID: "yRD"
},
{
backgroundColor: "#FA7D03",
borderColor: "#FA7D03",
fill: false,
label: "CPU",
data: [0,0,0
],
yAxisID: "yCPU"
},
{
backgroundColor: "#03e5fa",
borderColor: "#03e5fa",
fill: false,
label: "Disque",
yAxisID: "yRD",
data: [0,0,0]
}
]
}
}
},
computed: {
chartData: {
// getter
get() {
return this.cData;
},
// setter
set(newValue) {
console.log(newValue);
//this.cData.datasets = newValue.datasets;
}
}
},
mounted() {
const instance = this;
this.chartData.datasets.push({
data: [0, 1, 3]
})
this.chartData.datasets[0].data.push(0)
console.log(this.chartData);
if(this.optionsAdd != null) console.log("not null");
this.$socket.emit("stats", this.$parent.$parent.hash);
this.sockets.subscribe('stats', (data) => {
if (data != null) {
var cpu = parseInt(data.cpu / 20);
var memory = parseInt(data.memory / 1048576);
const unit = data.unit;
var disk = parseInt(data.size);
switch (unit) {
case "Go":
disk *= 1024;
break;
case "Ko":
disk /= 1024;
break;
}
//var oldStas = instance.data;
//instance.dataValue.labels.push(new Date(Date.now()));
//On insére les valeur de la ram avec la date dans le tableau
/*instance.dataValue.datasets[0].data.push(memory);
//On insére les valeur du cpu avec la date dans le tableau
instance.dataValue.datasets[1].data.push(cpu);
instance.dataValue.datasets[2].data.push(disk);
if (instance.dataValue.datasets[0].data.length > 30)
instance.dataValue.datasets[0].data.splice(0, 1);
if (instance.dataValue.datasets[1].data.length > 30)
instance.dataValue.datasets[1].data.splice(0, 1);
if (instance.dataValue.datasets[2].data.length > 30)
instance.dataValue.datasets[2].data.splice(0, 1);*/
//instance.data = oldStas;
//instance.$refs.stats.chart.update()
}
//dara players nodejs
if (this.$parent.is_start)
fetch("/api/service/" + this.$parent.id_server + "/minecraft/list").then(response => response.json())
.then(json => {
this.players = json.counts;
if (this.$parent.list === "online")
this.$parent.playersList = json.players;
});
});
},
methods: {
hide: function(type) {
let obj = {RAM: 0, CPU: 1, DISK: 2};
if(this.$refs.stats.chart.getDataVisibility(obj[type])) {
this.$refs.stats.chart.hide(obj[type]);
this.style[type] = "line-through";
} else {
this.$refs.stats.chart.show(obj[type]);
this.style[type] = "none";
}
this.$refs.stats.chart.toggleDataVisibility(obj[type]);
this.$refs.stats.chart.update();
},
}
}
</script>
How to solve the recursion problem ?
It is because the object is so complex ?
I use vue-js 3.2.45 and vue-chartjs 5.1.0
Thanks for your help !

Unable to display multiple line charts in javascript

I am very new to java-script and was trying to learn how to add multiple line charts to my web UI. But unfortunately I am stuck with a problem, I am unable to add multiple line charts to my web UI.
I am unable to understand what I am doing wrong. I tried several approaches but couldn't find the solution.
Appreciate the help!
Below is my code for your reference.
var xValues = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150];
var yValues = [7, 8, 8, 9, 9, 9, 10, 11, 14, 14, 15];
function displayPanel(i) {
var panel = document.getElementById('panel');
panel.innerHTML += `
<div class="row">
<div class="column">
<form>
<label id="paramname_${i}" for="paramvalue">${i}</label>
<input type="text" id="paramvalue_${i}" name="param" value=${i} readonly>
</form>
</div>
<div id="chart_${i}" class="column">
<canvas id="myChart${i}" style="width:100%;max-width:600px"></canvas>
</div>
</div>`;
new Chart("myChart" + i, {
type: "line",
data: {
labels: xValues,
datasets: [{
fill: false,
lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
data: yValues
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
min: 6,
max: 16
}
}],
}
}
});
new Chart("myChart" + i, {
type: "line",
data: {
labels: xValues,
datasets: [{
fill: false,
lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
data: yValues
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
min: 6,
max: 16
}
}],
}
}
});
}
for (i = 0; i < 2; i++) {
displayPanel(i);
}
<style>.column {
float: left;
align-self: right;
width: 50%;
padding: 10px;
}
.row {
content: "";
clear: both;
display: table;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<!DOCTYPE html>
<html>
<body>
<div id="panel"></
----------
div>
</body>
function addParamsToPanel(parameter, paramValue, isDisplay, i) {
console.log("XXXX" + parameter);
if (isDisplay) {
displayPanel(parameter, paramValue,i);
}
}
function updatePanel(paramList, valueList) {
param = paramList.toString().split(',');
paramValue = valueList.toString().split(',');
for (var i = 0; i < param.length; i++) {
var p = document.createElement("div");
var checkBox = document.createElement("input");
var label = document.createElement("label");
checkBox.type = "checkbox";
checkBox.id = param[i];
p.appendChild(checkBox);
p.appendChild(label);
document.getElementById("cboxes").appendChild(p);
label.appendChild(document.createTextNode(param[i]));
document.getElementById(param[i]).checked = true;
addParamsToPanel(param[i], paramValue[i], document.getElementById(param[i]).checked, i);
}
}
function displayPanel(parameter, paramValue, i) {
var panel = document.getElementById('panel');
var today = new Date();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var newChart = 'paramChart_' + parameter;
panel.innerHTML += `
<div class="row">
<!--div class="col-md-9 col-lg-10 col-sm-11"-->
<div class="column">
<form>
<label id="paramname_${parameter}" for="paramvalue">${parameter}</label>
<input type="text" id="paramvalue_${parameter}" name="param" value=${paramValue} readonly>
</form>
</div>
<div id="chart_${i}" class="column">
<canvas id=${newChart} style="width:100%;max-height:100px;max-width:700px;border: solid;rgb(4, 31, 65);"></canvas>
</div>
`;
console.log(newChart.value);
var chart = new Chart(newChart, {
type: "line",
data: {
labels: xValues,
datasets: [{
//label: 'set of ' + parameter,
fill: false,
//lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
data: yValues,
showLine: true,
spanGaps: true
}]
},
options: {
legend: { display: false }
}
});
chartMap.set(newChart, chart);
chart.data.datasets[0].data.push(i.value);
chart.data.labels.push(time);
chart.update();
}
updatePanel(paramList, valueList);
It seems like that when you add a new part to the inner html it has some weird behaviour with chart.js, if you first make all the divs with forms and canvasses and then create the charts it works fine:
var xValues = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150];
var yValues = [7, 8, 8, 9, 9, 9, 10, 11, 14, 14, 15];
function displayPanel(i) {
var panel = document.getElementById('panel');
panel.innerHTML += `
<div class="row">
<div class="column">
<form>
<label id="paramname_${i}" for="paramvalue">${i}</label>
<input type="text" id="paramvalue_${i}" name="param" value=${i} readonly>
</form>
</div>
<div id="chart_${i}" class="column">
<canvas id="myChart${i}" style="width:100%;max-width:600px"></canvas>
</div>`;
}
function createChart(i) {
new Chart("myChart" + i, {
type: "line",
data: {
labels: xValues,
datasets: [{
fill: false,
lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
data: yValues
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
min: 6,
max: 16
}
}],
}
}
});
}
function createUI(k) {
for (i = 0; i < k; i++) {
displayPanel(i);
}
for (i = 0; i < k; i++) {
createChart(i);
}
}
createUI(3)
<style>.column {
float: left;
align-self: right;
width: 50%;
padding: 10px;
}
.row {
content: "";
clear: both;
display: table;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<!DOCTYPE html>
<html>
<body>
<div id="panel"></div>
</body>

Adding Context to Django View Causing My Highcharts Map to Disappear

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>

How to get values for a chart with JavaScript in Django?

I created an application with Django. In this system, there is an approval system. I created an ApprovalProcess model and it has a beginning_date field. I crated a chart for showing how many approval processes are started on which day? But I cannot fill this chart.
But I cannot figure it out how can I get approval process values as my data? the data that I want to display is all_approvals in my views.
models.py
class ApprovalProcess(models.Model):
id = models.AutoField(primary_key=True)
user_id = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, related_name='starter')
doc_id = models.ForeignKey(Pdf, on_delete=models.CASCADE, null=True)
begin_date = models.DateTimeField(auto_now=True)
end_date = models.DateTimeField(auto_now=True)
status = models.IntegerField(default=0)
highest_rank = models.IntegerField(default=0)
last_approved = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, related_name='last_approved')
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True)
views.py
def approval_context_processor(request):
if request.user.is_authenticated:
current_user = request.user
rank_priority = RankPriority.objects.filter(rank=current_user.rank)
priority = rank_priority[0].priority
pend_list = ApprovalProcess.objects.filter(status=priority)
submit_list = ApprovalProcess.objects.filter(user_id=current_user)
userP = UserProfile.objects.get_or_create(username=current_user)
customer_list = Customer.objects.filter(company=userP[0].company)
all_approvals = ApprovalProcess.objects.filter(user_id__company=request.user.company)
approved_reports = 0
waiting_reports = 0
for submit in submit_list:
if submit.status - submit.highest_rank == 1:
approved_reports += 1
else:
waiting_reports += 1
else:
pend_list = 0
submit_list = 0
context = {
'pend_list': pend_list,
'submit_list': submit_list,
'approved_reports': approved_reports,
'waiting_reports': waiting_reports,
'customer_list': customer_list,
'all_approvals': all_approvals
}
return context
chart
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="card-head-row">
<div class="card-title">User Statistics</div>
<div class="card-tools">
</div>
</div>
</div>
<div class="card-body">
<div class="chart-container" style="min-height: 375px">
<canvas id="statisticsChart"></canvas>
</div>
<div id="myChartLegend"></div>
</div>
</div>
</div>
...
...
var ctx = document.getElementById('statisticsChart').getContext('2d');
var statisticsChart = new Chart(ctx, {
type: 'line',
data: {
labels: [
],
datasets: [ {
label: "Approval Processes",
borderColor: '#f3545d',
pointBackgroundColor: 'rgba(243, 84, 93, 0.6)',
pointRadius: 0,
backgroundColor: 'rgba(243, 84, 93, 0.4)',
legendColor: '#f3545d',
fill: true,
borderWidth: 2,
data: [100, 184, 250, 203, 210, 231, 240, 278, 252, 312, 320, 374]
}, ]
},
options : {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
},
tooltips: {
bodySpacing: 4,
mode:"nearest",
intersect: 0,
position:"nearest",
xPadding:10,
yPadding:10,
caretPadding:10
},
layout:{
padding:{left:5,right:5,top:15,bottom:15}
},
scales: {
yAxes: [{
ticks: {
fontStyle: "500",
beginAtZero: false,
maxTicksLimit: 5,
padding: 10
},
gridLines: {
drawTicks: false,
display: false
}
}],
xAxes: [{
gridLines: {
zeroLineColor: "transparent"
},
ticks: {
padding: 10,
fontStyle: "500"
}
}]
},
legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend html-legend">');
for (var i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><span style="background-color:' + chart.data.datasets[i].legendColor + '"></span>');
if (chart.data.datasets[i].label) {
text.push(chart.data.datasets[i].label);
}
text.push('</li>');
}
text.push('</ul>');
return text.join('');
}
}
});
i don't know which data you want to get from ApprovalProcess model but suppose you want to get highest_rank field to pass it to data chart
you code will be like this :
import json
def approval_context_processor(request):
if request.user.is_authenticated:
current_user = request.user
rank_priority = RankPriority.objects.filter(rank=current_user.rank)
priority = rank_priority[0].priority
pend_list = ApprovalProcess.objects.filter(status=priority)
submit_list = ApprovalProcess.objects.filter(user_id=current_user)
userP = UserProfile.objects.get_or_create(username=current_user)
customer_list = Customer.objects.filter(company=userP[0].company)
all_approvals = ApprovalProcess.objects.filter(user_id__company=request.user.company)
approved_reports = 0
waiting_reports = 0
for submit in submit_list:
if submit.status - submit.highest_rank == 1:
approved_reports += 1
else:
waiting_reports += 1
else:
pend_list = 0
submit_list = 0
context = {
'pend_list': pend_list,
'submit_list': submit_list,
'approved_reports': approved_reports,
'waiting_reports': waiting_reports,
'customer_list': customer_list,
'all_approvals': json.dumps([e.highest_rank for e in all_approvals])
}
return context
then you get your data in template like this :
var ctx = document.getElementById('statisticsChart').getContext('2d');
var statisticsChart = new Chart(ctx, {
type: 'line',
data: {
labels: [
],
datasets: [ {
label: "Approval Processes",
borderColor: '#f3545d',
pointBackgroundColor: 'rgba(243, 84, 93, 0.6)',
pointRadius: 0,
backgroundColor: 'rgba(243, 84, 93, 0.4)',
legendColor: '#f3545d',
fill: true,
borderWidth: 2,
data: {{ all_approvals|safe }}
}, ]
},
options : {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
},
tooltips: {
bodySpacing: 4,
mode:"nearest",
intersect: 0,
position:"nearest",
xPadding:10,
yPadding:10,
caretPadding:10
},
layout:{
padding:{left:5,right:5,top:15,bottom:15}
},
scales: {
yAxes: [{
ticks: {
fontStyle: "500",
beginAtZero: false,
maxTicksLimit: 5,
padding: 10
},
gridLines: {
drawTicks: false,
display: false
}
}],
xAxes: [{
gridLines: {
zeroLineColor: "transparent"
},
ticks: {
padding: 10,
fontStyle: "500"
}
}]
},
legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend html-legend">');
for (var i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><span style="background-color:' + chart.data.datasets[i].legendColor + '"></span>');
if (chart.data.datasets[i].label) {
text.push(chart.data.datasets[i].label);
}
text.push('</li>');
}
text.push('</ul>');
return text.join('');
}
}
});

Chart.js stacked bar chart text on top of the stacked bars

I have Chart.js chart inside a div element. The way that I got so far is good looking and it is what I need, but it is missing one big part, a dynamic text that has to aggregate the data of the chart and show a summary. Not bar by bar , but a summary of the two bars. This is where I got so far:
var chart;
var opts = {
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
enabled: false,
},
scales: {
xAxes: [{
stacked: true,
display: false,
ticks: {
fontColor: "#fff",
}
}, ],
yAxes: [{
stacked: true,
display: false,
ticks: {
fontColor: "#fcafe4",
mirror: true
}
}]
}
};
var datasets = [{
label: "My Label",
backgroundColor: ["#FF3A2F"],
data: [],
},
{
label: "Your Label",
backgroundColor: ["#0CB04A"],
data: [],
}
];
var labels = ['Label 1'];
var ctx = document.getElementById('chart-canvas');
chart = new Chart(ctx, {
type: "horizontalBar",
data: {
labels: labels,
datasets: datasets
},
options: opts
});
function refresh() {
chart.data.datasets[0].data[0] = Math.floor(Math.random() * 1000) + 1;
chart.data.datasets[1].data[0] = Math.floor(Math.random() * 1000) + 1;
chart.config.options.scales.xAxes[0].ticks.max = chart.data.datasets[0].data[0] + chart.data.datasets[1].data[0];
chart.update();
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<div class="row">
<div class="col-lg-5 small">My Stacked Chart</div>
<div class="col-lg-6">
<div class="chart-container">
<canvas id="chart-canvas"></canvas>
</div>
</div>
<div class="col-lg-1 my-auto">
<div class="btn-group">
<button type="button" class="btn btn-primary btn-md btn-sm" onClick="refresh()">
Refresh
</button>
</div>
</div>
</div>
I'm wondering if there is a way that I can add a text that will be in the middle of the canvas and will show data that is in the chart. For example XXXX of Total and will be updated every time the Refresh button is clicked. Something like that:
Thanks in advance!
Julian
The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterDraw hook to draw text directly on the canvas using CanvasRenderingContext2D.fillText().
chart = new Chart(ctx, {
type: "horizontalBar",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var value = chart.config.data.datasets[0].data[0];
var total = chart.config.data.datasets.reduce((t, ds) => t + ds.data[0], 0);
var percent = Math.round(1000 / total * value) / 10;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = "24px Arial";
ctx.fillText(value + ' (' + percent + '%) of ' + total, xAxis.right / 2, (yAxis.bottom + yAxis.top) / 2);
ctx.restore();
}
}],
...
Please have a look at your amended code below.
var chart;
var opts = {
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
enabled: false,
},
scales: {
xAxes: [{
stacked: true,
display: false,
ticks: {
fontColor: "#fff",
}
}, ],
yAxes: [{
stacked: true,
display: false,
ticks: {
fontColor: "#fcafe4",
mirror: true
}
}]
}
};
var datasets = [{
label: "My Label",
backgroundColor: ["#FF3A2F"],
data: [],
},
{
label: "Your Label",
backgroundColor: ["#0CB04A"],
data: [],
}
];
var labels = ['Label 1'];
var ctx = document.getElementById('chart-canvas');
chart = new Chart(ctx, {
type: "horizontalBar",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var value = chart.config.data.datasets[0].data[0];
var total = chart.config.data.datasets.reduce((t, ds) => t + ds.data[0], 0);
var percent = Math.round(1000 / total * value) / 10;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = "24px Arial";
ctx.fillText(value + ' (' + percent + '%) of ' + total, xAxis.right / 2, (yAxis.bottom + yAxis.top) / 2);
ctx.restore();
}
}],
data: {
labels: labels,
datasets: datasets
},
options: opts
});
refresh();
function refresh() {
chart.data.datasets[0].data[0] = Math.floor(Math.random() * 1000) + 1;
chart.data.datasets[1].data[0] = Math.floor(Math.random() * 1000) + 1;
chart.config.options.scales.xAxes[0].ticks.max = chart.data.datasets[0].data[0] + chart.data.datasets[1].data[0];
chart.update();
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<div class="row">
<div class="col-lg-5 small">My Stacked Chart</div>
<div class="col-lg-6">
<div class="chart-container">
<canvas id="chart-canvas"></canvas>
</div>
</div>
<div class="col-lg-1 my-auto">
<div class="btn-group">
<button type="button" class="btn btn-primary btn-md btn-sm" onClick="refresh()">
Refresh
</button>
</div>
</div>
</div>

Categories