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)
Related
Is it possible to show the tooltip square only in one (certain) row?
Now it just duplicates color square for each line:
The goal is to add square only to first line "metric_val" to make it like that:
I tried labelColor callback but looks like it does not work in that way (it manipulates squares that appears in each row).
Text with colored square should be in label
Text without colored square should be in footer:
tooltips: {
callbacks: {
footer: function(tooltipItems, data) {
return ['Description 1', 'Description 2'];
}
}
}
i'm trying to achieve something like this but with legend on bottom.
When i try adding it at most i can get something like this:
i'm considering separating legend to another div like
<div id="js-legend" class="chart-legend"></div>
but it would be nice to achieve it with the former solution.
Thanks in advance for the help
I think something like this should work.
plugins: [{
beforeInit: (chart, options) => {
chart.legend.afterFit = () => {
if (chart.legend.margins) {
// Put some padding around the legend/labels
chart.legend.options.labels.padding = 20;
// Because you added 20px of padding around the whole legend,
// you will need to increase the height of the chart to fit it
chart.height += 40;
}
};
}
}]
you can use margin-top for #js-legend.
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
I'm trying to understand how sets work with transforms. Basically, I would like to have a 'container' set with all children in it, that I can move around the canvas.
I created a fiddle to show what I mean, this is a simplification of a larger drawing. http://jsfiddle.net/thibs/Hsvpf/
I've created 3 squares, red, black, blue. Each are added to a set and then they are added to a main container (set). I've added outlines to show canvas and set.
Red and black sets do not have transforms on them, but blue does. Blue remains in the 'container' set... until the container gets a transform.
Why is that? I thought that transforms were applied to all the chidlren of the set...?
Thanks in advance
Here is the fiddle code:
var paper = Raphael('holder');
var container = paper.set();
paper.rect(0, 0, '100%', '100%').attr({
stroke : 'red'
});
var rectRedSet = paper.set();
var rectRed = paper.rect(100, 10, 20, 20).attr({
'fill' : 'red',
'stroke-opacity' : 0
});
rectRedSet.push(rectRed);
container.push(rectRedSet);
var rectBlackSet = paper.set();
var rectBlack = paper.rect(150, 10, 20, 20).attr({
'fill' : 'black',
'stroke-opacity' : 0
});
rectBlackSet.push(rectBlack);
container.push(rectBlackSet);
var rectBlueSet = paper.set();
rectBlue = paper.rect(0, 0, 20, 20).attr({
'fill' : 'blue',
'stroke-opacity' : 0
});
rectBlueSet.push(rectBlue);
rectBlueSet.transform('t50,150');
container.push(rectBlueSet);
var containerBBox = container.getBBox();
paper.rect(containerBBox.x, containerBBox.y, containerBBox.width, containerBBox.height).attr({
stroke : 'black'
});
//trying to get the entire container and its children to move to 0,0
//commenting out the transform below will keep rectBlue in the container...?
container.transform('t0,0');
A "set" in Raphael is not like a "group" in SVG. A set in Raphael is just a collection of elements that you can manipulate at the same time. So when you set the transform on the container set, it is really just setting the transform on every element inside the set, overwriting any previous transform settings.
You can append or prepend to existing transformations in Raphael using "..." notation.You need to change your last line to:
container.transform("...t0,0")
But "t0,0" doesn't actually move anything anywhere. If you want to move the container so the top left corner is at 0,0, then you need to write:
container.transform('...t-' + containerBBox.x + ',-' + containerBBox.y);
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
});