Align line annotation label and label annotation - chart.js

I'm using chartjs-plugin-annotation version 2.1.1 to draw a line and a couple of labels on a chart.
With position: 'end' the label is aligned to the right.
const l1 = {
type: 'line',
label: {
display: true,
content: 'line',
position: 'end',
},
scaleID: 'y',
value: 62,
};
However, I am not able to draw a label annotation vertically-aligned (to the right) with the label of the line.
I have tried several
const l2 = {
type: 'label',
yValue: 0,
position: 'end',
// position { x: 'end' },
content: 'label'
}
Am I missing anything here?

The position of the label can be used to define where the label must be located, compared to the point defined by xValue and yValue option.
Probably the best way is to use line annotations, with the same config, apart for value.
const l2 = {
type: 'line',
label: {
display: true,
content: 'line',
position: 'end',
},
borderWidth: 0, // no line
scaleID: 'y',
value: 0
};
Or in you label annotation, you could set xValue and xAdjust as following:
const l2 = {
type: 'label',
yValue: 0,
xValue: (context) => context.chart.scales.x.max,
position: 'end',
content: 'label',
color: 'white',
xAdjust: (context) => -context.chart.options.plugins.annotation.annotations.l1.label.padding,
backgroundColor: 'black'
}

Related

Charts.js renders axes, but not the dataset

I'm trying to use Charts.js on an AWS Lambda function to create a chart image (png).
However, for some reason it plots the axes, but no data.
this is my code:
export const plotData = (values: number[]): Buffer | null => {
const canvas = createCanvas(800, 600);
let ctx: ChartItem = canvas as unknown as ChartItem;
const plugin: Plugin = {
id: "customCanvasBackgroundColor",
beforeDraw: (chart: any, _args: any, options: any) => {
const { ctx: context } = chart;
context.save();
context.globalCompositeOperation = "destination-over";
context.fillStyle = options.color || "#99ffff";
context.fillRect(0, 0, chart.width, chart.height);
context.restore();
},
};
const chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "ph",
data: values.map((y) => ({
y,
t: new Date(),
})),
borderWidth: 2,
borderColor: "red",
backgroundColor: "rgb(255, 0, 0, 0.5)",
},
],
},
options: {
responsive: false,
animation: false,
scales: {
y: {
beginAtZero: true,
},
},
plugins: {
legend: {
position: "top",
},
title: {
display: true,
text: "TEstuibg",
},
customCanvasBackgroundColor: {
color: "rgba(255,255,255, 1)",
},
},
},
plugins: [plugin],
});
// chart.draw();
chart.update();
return canvas.toBuffer("image/png");
};
And this is what it is rendering when I call plotData([100, 200, 300, 400, 500, 1600]):
I am already disabling animations and responsiveness. Is there something else I need to do?
I would create the image on the onComplete event, than everything should be visible, atleast this works in browsers.
from the documentation: "...The animation configuration provides callbacks which are useful for synchronizing an external draw to the chart animation....", but works surely for your image creating process. link to documentation
...
options: {
animation:{
duration: 0, // "no" animation
onComplete: () => {
...
// create image
...
}
}
}
...
Ofcourse: in this case your function plotData would have to be async or pass a callback function for when the event onComplete fires.

ChartJS Choropleth Focusing On US and Not The Entire Earth?

I created this chartJS map to showcase the distribution of registrations for this course. However, i can only see US in the map. Is there an issue with the library or should i use a different project ?
Thank you in Advance
Here is the code:
fetch('https://unpkg.com/world-atlas/countries-50m.json').then((r) => r.json()).then((data) = {
const countries = ChartGeo.topojson.feature(data, data.objects.countries).features;
const dataCountries = <?= json_encode($WorldMapData) ?>;
const chart = new Chart(canvas.getContext("2d"), {
type: 'choropleth',
data: {
labels: countries.map((d) => d.properties.name),
datasets: [{
label: 'Course Registrations',
data: countries.map((d) => ({
feature: d,
value: dataCountries[dataCountries.indexOf(d.properties.name) + 1],
})),
}]
},
options: {
legend: {
display: true
},
scale: {
projection: 'equalEarth'
},
geo: {
colorScale: {
display: true,
position: 'bottom',
quantize: 1,
legend: {
position: 'bottom-right',
},
},
},
}
});
});
This is what I see:
enter image description here
I tried to get a map showcasing the entire earth but it is only showing US.

How to use Chartjs to plot a single row of colored bars with a time based x axis

I have some time based data I want a graphical representation of, and was hoping to use Chartjs to plot this.
The data looks something like the following:
Time State
--------------
7am up
9am down
10.45am out
17.35 up
Also, each "state" will have its own color, so I would use this as a bar color when using a bar graph
up = red
down = yellow
out = green
The end result I am after is a simple one row bar like the following...
I thought I may be able to use a Chartjs horizontal stacked bar chart (https://www.chartjs.org/docs/latest/charts/bar.html#horizontal-bar-chart) to do this somehow, but I just can't work out how to get this working.
Some (not working) experimental code is as follows:
private createChart(): void {
if (this.chart !== undefined) {
return;
}
Chart.register(BarController, PointElement, Tooltip, Legend, TimeScale, LinearScale, CategoryScale, LinearScale, BarElement);
const options: ChartOptions = {
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
stacked: true,
type: 'time',
display: true,
// position: 'bottom',
time: {
unit: 'minute',
displayFormats: {
minute: 'h:mm a'
}
}
},
x: {
stacked: false,
}
}
};
this.chart = new Chart(this.canvasRef.nativeElement, {
type: 'bar',
data: this.chartData,
options
});
this.chart.config.options.scales.y.min = new Date('2023-02-13T06:19:31.842Z').getTime();
const labels = [
'up',
'down'
// 'Dataset 2'
];
const d1 = new Date('2023-02-13T06:20:32.842Z').getTime();
const d2 = new Date('2023-02-13T06:21:33.842Z').getTime();
this.chartData = {
labels,
datasets: [{
label: 'up',
data: [{x: 10, y: d1}],
backgroundColor: 'red',
},
{
label: 'down',
data: [{x: 20, y: d2}],
backgroundColor: 'green',
}
]
};
this.chart.update();
}
In the above I have tried various combinations of labels, x values, y values, data shapes, but I only even get an empty graph.
Perhaps this is not really possible (I am trying to use the wrong component).
How can I achieve this using chartjs?
Update
Using example from #winner_joiner below, I have put a copy of it at plunkr and have tried to use the time in the x axis, but can see it is still not plotting the bars using the dates as the length
Well your code basically works, here a slightly modified version of your code.
After your comments and updated question, I reworke the example (seen below). Although it is possible to do with chart.js the question is, maybe for this specific task a different library or solution would be better/more convenient.
Update Chart, with some similar values from your question:
(I'm using here momentjs, since it is recommend usually needed form date/time actions in chartjs, as mentioned in the documentation)
const d0 = moment.duration('07:00:00').asMinutes();
const d1 = moment.duration('09:00:00').asMinutes();
const d2 = moment.duration('10:45:00').asMinutes();
const d3 = moment.duration('17:35:00').asMinutes();
const d4 = moment.duration('19:00:00').asMinutes();
let values = [d0, d1, d2, d3, d4];
let data = {
labels: [''],
datasets: [{
label: 'up',
axis: 'y',
data: [d1],
backgroundColor: 'red',
},{
label: 'down',
axis: 'y',
data: [d2],
backgroundColor: 'yellow',
},{
label: 'out',
axis: 'y',
data: [d3],
backgroundColor: 'green',
},{
label: 'up',
axis: 'y',
data: [d4],
backgroundColor: 'red',
}
]
};
const config = {
data,
type: 'bar',
options:{
plugins: {
tooltip: {
mode: 'dataset',
callbacks: {
label: function(item){
return moment().startOf('day').add({ minute: item.raw}).format('HH:mm');
}
}
},
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
min: d0,
ticks: {
callback: function(value, index, ticks) {
return moment().startOf('day').add({ minute: value}).format('HH:mm');
}
},
afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
},
y: {
stacked: true
},
}
}};
new Chart(document.getElementById("chart"), config);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<script src="//cdn.jsdelivr.net/npm/moment#^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>

Chart.js: Strikethrough tick labels

I'd like to conditionally add a strikethrough to tick labels. As far as I can tell, there's no option to natively do that through Chart.js. Is there a way to hook in through the axes callbacks to add that?
I don't know if that is possible because you are dealing with a canvas element, but you can customize the text in the labels by using the ticks callback as in this example:
new Chart(document.getElementById("bar-chart"), {
type: 'bar',
data: {
labels: ["One", "Two", "Three", "Four", "Five"],
datasets: [
{
label: "A chart",
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
data: [2478, 5267, 734, 784, 433]
}
]
},
options: {
legend: { display: false },
title: {
display: true,
text: 'A chart with columns and custom vertical labels'
},
scales: {
yAxes: [{
ticks: {
callback: function (value, index, values) {
return index % 2 == 0 ? value : '**' + value + '**';
}
}
}]
}
}
});
Note the callback funcion there, maybe you can use this to give some labels a distinctive text.
The chart of this example looks like this:

ChartJS Update specific bar's background colour

I would like to update specific column background colour but I couldn't do this. Seem like it is very easy but all the solution I tried out from google doesn't work. The code is as below.
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels : ["A","B","C","D","E"],
datasets: [{
data : [<?php echo $graph_data;?>],
backgroundColor: "rgba(0,0,220,0.5)",
borderColor: "rgba(0,0,220,1)",
borderWidth: 2
}]
}
});
//I would like to achieve something like this, let's say change the first and second bar's background color
myChart.datasets[0].bars[0].fillColor = "rgba(220,0,0,0.5)";
myChart.datasets[0].bars[1].fillColor = "rgba(220,0,0,0.5)";
myChart.update();
I had an old code which run succesfully under version 1.0.1-beta.4, but now I world like to use the latest version 2.5.0, and then I faced this issue.
Thanks for any helps!
You can just pass an array to the backgroundColor bar chart dataset property (instead of a single color) where the position in the array maps to the position in the data array.
For example, if you have 3 bars and want all 3 to be a different color, just pass an array to backgroundColor where all 3 elements have a different color value.
var ctx = document.getElementById("canvas").getContext("2d");
var myBar = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Car", "Bike", "Walking"],
datasets: [{
label: 'Fuel',
backgroundColor: [
chartColors.red,
chartColors.blue,
chartColors.yellow],
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
]
}]
},
options: {
title: {
display: true,
text: "Chart.js - Different Bar Colors"
},
tooltips: {
mode: 'index',
intersect: false
},
legend: {
display: false,
},
responsive: true,
}
});
Here is a codepen example demonstrating this.