score:58
the below answer is concerned with chart.js 1.x. chart.js 2.x supports this chart.js how to get combined bar and line charts?
edit 2 i have now added this feature to my custom build of chartjs if you want to use that https://github.com/leighquince/chart.js the only difference is i named it overlay not linebar so to use it just create a graph using var myoverlaychart = new chart(linebar).overlay(data);
everything else is the same though.
ok so had a quick go at seeing if this was possible and the short answer is yes but would need more work truly integrate this into the build of chart js. here is a fiddle showing it in action with a line and bar chart to compare against: http://fiddle.jshell.net/leighking2/898kzyp7/
so my solution was to create a new chart type called linebar (could have gone for the extending option but before starting i felt like this was going to need a lot of method overriding so went for a new graph, it also means i didn't have to re-declare helpers as chart.helpers not a huge thing but was reason enough at the time).
at it's core it is the bar chart but it keeps a track of datasets in separate linedatasets
and bardatasets
variables. then when it needs to draw/check-events /use-the-data it loops other both of the new datasets separately.
whenever it is looping over the linedatasets
variable it is performing code from the current line graph and visa versa for the bar graph
so i'll paste the new graph at the bottom of this answer as it's pretty large, to use it copy and paste it into your own chart.js file at the bottom or paste it after you include chart.js on your page.
to then make use of it you can now declare your data with an extra option called type
var data = {
labels: ["january", "february", "march", "april", "may", "june", "july"],
datasets: [{
label: "my first dataset",
//new option, type will default to bar as that what is used to create the scale
type: "line",
fillcolor: "rgba(220,220,220,0.2)",
strokecolor: "rgba(220,220,220,1)",
pointcolor: "rgba(220,220,220,1)",
pointstrokecolor: "#fff",
pointhighlightfill: "#fff",
pointhighlightstroke: "rgba(220,220,220,1)",
data: [65, 59, 4, 81, 56, 55, 40]
}, {
label: "my first dataset",
//new option, type will default to bar as that what is used to create the scale
type: "bar",
fillcolor: "rgba(220,20,220,0.2)",
strokecolor: "rgba(220,20,220,1)",
pointcolor: "rgba(220,20,220,1)",
pointstrokecolor: "#fff",
pointhighlightfill: "#fff",
pointhighlightstroke: "rgba(220,220,220,1)",
data: [32, 25, 33, 88, 12, 92, 33]
}]
};
then just create a new chart of type linebar
var linebar = document.getelementbyid("line-bar").getcontext("2d");
var mylinebarchart = new chart(linebar).linebar(data);
result
edit: updated it so now it has the tooltips and removedata/adddata functionality working. see the fiddle for examples of these. you can also add as many datasets as you like both line and bar and it will display them all on the same graph.
limitation - if bar and line get updated their respective pieces have to be updated here as well which isn't great, they won't break if bar and line get updated it just might mean they don't look the same whatever gets updated
and here is the actual new chart
//new chart type linebar - its a bit like bar and line
//were slammed together at high speed, not pretty,
//but they are part of each other now
(function(){
"use strict";
var root = this,
chart = root.chart,
helpers = chart.helpers;
var defaultconfig = {
//function - whether the current x-axis label should be filtered out, takes in current label and
//index, return true to filter out the label return false to keep the label
labelsfilter : function(label,index){return false;},
//boolean - whether the scale should start at zero, or an order of magnitude down from the lowest value
scalebeginatzero : true,
//boolean - whether grid lines are shown across the chart
scaleshowgridlines : true,
//string - colour of the grid lines
scalegridlinecolor : "rgba(0,0,0,.05)",
//number - width of the grid lines
scalegridlinewidth : 1,
//boolean - if there is a stroke on each bar
barshowstroke : true,
//number - pixel width of the bar stroke
barstrokewidth : 2,
//number - spacing between each of the x value sets
barvaluespacing : 5,
//number - spacing between data sets within x values
bardatasetspacing : 1,
//boolean - whether the line is curved between points
beziercurve : true,
//number - tension of the bezier curve between points
beziercurvetension : 0.4,
//boolean - whether to show a dot for each point
pointdot : true,
//number - radius of each point dot in pixels
pointdotradius : 4,
//number - pixel width of point dot stroke
pointdotstrokewidth : 1,
//number - amount extra to add to the radius to cater for hit detection outside the drawn point
pointhitdetectionradius : 20,
//boolean - whether to show a stroke for datasets
datasetstroke : true,
//number - pixel width of dataset stroke
datasetstrokewidth : 2,
//boolean - whether to fill the dataset with a colour
datasetfill : true,
//string - a legend template
legendtemplate : "<ul class=\"<%=name.tolowercase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillcolor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
};
chart.type.extend({
name: "linebar",
defaults : defaultconfig,
initialize: function(data){
//expose options as a scope variable here so we can access it in the scaleclass
var options = this.options;
//two new varibale to hold the different graph types
this.bardatasets = [];
this.linedatasets = [];
//generate the scale, let bar take control here as he needs the width.
this.scaleclass = chart.scale.extend({
offsetgridlines : true,
calculatebarx : function(datasetcount, datasetindex, barindex){
//reusable method for calculating the xposition of a given bar based on datasetindex & width of the bar
var xwidth = this.calculatebasewidth(),
xabsolute = this.calculatex(barindex) - (xwidth/2),
barwidth = this.calculatebarwidth(datasetcount);
return xabsolute + (barwidth * datasetindex) + (datasetindex * options.bardatasetspacing) + barwidth/2;
},
calculatebasewidth : function(){
return (this.calculatex(1) - this.calculatex(0)) - (2*options.barvaluespacing);
},
calculatebarwidth : function(datasetcount){
//the padding between datasets is to the right of each bar, providing that there are more than 1 dataset
var basewidth = this.calculatebasewidth() - ((datasetcount - 1) * options.bardatasetspacing);
return (basewidth / datasetcount);
}
});
//declare the extension of the default point, to cater for the options passed in to the constructor
this.pointclass = chart.point.extend({
strokewidth : this.options.pointdotstrokewidth,
radius : this.options.pointdotradius,
display: this.options.pointdot,
hitdetectionradius : this.options.pointhitdetectionradius,
ctx : this.chart.ctx,
inrange : function(mousex){
return (math.pow(mousex-this.x, 2) < math.pow(this.radius + this.hitdetectionradius,2));
}
});
this.datasets = [];
//set up tooltip events on the chart
if (this.options.showtooltips){
helpers.bindevents(this, this.options.tooltipevents, function(evt){
var activedata = (evt.type !== 'mouseout') ? this.getdataatevent(evt) : [];
this.eachbars(function(bar){
bar.restore(['fillcolor', 'strokecolor']);
});
this.eachpoints(function(point){
point.restore(['fillcolor', 'strokecolor']);
});
helpers.each(activedata, function(active){
active.fillcolor = active.highlightfill;
active.strokecolor = active.highlightstroke;
});
this.showtooltip(activedata);
});
}
//declare the extension of the default point, to cater for the options passed in to the constructor
this.barclass = chart.rectangle.extend({
strokewidth : this.options.barstrokewidth,
showstroke : this.options.barshowstroke,
ctx : this.chart.ctx
});
//iterate through each of the datasets, and build this into a property of the chart
helpers.each(data.datasets,function(dataset,datasetindex){
var datasetobject = {
label : dataset.label || null,
fillcolor : dataset.fillcolor,
strokecolor : dataset.strokecolor,
type: dataset.type,
bars : [],
pointcolor : dataset.pointcolor,
pointstrokecolor : dataset.pointstrokecolor,
points : []
};
this.datasets.push(datasetobject);
switch(dataset.type)
{
case "line":
this.linedatasets.push(datasetobject);
helpers.each(dataset.data,function(datapoint,index){
//add a new point for each piece of data, passing any required data to draw.
datasetobject.points.push(new this.pointclass({
value : datapoint,
label : data.labels[index],
datasetlabel: dataset.label,
strokecolor : dataset.pointstrokecolor,
fillcolor : dataset.pointcolor,
highlightfill : dataset.pointhighlightfill || dataset.pointcolor,
highlightstroke : dataset.pointhighlightstroke || dataset.pointstrokecolor
}));
},this);
break;
default:
this.bardatasets.push(datasetobject);
helpers.each(dataset.data,function(datapoint,index){
//add a new point for each piece of data, passing any required data to draw.
datasetobject.bars.push(new this.barclass({
value : datapoint,
label : data.labels[index],
datasetlabel: dataset.label,
strokecolor : dataset.strokecolor,
fillcolor : dataset.fillcolor,
highlightfill : dataset.highlightfill || dataset.fillcolor,
highlightstroke : dataset.highlightstroke || dataset.strokecolor
}));
},this);
break;
}
},this);
this.buildscale(data.labels);
helpers.each(this.linedatasets,function(dataset,datasetindex){
//iterate through each of the datasets, and build this into a property of the chart
this.eachpoints(function(point, index){
helpers.extend(point, {
x: this.scale.calculatex(index),
y: this.scale.endpoint
});
point.save();
}, this);
},this);
this.barclass.prototype.base = this.scale.endpoint;
this.eachbars(function(bar, index, datasetindex){
helpers.extend(bar, {
width : this.scale.calculatebarwidth(this.bardatasets.length),
x: this.scale.calculatebarx(this.bardatasets.length, datasetindex, index),
y: this.scale.endpoint
});
bar.save();
}, this);
this.render();
},
update : function(){
this.scale.update();
// reset any highlight colours before updating.
helpers.each(this.activeelements, function(activeelement){
activeelement.restore(['fillcolor', 'strokecolor']);
});
this.eachbars(function(bar){
bar.save();
});
this.eachpoints(function(point){
point.save();
});
this.render();
},
eachpoints : function(callback){
//use the linedatasets
helpers.each(this.linedatasets,function(dataset){
helpers.each(dataset.points,callback,this);
},this);
},
eachbars : function(callback){
//user the bardatasets
helpers.each(this.bardatasets,function(dataset, datasetindex){
helpers.each(dataset.bars, callback, this, datasetindex);
},this);
},
getdataatevent : function(e)
{
return this.getpointsatevent(e).concat(this.getbarsatevent(e));
},
getpointsatevent : function(e){
var pointsarray = [],
eventposition = helpers.getrelativeposition(e);
helpers.each(this.linedatasets,function(dataset){
helpers.each(dataset.points,function(point){
if (point.inrange(eventposition.x,eventposition.y)) pointsarray.push(point);
});
},this);
return pointsarray;
},
getbarsatevent : function(e){
var barsarray = [],
eventposition = helpers.getrelativeposition(e),
datasetiterator = function(dataset){
barsarray.push(dataset.bars[barindex]);
},
barindex;
for (var datasetindex = 0; datasetindex < this.bardatasets.length; datasetindex++) {
for (barindex = 0; barindex < this.bardatasets[datasetindex].bars.length; barindex++) {
if (this.bardatasets[datasetindex].bars[barindex].inrange(eventposition.x,eventposition.y)){
helpers.each(this.bardatasets, datasetiterator);
return barsarray;
}
}
}
return barsarray;
},
buildscale : function(labels){
var self = this;
var datatotal = function(){
var values = [];
self.eachbars(function(bar){
values.push(bar.value);
});
return values;
};
var scaleoptions = {
labelsfilter: this.options.labelsfilter,
templatestring : this.options.scalelabel,
height : this.chart.height,
width : this.chart.width,
ctx : this.chart.ctx,
textcolor : this.options.scalefontcolor,
fontsize : this.options.scalefontsize,
fontstyle : this.options.scalefontstyle,
fontfamily : this.options.scalefontfamily,
valuescount : labels.length,
beginatzero : this.options.scalebeginatzero,
integersonly : this.options.scaleintegersonly,
calculateyrange: function(currentheight){
var updatedranges = helpers.calculatescalerange(
datatotal(),
currentheight,
this.fontsize,
this.beginatzero,
this.integersonly
);
helpers.extend(this, updatedranges);
},
xlabels : labels,
font : helpers.fontstring(this.options.scalefontsize, this.options.scalefontstyle, this.options.scalefontfamily),
linewidth : this.options.scalelinewidth,
linecolor : this.options.scalelinecolor,
gridlinewidth : (this.options.scaleshowgridlines) ? this.options.scalegridlinewidth : 0,
gridlinecolor : (this.options.scaleshowgridlines) ? this.options.scalegridlinecolor : "rgba(0,0,0,0)",
padding : (this.options.showscale) ? 0 : (this.options.barshowstroke) ? this.options.barstrokewidth : 0,
showlabels : this.options.scaleshowlabels,
display : this.options.showscale
};
if (this.options.scaleoverride){
helpers.extend(scaleoptions, {
calculateyrange: helpers.noop,
steps: this.options.scalesteps,
stepvalue: this.options.scalestepwidth,
min: this.options.scalestartvalue,
max: this.options.scalestartvalue + (this.options.scalesteps * this.options.scalestepwidth)
});
}
this.scale = new this.scaleclass(scaleoptions);
},
adddata : function(valuesarray,label){
//map the values array for each of the datasets
var linedatasetindex = 0;
var bardatasetindex = 0;
helpers.each(valuesarray,function(value,datasetindex){
switch(this.datasets[datasetindex].type)
{
case "line":
//add a new point for each piece of data, passing any required data to draw.
this.linedatasets[linedatasetindex].points.push(new this.pointclass({
value : value,
label : label,
x: this.scale.calculatex(this.scale.valuescount+1),
y: this.scale.endpoint,
strokecolor : this.linedatasets[linedatasetindex].pointstrokecolor,
fillcolor : this.linedatasets[linedatasetindex].pointcolor
}));
linedatasetindex++;
break;
default:
//add a new point for each piece of data, passing any required data to draw.
this.bardatasets[bardatasetindex].bars.push(new this.barclass({
value : value,
label : label,
x: this.scale.calculatebarx(this.bardatasets.length, bardatasetindex, this.scale.valuescount+1),
y: this.scale.endpoint,
width : this.scale.calculatebarwidth(this.bardatasets.length),
base : this.scale.endpoint,
strokecolor : this.bardatasets[bardatasetindex].strokecolor,
fillcolor : this.bardatasets[bardatasetindex].fillcolor
}));
bardatasetindex++;
break;
}
},this);
this.scale.addxlabel(label);
//then re-render the chart.
this.update();
},
removedata : function(){
this.scale.removexlabel();
//then re-render the chart.
helpers.each(this.bardatasets,function(dataset){
dataset.bars.shift();
},this);
helpers.each(this.linedatasets,function(dataset){
dataset.points.shift();
},this);
this.update();
},
reflow : function(){
helpers.extend(this.barclass.prototype,{
y: this.scale.endpoint,
base : this.scale.endpoint
});
var newscaleprops = helpers.extend({
height : this.chart.height,
width : this.chart.width
});
this.scale.update(newscaleprops);
},
draw : function(ease){
var easingdecimal = ease || 1;
this.clear();
var ctx = this.chart.ctx;
// some helper methods for getting the next/prev points
var hasvalue = function(item){
return item.value !== null;
},
nextpoint = function(point, collection, index){
return helpers.findnextwhere(collection, hasvalue, index) || point;
},
previouspoint = function(point, collection, index){
return helpers.findpreviouswhere(collection, hasvalue, index) || point;
};
this.scale.draw(easingdecimal);
//draw all the bars for each dataset
helpers.each(this.linedatasets,function(dataset,datasetindex){
var pointswithvalues = helpers.where(dataset.points, hasvalue);
//transition each point first so that the line and point drawing isn't out of sync
//we can use this extra loop to calculate the control points of this dataset also in this loop
helpers.each(dataset.points, function(point, index){
if (point.hasvalue()){
point.transition({
y : this.scale.calculatey(point.value),
x : this.scale.calculatex(index)
}, easingdecimal);
}
},this);
// control points need to be calculated in a seperate loop, because we need to know the current x/y of the point
// this would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
if (this.options.beziercurve){
helpers.each(pointswithvalues, function(point, index){
var tension = (index > 0 && index < pointswithvalues.length - 1) ? this.options.beziercurvetension : 0;
point.controlpoints = helpers.splinecurve(
previouspoint(point, pointswithvalues, index),
point,
nextpoint(point, pointswithvalues, index),
tension
);
// prevent the bezier going outside of the bounds of the graph
// cap puter bezier handles to the upper/lower scale bounds
if (point.controlpoints.outer.y > this.scale.endpoint){
point.controlpoints.outer.y = this.scale.endpoint;
}
else if (point.controlpoints.outer.y < this.scale.startpoint){
point.controlpoints.outer.y = this.scale.startpoint;
}
// cap inner bezier handles to the upper/lower scale bounds
if (point.controlpoints.inner.y > this.scale.endpoint){
point.controlpoints.inner.y = this.scale.endpoint;
}
else if (point.controlpoints.inner.y < this.scale.startpoint){
point.controlpoints.inner.y = this.scale.startpoint;
}
},this);
}
//draw the line between all the points
ctx.linewidth = this.options.datasetstrokewidth;
ctx.strokestyle = dataset.strokecolor;
ctx.beginpath();
helpers.each(pointswithvalues, function(point, index){
if (index === 0){
ctx.moveto(point.x, point.y);
}
else{
if(this.options.beziercurve){
var previous = previouspoint(point, pointswithvalues, index);
ctx.beziercurveto(
previous.controlpoints.outer.x,
previous.controlpoints.outer.y,
point.controlpoints.inner.x,
point.controlpoints.inner.y,
point.x,
point.y
);
}
else{
ctx.lineto(point.x,point.y);
}
}
}, this);
ctx.stroke();
if (this.options.datasetfill && pointswithvalues.length > 0){
//round off the line by going to the base of the chart, back to the start, then fill.
ctx.lineto(pointswithvalues[pointswithvalues.length - 1].x, this.scale.endpoint);
ctx.lineto(pointswithvalues[0].x, this.scale.endpoint);
ctx.fillstyle = dataset.fillcolor;
ctx.closepath();
ctx.fill();
}
//now draw the points over the line
//a little inefficient double looping, but better than the line
//lagging behind the point positions
helpers.each(pointswithvalues,function(point){
point.draw();
});
},this);
helpers.each(this.bardatasets,function(dataset,datasetindex){
helpers.each(dataset.bars,function(bar,index){
if (bar.hasvalue()){
bar.base = this.scale.endpoint;
//transition then draw
bar.transition({
x : this.scale.calculatebarx(this.bardatasets.length, datasetindex, index),
y : this.scale.calculatey(bar.value),
width : this.scale.calculatebarwidth(this.bardatasets.length)
}, easingdecimal).draw();
}
},this);
},this);
},
showtooltip : function(chartelements, forceredraw){
// only redraw the chart if we've actually changed what we're hovering on.
if (typeof this.activeelements === 'undefined') this.activeelements = [];
var ischanged = (function(elements){
var changed = false;
if (elements.length !== this.activeelements.length){
changed = true;
return changed;
}
helpers.each(elements, function(element, index){
if (element !== this.activeelements[index]){
changed = true;
}
}, this);
return changed;
}).call(this, chartelements);
if (!ischanged && !forceredraw){
return;
}
else{
this.activeelements = chartelements;
}
this.draw();
if (chartelements.length > 0){
// if we have multiple datasets, show a multitooltip for all of the data points at that index
if (this.datasets && this.datasets.length > 1) {
var dataarray,
dataindex;
for (var i = this.linedatasets.length - 1; i >= 0; i--) {
dataarray = this.datasets[i].points;
dataindex = helpers.indexof(dataarray, chartelements[0]);
if (dataindex !== -1){
break;
}
}
if(dataindex === -1)
{
for (i = this.bardatasets.length - 1; i >= 0; i--) {
dataarray = this.datasets[i].bars;
dataindex = helpers.indexof(dataarray, chartelements[0]);
if (dataindex !== -1){
break;
}
}
}
var tooltiplabels = [],
tooltipcolors = [],
medianposition = (function(index) {
// get all the points at that particular index
var elements = [],
datacollection,
xpositions = [],
ypositions = [],
xmax,
ymax,
xmin,
ymin;
helpers.each(this.linedatasets, function(dataset){
datacollection = dataset.points;
if (datacollection[dataindex] && datacollection[dataindex].hasvalue()){
elements.push(datacollection[dataindex]);
}
});
helpers.each(this.bardatasets, function(dataset){
datacollection = dataset.bars;
if (datacollection[dataindex] && datacollection[dataindex].hasvalue()){
elements.push(datacollection[dataindex]);
}
});
helpers.each(elements, function(element) {
xpositions.push(element.x);
ypositions.push(element.y);
//include any colour information about the element
tooltiplabels.push(helpers.template(this.options.multitooltiptemplate, element));
tooltipcolors.push({
fill: element._saved.fillcolor || element.fillcolor,
stroke: element._saved.strokecolor || element.strokecolor
});
}, this);
ymin = helpers.min(ypositions);
ymax = helpers.max(ypositions);
xmin = helpers.min(xpositions);
xmax = helpers.max(xpositions);
return {
x: (xmin > this.chart.width/2) ? xmin : xmax,
y: (ymin + ymax)/2
};
}).call(this, dataindex);
new chart.multitooltip({
x: medianposition.x,
y: medianposition.y,
xpadding: this.options.tooltipxpadding,
ypadding: this.options.tooltipypadding,
xoffset: this.options.tooltipxoffset,
fillcolor: this.options.tooltipfillcolor,
textcolor: this.options.tooltipfontcolor,
fontfamily: this.options.tooltipfontfamily,
fontstyle: this.options.tooltipfontstyle,
fontsize: this.options.tooltipfontsize,
titletextcolor: this.options.tooltiptitlefontcolor,
titlefontfamily: this.options.tooltiptitlefontfamily,
titlefontstyle: this.options.tooltiptitlefontstyle,
titlefontsize: this.options.tooltiptitlefontsize,
cornerradius: this.options.tooltipcornerradius,
labels: tooltiplabels,
legendcolors: tooltipcolors,
legendcolorbackground : this.options.multitooltipkeybackground,
title: chartelements[0].label,
chart: this.chart,
ctx: this.chart.ctx
}).draw();
} else {
each(chartelements, function(element) {
var tooltipposition = element.tooltipposition();
new chart.tooltip({
x: math.round(tooltipposition.x),
y: math.round(tooltipposition.y),
xpadding: this.options.tooltipxpadding,
ypadding: this.options.tooltipypadding,
fillcolor: this.options.tooltipfillcolor,
textcolor: this.options.tooltipfontcolor,
fontfamily: this.options.tooltipfontfamily,
fontstyle: this.options.tooltipfontstyle,
fontsize: this.options.tooltipfontsize,
caretheight: this.options.tooltipcaretsize,
cornerradius: this.options.tooltipcornerradius,
text: template(this.options.tooltiptemplate, element),
chart: this.chart
}).draw();
}, this);
}
}
return this;
},
});
}).call(this);
//here ends the linebar
score:-3
this worked for me to change the z-index of lines and bars. swap the next two code blocks:
helpers.each(this.bardatasets, function (dataset, datasetindex) ... , this);
helpers.each(this.linedatasets, function (dataset, datasetindex) ... , this);
like this:
helpers.each(this.linedatasets, function (dataset, datasetindex) ... , this);
helpers.each(this.bardatasets, function (dataset, datasetindex) ... , this);
good luck.
score:1
but we want to show gridlines
var scaleoptions = {
linecolor : this.options.scalelinecolor,
// missing code ↓↓↓
showhorizontallines: this.options.scaleshowhorizontallines,
showverticallines: this.options.scaleshowverticallines,
//missing code ↑↑↑
}
score:2
one minor code addition is needed. in the "buildscale" section, you need to include the data from eachpoints as well. this is, because calculatedy is only using the data from bar to determine the height; the data using line is ignored. if the data using the line is higher than the data using bar, the line graph will be cut off at the top.
buildscale : function(labels){
var self = this;
var datatotal = function(){
var values = [];
self.eachbars(function(bar){
values.push(bar.value);
});
// missing code ↓↓↓
self.eachpoints(function(point){
values.push(point.value);
});
// missing code ↑↑↑
return values;
};
score:14
new version of charts.js (v2.0) supports combined bar and line chart.
v2.0 is currently in beta
link to plunker
score:18
with chart.js 2.0 you do it like this:
var chartinstance = new chart(ctx, {
type: 'bar', // set the default type
data: {
datasets: [{
// default type will be used
data: []
}, {
type: 'line', // override the default type
data: []
}]
}
});
Source: stackoverflow.com
Related Query
- Chart.js how to get Combined Bar and line charts?
- How to add second Y-axis for Bar and Line chart in Chart.js?
- How to hide the y axis and x axis line and label in my bar chart for chart.js
- How to show data values in top of bar chart and line chart in chart.js 3
- Chart.js combined line and bar chart with differing data points
- How can I get my Chart.JS bar chart to stack two data values together on each bar, and print a calculated value on each bar?
- How can i launch a modal after clicking each bar in Bar chart in Chartjs and also how can i get its data?
- How can i get the Chart JS Bar Graph Bar Label and Value on click?
- How to add vertical line in bar chart using chartJs and ng2-charts?
- Chartjs 2 - Stacked bar and unstacked line on same chart with same y axis
- How to save Chart JS charts as image without black background using blobs and filesaver?
- Chart.js Mixed Bar and Line chart with different scales
- How do I draw a vertical line on a horizontal bar chart with ChartJS?
- Can Chart.js combines Line Chart and Bar Chart in one canvas
- Chart.js - mixing bar and line graphs - can I get the lines to fill the full column?
- How to draw Horizontal line on Bar Chart Chartjs
- How do I make line charts overlay over bar charts in chartjs
- How to get the actual chart width and height in chart.js
- How do I keep chart.js charts in one JS file, and not get errors when the ID from the JS file don't exist on one specific html page?
- ChartJS (React) Line Chart - How to show single tooltip with data and labels from 3 (multiple) dataset?
- In Stacked horizontal bar chart how to remove the vertical line in Chart.js?
- Chart.js: Combined Line and Bar Data
- Chart.js Date and Time Bar Chart Not Rendering - Line Works Though
- How to get chart from data points (arrays) with inconsistent time intervals and chart.js?
- How to change the label and grid line position on a timeseries chart in Chart.js 3?
- Chart.js v2 - combined stacked bar chart and 2 unstacked lines
- Chart.js: How to get x-axis labels to show on top of bars in bar chart
- How to sort XY line chart tooltip items based on value and add thousands separators?
- Click on interactive chart.js bar chart and get value for labels and groups in JS
- Chart.js Bar and Line chart
More Query from same tag
- How to show lables just outside the the doughnut chart in Chartjs?
- How to label x-Axis in Chart.js by days?
- How can configure my y-axis on chart.js?
- Chart.js Draw a Stacked Bar Chart with Limit Line
- chartjs - bar graphs size not increasing
- Chartjs-plugin-zoom plugin does not change x axis labels
- How to set Custom tooltip event with Chartjs version 2.X
- How can I create a horizontal scroll effect with angular-chart.js and chart.js
- Chart.JS custom legend onClick event returns error when calling original event handler
- ChartJS V3 Radar chart Label Font Size
- How to display currency in Chart js
- Change background color of all charts beside the one hovered
- Angular with ng2charts for bar chart shows NAN% when no data present
- Is it possible to reverse the display order of segments in polar chart?
- Chart.js how to rewrite x for webAPP
- Ionic using multiple chart.js canvas in the same page
- How to solve a Chart.js 2.0 issue with mouseover and several updates?
- How to use ChartJS object in a click event handler?
- Place Text in Chart-Canvas Area in ChartJS
- ChartJS does not work on Windows 10 - in any browser
- Chart js - Line chart - How to hide the data label on the line?
- How to remove excess lines on X axis using chartjs?
- Update chartjs chart within random data once per second
- Why my ajax function does not work on yii2
- How to wrap legend text in Chartjs?
- is there a way to do automatic scrolling?
- Chart.js 3.3.0 - Draw text on top of chart
- Yii2 Chart is not defined
- Chart.js how to display % on tooltip
- chart.js npm module not working