Chartjs Custom Legend with Time on Y-axis - javascript

I am creating a very simple chart with chart.js and stuck with the two small issues.
Below is the code that I am using to create the chart/graph
<div style="width: 400px; height: 400px;">
<canvas name="myChart" id="myChart" width="400px" height="400px"> </canvas>
</div>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
animation: false,
data: {
labels: ["Service A", "Service B", "Service C"],
datasets: [{
label: 'Time In Service',
data: [180, 360, 180],
backgroundColor: [
'#0073CF',
'#FF0000',
'#7DC24B'
],
borderColor: [
'#fff',
'#fff',
'#fff'
],
borderWidth: 2
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
The current chart can be seen here Chart Generated
What is Need is something like Chart Needed
I want the x-axis labels in legend on right side
Currently the time is in seconds in data. I want to Show time spend on x-axis in hours:min
Any little help will be appreciated.

Have a try like this,
Need to modify your data structure a little and set the y=axis properties for displaying the required label format.
P.S : you need to use the latest chart.js library since the position right functionality was recently added and also i have increased the second value in your given example to display some meaningful data in hh:mm format.
function formatTime(secs)
{
var hours = Math.floor(secs / (60 * 60));
var divisor_for_minutes = secs % (60 * 60);
var minutes = Math.floor(divisor_for_minutes / 60);
var divisor_for_seconds = divisor_for_minutes % 60;
var seconds = Math.ceil(divisor_for_seconds);
return hours + ":" + minutes;
}
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
animation: false,
data: {
labels: ["Time"],
datasets: [{
label: "Service A",
data: [1800],
backgroundColor: '#0073CF',
borderColor: '#fff',
borderWidth: 2
},
{
label: "Service B",
data: [36000],
backgroundColor: '#FF0000',
borderColor: '#fff',
borderWidth: 2
},
{
label: "Service C",
data: [8000],
backgroundColor: '#7DC24B',
borderColor: '#fff',
borderWidth: 2
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
callback: function(label, index, labels) {
return formatTime(label);
}
}
}]
},
legend: {
position: "right",
display:true
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<div style="width: 400px; height: 400px;">
<canvas name="myChart" id="myChart" width="400px" height="400px"> </canvas>
</div>

Related

How to get radar chart coordinates using getValueForDistanceFromCenter with Chart.js?

I am experimenting with Chart.js to build radar charts. I mastered the basics (see basic chart below), but I would like to use the x y coordinates of the graph to place texts directly on the canvas.
After some digging, I found out that it is not possible to use getValueForPixel or getPixelForTick in a radar chart. See this github issue. In the connecting thread, a new method getValueForDistanceFromCenter is introduced.
As I understand it, it would be possible to calculate the distance from the center with this method, and use it to get coordinates. I searched the Chart.js documentation and other sites, but cannot find any code examples or information on how to implement this.
Can somebody point me in the right direction how to implement the method in the code?
var data = {
labels: ["Ball Skills", "Shooting", "Physical"],
datasets: [{
label: [`ikke`, `jij`],
backgroundColor: "rgba(38,120,255,0.2)",
borderColor: "rgba(38,120,255, 1)",
data: [90, 90, 90]
}]
};
var options = {
responsive: true,
tooltips: false,
title: {
text: 'Basic example',
display: true,
position: `bottom`,
},
scale: {
angleLines: {
display: true
},
ticks: {
suggestedMin: 0,
suggestedMax: 100,
stepSize: 25,
maxTicksLimit: 11,
display: false,
}
},
legend: {
labels: {
padding: 10,
fontSize: 14,
lineHeight: 30,
},
},
};
var myChart = new Chart(document.getElementById("chart"), {
type: 'radar',
data: data,
options: options
});
The radialLinear scale (in version 2.9.4 that I have seen your are using version 2) there is the method getValueForDistanceFromCenter(value) to get the distance from center but there is another method getPointPositionForValue(index, value) which can provide you the point at a specif index of your data.
To use them and to draw what you want on chart using those points, you need to implement a plugin.
In the below snippet, I'm drawing a rect between the points at a specific value.
const ctx = document.getElementById("myChart");
const data = {
labels: ["Ball Skills", "Shooting", "Physical"],
datasets: [{
label: [`ikke`, `jij`],
backgroundColor: "rgba(38,120,255,0.2)",
borderColor: "rgba(38,120,255, 1)",
data: [50, 50, 50]
}]
};
const options = {
responsive: true,
tooltips: false,
title: {
text: 'Basic example',
display: true,
position: `bottom`,
},
scale: {
angleLines: {
display: true
},
ticks: {
suggestedMin: 0,
suggestedMax: 100,
stepSize: 25,
maxTicksLimit: 11,
display: false,
}
},
legend: {
labels: {
padding: 10,
fontSize: 14,
lineHeight: 30,
},
},
};
const plugin = {
id: 'getDistance',
afterDraw(chart) {
const c = chart.ctx;
const rScale = chart.scale;
c.save();
chart.data.datasets[0].data.forEach(function(item, index) {
const point = rScale.getPointPositionForValue(0.5 + index, 50);
c.beginPath();
c.fillStyle = 'red';
c.fillRect(point.x - 5, point.y - 5, 10, 10);
c.fill();
});
c.restore();
}
};
const myChart = new Chart(ctx, {
type: 'radar',
plugins: [plugin],
data: data,
options: options
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"/>
</div>
</body>
</html>

Chart.js : How I change the x axes ticks labels alignment in any sizes?

How can I move my labels on my x axes in between another x axes label. Nothing seems to work and I was unable to find anything on the docs. Is there a workaround? I'm using line chart time series.
https://www.chartjs.org/samples/latest/scales/time/financial.html
Currently, with the code I have its generating the figure below:
var cfg = {
elements:{
point: {
radius: 4
}
},
data: {
datasets: [
{
label: 'vsy',
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
borderColor: window.chartColors.red,
data: firstData,
type: 'line',
pointRadius: 2,
fill: false,
lineTension: 0,
borderWidth: 2
},
{
label: 'de vsy',
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
borderColor: window.chartColors.blue,
data: dataMaker(15),
type: 'line',
pointRadius: 2,
fill: false,
lineTension: 0,
borderWidth: 2
}
],
},
options: {
animation: {
duration: 0
},
scales: {
xAxes: [{
type: 'time',
distribution: 'series',
offset: true,
time: {
unit: 'month',
displayFormats: {
month: 'MMM'
}
},
ticks: {
autoSkip: true,
autoSkipPadding: 75,
sampleSize: 100
},
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index',
}
}
};
This is what I have now:
I want the labels on the x-axis to be on center instead of below the y axis grid line.
Thanks to uminder, with his comment it solves the issue but now I have a conflicting tooltip which lie on a same grid. When I hover to april line first point it shows me mar 30 which lies just above it and vice versa.
I fixed it by changing the mode to nearest but why is it activating the another point?
The option you're looking for is offsetGridLines.
If true, grid lines will be shifted to be between labels.
xAxes: [{
...
gridLines: {
offsetGridLines: true
}
In most cases, this produces the expected result. Unfortunately it doesn't work for time axes as documented in Chart.js issue #403. Thanks to Antti Hukkanen, there exists a workaround.
Please have a look at below runnable code snippet to see how it works.
function generateData() {
var unit = 'day';
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomPoint(date, lastClose) {
var open = randomNumber(lastClose * 0.95, lastClose * 1.05).toFixed(2);
var close = randomNumber(open * 0.95, open * 1.05).toFixed(2);
return {
t: date.valueOf(),
y: close
};
}
var date = moment().subtract(1, 'years');
var now = moment();
var data = [];
for (; data.length < 600 && date.isBefore(now); date = date.clone().add(1, unit).startOf(unit)) {
data.push(randomPoint(date, data.length > 0 ? data[data.length - 1].y : 30));
}
return data;
}
var TimeCenterScale = Chart.scaleService.getScaleConstructor('time').extend({
getPixelForTick: function(index) {
var ticks = this.getTicks();
if (index < 0 || index >= ticks.length) {
return null;
}
// Get the pixel value for the current tick.
var px = this.getPixelForOffset(ticks[index].value);
// Get the next tick's pixel value.
var nextPx = this.right;
var nextTick = ticks[index + 1];
if (nextTick) {
nextPx = this.getPixelForOffset(nextTick.value);
}
// Align the labels in the middle of the current and next tick.
return px + (nextPx - px) / 2;
},
});
// Register the scale type
var defaults = Chart.scaleService.getScaleDefaults('time');
Chart.scaleService.registerScaleType('timecenter', TimeCenterScale, defaults);
var cfg = {
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
backgroundColor: 'red',
borderColor: 'red',
data: generateData(),
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2
}]
},
options: {
animation: {
duration: 0
},
scales: {
xAxes: [{
type: 'timecenter',
time: {
unit: 'month',
stepSize: 1,
displayFormats: {
month: 'MMM'
}
},
gridLines: {
offsetGridLines: true
}
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index'
}
}
};
var chart = new Chart('chart1', cfg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart1" height="90"></canvas>
For chartJs v3 you can use offset property:
scales: {
x: {
grid: {
offset: true
}
},
...
}

Chart displaying values outside the min and max ranges (Chart.js)

When I set a min and max value for my chart it still displays all the MIN values squished up to the left of my graph, but the max values disappear as they should.
HTML
<div id="graph">
<canvas id="line-chart" width="400" height="225"></canvas>
</div>
<button id="12hours">12 Hours</button>
<button id="24hours">24 Hours</button>
JS
function displayGraph(object)
{
timestamp = getDataForGraph(object, 'timestamp');
temp1 = getDataForGraph(object, 'temp1');
temp2 = getDataForGraph(object, 'temp2');
temp3 = getDataForGraph(object, 'temp3');
var mychart = new Chart(document.getElementById("line-chart"), {
type: 'line',
data: {
labels: timestamp,
datasets: [{
data: temp1,
label: "Temp 1",
borderColor: "#ff0000",
fill: false
}, {
data: temp2,
label: "Temp 2",
borderColor: "#3bff00",
fill: false
}, {
data: temp3,
label: "Temp 3",
borderColor: "#00edff",
fill: false
}
]
},
options: {responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
ticks: {
fontSize: 5
},
type: 'time',
time: {
unit: 'hour',
displayFormats: {
hour: 'HH:mm:ss'
}
}
}],
yAxes: [{
ticks: {
fontSize: 5
}
}]
}
}
});
$('#12hours').off().on('click', function () {
mychart.options.scales.xAxes[0].time.min = '2018-10-29 08:00:00';
mychart.options.scales.xAxes[0].time.max = '2018-10-29 20:00:00';
mychart.update();
});
$('#24hours').off().on('click', function () {
mychart.options.scales.xAxes[0].time.min = '2018-10-29 00:00:00';
mychart.options.scales.xAxes[0].time.max = '2018-10-29 23:59:59';
mychart.update();
});
}
Current output when using min and max values.
would like to get rid of all the values before 08:00 that are showing up on the left hand side of the axes.
What it looks like when max and min are placed
What it looks like with no max or min placed

RGraph with missing data points

I want to plot an area fill line chart with multiple series, using javascript & RGraph, for a period between two dates, but I do not have data points for every date; how do I do this with RGraph?
I cannot miss out dates in the data I pass to RGraph because although some of the series do not have that data, it might be that other series do (e.g. ABC has data for January and March, and XYZ has data for January and April).
I must have all dates for the year, which is represented with a horizontal axis showing just the month/period labels.
I have boiled this down to a simplified example below, and with a jsFiddle example on https://jsfiddle.net/Abeeee/25m1sc7d/1/
Both the code below and the JSFiddle show two charts controlled by the drawAll() function, which has a variable x in it. I want the second chart (cvs2) which uses x=null to not include plotting that null but simply draw the red line/area between 100 and 200, resulting a similar chart to the first one (cvs1).
<!DOCTYPE HTML>
<html>
<head>
<script src='https://www.rgraph.net/libraries/RGraph.common.core.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.dynamic.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.effects.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.key.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.tooltips.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.drawing.rect.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.line.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'>
</script>
</head>
<body>
<canvas id='cvs1' width='900' height='300' style='border:solid 1pt red'>
[No canvas support]
</canvas>
<hr>
<canvas id='cvs2' width='900' height='300' style='border:solid 1pt blue'>
[No canvas support]
</canvas>
<script type='text/Javascript'>
drawAll();
$(window).resize(function() {
drawAll();
});
function drawAll() {
var x=150;
var data = [[0, 50, 100, x, 200],[10,20,30,40,50]];
drawChart('cvs1', data);
x=null;
var data = [[0, 50, 100, x, 200],[10,20,30,40,50]];
drawChart('cvs2', data);
}
function drawChart(canvasId, data) {
var canvas = document.getElementById(canvasId);
RGraph.Reset(canvas);
canvas.width = $(window).width() * 0.9;
var text_size = Math.min(10, ($(window).width() / 1000) * 20 );
var linewidth = $(window).width() > 500 ? 2 : 1;
linewidth = $(window).width() > 750 ? 3 : linewidth;
var line = new RGraph.Line(canvasId, data);
line.set('chart.text.size', text_size);
line.Set('chart.background.barcolor1', 'rgba(255,255,255,1)');
line.Set('chart.background.barcolor2', 'rgba(255,255,255,1)');
line.Set('chart.background.grid.color', 'rgba(238,238,238,1)');
line.Set('chart.colors', [ 'red', 'green', 'blue']);
line.Set('chart.linewidth', 1);
line.Set('chart.hmargin', 15);
line.Set('chart.labels', ['Q1\n2017','Q2','Q3','Q4','Q1\n2018']);
line.Set('chart.gutter.left',40);
line.Set('chart.gutter.right',10);
line.Set('chart.gutter.bottom',50);
line.Set('chart.filled', true);
line.Set('chart.filled.accumulative',true);
line.Set('chart.key', ['ABC', 'DEF']);
line.Set('chart.tickmarks.dot.color','white');
line.Set('chart.backgroundGridAutofitNumvlines',data.length);
line.Set('key.position','gutter'); // or graph
line.Set('chart.ymin',0);
line.Set('chart.ymax',250);
line.Set('chart.numyticks',5);
line.Set('chart.key.position.x',50);
line.Set('chart.key.position.y',10);
line.draw();
}
</script>
</body>
</html>
So, how do you tell RGraph to just draw the points with data and ignore those without whilst keeping all the date points?
Thanks
Abe
You can use null values in your data. The behaviour is slightly different for a single dataset vs multiple data sets though:
var data = [4,8,6,3,5,4,2,null,8,6,3,5,8,null,4,9,8];
Well it seems that RGraph doesn't do it, so I've resorted to ChartJS and on the whole it works - see https://jsfiddle.net/Abeeee/6xrk1m23/41/
<script type='text/JavaScript' src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.js'></script>
<div style="width:100%; height:300px">
<canvas id="canvas" style='width:100%; height:300px'></canvas>
</div>
<button id='on'>
Span Gaps=true
</button>
<button id='off'>
Span Gaps=false
</button>
var config = {
type: 'line',
data: {
labels: ['Jan\n2018', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [{
label: 'Red',
borderColor: '#FF0000',
backgroundColor: '#FF0000',
data: [
10, 20, 30, 40, 50, 60, undefined, 80, 90, 100, 90, 80
],
}, {
label: 'Blue',
borderColor: '#0000FF',
backgroundColor: '#0000FF',
data: [
10, 20, undefined, 40, 50, 60, 70, 80, 92, undefined, 90, 80
],
}]
},
options: {
spanGaps: true,
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'Chart.js Line Chart - Stacked Area'
},
tooltips: {
mode: 'index',
},
hover: {
mode: 'index'
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
}
}
};
var ctx1 = document.getElementById('canvas').getContext('2d');
var myChart = new Chart(ctx1, config);
$("#on").on("click", function() {
myChart.options.spanGaps=true;
myChart.update();
});
$("#off").on("click", function() {
myChart.options.spanGaps=false;
myChart.update();
});
Use the buttons to switch spanGaps on and off.
Note, I say on the whole, as it fixes my problem (of underlying data gaps), but it seems to fail to span if the dataset is sitting on top of another (a ChartJS bug perhaps?)

Make Chart.js horizontal bar labels multi-line

Just wondering if there is any way to set the horizontal bar labels for y-axis using chart.js. Here is how I set up the chart:
<div class="box-body">
<canvas id="chart" style="position: relative; height: 300px;"></canvas>
</div>
Javascript:
var ctx = document.getElementById('chart').getContext("2d");
var options = {
layout: {
padding: {
top: 5,
}
},
responsive: true,
animation: {
animateScale: true,
animateRotate: true
},
};
var opt = {
type: "horizontalBar",
data: {
labels: label,
datasets: [{
data: price,
}]
},
options: options
};
if (chart) chart.destroy();
chart= new Chart(ctx, opt);
chart.update();
As you all can see, the first and third labels are too long and cut off. Is there a way to make the label multi-line?
If you want to have full control over how long labels are broken down across lines you can specify the breaking point by providing labels in a nested array. For example:
var chart = new Chart(ctx, {
...
data: {
labels: [["Label1 Line1:","Label1 Line2"],["Label2 Line1","Label2 Line2"]],
datasets: [{
...
});
You can use the following chart plugin :
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
add this followed by your chart options
ᴜꜱᴀɢᴇ :
add a new line character (\n) to your label, wherever you wish to add a line break.
ᴅᴇᴍᴏ
var chart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: ['Jan\n2017', 'Feb', 'Mar', 'Apr'],
datasets: [{
label: 'BAR',
data: [1, 2, 3, 4],
backgroundColor: 'rgba(0, 119, 290, 0.7)'
}]
},
options: {
scales: {
xAxes: [{
ticks: {
beginAtZero: true
}
}]
}
},
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>

Categories