I want to add shadow for the line in my chart.
My code is like so
import { Line } from 'vue-chartjs'
import Chart from 'chart.js'
let draw = Chart.controllers.line = Chart.controllers.line.extend({
draw: function() {
let ctx = this.chart.chart.ctx;
ctx.save();
ctx.shadowColor = 'red';
ctx.shadowBlur = 12;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 5;
ctx.stroke();
draw.apply(this, arguments);
ctx.restore();
}
});
const BasicLineChart = {
extends: Line,
props: ['data', 'options'],
mounted () {
const options = this.options || {
responsive: true,
maintainAspectRatio: false,
borderWidth: 1,
legend: {
display: false
},
scales: {
yAxes: [{
position: 'right',
scaleLabel: {
display: false,
labelString: 'Pris',
fontFamily: 'apercu-light',
},
gridLines: {
display:true,
color: 'rgba(255, 255, 255, 0.6)'
},
ticks: {
beginAtZero:false,
mirror: true
}
}],
xAxes: [{
ticks: {
display: true,
},
scaleLabel: {
display: false,
},
gridLines: {
display:true,
color: 'rgba(255, 255, 255, 0.6)'
}
}]
}
}
this.renderChart(this.data, options)
}
}
export default {
props: ['id'],
components: {
BasicLineChart,
},
created() {
this.draw()
},
data() {
return {
chartData: {},
showChart: false
}
},
methods: {
draw() {
axios.get('url/' + this.id).then(({ data })=> {
this.showChart = true;
})
}
}
};
With that code I was able to add the shadow for line. However the grids for added blue shadow as well, which is not desired behavior. The grids should not have any shadow.
The screen shot of the shadow on grids and line. Notice the slighly blue shade along the grids line? I want to get rid of it
What could be done to get rid of the shadow on the grids ?
UPDATED:
I updated the code as suggested. I got this error
app.js?v=79:76561 Uncaught TypeError: this.chart.getDatasetMeta is not a function
at ChartElement.getMeta (app.js?v=79:76561)
at ChartElement.linkScales (app.js?v=79:76545)
at ChartElement.initialize (app.js?v=79:76535)
at ChartElement.Chart.DatasetController (app.js?v=79:76514)
at ChartElement [as constructor] (app.js?v=79:5711)
at ChartElement [as constructor] (app.js?v=79:5711)
at ChartElement.draw (app.js?v=79:71285)
at Chart.drawDataset (app.js?v=79:76122)
at Chart.drawDatasets (app.js?v=79:76097)
at Chart.draw (app.js?v=79:76061)
Try changing Chart.controllers.line.extend to this:
Chart.controllers.line = Chart.controllers.line.extend({
draw: function() {
let ctx = this.chart.chart.ctx;
ctx.save();
ctx.shadowColor = 'red';
ctx.shadowBlur = 12;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 5;
ctx.stroke();
draw.apply(this, arguments);
ctx.restore();
}
});
to avoid stroke() method stay redefined also for gridlines drawing.
Check this example (non vue.js): https://jsfiddle.net/beaver71/aorgfd0z/
let draw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function () {
let ctx = this.chart.ctx;
ctx.save();
ctx.shadowColor = "rgba(54, 54, 54, 0.2)";
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 4;
draw.apply(this, arguments);
ctx.restore();
},
});
Use this way, shadows won't appear on your gridlines, also if you are using annotation line then also it won't give any problem to you.
I have implemented this in Vue.js
Related
The Chart.js plugin is super, excellent, beautiful and easily customizable.
But even all this did not help me solve a few problems.
I have to create pixel perfect chart according to design shown on picture 1
I hope for your help!!
How to make those lines that without signatures be longer than those with signatures
I did the indentation from the scales to the graphs using the tickMarkLength parameter, but maybe it’s possible somehow under another, because you can see the overlap of one scale on another.
How to make the grid lines of the left and right scales coincide?
I set beforeUpdate .stepSize, but in spite of the fact that I specify that there should be 8 intervals, sometimes 8, then 9.
There is a link to my current code:
function data_generation(values_obj) {
let max_val=-900;
let min_val=0;
Object.keys(values_obj).forEach(function(key) {
chart_object={};
chart_object.label= values_obj[key].name;
chart_object.data= Object.values(values_obj[key].data);
chart_object.backgroundColor= values_obj[key].color;
if(key == 'TempOutdoor') {
chart_object.yAxisID = 'right-y-axis';
chart_object.backgroundColor= "transparent";
chart_object.pointRadius= 4;
chart_object.lineTension= 0;
chart_object.pointBackgroundColor="#FFF";
chart_object.pointBorderColor= "#60AD5E";
chart_object.borderColor= "#60AD5E";
chart_object.pointBorderWidth= 2;
chart_object.type= 'line';
} else {
chart_object.yAxisID = 'left-y-axis';
chart_object.lineTension= 0;
}
config.data.datasets.push(chart_object);
//find common min and max values
//min
if(min_val>parseFloat(values_obj[key].min)) {
min_val = parseFloat(values_obj[key].min);
}
//max
if(max_val < parseFloat(values_obj[key].max)) {
max_val = parseFloat(values_obj[key].max);
}
});
}
var config = {
drawTicks:false,
type: 'bar',
data: {
datasets: [ ],
labels: ''
},
options: {
animation: {
duration: 0
},
'legend':false,
responsive:true,
maintainAspectRatio: false,
scales: {
xAxes: [{
stacked: true,
barThickness: ($(window).width()<991.99)?14:24,
ticks: {
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines : {
display : false
}
}],
yAxes: [
{
beforeUpdate: function(scale) {
//1 find max and min through all leftlabels
var left_side_list = config.data.datasets.filter(obj => {return obj.yAxisID == "left-y-axis"});
var left_side_list_data = [].concat(...Object.keys(left_side_list).map(e => left_side_list[e].data));
let max_val = Math.max.apply(Math,left_side_list_data);
let min_val = Math.min.apply(Math,left_side_list_data);
// 8 intervals - 9 lines
let left_iterval = (max_val - min_val) / 8;
//set stepsize
scale.chart.options.scales.yAxes[0].ticks.stepSize = left_iterval;
return;
},
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
callback: function(value, index, values) {
if(index % 2 == 0 || index==0) {
return ' ';
} else {
return " "+value.toFixed(0)+" ";
}
}
},
gridLines: {
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
},
{
beforeUpdate: function(scale) {
//var nMaxRev = Math.max.apply(Math,scale.chart.config.data.datasets[1].data);
//get right object data
var temp_list = config.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
//var temp_list = scale.chart.config.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
//console.log(temp_list);
if(temp_list[0].data !== undefined || temp_list[0].data != []) {
var nMaxRev = Math.max.apply(Math, temp_list[0].data);
var nMinRev = Math.min.apply(Math, temp_list[0].data);
var nLeftTickCount = 8;
if(nMinRev<0) {
nLeftTickCount = 7;
}
var nTickInterval = (nMaxRev - nMinRev) / nLeftTickCount;
scale.chart.options.scales.yAxes[1].ticks.stepSize = nTickInterval;
}
return;
},
id: 'right-y-axis',
type: 'linear',
position: 'right',
ticks: {
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
callback: function(value, index, values) {
if(index % 2 == 0 || index==0) {
return '';
} else {
return " "+value.toFixed(0);
}
}
},
gridLines: {
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
}
]
}
}
};
window.onload = function() {
var data_string='{"success":true,"axis":["Пн","Вт","Ср","Чт","Пт","Сб","Вс"],"data":{"TempOutdoor":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":-4.9787234042553195,"Вт":-2.9166666666666665,"Ср":-3.3125,"Чт":2.5208333333333335,"Пт":6.84375,"Сб":0,"Вс":0},"min":"-4.98","max":"6.84","avg":"-0.26","sum":"-1.84","name":"Температура на улице","color":"#60AD5E","value_type":"instant"},"MotoHW":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":11,"Вт":15,"Ср":13,"Чт":12,"Пт":9,"Сб":0,"Вс":0},"min":"0.00","max":"15.00","avg":"8.57","sum":"60.00","name":"Мотогодини: Гаряча вода","color":"#29819D","value_type":"counter"}},"closestPeriods":{"previous":{"2021-05-03 00:00:00":"03.05 - 09.05"},"current":{"2021-05-10 00:00:00":"10.05 - 16.05"},"next":null}}';
var data = JSON.parse(data_string);
config.data.labels = data.axis;
var values_obj = data.data;
data_generation(values_obj);
//console.log(JSON.stringify(config));
var ctx = document.getElementById('StatisticsChartCanvas').getContext('2d');
window.StatisticsChart = new Chart(ctx,config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrapper" style="width:548px; height:265px;">
<canvas id="StatisticsChartCanvas"></canvas>
</div>
After a huge amount of ideas, attempts and errors, I found a solution for the full customization of the scale.
For this I
Disabled the display of gridlines and ticks using property
display:false,
Wrote a plugin that draw gridlines and ticks in accordance with the design.
That's what happened
var AikGridLinePlugin = {
beforeDraw: function(chartInstance) {
var yScaleLeft = chartInstance.scales["left-y-axis"];
var yScaleRight = chartInstance.scales["right-y-axis"];
var canvas = chartInstance.chart;
var ctx = canvas.ctx;
//left axis
var left_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "left-y-axis"});
var left_side_list_data = [].concat(...Object.keys(left_side_list).map(e => left_side_list[e].data));
let left_side_list_max = Math.max.apply(Math,left_side_list_data);
let left_side_list_min = Math.min.apply(Math,left_side_list_data);
let left_iterval = (left_side_list_max - left_side_list_min) / 8;
// right axis
var right_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
var right_side_list_data = [].concat(...Object.keys(right_side_list).map(e => right_side_list[e].data));
let right_side_list_max = Math.max.apply(Math,right_side_list_data);
let right_side_list_min = Math.min.apply(Math,right_side_list_data);
let right_iterval = (right_side_list_max - right_side_list_min) / 8;
var current_value_left = left_side_list_min,
current_value_right = right_side_list_min,
current_value_right_text=0;
for(var i=1;i<10;i++) {
ctx.lineWidth = 1;
ctx.font = "13px Roboto";
ctx.fillStyle = "#666666";
ctx.beginPath();
if(i%2==0) {
ctx.moveTo(47, yScaleLeft.getPixelForValue(current_value_left));
ctx.lineTo((canvas.width-47), yScaleLeft.getPixelForValue(current_value_left));
ctx.fillText((current_value_left>1)?current_value_left.toFixed(0):current_value_left.toFixed(1), 5, yScaleLeft.getPixelForValue(current_value_left)+5);
current_value_right_text=(current_value_right>1 || current_value_right<-1)?current_value_right.toFixed(0):current_value_right.toFixed(1);
ctx.fillText(current_value_right_text, (canvas.width-5-ctx.measureText(current_value_right_text).width), yScaleLeft.getPixelForValue(current_value_left)+5);
} else {
ctx.moveTo(15, yScaleLeft.getPixelForValue(current_value_left));
ctx.lineTo((canvas.width-15), yScaleLeft.getPixelForValue(current_value_left));
}
ctx.strokeStyle = "#91979F";
ctx.stroke();
current_value_left = current_value_left+left_iterval;
current_value_right = current_value_right+right_iterval;
}
return;
}
};
Chart.pluginService.register(AikGridLinePlugin);
function data_generation(values_obj) {
let max_val=-900;
let min_val=0;
Object.keys(values_obj).forEach(function(key) {
chart_object={};
chart_object.label= values_obj[key].name;
chart_object.data= Object.values(values_obj[key].data);
chart_object.backgroundColor= values_obj[key].color;
if(key == 'TempOutdoor') {
chart_object.yAxisID = 'right-y-axis';
chart_object.backgroundColor= "transparent";
chart_object.pointRadius= 4;
chart_object.lineTension= 0;
chart_object.pointBackgroundColor="#FFF";
chart_object.pointBorderColor= "#60AD5E";
chart_object.borderColor= "#60AD5E";
chart_object.pointBorderWidth= 2;
chart_object.type= 'line';
} else {
chart_object.yAxisID = 'left-y-axis';
chart_object.lineTension= 0;
}
config.data.datasets.push(chart_object);
//find common min and max values
//min
if(min_val>parseFloat(values_obj[key].min)) {
min_val = parseFloat(values_obj[key].min);
}
//max
if(max_val < parseFloat(values_obj[key].max)) {
max_val = parseFloat(values_obj[key].max);
}
});
}
var config = {
drawTicks:false,
type: 'bar',
data: {
datasets: [ ],
labels: ''
},
options: {
animation: {
duration: 0
},
'legend':false,
responsive:true,
maintainAspectRatio: false,
scales: {
xAxes: [{
id: 'x-axis',
stacked: true,
barThickness: ($(window).width()<991.99)?14:24,
ticks: {
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines : {
display : false
}
}],
yAxes: [
{
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
display:false,
},
gridLines: {
display : false,
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
},
{
id: 'right-y-axis',
type: 'linear',
position: 'right',
ticks: {
display : false,
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines: {
display : false,
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
}
]
}
}
};
window.onload = function() {
var data_string='{"success":true,"axis":["Пн","Вт","Ср","Чт","Пт","Сб","Вс"],"data":{"TempOutdoor":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":-4.9787234042553195,"Вт":-2.9166666666666665,"Ср":-3.3125,"Чт":2.5208333333333335,"Пт":6.84375,"Сб":0,"Вс":0},"min":"-4.98","max":"6.84","avg":"-0.26","sum":"-1.84","name":"Температура на улице","color":"#60AD5E","value_type":"instant"},"MotoHW":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":11,"Вт":15,"Ср":13,"Чт":12,"Пт":9,"Сб":0,"Вс":0},"min":"0.00","max":"15.00","avg":"8.57","sum":"60.00","name":"Мотогодини: Гаряча вода","color":"#29819D","value_type":"counter"}},"closestPeriods":{"previous":{"2021-05-03 00:00:00":"03.05 - 09.05"},"current":{"2021-05-10 00:00:00":"10.05 - 16.05"},"next":null}}';
var data = JSON.parse(data_string);
config.data.labels = data.axis;
var values_obj = data.data;
data_generation(values_obj);
//console.log(JSON.stringify(config));
var ctx = document.getElementById('StatisticsChartCanvas').getContext('2d');
window.StatisticsChart = new Chart(ctx,config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrapper" style="width:548px; height:265px;">
<canvas id="StatisticsChartCanvas"></canvas>
</div>
is there any way to change style of hover as well as the tooltip with chartjs or ng2-charts? I want to hide the hover points and only display them whenever I hover on them along with the indicator as the line. Here is the exact chart model I want to build:
https://interactive-bitcoin-price-chart-foxkmkynmg.now.sh/
Thank you in advance for your tips.
EDIT: I followed instructions of GRUNT to apply this chart option into my Angular app, the full chart is shown with tooltip whenever I hover, but the line-trace indicator is not. Here are my codes:
plugin-hoverline.ts:
export class PluginHoverline {
posX: null;
isMouseOut:boolean = false;
drawLine(chart, posX) {
const ctx = chart.ctx,
x_axis = chart.scales['x-axis-0'],
y_axis = chart.scales['y-axis-0'],
x = posX,
topY = y_axis.top,
bottomY = y_axis.bottom;
if (posX < x_axis.left || posX > x_axis.right) return;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = chart.options.lineOnHover.lineWidth;
ctx.strokeStyle = chart.options.lineOnHover.lineColor;
ctx.stroke();
ctx.restore();
};
beforeInit(chart) {
chart.options.events.push('mouseover');
};
afterEvent(chart, event) {
if (!chart.options.lineOnHover || !chart.options.lineOnHover.enabled) return;
if (event.type !== 'mousemove' && event.type !== 'mouseover') {
if (event.type === 'mouseout') this.isMouseOut = true;
chart.clear();
chart.draw();
return;
}
this.posX = event.x;
this.isMouseOut = false;
chart.clear();
chart.draw();
this.drawLine(chart, this.posX);
var metaData = chart.getDatasetMeta(0).data,
radius = chart.data.datasets[0].pointHoverRadius,
posX = metaData.map(e => e._model.x);
posX.forEach(function(pos, posIndex) {
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.updateHoverStyle([metaData[posIndex]], null, true);
chart.tooltip._active = [metaData[posIndex]];
} else chart.updateHoverStyle([metaData[posIndex]], null, false);
}.bind(this));
chart.tooltip.update();
};
afterDatasetsDraw(chart, ease) {
if (!this.posX) return;
if (!this.isMouseOut) this.drawLine(chart, this.posX);
};
}
banner.component.ts: (chart component)
import { Component, OnInit } from '#angular/core';
import { HistoricalBpiService } from '../../services/historical-bpi.service';
import { PluginHoverline } from './plugin-hoverline';
#Component({
selector: 'app-banner',
templateUrl: './banner.component.html',
styleUrls: ['./banner.component.scss']
})
export class BannerComponent implements OnInit {
private dataUrl: string = 'historical/close.json';
constructor(
private historicalBpiService:HistoricalBpiService
) {}
// lineChart
public lineChartData:any = [
{ data:[], label: 'Bitcoin price' }
];
public lineChartLabels:Array<any> = [];
public lineChartOptions:any = {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: 0
},
lineOnHover: {
enabled: true,
lineColor: '#bbb',
lineWidth: 1
},
scales: {
yAxes: [{
display: true,
scaleLabel: {
display: false,
labelString: 'USD'
},
ticks: {
display: false
},
gridLines: {
display: true,
tickMarkLength: 0
}
}],
xAxes: [{
ticks: {
display: false
},
gridLines: {
display: false,
tickMarkLength: 0
}
}]
},
elements: {
point: {
radius: 3
},
line: {
tension: 0.4, // 0 disables bezier curves
}
},
hover: {
mode: 'nearest',
intersect: false
},
tooltips: {
mode: 'nearest',
intersect: false,
backgroundColor: 'rgb(95,22,21)',
callbacks: {
label: function (tooltipItems, data) {
return data.datasets[tooltipItems.datasetIndex].label + ' : ' + '$' + tooltipItems.yLabel.toLocaleString();
},
labelColor: function(tooltipItem, chart) {
var dataset = chart.config.data.datasets[tooltipItem.datasetIndex];
return {
backgroundColor : dataset.backgroundColor
}
}
}
}
};
public lineChartColors:Array<any> = [
{
backgroundColor: 'rgba(199,32,48,0.8',
borderColor: 'rgb(95,22,21);',
pointBackgroundColor: 'rgba(218,208,163,0.8)',
pointHoverBackgroundColor: 'rgba(218,208,163,0.8)',
pointHoverBorderColor: 'rgb(218,208,163)',
pointHoverRadius: 6,
steppedLine: false
}
];
public lineChartLegend:boolean = false;
public lineChartType:string = 'line';
// events
public chartClicked(e:any):void {
console.log(e);
}
public chartHovered(e:any):void {
console.log(e);
}
ngOnInit(){
this.historicalBpiService.getBpiData(this.dataUrl)
.subscribe(
res => {
//this.lineChartData = Object.keys(res.bpi).map(function (key) { return res.bpi[key];});
this.lineChartData[0].data = Object.values(res.bpi);
this.lineChartLabels = Object.keys(res.bpi);
//console.log(this.lineChartData,this.lineChartLabels);
}
)
}
}
template:
<div class="chart">
<canvas baseChart height="360px"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[colors]="lineChartColors"
[legend]="lineChartLegend"
[chartType]="lineChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"></canvas>
</div>
Unfortunately there is no built-in functionality for this yet. However you can use this chart plugin (once created for my own purpose) to achieve your goal.
To utilize the plugin, set the following option in your chart's options config :
lineOnHover: {
enabled: true,
lineColor: '#bbb',
lineWidth: 1
}
also, make sure to set the following properties for your dataset :
pointRadius: 0,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'white'
see - live demo
This answer is to build on top of GRUNT's answer above to be able to display if its a multiline graph:
Just change the following (in the code snippet he provide here):
posX.forEach(function(pos, posIndex) {
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.updateHoverStyle([metaData[posIndex]], null, true);
chart.tooltip._active = [metaData[posIndex]];
} else chart.updateHoverStyle([metaData[posIndex]], null, false);
}.bind(this));
to:
posX.forEach(function(pos, posIndex) {
var metaDatum = []
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.data.datasets.forEach((dataset, ind) => {
metaDatum.push(chart.getDatasetMeta(ind).data[posIndex]);
})
chart.updateHoverStyle(metaDatum, null, true);
chart.tooltip._active = metaDatum;
} else {
metaDatum.push(metaData[posIndex]);
chart.updateHoverStyle(metaDatum, null, false);
}
}.bind(this));
I have this code:
animation: {
duration: 500,
onComplete: function() {
var ctx = this.chart.ctx;
var chart = this;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var datasets = this.config.data.datasets;
ctx.font = "15px QuickSand";
datasets.forEach(function (dataset, i) {
switch ( chart.getDatasetMeta(i).type ) {
case "bar":
ctx.fillStyle = "#303030";
chart.getDatasetMeta(i).data.forEach(function (p, j)
{
ctx.fillText(datasets[i].data[j], p._model.x, p._model.y - 10);
});
break;
}
});
}
}
And these datasets:
datasets: [
{
backgroundColor: '#f87979',
data: [6500, 5500]},
{
backgroundColor: '#f8f8ee',
data: [4800, 5600]
}
]
The dataset is set to be stacked using.
scales: {
xAxes: [{
barThickness: 25,
stacked: true,
ticks: {
beginAtZero: true,
padding: 0,
fontSize: 13
}
}],
yAxes: [{
stacked: true,
display: false
}]
},
What the above code does is placing the values over the bars. My problem is that i want to show the highest value from each dataset at above each bar.
And not all the values from each point.
Can you guys help me with this? I have been trying to do this for like a 1 day now.
To clearify instead of this:
Image with all values
I want this:
Image with wanted values
check out this jsfiddle: https://jsfiddle.net/umsbywLg/2/
essentially I calculated the max value and then drew that on top on the stacked bars:
onComplete: function() {
var ctx = this.chart.ctx;
var chart = this;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var datasets = this.config.data.datasets;
ctx.font = "15px QuickSand";
ctx.fillStyle = "#303030";
datasets.forEach(function (dataset, i) {
var maxValue = 0;
chart.getDatasetMeta(i).data.forEach(function (p, j) {
if(maxValue < datasets[j].data[i]) {
maxValue = datasets[j].data[i];
}
});
ctx.fillText(maxValue, datasets[i]._meta[0].data[i]._view.x, 20);
});
}
I have a bit of a strange config of my chart.js because of the data that is being fed into it and also the line colours. However I was wondering if somebody could point me in the direction of how to customise the legend:
$(document).ready(function(){
$.ajax({
url : "../acredash/teamData.php",
timeout: 4000,
type : "GET",
success :function(data){
console.log(data);
var chartata = {
labels: [
"Strategic Development and Ownership",
"Driving change through others",
"Exec Disposition",
"Commercial Acumen",
"Develops High Performance Teams",
"Innovation and risk taking",
"Global Leadership",
"Industry Leader"
]};
var ctx = $("#mycanvas");
var config = {
type: 'radar',
data: chartata,
animationEasing: 'linear',
options: {
legend: {
display: true,
position: 'bottom'
},
tooltips: {
enabled: true
},
scale: {
ticks: {
fontSize: 15,
beginAtZero: true,
stepSize: 1
}
}
},
},
LineGraph = new Chart(ctx, config);
var colorArray = [
["#7149a5", false],
["#57B6DD", false],
["#36bfbf", false],
["#69bd45", false],
['#9adfdf', false],
['#c6b6db' ,false],
["#5481B1", false],
['#8d6db7', false],
['#d2ebc7', false],
["#6168AC", false]
];
for (var i in data) {
tmpscore=[];
tmpscore.push(data[i].score_1);
tmpscore.push(data[i].score_2);
tmpscore.push(data[i].score_3);
tmpscore.push(data[i].score_4);
tmpscore.push(data[i].score_5);
tmpscore.push(data[i].score_6);
tmpscore.push(data[i].score_7);
tmpscore.push(data[i].score_8);
var color, done = false;
while (!done) {
var test = colorArray[parseInt(Math.random() * 10)];
if (!test[1]) {
color = test[0];
colorArray[colorArray.indexOf(test)][1] = true;
done = !done;
}
}
newDataset = {
label: data[i].firstName+' '+data[i].lastName,
borderColor: color,
backgroundColor: "rgba(0,0,0,0)",
data: tmpscore,
};
config.data.datasets.push(newDataset);
}
LineGraph.update();
},
});
});
I have looked around without much luck because of how my chart is being generated. It just used the default legend and its a it messy. I would like to just have control over it.
Step 1:
set callback for legend on options
legendCallback: function(chart) {
var legendHtml = [];
legendHtml.push('<ul>');
var item = chart.data.datasets[0];
for (var i=0; i < item.data.length; i++) {
legendHtml.push('<li>');
legendHtml.push('<span></span>');//add what ever you want :-p
legendHtml.push('<span class="chart-legend-label-text">' + chart.data.labels[i]+'</span>');
legendHtml.push('</li>');
}
legendHtml.push('</ul>');
return legendHtml.join("");
},legend:false,
Step 2:
Place your legend where ever you want :-p
<div id="my-legend-con" class="legend-con"></div>
Step 3:
Initialise the legend.
$('#my-legend-con').html(myChartName.generateLegend());
Step 3:
Do what ever you want...
Using ChartJs (v2.2.2) can you change the line style between the last 2 points on a graph. e.g. have a solid line all the way and then dashed at the end? see picture below
The borderDashproperty (scroll to Line Configuration) is the key to your problem.
The thing is, the full chart is drawn with a border dash, you cannot choose where it starts and where it ends.
A simple workaround is to create two identical datasets. One dotted and one with a plain line. Then you remvoe the last data of your plain one, and they both will be displayed as how you want it.
You can see the full code in this jsFiddle, and here is its result :
Note :
Since there are two datasets now, the legend will display both of them. Setting the display to false fixes it (more or less).
The declaration order doesn't matter since the plain line will always overwrite the dotted one.
Having a bezier curve (tension property > 0) can create a display problem since the data is not the same in both datasets.
You can create a scatter chart and draw the lines directly on the canvas using the Plugin Core API. The API offers a range of hooks that can be used for performing custom code. The advantage of this approach is that you can customize the style of every single connection line (width, color, dash pattern etc.).
const labels = [1, 2, 3, 4, 5, 6];
const values = [12, 19, 3, 5, 2, 3];
const data = labels.map((label, index) => ({ x: label, y: values[index]}));
var lineChart = new Chart(document.getElementById("chart"), {
type: "scatter",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
chart.config.data.datasets[0].data.forEach((value, index) => {
if (index > 0) {
var valueFrom = data[index - 1];
var xFrom = xAxis.getPixelForValue(valueFrom.x);
var yFrom = yAxis.getPixelForValue(valueFrom.y);
var xTo = xAxis.getPixelForValue(value.x);
var yTo = yAxis.getPixelForValue(value.y);
ctx.save();
ctx.strokeStyle = '#922893';
ctx.lineWidth = 2;
if (index + 1 == data.length) {
ctx.setLineDash([5, 10]);
}
ctx.beginPath();
ctx.moveTo(xFrom, yFrom);
ctx.lineTo(xTo, yTo);
ctx.stroke();
ctx.restore();
}
});
}
}],
data: {
datasets: [{
label: "My Dataset",
data: data,
borderColor: '#922893',
pointBackgroundColor: "transparent"
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
stepSize: 1
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="90"></canvas>
const labels = [1, 2, 3, 4, 5, 6];
const values = [12, 19, 3, 5, 2, 3];
const data = labels.map((label, index) => ({ x: label, y: values[index]}));
var lineChart = new Chart(document.getElementById("chart"), {
type: "scatter",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
chart.config.data.datasets[0].data.forEach((value, index) => {
if (index > 0) {
var valueFrom = data[index - 1];
var xFrom = xAxis.getPixelForValue(valueFrom.x);
var yFrom = yAxis.getPixelForValue(valueFrom.y);
var xTo = xAxis.getPixelForValue(value.x);
var yTo = yAxis.getPixelForValue(value.y);
ctx.save();
ctx.strokeStyle = '#922893';
ctx.lineWidth = 2;
if (index + 1 == data.length) {
ctx.setLineDash([5, 10]);
}
ctx.beginPath();
ctx.moveTo(xFrom, yFrom);
ctx.lineTo(xTo, yTo);
ctx.stroke();
ctx.restore();
}
});
}
}],
data: {
datasets: [{
label: "My Dataset",
data: data,
borderColor: '#922893',
pointBackgroundColor: "transparent"
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
stepSize: 1
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="90"></canvas>