Dynamically add Chart.js object using Mapbox GL JS - javascript

I'm using Mapbox GL JS and Chart.js to visualize a map with clickable markers. When clicked on a marker a Chart.js graph should be shown in the Mapbox popup, with the graph based on information of the clicked marker. Right now, this is how I achieve it:
var i = 0;
map.on("click", "trips", function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var nTripsMonth = e.features[0].properties.nTripsMonth;
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML('<canvas id="foo' + i + '"></canvas>')
.addTo(map);
map.flyTo({center: e.features[0].geometry.coordinates, zoom: 18});
var ctx = document.getElementById('foo' + i).getContext('2d');
console.log(ctx)
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Distribution',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: nTripsMonth
}]
},
});
i++;
});
This works the way I want it, however I feel like this is not the correct way.

Related

How to have mutiple charts in a single page using Chart.js?

I tried to draw more than two charts with Chart.js on the same page and created a dynamic div in a loop with all the data for the chart like this:
<div class="col-4">
<canvas class="trend-chart" id="chart{{ p.sNo }}" width="500" height="100" role="img" data-pv="{{ p.recentPageViews }}">
</canvas>
</div>
The JavaScript code to dynamically create a charts based on the class name:
const labels = [
'22-12-12',
'22-12-13',
'22-12-14',
'22-12-15',
'22-12-16',
'22-12-17',
'22-12-18',
'22-12-19',
'22-12-20',
'22-12-21'
];
const config = {
type: 'line',
animation: true,
options: {}
};
var charts = document.getElementsByClassName("trend-chart");
for (var i = 0; i < charts.length; i++) {
pv = charts[i].getAttribute('data-pv');
id = charts[i].getAttribute('id');
window['config' + id] = config;
window['data' + id] = {
labels: labels,
datasets: [{
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: JSON.parse(pv),
}]
};
window['config' + id]['data'] = window['data' + id];
window['ctx' + id] = document.getElementById(id).getContext('2d');
window['myChart' + id] = new Chart(
window['ctx' + id],
window['config' + id]
);
}
Everything works fine except the tooltip when I mouse hover to the chart data points. I am not seeing the tooltip and I get the following error:
Uncaught TypeError: Cannot read properties of null (reading 'getLabelAndValue')
at Eo (chart.js:13)
at Ho._createItems (chart.js:13)
at Ho.update (chart.js:13)
at Ho.handleEvent (chart.js:13)
at Object.afterEvent (chart.js:13)
at Q (chart.js:13)
at Vs._notify (chart.js:13)
at Vs.notify (chart.js:13)
at hn.notifyPlugins (chart.js:13)
at hn._eventHandler (chart.js:13)*
Please add label property in the datasets as per below code.
datasets: [{
label: 'Some text',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: JSON.parse(pv),
}]
Hi figure it out how to fix it, the main issue the context is not setting properly so I did like below to overcome
window.addEventListener('load', function() {
var charts = document.getElementsByClassName("trend-chart");
for (var i = 0; i < charts.length; i++) {
pv = charts[i].getAttribute('data-pv');
id = charts[i].getAttribute('id');
new Chart(
document.getElementById(id).getContext('2d'), {
type: 'line',
animation: true,
data: {
labels: JSON.parse(charts[i].getAttribute('data-pvd')),
datasets: [{
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: JSON.parse(pv),
}]
},
options: {plugins: {......},scales: {......}}
}
);
}
});

How can I configure Chart.js in a Electron app?

I'm new to electron so I'm learning the basic configuration.
So, i want to implement chart.js in my electron app.
The problem is: on my main page, the chart is simply a blank space... but with a look in the html inspector I can see the canvas created.
What I already did:
I've installed chart.js with npm install chart.js --save which we can find in the official chart.js documentation (https://www.chartjs.org/docs/latest/getting-started/installation.html).
My feeling tells me that I'm doing something wrong in the call for the chart library or something like that. My code is below:
<canvas id="myChart"></canvas>
<script>
const { chart } = require('electron-chartjs');
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45]
}]
},
// Configuration options go here
options: {}
});
</script>
As you can see, I'm using the official example. The only addition was the const { chart } = require('electron-chartjs');. So, I believe I'm doing something wrong or ignoring some big step.
Update:
Here is the new code:
<canvas id="chart"></canvas>
<script>
var Chart = require('chart.js');
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45]
}]
},
// Configuration options go here
options: {}
});
</script>
I had to require "chart.js", but i was requiring "electron-chart,js". And the canvas id was wrong.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script>
// ** entire Chart.js library **
</script>
<style>
</style>
</head>
<body>
<canvas id="myChart"></canvas>
<script>
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: {{chartData}}
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Line(data);
</script>
</body>
</html>
Notice the placeholder {{chartData}}. Also do note that you have to substitute in the actual script from the Chart.js file (you could link to the script file, but then you'll need a module that serves up static files)
var http = require('http');
var fs = require('fs');
http.createServer(function (req, response) {
fs.readFile('index.html', 'utf-8', function (err, data) {
response.writeHead(200, { 'Content-Type': 'text/html' });
var chartData = [];
for (var i = 0; i < 7; i++)
chartData.push(Math.random() * 50);
var result = data.replace('{{chartData}}', JSON.stringify(chartData));
response.write(result);
response.end();
});
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
We just substitute the placeholder with actual data.
Update for electron 21.2.0.
Download chart.js module from npm
Modify Index.html:
Add 'unsafe-inline' in meta
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
Now we can use chart.js as usual.
I only have no idea how to set custom width/height of my chart ):
Demo code is available on:
https://github.com/zdzmzych/electronNoiseAnalyzer

Chart JS Crosshair - Linked Charts without linked Legends

I have an application using Chart JS and the great extension chartjs-plugin-crosshair to provide zoom and a vertical line on hover. It's ability to 'link' charts is critical as it highlights values on separate charts across the same x-axis.
The issue is the linked charts also have linked legends. I've created a simple example: https://codepen.io/sheixt/pen/JjGvbVJ
Here is an extract of the Chart option config (see the link for the full script):
const options = {
plugins: {
crosshair: {
sync: {
enabled: true
}
}
},
tooltips: {
mode: "interpolate",
intersect: false,
callbacks: {
title: function (a, d) {
return a[0].xLabel.toFixed(2);
},
label: function (i, d) {
return d.datasets[i.datasetIndex].label + ": " + i.yLabel.toFixed(2);
}
}
}
};
As you can see, if you "turn off" a dataset (e.g. Dataset 1, A in chart 1, D in chart 2, and G in chart 3), the dataset is removed from all of the linked charts.
I have a series of charts that are based on the same x-axis data so the crosshair line & the tooltip appearing on all of the linked charts is ideal. But as each dataset that is plotted is not the same across the various charts, I do not want it to disappear on click.
So in my example deselecting Dataset 1 on chart 1 A would be removed but D in chart 2, and G in chart 3 should remain.
Is this feasible?
You can extend the chart and write your own type with horizontal and vertical arbitrary lines as it is shown in this answer.
Here is an update if you need it for version 2
HTML
<canvas id="chart" width="600" height="400"></canvas>
SCRIPT
var ctx = document.getElementById('chart').getContext('2d');
Chart.defaults.crosshair = Chart.defaults.line;
Chart.controllers.crosshair = Chart.controllers.line.extend({
draw: function (params) {
Chart.controllers.line.prototype.draw.call(this, params);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
y = activePoint.tooltipPosition().y,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom,
startX = this.chart.scales['x-axis-0'].left,
endX = this.chart.scales['x-axis-0'].right;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.moveTo(startX, y);
ctx.lineTo(endX, y);
ctx.lineWidth = 2.5;
ctx.strokeStyle = 'rgb(55, 55, 55)';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'crosshair',
// The data for our dataset
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgba(255, 255, 255,0)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45]
}]
},
// Configuration options go here
options: {}
});
Result
var ctx = document.getElementById('chart').getContext('2d');
Chart.defaults.crosshair = Chart.defaults.line;
Chart.controllers.crosshair = Chart.controllers.line.extend({
draw: function (params) {
Chart.controllers.line.prototype.draw.call(this, params);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
y = activePoint.tooltipPosition().y,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom,
startX = this.chart.scales['x-axis-0'].left,
endX = this.chart.scales['x-axis-0'].right;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.moveTo(startX, y);
ctx.lineTo(endX, y);
ctx.lineWidth = 2.5;
ctx.strokeStyle = 'rgb(55, 55, 55)';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'crosshair',
// The data for our dataset
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgba(255, 255, 255,0)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45]
}]
},
// Configuration options go here
options: {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<canvas id="chart" width="600" height="400"></canvas>

Is there any way to display float bar in chart.js?

I am trying to display float bar on a browser.
But the item of float bar can not be found.
Is there no way to display it in Chart.js?
This page I found on GitHub was modifying Chart.js.
https://github.com/chartjs/Chart.js/pull/5262
http://pravopys.net/chartjs/samples/charts/bar/horizontal.html
However, I did not understand how to modify it.
Also, this page seemed to be trying to implement float bar support. However, it does not seem to be implemented yet.
https://github.com/chartjs/Chart.js/pull/6056
I will put the code of the page of float bar introduced above.
However, even if this code was used, only the lower part was displayed.
I think that it is also necessary to modify Chart.js itself.
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
window.randomScalingFactor = function() {
// return Math.round(Samples.utils.rand(-100, 100));
return (Math.random()*200 - 100);
};
if (document.location.hostname.match(/^(www\.)?chartjs\.org$/)) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-28909194-3', 'auto');
ga('send', 'pageview');
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
var color = Chart.helpers.color;
var horizontalBarChartData = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
borderColor: window.chartColors.red,
borderWidth: 1,
data: [
[20, 70],
[-20,-70],
[getRandomInt(10,50), getRandomInt(50,100)],
[getRandomInt(10,50), getRandomInt(50,100)],
[getRandomInt(10,50), getRandomInt(50,100)],
[getRandomInt(10,50), getRandomInt(50,100)],
randomScalingFactor(),
randomScalingFactor()
]
}, {
label: 'Dataset 2',
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
borderColor: window.chartColors.blue,
data: [
[-10, 30],
[-20,-70],
[getRandomInt(-10,-50), getRandomInt(-50,-100)],
[getRandomInt(-10,-50), getRandomInt(-50,-100)],
[getRandomInt(-10,-50), getRandomInt(-50,-100)],
[getRandomInt(-10,-50), getRandomInt(-50,-100)],
randomScalingFactor(),
randomScalingFactor()
]
}]
};
console.log(horizontalBarChartData);
window.onload = function() {
console.log('t');
console.log(horizontalBarChartData);
let ctx = document.getElementById("Chart").getContext('2d');
window.myHorizontalBar = new Chart(ctx, {
type: 'horizontalBar',
data: horizontalBarChartData,
options: {
// Elements options apply to all of the options unless overridden in a dataset
// In this case, we are setting the border of each horizontal bar to be 2px wide
elements: {
rectangle: {
borderWidth: 2,
}
},
responsive: true,
legend: {
position: 'right',
},
title: {
display: true,
text: 'Chart.js Horizontal Bar Chart'
}
}
});
};
document.getElementById('randomizeData').addEventListener('click', function() {
var zero = Math.random() < 0.2 ? true : false;
horizontalBarChartData.datasets.forEach(function(dataset) {
dataset.data = dataset.data.map(function() {
return zero ? 0.0 : randomScalingFactor();
});
});
window.myHorizontalBar.update();
});
var colorNames = Object.keys(window.chartColors);
document.getElementById('addDataset').addEventListener('click', function() {
var colorName = colorNames[horizontalBarChartData.datasets.length % colorNames.length];
var dsColor = window.chartColors[colorName];
var newDataset = {
label: 'Dataset ' + horizontalBarChartData.datasets.length,
backgroundColor: color(dsColor).alpha(0.5).rgbString(),
borderColor: dsColor,
data: []
};
for (var index = 0; index < horizontalBarChartData.labels.length; ++index) {
newDataset.data.push(randomScalingFactor());
}
horizontalBarChartData.datasets.push(newDataset);
window.myHorizontalBar.update();
});
document.getElementById('addData').addEventListener('click', function() {
if (horizontalBarChartData.datasets.length > 0) {
var month = MONTHS[horizontalBarChartData.labels.length % MONTHS.length];
horizontalBarChartData.labels.push(month);
for (var index = 0; index < horizontalBarChartData.datasets.length; ++index) {
horizontalBarChartData.datasets[index].data.push(randomScalingFactor());
}
window.myHorizontalBar.update();
}
});
document.getElementById('removeDataset').addEventListener('click', function() {
horizontalBarChartData.datasets.splice(0, 1);
window.myHorizontalBar.update();
});
document.getElementById('removeData').addEventListener('click', function() {
horizontalBarChartData.labels.splice(-1, 1); // remove the label first
horizontalBarChartData.datasets.forEach(function(dataset) {
dataset.data.pop();
});
window.myHorizontalBar.update();
});
I asked for a float bar. However, in fact, only a bar chart was displayed.
If you can not do it in Chart.js, I would appreciate it if you could show other possible libraries.
Floating bars are officially available since Chart.js v2.9.0. The feature was merged into chartjs:master with pull request #6056. Individual bars can now be specified with the syntax [min, max].
<html>
<head>
<title>Floating Bars</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div>
<canvas id="canvas" height="100"></canvas>
</div>
<script>
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'data',
data: [[-3, 5], [2, 10], [1, 3], [-4, -1], [4, 8]],
backgroundColor: 'lightblue'
}]
},
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Horizontal Floating Bars'
}
}
});
};
</script>
</body>
</html>

ChartJS replay chart animation when called by show()

I have a page full of charts that automatically generates all charts available (because the default page is "All Charts"). In it, there's a select department tag that will hide all charts other than those owned by the selected department. Here's my code:
$(window).load(function(){
$('#department').change(function(){
active_department($(this).val());
});
function active_department(department){
for(var i = 0; i < dept['namedept'].length; i++){
if(department!='All'){
$('.'+dept['namedept'][i]).hide(500);
} else {
if(typeof rCharts[dept['namedept'][i]] != 'undefined'){
$('.'+dept['namedept'][i]).show(500);
} else {
$('.no-chart-'+dept['namedept'][i]).hide(500);
}
}
}
if(typeof rCharts[department] != 'undefined'){
$('.'+department).show(500);
} else {
$('.no-chart-'+department).hide(500);
}
}
});
I want ChartJS animation to re-appear every time I select a department. So far I've tried easing, onProgress, and jQuery animate. none's working. Is it possible to re-animate the chart? If so, how?
From this answer and from the lack of options available in the Docs, it looks like the only feasible options would be these hacks:
redraw the chart with JS using new Chart or
change some minor configuration, or recreate an instance of the chart data and then call the update() method.
e.g.: Call the data through a function, and when you want the animation to happen, call the same function again. Because it now has a new array (even though it's the same data), the chart re-animates.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<button onclick="updateChart()">Update</button>
<canvas id="myChart"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var chartData = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: createDataset()
}
};
var chart = new Chart(ctx, chartData);
function updateChart(){
chartData.data.datasets = createDataset()
chart.update();
}
function createDataset(){
return [{
label: "My First dataset",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45],
fill: false
}];
}
//ignore next line, it's to deal with a bug from chartjs cdn on stackoverflow
console.clear();
</script>

Categories