so I'm generating charts with a database and displaying them with JSON script and it works fine but the chart only displays when I click an option value, what I'm trying to do now is set a default value option for when the website opens it displays a default chart if that makes sense, below is my chart.js code.
function renderHtmlChart(){
$(document).ready(function (){
var selection= document.getElementById('YEAR').value;
var link = "https://udon.ads.ntu.ac.uk/web/itec30151/N0773065/new/data.php?YEAR='"+selection+"'";
$.ajax({
url: link,
method: "GET",
success: function(data=this.responseText) {
console.log(data);
var Destination = [];
var Bookings = [];
for(var i in data) {
Destination.push(data[i].Destination);
Bookings.push(data[i].Bookings);
}
createChart(Destination,Bookings,selection)
},
error: function(data) {
console.log(data);
}
});
});
}
function createChart(Destination,Bookings,selection){
var universalOptions = {
maintainAspectRatio: true,
responsive: false,
title: {
display: true,
text: 'Top 5 Flight Bookings'
},
legend: {
display: true,
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
},
scaleLabel: {
display: true,
labelString: 'Bookings'
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Destinations'
}
}],
}
}
var chartdata = {
labels: Destination,
datasets : [
{
label: selection,
data: Bookings,
backgroundColor: ["#3366cc","#dc3912","#ff9900","#109618","#990099"],
borderWidth: '1',
borderColour: 'grey',
hoverBorderColor: 'black',
fill: false,
pointRadius: 0,
}
]
};
//stop overlap
$('select').on('change',function(){
barGraph.destroy();
});
// this makes legend hidden
var update_caption = function(legend) {
labels[legend.text] = legend.hidden;
var selected = Object.keys(labels).filter(function(key) {
return labels[key];
});
};
//this creates new graph
var ctx = document.getElementById('myChart');
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata,
options: universalOptions,
responsive: false,
});
}
hope you have latest version of jquery like:-
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
hope this will help
//create renderHtmlChart function
function renderHtmlChart()
{
var selection= document.getElementById('YEAR').value;
var link = "https://udon.ads.ntu.ac.uk/web/itec30151/N0773065/new/data.php?YEAR='"+selection+"'";
$.ajax({
url: link,
method: "GET",
success: function(data=this.responseText)
{
console.log(data);
var Destination = [];
var Bookings = [];
for(var i in data)
{
Destination.push(data[i].Destination);
Bookings.push(data[i].Bookings);
}
createChart(Destination,Bookings,selection)
},
error: function(data)
{
console.log(data);
}
});
}
//create createChart function
function createChart(Destination,Bookings,selection)
{
var universalOptions =
{
maintainAspectRatio: true,
responsive: false,
title:
{
display: true,
text: 'Top 5 Flight Bookings'
},
legend:
{
display: true,
},
scales:
{
yAxes: [{
ticks: {
beginAtZero: true,
},
scaleLabel: {
display: true,
labelString: 'Bookings'
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Destinations'
}
}],
}
}
var chartdata = {
labels: Destination,
datasets : [
{
label: selection,
data: Bookings,
backgroundColor: ["#3366cc","#dc3912","#ff9900","#109618","#990099"],
borderWidth: '1',
borderColour: 'grey',
hoverBorderColor: 'black',
fill: false,
pointRadius: 0,
}
]
};
// this makes legend hidden
var update_caption = function(legend) {
labels[legend.text] = legend.hidden;
var selected = Object.keys(labels).filter(function(key) {
return labels[key];
});
};
//this creates new graph
var ctx = document.getElementById('myChart');
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata,
options: universalOptions,
responsive: false,
});
}
$(funtion(){
//onload call renderHtmlChart function
renderHtmlChart();
//on select input change call renderHtmlChart function
$('select').on('change',function(){
renderHtmlChart();
});
})
Related
I saw this other post on Stackoverflow and it is what I want to do. I have my awesome graph in my ASP.NET Core web application by Chart.js#2.9.4. I read the data from an API.
As I read, I added chartjs-plugin-datalabels on my project and add the script to the page.
$.ajax({
url: 'myapi',
dataType: 'json'
})
.fail(function (err) {
alert(err);
})
.done(function (data) {
$("#chart").html('');
$("#chart").html('<canvas id="barChart" style="min-height: 300px; height: 3000px; max-height: 300px; max-width: 100%;"></canvas>');
var stackedBarChartCanvas = $('#barChart').get(0).getContext('2d')
var stackedBarChartData = $.extend(true, {}, data)
var temp0 = data.datasets[0]
var temp1 = data.datasets[1]
stackedBarChartData.datasets[0] = temp1
stackedBarChartData.datasets[1] = temp0
var stackedBarChartOptions = {
responsive: true,
maintainAspectRatio: false,
tooltips: {
mode: 'label',
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + numberWithCommas(tooltipItem.yLabel);
}
}
},
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true,
max: 100,
ticks: {
callback: function (value) {
return numberWithCommas(value);
},
},
}]
},
plugins: {
datalabels: {
display: true,
align: 'center',
anchor: 'center',
display: function (context) {
return context.dataset.data[context.dataIndex] > 15;
},
font: {
weight: 'bold'
},
formatter: Math.round
}
}
}
var stackedBarChart = new Chart(stackedBarChartCanvas, {
type: 'bar',
data: stackedBarChartData,
options: stackedBarChartOptions,
onAnimationComplete: function () {
var ctx = this.chart.ctx;
ctx.font = this.scale.font;
ctx.fillStyle = this.scale.textColor
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
this.datasets.forEach(function (dataset) {
dataset.bars.forEach(function (bar) {
ctx.fillText(bar.value, bar.x, bar.y - 5);
});
})
}
})
})
If I move the mouse over the graph, nothing happens but in the Console I have this error
Uncaught TypeError: Cannot read property 'r' of null (Chart.js:1655)
Also, I want to fix the maximum value in the y-axis must be 100 because there are only percentage. Although, I set the y-axis to 100, the chart displays 120.
Chart.js doesn't show the data because it is required to set some parameters:
HoverBackgroundColor
HoverBorderWidth
HoverBorderColor
After settings them, the chart is working.
I need to display a bar chart that I must make with chartJs with dynamic data, I get these dynamic data from an xml link.
I work with two datafields: TaskName and TaskPercentCompleted
The final result must be something like this:
https://scontent.ftun3-1.fna.fbcdn.net/v/t1.15752-9/67290623_1101713790034749_6213821876259520512_n.png?_nc_cat=107&_nc_oc=AQkVef74ok1IcC0m0ujX4t7c4EhNAEs0C-lejsBTHCj9U2zrFRo2UA_gWnuOeA4ZJco&_nc_ht=scontent.ftun3-1.fna&oh=e8503be685f36c7440362b5a0d3c85f5&oe=5DA3B54E
And this is a part of the xml link:
https://scontent.ftun3-1.fna.fbcdn.net/v/t1.15752-9/66803472_2156647134463530_3324310068698021888_n.png?_nc_cat=100&_nc_oc=AQmuJ-gA1lT7F-whtw329vy_eciZoCWNn5hxCW2Zdp4X_RBfyZknVR1Bza-UF_nDn7s&_nc_ht=scontent.ftun3-1.fna&oh=d6ced2436a0c666be4dfd4fe5138a72f&oe=5DAADE21
I got a code but it doesn't work the way I want, it's regrouping data and I don't want that.
window.addEventListener('load',function() {
var dataURL = _spPageContextInfo.webAbsoluteUrl + "/_api/ProjectData/[en-US]/Tasks?$select=TaskName,TaskPercentCompleted&$filter=ProjectName%20eq%20%27Bay%20Plaza%27%20and%20TaskIsSummary%20eq%20true%20and%20TaskIsProjectSummary%20eq%20false";
$.ajax({
url: dataURL,
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
success: function(data) {
var dataResults = data.d.results;
var itermeidiaryObject = {};
$.each(dataResults, function(key, value) {
var nomTask = value.TaskName;
var epn = value.TaskPercentCompleted;
if (epn != null) {
itermeidiaryObject[epn] = ++itermeidiaryObject[epn] || 1;
}
});
var finalObject = Object.keys(itermeidiaryObject).map(function(key) {
return {
label: itermeidiaryObject[key],
y: key
}
});
var pievalues = finalObject.map(function(value, index) {
return value.y;
});
var labels = finalObject.map(function(value, index) {
return value.label;
});
var colorscheme = colors.slice(0, labels.length);
var ctx = document.getElementById('myChart2').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: pievalues,
backgroundColor: colorscheme
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
ticks: {
beginAtZero: true // Edit the value according to what you need
}
}],
yAxes: [{
stacked: true
}]
},
title: {
display: true,
position: "top",
text: "Nombre de projets par direction",
fontSize: 18,
fontColor: "#111"
},
legend: {
display: false
}
}
});
}
});
});
var colors = ["#0074D9", "#FF4136", "#2ECC40", "#FF851B", "#7FDBFF", "#B10DC9", "#FFDC00", "#001f3f", "#39CCCC", "#01FF70", "#85144b", "#F012BE", "#3D9970", "#111111", "#AAAAAA"];
I solved the problem
window.addEventListener('load',function() {
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/ProjectData/[en-US]/Tasks?$select=TaskName,TaskPercentCompleted&$filter=ProjectName%20eq%20%27Bay%20Plaza%27%20and%20TaskIsSummary%20eq%20true%20and%20TaskIsProjectSummary%20eq%20false",
method: "GET",
headers: { "Accept": "application/json; odata=nometadata" },
success: function (data) {
if (data.value.length > 0) {
var pieValues = [];
var pieLabels = [];
for (var i = 0; i < data.value.length; i++) {
pieValues.push(parseInt(data.value[i].TaskPercentCompleted));
pieLabels.push(data.value[i].TaskName);
}
var pieData = {
datasets: [{
data: pieValues,
backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850",
"#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850",
"#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850",
"#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850",
"#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850",
"#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850","#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
}],
labels: pieLabels
};
var ctx = document.getElementById("myChart2");
var myPieChart = new Chart(ctx, {
//type: 'pie',
type: 'bar',
data: pieData,
options: {
responsive: true,
legend: { display: false },
title: {
display: true,
text: 'Nom de tâche par pourcentage'
},
scales: {
xAxes: [{
ticks: {
maxRotation: 90,
minRotation: 90,
display: false
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
},
error: function (data) {
//
}
});
});
I’m using ChartJs, to display a Line chart and I’m trying to do 2 things :
The first one is to display different colors based on the tooltip’s value. Highest value vs Medium value
The second one is to display a different tooltip if the tooltips value is the lowest. Minimun value
I’ve tried to use a custom plugins to do this, but It didn’t work
This is the code I've managed to do so far :
Chart.plugins.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
console.log(j, sector);
chart.pluginTooltips.push(
new Chart.Tooltip(
{
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector],
},
chart
)
);
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
if (!chart.allTooltipsOnce) {
if (easing !== 1) return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip._options.bodyFontFamily = "Visby";
// Change color based on value
tooltip._options.bodyFontColor = '#FEB122';
// Change tooltip's html if minimun value of dataset
// Values .datapoints[0].value
// console.log(tooltip._model);
tooltip._options.displayColors = false;
tooltip._options.bodyFontSize = tooltip._chart.height * 0.05;
tooltip._options.yPadding = 0;
tooltip._options.xPadding = 0;
tooltip.update();
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
let canvas = document.getElementById("myLineChart");
Chart.defaults.global.defaultFontFamily = "Visby";
const ctx = canvas.getContext('2d');
const labels = JSON.parse(ctx.canvas.dataset.dates);
const prices = JSON.parse(ctx.canvas.dataset.prices);
const myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: "Prix du billet",
data: prices,
backgroundColor: [
'rgba(0, 0, 0, 0)',
],
borderColor: [
'#F2F2F2',
],
pointBackgroundColor:
'#FEB122',
pointBorderColor:
'#FEB122',
borderWidth: 3,
}]
},
options: {
showAllTooltips: true, // call plugin we created
responsive: true,
cutoutPercentage: 60,
legend: {
position: "bottom"
},
animation: {
animateScale: true,
animateRotate: true
},
tooltips: {
enabled: false,
backgroundColor:"rgba(0,0,0,0)",
callbacks: {
title: function(tooltipItems, data) {
return "";
},
label: function(tooltipItem, data) {
var datasetLabel = "";
var label = data.labels[tooltipItem.index];
return data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + '€';
},
labelColor: function(tooltipItem, data) {
// console.log(data);
}
}
},
legend: {
display: false
},
layout: {
padding: {
left: 32,
right: 32,
top: 32,
bottom: 32
}
},
scales: {
xAxes: [{
gridLines: {
display: false,
drawBorder: false,
},
}],
yAxes: [{
display: false
}]
}
}
});
How could I make this work ?
I've managed to do that by using the plugin Chartjs Datalabels.
And using the scriptable colors options.
The documentation for time in ChartJs is extremely vague and gives little working examples so I'm struggling to get a time series working for temperature data recorded at a particular time. I can get the correct time format to appear in the tooltip, but it will not appear on the X axis.
Graph code:
<script>
var ctx = document.getElementById('myChart');
var data = {
labels: [],
datasets: [{
label: "Temperature Graph",
fill: false,
borderColor: '#3cba9f',
data: []
}]
}
const options = {
type: 'line',
data: data,
options: {
fill: false,
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day',
stepSize: 1,
displayFormats: {
day: 'MMM D'
}
},
display: true,
scaleLabel: {
display: true,
labelString: "Date",
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
},
display: true,
scaleLabel: {
display: true,
labelString: "Temperature",
}
}]
}
}
}
var chart = new Chart(ctx, options)
</script>
Data collection code:
window.onload = function load() {
getData();
}
var prevData = [];
var prevLabels = [];
function getData() {
var xhr = new XMLHttpRequest();
xhr.open('GET', encodeURI('http://localhostlocalhost/getTemp'));
xhr.onload = function() {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
console.log(data);
var label = data.timestamp * 1000;
prevData.push(data.temperature);
prevLabels.push(label);
chart.data.datasets[0].data = prevData;
chart.data.labels = prevLabels;
chart.update();
}
else {
alert(xhr.status);
}
};
xhr.send();
setTimeout(getData, 10000);
}
Example xhr response:
{temperature: 17, humidity: 38, location: "location", timestamp: 1542824305}
The data is plotted to the graph and all works as expected, the time just does not appear on the X axis
I am trying to import and read from a JSON file that gets updated every few minutes by a different process. I need to loop through the values in this JSON files for use with ChartJS.org.
If I keep the JSON data local to the script in a var (var jsonfile={}) the chart works as expected.
What I am struggling to do is import the JSON file from outside the script (it is on the local web server under a different folder).
The JSON file looks exactly the same as data in the var below.
The below works as expected.
<div class="row">
<div class="col-4">
<div class="ca-comms-by-month">
</div>
<script>
var jsonfile = {
"comms_by_month": [
{
"name": "July",
"count": 2130
},
{
"name": "August",
"count": 890
},
{
"name": "September",
"count": 1654
},
{
"name": "October",
"count": 120
}
]
};
var labels = jsonfile.comms_by_month.map(function(e) {
return e.name;
});
var data = jsonfile.comms_by_month.map(function(e) {
return e.count;
});
function createConfig(details, data) {
return {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Comms count by month',
steppedLine: details.steppedLine,
data: data,
borderColor: details.color,
fill: true,
}]
},
options: {
responsive: true,
title: {
display: false,
text: details.label,
},
tooltips: {
enabled:true, // Disable this for custom tool tips || http://www.chartjs.org/docs/latest/configuration/tooltip.html
mode: 'index',
intersect: false,
cornerRadius:0
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Count'
},
ticks: {
beginAtZero:true
}
}]
},
legend: {
display: false, // False to hide the legdend dataset tile
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
};
}
window.onload = function()
{
var container = document.querySelector('.ca-comms-by-month');
var steppedLineSettings = [{
steppedLine:false,
label: '',
color: window.chartColors.purple
}];
steppedLineSettings.forEach(function(details) {
var div = document.createElement('div');
div.classList.add('chart-container');
var canvas = document.createElement('canvas');
div.appendChild(canvas);
container.appendChild(div);
var ctx = canvas.getContext('2d');
var config = createConfig(details, data);
new Chart(ctx, config);
});
};
</script>
</div>
</div>
The below code will display some of the data in the updated JSON file based on the getElementById names but this is no good to me as I need the ChartJS to go and get the values.
<h1 class="toolsportal text-right">Temp</h1>
<p id="demo"></p>
<p id="demo1"></p>
<br /><br /><br /><br />
<script>
var jsonurl = 'http://mydevicename/portal/js/export_json/dash-comms-month.json';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
{
var jsonfile = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = jsonfile.comms_by_month[0].month;
document.getElementById("demo1").innerHTML = jsonfile.comms_by_month[0].name;
}
};
xmlhttp.open("GET", jsonurl, true);
xmlhttp.send();
</script>
What I can't put together is how I can get the values out of the updated JSON file using the below functions that happily go and get the data from the local jsonfile{} var.
var labels = jsonfile.comms_by_month.map(function(e){return e.name;});
var data = jsonfile.comms_by_month.map(function(e){return e.count;});
I am clearly missing something fundamental, any pointers would be great.
Thanks
I have answered my own question by properly looking into what XMLHttpRequest() & JSON.parse() does.
If someone is looking to hook a JSON file into https://www.chartjs.org/ charts then the below might help.
The JSON file
"comms_by_month":[
{
"name": "July",
"month":7,
"count":0
},
{
"name": "August",
"month":8,
"count":1652
},
{
"name": "September",
"month":9,
"count":600
},
{
"name": "October",
"month":10,
"count":0
},
{
"name": "November",
"month":11,
"count":0
},
{
"name": "December",
"month":12,
"count":0
}
]
Get the JSON file into a var
<script>
// Set the var for the json file located on the web server
var jsonFile_dash_comms_by_month = 'http://hostname/portal/js/export_json/dash-comms-by-month.json';
var request = new XMLHttpRequest();
request.open("GET",jsonFile_dash_comms_by_month,false);
request.send(null)
var jsonObj_dash_comms_by_month = JSON.parse(request.responseText);
</script>
A div where the chart will be displayed
<div class="ca-comms-by-month"></div>
Functions to get the labels and datasets into a var
<script>
var labels = jsonObj_dash_comms_by_month.comms_by_month.map(function(e) {
return e.name;
});
var data = jsonObj_dash_comms_by_month.comms_by_month.map(function(e) {
return e.count;
});
</script>
Function to create the CharJS config
See (http://www.chartjs.org/docs/latest/configuration/) for more about ChartJs config.
<script>
function createConfig(details, data) {
return {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Comms count by month',
steppedLine: details.steppedLine,
data: data,
borderColor: details.color,
fill: true,
}]
},
options: {
responsive: true,
title: {
display: false,
text: details.label,
},
tooltips: {
enabled:true, // Disable this for custom tool tips || http://www.chartjs.org/docs/latest/configuration/tooltip.html
mode: 'index',
intersect: false,
cornerRadius:0
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Count'
},
ticks: {
beginAtZero:true
}
}]
},
legend: {
display: false, // False to hide the legdend dataset tile
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
};
}<script>
On load function to display the chart
<script>
window.onload = function()
{
var container = document.querySelector('.ca-comms-by-month');
var steppedLineSettings = [{
steppedLine:false,
label: '',
color: window.chartColors.purple
}];
steppedLineSettings.forEach(function(details) {
var div = document.createElement('div');
div.classList.add('chart-container');
var canvas = document.createElement('canvas');
div.appendChild(canvas);
container.appendChild(div);
var ctx = canvas.getContext('2d');
var config = createConfig(details, data);
new Chart(ctx, config);
});
};
</script>
This gave me the below chart
I would be keen to hear from anyone who can point out any improvements on the above. I am expecting to have 10+ charts on a dashboard type page.
Thanks
edwoli