How to style specific gridlines differently in chartJs? - javascript

I am using chartJS to draw a bubble chart with an x axis running from -5 to +5 and a y axis running from -5 to +5. I was able to change the grid line styling using
x: {
grid: {
borderDash: [2, 10],
lineWidth: 1,
color: `#000`,
},
to get this result.
my chart output so far
I need to have the X and Y axis at 0 on both to be solid bold. Is there a way to style gridline at specific tick points?
desired result is this...
desired chart styling

The borderDash option is non scriptable so to achieve this behaviour you will need to use a custom plugin to draw over the default grid lines:
const zeroZeroLines = {
id: 'zeroZeroLines',
beforeDatasetsDraw: (chart, args, opts) => {
const {
ctx,
chartArea: {
top,
bottom,
left,
right
},
scales: {
x,
y
}
} = chart;
const color = opts.color || 'black';
const width = opts.width || 1;
ctx.beginPath();
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.moveTo(x.getPixelForValue(0), bottom);
ctx.lineTo(x.getPixelForValue(0), top);
ctx.moveTo(left, y.getPixelForValue(0));
ctx.lineTo(right, y.getPixelForValue(0));
ctx.stroke();
}
}
const options = {
type: 'bubble',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: -4,
y: 0,
r: 4
}, {
x: 1,
y: -3,
r: 10
}, {
x: 3,
y: 3,
r: 20
}, {
x: 0,
y: 0,
r: 20
}],
backgroundColor: 'pink'
}]
},
options: {
scales: {
x: {
min: -5,
max: 5,
grid: {
borderDash: [2, 2]
}
},
y: {
min: -5,
max: 5,
grid: {
borderDash: [2, 2]
}
}
},
plugins: {
zeroZeroLines: {
color: 'black',
width: 1
}
}
},
plugins: [zeroZeroLines]
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>

Related

Bar dashed chart is overlapping in chartjs

I have data and I am creating a stacked bar chart, I want one of the datasets to be a dashed bar chart.
The live: demo
Here is what I have done so far.
HTML.
<canvas id="myChart"></canvas>
And Js.
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: 'Employee',
backgroundColor: "blue",
data: [12, 59, 5, 56, 58,12, 59, 87, 45],
borderColor:"#45c490",
borderWidth: 0
}, {
label: 'Engineer',
backgroundColor: "orange",
data: [12, 59, 5, 56, 58,12, 59, 85, 23],
borderColor:"#caf270",
borderWidth: 0
}, {
label: 'Government',
backgroundColor: "pink",
data: [12, 59, 5, 56, 58,12, 59, 65, 51],
borderColor: "rgba(255,99,132,1)",
borderWidth: 0
}, {
label: 'Political parties',
backgroundColor: "gray",
data: [12, 59, 5, 56, 58, 12, 59, 12, 74],
borderColor:"#caf270",
borderWidth: 0
}],
},
options: {
tooltips: {
displayColors: true,
callbacks:{
mode: 'x',
},
},
scales: {
xAxes: [{
stacked: true,
gridLines: {
display: false,
}
}],
yAxes: [{
stacked: true,
ticks: {
beginAtZero: true,
},
type: 'linear',
}]
},
responsive: true,
maintainAspectRatio: false,
legend: { position: 'bottom' },
},
plugins: [{
afterDatasetDraw: function(chart, args, options) {
args.meta.data.forEach(function(element) {
var borderWidth = 3;
var ctx = chart.ctx;
var vm = element._view;
var half = vm.width / 2;
var left = vm.x - half;
var right = vm.x + half;
var top = vm.y;
var width = right - left;
var height = chart.chartArea.bottom - top + (borderWidth / 2) - 1;
let label = vm.datasetLabel;
if(label.includes("Government")){
ctx.setLineDash([5,5]);
borderWidth=1;
}else{
ctx.setLineDash([0,0]);
borderWidth=1
}
ctx.beginPath();
ctx.lineWidth = borderWidth;
ctx.strokeStyle = vm.borderColor;
ctx.moveTo(left, top);
ctx.lineTo(left, top + height);
ctx.moveTo(left, top);
ctx.lineTo(left + width, top);
ctx.moveTo(left + width, top);
ctx.lineTo(left + width, top + height);
ctx.stroke();
ctx.save();
});
}
}]
});
I want only if the dataset label is Government then create the dashed bar otherwise just normal
The problem
In the picture above you can see the government dataset has dashed and the blue border.
How can I eliminate this blue border here?
The issue should be in the height calculation because the plugin was thought for no-stacked bar.:
var height = chart.chartArea.bottom - top + (borderWidth / 2) - 1;
As you can see, the height is calculated assuming to go to the bottom of chart area.
You can try the following, overriding the above row:
const valueTop = element._yScale.getValueForPixel(top);
const value = chart.data.datasets[element._datasetIndex].data[element._index];
const bottom = element._yScale.getPixelForValue(valueTop - value);
var height = bottom - top + (borderWidth / 2) - 1;

Draw Circle on EChart

I have the following Apache EChart:
var option = {
series: [
{
name: 'RollPitch',
type: 'gauge',
data: [
{
value: 0,
name: '',
itemStyle: { color: '#CF4437' },
},
],
min: 0,
max: 360,
splitNumber: 4,
splitLine: {
show: false,
},
startAngle: 0,
endAngle: 359.9999999,
axisLine: {
lineStyle: {
color: [[100, '#D8D8D8']],
width: 50,
},
},
axisTick: {
show: false,
},
pointer: {
show: true,
length: '110%',
width: 8,
},
detail: {
show: false,
},
},
],
};
https://echarts.apache.org/examples/en/editor.html?
What I want to achieve is to draw a circle given with x and y coordinates.
Can somebody give me a hint how a possible solution would be achieved?
Shall I draw on the canvas that is created by ECharts? How to map the position?
To draw a shape you can with the two ways:
The custom series (too expensive and complex for this case)
With the graphic component (more suitable option)
In general you need to add the component then setup predefined shape circle and you will have small circle.
var option = {
graphic: [{
elements: [{
id: 'small_circle',
type: 'circle',
z: 100,
shape: {
cx: 350,
cy: 200,
r: 20,
},
style: {
fill: 'rgba(0, 140, 250, 0.5)',
stroke: 'rgba(0, 50, 150, 0.5)',
lineWidth: 2,
}
}]
}]
// series: [...]
}
Bonus: how to update circle coordinates:
var myChart = echarts.init(document.getElementById('main'));
var option = {
graphic: [{
elements: [{
id: 'small_circle',
type: 'circle',
z: 100,
shape: {
// "... draw a circle given with x and y coordinates." — it's here
cx: 350,
cy: 200,
r: 20,
},
style: {
fill: 'rgba(0, 140, 250, 0.5)',
stroke: 'rgba(0, 50, 150, 0.5)',
lineWidth: 2,
}
}]
}],
series: [{
name: 'RollPitch',
type: 'gauge',
data: [{
value: 0,
name: '',
itemStyle: {
color: '#CF4437'
},
}, ],
min: 0,
max: 360,
splitNumber: 4,
splitLine: {
show: false,
},
startAngle: 0,
endAngle: 359.9999999,
axisLine: {
lineStyle: {
color: [
[100, '#D8D8D8']
],
width: 50,
},
},
axisTick: {
show: false,
},
pointer: {
show: true,
length: '110%',
width: 8,
},
detail: {
show: false,
},
}, ],
};
myChart.setOption(option);
/* Taken from https://stackoverflow.com/a/35455786/1597964 */
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return [
centerX + (radius * Math.cos(angleInRadians)),
centerY + (radius * Math.sin(angleInRadians))
]
}
var angle = 90;
setInterval(function() {
var [cx, cy] = polarToCartesian(300, 200, 50, angle);
myChart.setOption({
graphic: [{
id: 'small_circle',
shape: {
cx: cx,
cy: cy,
}
}]
});
angle = angle + 1;
}, 20);
<script src="https://cdn.jsdelivr.net/npm/echarts#4.8.0/dist/echarts.min.js"></script>
<div id="main" style="width: 600px;height:400px;"></div>

Can chart.js display text associated with each point on a line chart that is permanently visible?

Reading https://www.chartjs.org/docs/latest/charts/line.html#general there does not appear to be an option to add a permanently visible label associated with each data point.
For example in below fiddle the data values are:
[{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}]
Can chart.js display some text associated with each point that is permanently visible?
So instead of above data struture use :
[{x: 1, y: 2, text:'Test1'}, {x: 2, y: 4, text:'Test2'}, {x: 3, y: 8, text:'Test3'},{x: 4, y: 16, text:'Test4'}]
The attribute text contains the text data to be displayed for the given point.
Fiddle: https://jsfiddle.net/adrianfiddleuser/0j6L2mag/3/
Fiddle src:
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart"></canvas>
Javascript:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [
{
label: 'test',
data: [{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}],
showLine: true,
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
}
]
},
options: {
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
Update:
This code:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["T", "A", "s" , "sdfs"],
datasets: [
{
label: 'test',
data: [{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}],
showLine: true,
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
}
]
},
options: {
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
Achieves the desired behaviour partially. Can the tooltips be permanently displayed?
Updated fiddle: https://jsfiddle.net/adrianfiddleuser/0j6L2mag/14/
When using the latest stable version of Chart.js (2.9.3), it can be done through global plugins for example.
Please have a look at your amended code below. Note that the option showAllTooltips lets you enable the feature for individual charts in case you you want to include multiple charts with different behavior on the same page.
Chart.plugins.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips,
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
chart.options.tooltips.enabled = false; // turn off normal tooltips
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
if (!chart.allTooltipsOnce) {
if (easing !== 1) {
return;
}
chart.allTooltipsOnce = true;
}
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip.update();
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["T", "A", "s" , "sdfs"],
datasets: [
{
label: 'test',
data: [{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}],
showLine: true,
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
}
]
},
options: {
showAllTooltips: true,
hover: {
mode: 'nearest',
intersect: true
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart"></canvas>

Chart.JS plugin, draw after animation

I'm trying to write a chart.js (v.2.7) plugin to show errorbars on my scatter / line plots.
I managed to get the pixel positions from the chart and draw the errorbars on the canvas, but i cannot get the timing to look right. I want them to appear after the lines animate, then stay attached (& move with) if the datasets are hidden->shown.
I've tried:
The afterDraw / afterDataset(s)Draw / beforeDraw hooks: the error bars are already on the plot before the lines animate (as in example). When hidden->shown, the error bars are in place.
afterRender / afterEvent hook: draws them after the animation finishes, but then redraws them everytime the datasets are hidden->shown (after a pause)
beforeRender / any earlier hooks: gives no errorbars
setTimout() on the draw function, or at various places inside it: does nothing
sleep() before the draw function or other places: slows down the whole animation but the errorsbars are unaffected.
I couldn't find a way to invoke plugin functions after animation or get to then via the options.animation.onComplete
Is there a way to get the errorbars to behave as in the example, but the initial appearance occurs after the line animation (with a plugin?)
var errorbarPlugin = {
calcPoints: function(chartInstance, dataList){
var ds = chartInstance.data.datasets
var meta = chartInstance.getDatasetMeta(0)
var yScale = chartInstance.scales[meta.yAxisID];
var xScale = chartInstance.scales[meta.xAxisID];
var yList = []; var xList = [];
for(var i = 0; i < dataList.length; i++){
var yValue = dataList[i].y
var yPixel = yScale.getPixelForValue(yValue)
yList.push(yPixel)
var xValue = dataList[i].x
var xPixel = xScale.getPixelForValue(xValue)
xList.push(xPixel)
}
return {yList: yList, xList: xList}
},
calcErrorbars: function(chartInstance, ds_num){
var ds = chartInstance.data.datasets
var data_list = ds[ds_num].data
var isHidden = ds[ds_num]._meta[Object.keys(chartInstance.data.datasets[ds_num]._meta)[0]].hidden;
var yList = this.calcPoints(chartInstance, data_list).yList
var xList = this.calcPoints(chartInstance, data_list).xList
if(ds[ds_num].errors){
var errors = ds[ds_num].errors
} else {errors = 0}
return [xList, yList, errors, isHidden]
},
drawErrorbars: function(chartInstance){
var ctx = chartInstance.chart.ctx
var ds = chartInstance.data.datasets
for(var ds_num = 0; ds_num < ds.length; ds_num++){
var errCalc = this.calcErrorbars(chartInstance, ds_num)
var isHidden = errCalc[3]
var yList = errCalc[1]
var xList = errCalc[0]
var errors = errCalc[2]
var errWidth = 3
var capLen = 5
if(!isHidden){
for(var k = 0; k < xList.length; k++){
ctx.strokeStyle = "red"
ctx.beginPath();
ctx.moveTo(xList[k], yList[k]-errors[k]);
ctx.lineTo(xList[k], yList[k]+errors[k]);
ctx.moveTo(xList[k]-capLen, yList[k]+errors[k]);
ctx.lineTo(xList[k]+capLen, yList[k]+errors[k]);
ctx.moveTo(xList[k]-capLen, yList[k]-errors[k]);
ctx.lineTo(xList[k]+capLen, yList[k]-errors[k]);
ctx.stroke()
}
}
}
},
afterDatasetsDraw: function(chartInstance) {
this.drawErrorbars(chartInstance)
},
}
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js"></script>
<script type="text/javascript" src="{% static 'js/charts/errorbarPlugin3.js' %}"></script>
<div id="canvas-holder" class="col-sm-3">
<canvas id="chart-gamma" width="200" height="200"/></canvas>
</div>
<script defer>
var gammaChartData = {
datasets: [
{
label: 'Red',
data: [{x: 15, y: 30}, {x: 35, y: 17}, {x: 55, y: 37}, {x: 72, y: 45},],
borderColor: "red",
errors: [10, 28, 30, 34],
},
]
}
var ctx_gamma = document.getElementById("chart-gamma").getContext("2d");
window.onload = function() {
var gamma_chart = new Chart(ctx_gamma, {
type: 'scatter',
data: gammaChartData,
plugins: [errorbarPlugin],
options: {showLines: true},
});
};
</script>
</body>
</html>
Edit: shortened snippet by removing formatting and default options
Here's what I came up with (snippet below)
The errorbars can either be fixed to the data or shown independantly, and animate in / are hidden / revealed with the data.
The plugin can add x or y axis errors, repesented as bars (with/without caps) or ovals / circles (filled or transparent).
"use strict";
var errorbarPlugin = {
afterDraw: function (chart) {
var type = chart.config.type;
var plugConfig = chart.config.options.errorbarPlugin;
if (plugConfig) {
if (plugConfig.showErrors) {
var showErrors = plugConfig.showErrors;
}
}
else
showErrors = true;
if (showErrors !== false) {
if (["line", "scatter"].includes(type)) {
errorbarPlugin.scatterErrorbars(chart);
}
else if (type == "bar") {
console.log("Bar charts not supported yet");
}
}
},
scatterErrorbars: function (chart) {
var ctx = chart.ctx;
var plugConfig = chart.config.options.errorbarPlugin;
chart.data.datasets.forEach(function (dataset, i) {
var ds = dataset;
var meta = chart.getDatasetMeta(i);
var showErrors;
(ds.showErrors === false) ? showErrors = false : showErrors = true;
var errWidth;
(ds.errWidth) ? errWidth = ds.errWidth : errWidth = 1;
var showCap;
(ds.showCap) ? showCap = ds.showCap : showCap = true;
var capLen;
(ds.capLen) ? capLen = ds.capLen : capLen = 3;
var errStyle;
(ds.errStyle) ? errStyle = ds.errStyle : errStyle = "T";
var errFillColor;
(ds.errFillColor) ? errFillColor = ds.errFillColor : errFillColor = "rgba(0,0,0,0)";
if (!meta.hidden && showErrors) {
meta.data.forEach(function (element, index) {
var x_point = element._model.x;
var y_point = element._model.y;
var errColor;
(ds.errColor) ? errColor = ds.errColor : errColor = element._view.borderColor;
var dataPoint = ds.data[index];
var yError;
var xError;
if (typeof (dataPoint) === "object" && 'r' in dataPoint) {
yError = dataPoint.r;
}
else if (ds.errors) {
yError = ds.errors[index];
}
else {
yError = null;
}
if (typeof (dataPoint) === "object" && dataPoint.e) {
xError = dataPoint.e;
}
else if (ds.xErrors) {
xError = ds.xErrors[index];
}
else {
xError = null;
}
var position = element.tooltipPosition();
if (errStyle == "circle") {
ctx.beginPath();
ctx.arc(position.x, position.y, yError, 0, 2 * Math.PI, false);
if (ds.hidden === true && meta.hidden === null) {
ctx.strokeStyle = "rgba(0,0,0,0)";
ctx.fillStyle = "rgba(0,0,0,0)";
}
else {
ctx.strokeStyle = errColor;
ctx.fillStyle = errFillColor;
}
console.log(meta.hidden);
ctx.fill();
ctx.stroke();
}
else if (errStyle == "oval" || errStyle == "ellipse") {
if (xError) {
var scaleFac = (xError) / yError;
}
else
scaleFac = 10 / yError;
ctx.beginPath();
ctx.save();
ctx.scale(scaleFac, 1);
ctx.arc(position.x / scaleFac, position.y, yError, 0, 2 * Math.PI, false);
ctx.restore();
if (ds.hidden === true && meta.hidden === null) {
ctx.strokeStyle = "rgba(0,0,0,0)";
}
else {
ctx.strokeStyle = errColor;
}
ctx.stroke();
}
else {
ctx.beginPath();
ctx.moveTo(position.x, position.y - yError);
ctx.lineTo(position.x, position.y + yError);
if (xError) {
ctx.moveTo(position.x - xError, position.y);
ctx.lineTo(position.x + xError, position.y);
}
if (ds.hidden === true && meta.hidden === null) {
ctx.strokeStyle = "rgba(0,0,0,0)";
}
else {
ctx.strokeStyle = errColor;
}
ctx.stroke();
if (showCap) {
ctx.beginPath();
ctx.moveTo(position.x - capLen, position.y - yError);
ctx.lineTo(position.x + capLen, position.y - yError);
ctx.moveTo(position.x - capLen, position.y + yError);
ctx.lineTo(position.x + capLen, position.y + yError);
if (xError) {
ctx.moveTo(position.x - xError, position.y - capLen);
ctx.lineTo(position.x - xError, position.y + capLen);
ctx.moveTo(position.x + xError, position.y - capLen);
ctx.lineTo(position.x + xError, position.y + capLen);
}
ctx.stroke();
}
}
});
}
});
}
};
<!DOCTYPE html>
<!--DOCTYPE html -->
<html>
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js'></script>
<body>
<div style = "position:relative;
width:60%;" >
<div id="canvas-holder" class="col-sm-6">
<canvas id="chart-gamma" width="500" height="500"/></canvas>
</div>
<div id="canvas-holderbf2" class="col-sm-6">
<canvas id="chart-humid" width="500" height="500"/></canvas>
</div>
<script defer>
Chart.defaults.global.legend.display = true
Chart.defaults.global.legend.position = 'right'
// Chart.defaults.global.legend.onHover = function(){}
// Chart.defaults.global.legend.onClick = function(){}
Chart.defaults.global.legend.labels.usePointStyle = true
Chart.defaults.global.legend.labels.fontsize = 12
Chart.defaults.global.legend.labels.padding = 10
var gammaChartData = {
datasets: [
{
label: 'Eu',
data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
borderColor: "red",
//fillColor: "pink",
errors: [15, 20, 30, 12, 10, 10],
xErrors: [3, 7, 16, 12, 12, 30, 10],
//hidden: true,
errColor: "blue",
errStyle: "circle",
errFillColor: "pink",
hidden: true,
errWidth: 2,
showCap: true,
capLen: 3,
showErrors: true,
},
{
label: 'Am',
data: [{x: 15, y: 85, r: 14}, {x: 25, y: 37, r: 8}, {x: 62, y: 135, r: 44},],
borderColor: "blue",
errColor: "red",
errStyle: "circle",
showErrors: true,
},
]
}
var options_gamma = {
animation: {
duration: 1000,
},
errorbarPlugin: {
showErrors: true,
marginsOfError: [100, 50, 10],
},
elements: {
line: { fill: false,
borderWidth: 1,
},
point: { radius: 0,
pointStyle: 'circle',
borderWidth: 1,
hitRadius: 18, //size if should hover
// hoverBorderWidth: 13,
hoverRadius: 10, //size when hovered
},
},
annotation: {
annotations: [{
id: 'h-line-01', // optional
type: 'line',
mode: 'horizontal',
scaleID: 'y-axis-0',
value: '125',
borderColor: 'red',
borderDash: [2, 2],
borderWidth: 2,
label: {
enabled: true,
backgroundColor: 'rgba(255,255,255,1)', // Background color of label, default below
//fontFamily: "sans-serif", // Font family of text, inherits from global
fontStyle: "normal", // Font style of text, default "bold"
fontSize: 12, // Font size of text, inherits from global
fontColor: "red",// Font color of text, default below
xPadding: 5,// Padding of label to add top/bottom, default below
yPadding: 5,// Radius of label rectangle, default below
cornerRadius: 10, // Anchor position of label on line, can be one of: top, bottom, left, right, center. Default below.
position: "left", // Adjustment along x-axis (left-right) of label relative to above number (can be negative)
// For horizontal lines positioned left or right, negative values move the label toward the edge, and negative values toward the center.
xAdjust: 290, // Adjustment along y-axis (top-bottom) of label relative to above number (can be negative)
// For vertical lines positioned top or bottom, negative values move the label toward the edge, and negative values toward the center.
yAdjust: 0, // Whether the label is enabled and should be displayed
// Text to display in label - default is null
content: "Max"
},
onClick: function(e) { // Fires when the user clicks this annotation on the chart (be sure to enable the event in the events array below).
}
}],
},
responsive: true,
showLines: true,
hoverMode: 'single', // should always use single for a scatter chart
legend: {},
scales: {
yAxes: [{
display: true,
position: 'left',
id: 'y-axis-0',
ticks: {min: 0, //beginAtZero:true,
max: 200,
//display: true,
//fontColor: "black"
},
scaleLabel: {display: true, labelString: 'Number'},
gridLines: {color: "black",
//display: true,
drawOnChartArea: false,
zeroLineColor: "black",
//drawTicks: true,
},
}],
xAxes: [{
display: true,
type: 'linear',
id: 'x-axis-0',
position: 'bottom',
ticks: {min: 0,
max: 100,
//display: true,
//fontColor: "black",
},
scaleLabel: {display: true, labelString: 'Volume'},
gridLines: {color: "black",
zeroLineColor: "black",
drawOnChartArea: false,
},
}],
},
}
var ctx_gamma = document.getElementById("chart-gamma").getContext("2d");
var humidChartData = {
datasets: [
{
label: 'B errors',
data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
borderColor: "green",
errors: [15, 20, 30, 12, 10, 10],
xErrors: [3, 7, 16, 12, 12, 30, 10],
errStyle: "oval",
showLine: false,
errColor: "border",
//pointBackgroundColor: "white",
//pointBordercolor: "white",
backgroundColor: "rgba(0,0,0,0)",
hidden: true,
errWidth: 2,
showCap: true,
capLen: 3,
radius: 0,
showErrors: true,
},
{
label: 'B trend',
data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
borderColor: "green",
errors: [15, 20, 30, 12, 10, 10],
xErrors: [3, 7, 16, 12, 12, 30, 10],
pointStyle: "line",
showErrors: false,
radius: 0,
},
{
label: 'B data',
data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
borderColor: "green",
backgroundColor: "green",
errors: [15, 20, 30, 12, 10, 10],
xErrors: [3, 7, 16, 12, 12, 30, 10],
showErrors: false,
showLine: false,
},
{
label: '',
data: [],
borderColor: "rgba(0,0,0,0)",
backgroundColor: "rgba(0,0,0,0)",
},
{
label: 'C data',
data: [{x: 15, y: 85, r: 14}, {x: 25, y: 37, r: 8}, {x: 62, y: 135, r: 44},],
borderColor: "blue",
backgroundColor: "rgba(0,0,0,0)",
xErrors: [3, 7, 16, 12, 12, 30, 10],
showLine: true,
showErrors: true,
},
]
}
var options_humid = {
hoverMode: 'single',
elements: {
line: { fill: false,
borderWidth: 2,
},
point: { radius: 3,
pointStyle: 'circle',
borderWidth: 1,
hitRadius: 0,
// hoverBorderWidth: 13,
hoverRadius: 9,
},
},
responsive: true,
showLines: true,
hoverMode: 'single', // should always use single for a scatter chart
legend: {
labels: {
usePointStyle: true,
// generateLabels: function() { }
}
},
scales: {
yAxes: [{
display: true,
position: 'left',
id: 'y-axis-0',
ticks: {min: 0, //beginAtZero:true,
max: 300 },
scaleLabel: {display: true, labelString: 'Number'},
gridLines: {zeroLineColor: "black", },
}],
xAxes: [{
display: true,
type: 'linear',
id: 'x-axis-0',
position: 'bottom',
ticks: {min: 0,
max: 200 },
scaleLabel: {display: true, labelString: 'Month'},
gridLines: {zeroLineColor: "black", },
}],
},
}
var ctx_humid = document.getElementById("chart-humid").getContext("2d");
window.onload = function() {
var humidChart = new Chart(ctx_humid, {
type: 'line',
data: humidChartData,
plugins: [errorbarPlugin],
options: options_humid,
});
var gamma_chart = new Chart(ctx_gamma, {
type: 'scatter',
data: gammaChartData,
plugins: [errorbarPlugin],
options: options_gamma,
});
};
</script>
</div>
</body>
</html>
I had a similar issue with rendered text in
plugins:[{
afterDatasetsDraw: function(chart, options) {
var ctx = chart.ctx;
ctx.font = Chart.defaults.global.defaultFontStyle;
ctx.fillStyle = "#666666";
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
chart.data.datasets.forEach(function(dataset, i) {
var meta = chart.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y);
});
});
}
}]
To fix, inside the meta.data.forEach(function (bar, index) { ... } loop, simply use:
var position = bar.tooltipPosition();
ctx.fillText(Math.round(dataset.data[index]), position.x, position.y);
(This is in #Yobmod's post, but it seems the key is to use the bar.tooltipPosition() location for the location of whatever is rendered.)

Intersection point in line graph in Chart.js?

Searched a lot about this but din't got any answer on this based on chart.js. I had already asked this question here in which I was using highchart.js and got the solution but now I am using chart.js library and trying to find the solution.
Below is my code I have tried. I need to find the intersection point between these 2 line graphs combo. See the Graph Image .
var config = {
type: 'bar',
data: {
labels: ["Year 0", "Year 1", "Year 2", "Year 3", "Year 4", "Year 5", "Year 6"],
datasets: [{
type: 'line',
label: 'Cost',
data: [150, 15, 25, 14, 10, 7],
borderColor: '#E35500',
fill: false,
lineTension: 0,
borderJoinStyle: 'miter',
}, {
type: 'line',
label: 'Cash Flow',
data: [20, 180, 170, 220, 160, 190],
borderColor: '#FFC000',
fill: false,
lineTension: 0,
borderJoinStyle: 'miter',
xAxes: [{
barPercentage: 0.4
}]
},
{
type: 'line',
label: 'Accumulative Flow',
data: [0, -10, 20, 30, 40, 50],
borderColor: 'red',
fill: false,
lineTension: 0,
borderJoinStyle: 'miter',
xAxes: [{
barPercentage: 0.4
}]
}, {
type: 'bar',
label: 'Benifit(One time)',
backgroundColor: "#005998",
data: [40, 50, 60, 80, 50, 60],
}, {
type: 'bar',
label: 'Benifit(Recurring)',
backgroundColor: "#0FAAFF",
data: [120, 150, 150, 180, 120, 140],
}
]
},
options: {
title: {
display: true,
text: 'Custom Chart Title'
},
scales: {
xAxes: [{
time: {
displayFormats: {
quarter: ' YYYY'
}
},
stacked: true,
beginAtZero: true,
barPercentage: 0.3,
id: 'x-axis-label',
position: 'bottom',
scaleStartValue: 20,
gridLines: {
display: false
},
}],
yAxes: [{
stacked: true,
id: 'y-axis-label',
ticks: {
max: 300,
min: -50,
stepSize: 50,
},
position: 'left',
gridLines: {
display: false
},
}]
},
legend: {
position: 'right'
},
maintainAspectRatio: false,
scaleBeginAtZero: true
}
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, config);
.GraphContain {
max-height: 500px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.0/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<div class="GraphContain">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
Anyone having any idea?? need a genius on this!!!
Here we are )))
https://jsfiddle.net/Falseclock/5nbecn0z/
If you need to show intersections with X axis, then just imitate line with Y=0
https://jsfiddle.net/Falseclock/8g0ucdb1/
var ORDER_STATS = {
"2016" : [10, 181, 194, -56, 130, 181, 179, 189, 30, 60, 193, 154],
"2015" : [124, -50, 152, 187, 10, 164, 129, -16, 115, 119, 129, 171],
"2014" : [-90, 80, 30, 59, 100, -30, 60, 116, 191, 181, -60, 106]
};
var colors = ['206,191,26','119,206,26','26,200,206','236,124,98','206,26,140','26,77,206'];
// Definning X
var ordersChartData = {
labels : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
datasets : []
}
Object.keys(ORDER_STATS).forEach(function (key) {
color = colors.shift();
ordersChartData.datasets.push(
{
label: key,
lineTension: 0,
type: 'line',
backgroundColor: "rgba("+color+",0.1)",
borderColor: "rgba("+color+",1)",
borderWidth: 2,
pointBackgroundColor : "rgba("+color+",1)",
pointBorderColor: "#fff",
pointBorderWidth: 1,
pointRadius: 4,
pointHoverBackgroundColor : "#fff",
pointHoverBorderColor: "rgba("+color+",1)",
pointHoverBorderWidth: 1,
data : ORDER_STATS[key]
}
);
});
var ctx = document.getElementById("myChart").getContext("2d");
Chart.defaults.global.defaultFontColor = 'grey';
Chart.defaults.global.defaultFontFamily = "Tahoma";
Chart.defaults.global.defaultFontSize = 11;
Chart.defaults.global.defaultFontStyle = 'normal';
var myChart = new Chart(ctx, {
type: 'line',
data: ordersChartData,
defaultFontSize: 11,
options: {
responsive: true,
title: {
display: true,
text: 'Intersection realization',
fontColor: "#444",
fontFamily: 'Tahoma',
padding: 0
},
legend: {
display: true,
labels: {
fontColor: 'grey',
usePointStyle: true
}
},
tooltips: {
mode: "index",
intersect: true,
position: 'nearest',
bodySpacing: 4
}
}
});
Chart.plugins.register({
afterDatasetsDraw: function(chartInstance, easing) {
var Y = chartInstance.scales['y-axis-0'];
var X = chartInstance.scales['x-axis-0'];
zeroPointY = Y.top + ((Y.bottom - Y.top) / (Y.ticks.length -1) * Y.zeroLineIndex);
zeroPointX = Y.right;
yScale = (Y.bottom - Y.top) / (Y.end - Y.start);
xScale = (X.right - X.left) / (X.ticks.length - 1);
var intersects = findIntersects(ORDER_STATS['2015'], ORDER_STATS['2014'] );
var context = chartInstance.chart.ctx;
intersects.forEach(function (result, idx) {
context.fillStyle = 'red';
context.beginPath();
context.arc((result.x * xScale) + zeroPointX, (Y.end - Y.start) - (result.y * yScale) - ((Y.end - Y.start) - zeroPointY), 3, 0, 2 * Math.PI, true);
context.fill();
});
}
});
function findIntersects(line1, line2)
{
var intersects = [];
line1.forEach(function(val,idx) {
var line1StartX = idx;
var line1StartY = line1[idx];
var line1EndX = idx + 1;
var line1EndY = line1[idx + 1];
var line2StartX = idx;
var line2StartY = line2[idx];
var line2EndX = idx + 1;
var line2EndY = line2[idx+1];
result = checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY);
if (result.onLine1 && result.onLine2) {
intersects.push(result);
}
});
return intersects;
}
function checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
var denominator, a, b, numerator1, numerator2, result = {
x: null,
y: null,
onLine1: false,
onLine2: false
};
denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
if (denominator == 0) {
return result;
}
a = line1StartY - line2StartY;
b = line1StartX - line2StartX;
numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
a = numerator1 / denominator;
b = numerator2 / denominator;
// if we cast these lines infinitely in both directions, they intersect here:
result.x = line1StartX + (a * (line1EndX - line1StartX));
result.y = line1StartY + (a * (line1EndY - line1StartY));
/*
// it is worth noting that this should be the same as:
x = line2StartX + (b * (line2EndX - line2StartX));
y = line2StartX + (b * (line2EndY - line2StartY));
*/
// if line1 is a segment and line2 is infinite, they intersect if:
if (a > 0 && a < 1) {
result.onLine1 = true;
}
// if line2 is a segment and line1 is infinite, they intersect if:
if (b > 0 && b < 1) {
result.onLine2 = true;
}
// if line1 and line2 are segments, they intersect if both of the above are true
return result;
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
<canvas id="myChart" width="650" height="241" style="display: block; width: 650px; height: 241px;"></canvas>

Categories