Chart.JS spacing and padding - chart.js

Is it possible to get some more space between the chart and the x-axis?
Is it possible to get some more space between the right side of the chart and the end of the canvas area? I want to add some more elements to the canvas right beside the chart but this is not possible because the chart takes the whole canvas width so it would overlap.

Shifting x axis Labels Vertically
The easiest way to do 1. is by adding spaces to your x labels. You can extend your chart type and override your initialize function to do this (increase 30 to something larger if your labels are long to start with anyway)
initialize: function(data){
data.labels.forEach(function(item, index) {
data.labels[index] += Array(Math.max(30 - item.length, 0)).join(" ");
})
Chart.types.Bar.prototype.initialize.apply(this, arguments);
},
Edit : As pointed out in the comments, this causes a horizontal shift as well and the label ends no longer align with the x axis markers.
Since both the x axis and the x labels are drawn in a single function and you have no other variables you can mess around with (safely) this means you'll have to change the actual scale draw function.
Look for a ctx.translate towards the end of the draw function and change it to
ctx.translate(xPos, (isRotated) ? this.endPoint + 22 : this.endPoint + 18);
You'll also have to adjust the endpoint (which drives the y limits) a bit so that the additional y offset doesn't cause the labels to overflow the chart (look for the line adjusting this in the draw override for 2.).
Leaving a gap on the Right Side
To do 2, you override your draw function (in your extended chart) and change xScalePaddingRight. However since this doesn't affect your horizontal grid lines you have to overlay a filled rectangle once your draw is complete. Your complete draw function would look like this
draw: function(){
// this line is for 1.
if (!this.scale.done) {
this.scale.endPoint -= 20
// we should do this only once
this.scale.done = true;
}
var xScalePaddingRight = 120
this.scale.xScalePaddingRight = xScalePaddingRight
Chart.types.Bar.prototype.draw.apply(this, arguments);
this.chart.ctx.fillStyle="#FFF";
this.chart.ctx.fillRect(this.chart.canvas.width - xScalePaddingRight, 0, xScalePaddingRight, this.chart.canvas.height);
}
Original fiddle - https://jsfiddle.net/gvdmxc5t/
Fiddle with modified Scale draw function - https://jsfiddle.net/xgc6a77a/ (I turned off animation in this one so that the endpoint is shifted only once, but you could just hard code it, or add some extra code so that it's done only once)

The 'tickMarkLength' option extends the grid lines outside the chart and pushes the ticks down.
xAxes: [
{
gridLines: {
tickMarkLength: 15
},
}
]

use this for chartjs 2.0
scales: {
xAxes: [{
barPercentage: 0.9,
categoryPercentage: 0.55
}]
Reference

In chartjs v3, there is an "offset" flag that you can set to true. This will create padding.
scales: {
x: {
offset: true,
}
}
If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to true for a bar chart by default.
Documentation

Related

ChartJS Data Labels

I am using the chartjs-plugin-datalabels library to help configure my datalabels in a chartjs.
The problem is the data labels keep overlapping on a simple line chart where the values between the two data sets for a given X axis are close.
Is there anyway to use the align function to dynamically change whether the data label is on the top or bottom?
Psedocode
if datasetOne of a given X axis item is > datasetTwo of a given X axis item then make the datalabel for dataSetOne[X] === Top else make it bottom
if datasetTwo of a given X axis item is > datasetOne of a given X axis item then make the datalabel for dataSetTwo[X] === Bottom else make it top
Currently I was doing something like this. But the overlapping issue happens again if my second dataset index has lower values than the first data set
align: function ( context: Context) {
if (context.datasetIndex === 0) {
return 'top';
} else {
return 'bottom';
}
}

How to align ticks label in chartJS 3.x?

is possible with chartJS chenge the align position of tick labels for scaleY and for scaleX?
In the image attached i want 300,150,60, 0 on top of the grid line and 9:56 aligned on the right of the first tick.
I try to modify the code in this answer, but without success.
After some research i adapted the method showned here to works with ChartJS 3.x:
plugins: [{
afterDraw: function (c) {
var yScale = c.scales['y'];
yScale.ticks.forEach(function (o, i) {
// top tick label indent
var yT_O = yScale.getPixelForTick(i) - 9;
// left tick label indent
var xT_O = c.width - 35;
c.ctx.fillStyle = "#707070"
c.ctx.fillText(o.label, xT_O, yT_O);
});
}
}]
Actually i'm not sure this is the best plugin event where do that.
I also had to put "display: false" on the ticks options in order to hide the originals tick labels.

How can I draw dotted line using chartjs?

I would like to draw dotted line using chartjs. I did not see any options in creating dotted lines. I feel we need to extend the chartjs to support this. Can some one help me in this?
In Chart.js 2.1+, use the borderDash option within your dataset. It takes an array of two numbers. See this codepen
For dotted lines use borderDash and borderCapStyle. The following example creates a dotted line (3px diameter):
data: {
datasets: [
{
data : data,
borderWidth : 3, // set diameter of dots here
borderColor : '#ccc',
fill : false,
pointRadius : 0,
borderDash : [0,6], // set 'length' of dash/dots to zero and
// space between dots (center to center)
// recommendation: 2x the borderWidth
borderCapStyle : 'round' // this is where the magic happens
}
]
}
Output
Output (better contrast for demonstration)
Drawing a Dotted Line
You don't need to extend the chart, but it would be cleaner to do it that way.
Preview
Script
Chart.types.Line.extend({
name: "LineAlt",
initialize: function () {
Chart.types.Line.prototype.initialize.apply(this, arguments);
var ctx = this.chart.ctx;
var originalBezierCurveTo = ctx.bezierCurveTo;
ctx.bezierCurveTo = function () {
ctx.setLineDash([10, 10]);
originalBezierCurveTo.apply(this, arguments)
}
}
});
...
new Chart(ctx).LineAlt(chartData);
Fiddle - https://jsfiddle.net/ahj6u14e/
Note - the alternative would be to just override bezierCurveTo using the chart object.
This works because bezierCurveTo is only used to draw the line. If you wanted to do this for straight lines it wouldn't work because lineTo is used for other stuff (axis, grid lines...)
Chart.js 2.0 had a borderDash option when I last checked (see https://stackoverflow.com/a/31428640/360067)

Spacing items on a row in QML?

I can move the "indicator" anywhere I want, but the "Button" and "DiagValue" I ONLY seem to be able move to different rows... I need to move to different columns or different "x".
Row{
spacing: table.rowSpacing
Button {
width: 60
//x: 100 //this does NOTHING!
//y: 159
text: tr_NOOP("Help")
onClicked: {
app.dialogs.message.title = trans("Water Status")
app.dialogs.message.body = trans("Rate is not met.")
app.dialogs.message.show();
}
}
Indicator {
x: -50
//y: 159
ok: false
}
DiagValue {
MeasuredValue {
id: lowFlowValueText
rawValueUnit: "gpm"
unit: "gpm"
precision: 1
}
label: trans("Water Flow Setting")
value: lowFlowValueText.text
}
}
I think if you set proper spacing in Row and align it horizontally, it should look like what you need.
Row {
spacing: table.rowSpacing
anchors.horizontalCenter: parent.horizontalCenter
...
}
And you don't need to supply x value when your elements are inside Row, Row element will decide x value based on spacing and width of individual child.
A Row will define the horizontal location and the horizontal extent (size) of the elements that it contains. It doesn't make sense to manually try to override either x or width for elements in a row, in fact it will generate warnings.
You can, of course, override the vertical position within a Row.
Your elements must be supplying sensible default sizes and must react sensibly to being resized, so without seeing how you define the components (Button, Indicator, DiagValue), it'd be impossible to say exactly where the problem is. For stock controls, it works fine.

raphael pie chart always blue when there is only 1 value (how to set color of a pie with one slice)

I am having an issue with raphael pie charts. The data I am using is dynamic, and in some instances, only 1 value is returned, meaning the whole chart is filled, as it is the ONLY slice. The problem is that when there is only 1 value, it ignores my color designation.
For example: Below is the creation of a raphael pie chart with 2 values, and each slice has the proper color designated in the "colors" section:
var r = Raphael("holder");
r.piechart(160, 136, 120, [100,200],{colors: ["#000","#cecece"]});
This works fine, and I get two properly sized slices, one black, and one grey.
However the example below creates one full pie, ALWAYS filled with blue, regardless of my color setting.
var r = Raphael("holder");
r.piechart(160, 136, 120, [100],{colors: ["#000"]});
In this situation, I really need that full pie to be black, as it is set in "colors"
Am I doing something wrong, or is this a bug?
INMO its a bug cause when the pie got only one slice its color is hard coded...
Here is how I solved it (all I did is use the colors arg if it exist...)
in g.pie.js after line 47 add this
var my_color = chartinst.colors[0];
if(opts.colors !== undefined){
my_color = opts.colors[0];
}
then in the following line (line 48 in the original js file)
series.push(paper.circle(cx, cy, r).attr({ fill: chartinst.colors[0]....
replace the chartinst.colors[0] with my_color
that's it
if (len == 1) {
var my_color = chartinst.colors[0];
if(opts.colors !== undefined){
my_color = opts.colors[0];
}
series.push(paper.circle(cx, cy, r).attr({ fill: my_color, ....
You've probably figured this out on your own since this question is already a day old... but you can "trick" Raphael into rendering a black unit by special-casing datasets of one to add an infinitesimal second value. So, given an array data with your data points...
if ( data.length == 1 )
data.push( 0.000001 );
canvas.piechart(250, 250, 120, data, {colors: ["#000", "#CECECE", "#F88" /*, ... */ ] });
The tiny sliver will still be rendered as a single-pixel line in the 180 degree position, but you could probably fudge that by playing with your color palette.
Yes, it's a trick. I don't believe gRaphael's behavior is buggy so much as poorly implemented (single-element datasets are obviously special cased since they produce a circle instead of a path as they would in all other cases).
Easy way for me without edit g.pie.js
var r = Raphael('st_diagram');
r.piechart(140, 140, 137, 100, 0.0001],{
colors:['#9ae013','#9ae013'],
strokewidth: 0
});