Which is the appropriate lifecycle hook to draw a line? - chart.js

I want to draw a line to show the zero value on a y axis. I have this working:
afterDraw(chart) {
const {ctx, scales} = chart;
Object.keys(scales).forEach((key) => {
const scale = scales[key];
if (scale.axis !== 'y') {
return;
}
const yCoordinate = scale.getPixelForValue(ZERO_COORDINATE);
ctx.fillStyle = 'blue';
ctx.fillRect(0, yCoordinate, 200, 5);
});
},
I had first attempted to use afterBuildTicks, but that didn't draw the line - or at least it wasn't visible. Is there guidance regarding when to use the different lifecycle hooks? Some seem obvious, others less so.
If I use the chart's context in any lifecycle hook, how do I ensure what I draw is on top of the chart? I saw an example where someone changed the background by supplying a beforeDraw callback - is the stacking context managed by order in which we draw via the different hooks?

There is a diagram in the chart.js documentation that shows when each hook is being called in the rendering process and what chart.js does between those hooks like drawing datasets, grids etc.
If you want to make sure what you are drawing is on top of everything else you will need to use the afterDraw hook to draw the things on the canvas that you want there.

Related

fill a freehand drawing with opacity

I have a simple fuction which fills the drawn image if the user chooses to
canvas.on('mouse:up', function() {
if(main.mode == 'fill') {
var object = main.canvas.item(main.canvas.getObjects().length-1);
object.fill = main.pColor();
canvas.renderAll();
}
})
this works fine for solid(opacity 1) colors. When using a color with less opacity:
It seems the stoke and fill overlap yielding a darker line.
I experimented with globalCompositeOperation. I am thinking eliminate the stroke or set the stroke opacity to zero. I hope there is a better answer.
I tried a few approaches: setting stroke opacity to zero and trying to get rid of the stroke altogether.
what works best is adding
object.set('strokeWidth', 0);
to the handler above.
set ensures the canvas will be updated.
It is working well.

How to Update beginAtZero in Chart.js

I have a graph that is already drawn. I'd like to toggle the beginAtZero property on the yAxis ticks: {beginAtZero: true} and use update() to force the graph to redraw so I don't have to reload the whole page.
Is this possible, and if so, how would one go about doing it?
Thanks for any help!
myBarChart.options.scales.yAxes[0].ticks.beginAtZero = false;
// You probably also want to move your min :
myBarChart.options.scales.yAxes[0].ticks.min = 100;
// and call update:
// myBarChart.update();
Here's pen with some buttons if you want to experiment:
Chart.js add/remove adjust data
Another thing you can do, is destroy and rebuild the chart :
Chart.js Toggle Chart

Chart.js Pie Chart: How to set background image for segment

I'm using Chart.js to create a pie chart (see below). Instead of the colors in each pie segment, I would like to use a background image.
Could you give me a pointer on how I could do this?
Thanks!
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
}
];
var myPieChart = new Chart(ctx[0]).Pie(data,options);
Subclass Pie, rewrite the initializer and addData - in the initializer re-define draw, adding one line:
if(this.bg_img)ctx.fillStyle=ctx.createPattern(this.bg_img,"repeat");
, right after it says:
ctx.fillStyle = this.fillColor;
(copy Pie's draw, add that line - or just copy my AltPie subclass from the bottom of the attached fiddle) This could be different for later versions but that's how Chart.js 1.01 is.
Also in your Pie subclass you will add a property (for example call it bg_img) for sending the background image through. To do this there is a one-line addition, so re-define addData inside AltPie and add the property inside the splice line:
bg_img : segment.bg_img,
for example somewhere around the line
fillColor : segment.color,
That's most of it - other than that you will load and then attach the images to the data you're making the chart with. To load them you can use
....img=new Image();...img.src=...and - img.onload=function()(..recurse-load-next,
with a recursing callback similar to solution #2 from this page:
stackoverflow.com/questions/4960111/image-as-a-background-to-a-drawn-shape
I think you would need to make sure the images are done loading before attaching them to the data and sending them through to the Chart.js renderer, hence the recursion pattern to load them one by one before attaching them to the chart data and then creating the new AltPie chart.
The end result is that your images will show up in the pie pieces backgrounds or you can still use a color background if there's no image. It changes the html5 canvas ink pattern
(ctx.fillStyle=ctx.createPattern(this.bg_img,"repeat"))
to be the image you attached to the chart data, also taken from solution #2 from the same page: stackoverflow.com/questions/4960111/image-as-a-background-to-a-drawn-shape.
For the complete working example see attached fiddle https://jsfiddle.net/arlon_arriola/pkwftkp2/
The dependencies for loading the page are Chart.js file (v1.01?) (which is just copy/pasted into the fiddle at the top making the code look extremely long but the relvant code is at the very bottom), and the images inside your ./imgs/patterns/ folder, and the reference to some hosted jquery (1.9?). (and a body tag)
I am sure you could get image rollovers too, just attach two images to the data, figure out where it re-draws for hovering and modify it the same way as the regular draw.

RaphaelJS Multiple animate same element

I currently have the following working fiddle
var moveAnim = Raphael.animation({ progress: 1 }, 5000, 'bounce').repeat(Infinity);
I animate a circle along a line.
I also want to make the circle flash at the same time but I can't seem to work out a way to do this?
I thought about adding the circle to a set and applying the additional animation to this but I can't see to get this either!
Any ideas?
This is a hack and I make no attempt to hide it, but it could be made a bit nicer.
There's a couple of problems depending on 'how' you want to animate the flash. The main problem is having 2 simultaneous animation on the same object, as Raphael doesn't do this (to my knowledge). Its easier if you want to animate an alternate attribute than the same one. If you want to animate a scale to indicate a flash, you will need to append the scale transform to the end of the path transform string ('t,s').
Example here, just uses opacity attribute.
Probably the nicest method would be to include something that figures out time running and amends an attribute manually within the animation function (paper.customAttributes.progress). However, that will probably take a bit longer.
Another alternative could be to animate another object off screen, that does all the calculations for you. It feels a bit ugly, but should work.
So earlier we create a dummy object off screen...
var dummy = paper.circle(-100,-100,10).attr({ opacity: 0 });
Within the progress func, you can then set the real circles opacity to be the same as the offscreen one.
this.attr('opacity', dummy.attr('opacity'));
And we get the dummy animation triggering later
dummy.animate(flashingAnim);
jsfiddle
As mentioned, I think there are cleaner ways, but may involve you writing a small linear animation func separately, but this may help if performance isn't an issue and you don't mind extra elements in the dom.
An alternative solution that I came up with is a looping callback. The very sound of a looping callback sounds ugly but I guess thats what an animation is?
It does appear that you can attach multiple animations to an element! Here's a an example
function animateIn() {
flashingCircle.animate({ fill: '#f00' }, 1000, animateOut);
}
function animateOut() {
flashingCircle.animate({ fill: '#fff' }, 1000, animateIn);
}
animateIn();

Google visualization

I am using google visualization for drawing a 3d chart.
I use - greg.ross.visualisation.SurfacePlot().
I am drawing chart in iframe.
If I call the method draw() once, the chart gets plotted properly. But, after that calling draw() again doesn't make any change. It doesn't draw the chart again.
Can anyone help me in this? I want to draw the chart again & again depending on user input.
Is there any way to redraw the chart?
or is tehre any way to flush the existing chart?
& one more question - why this is happening?
How do I delete a google chart and replace it with a new one in a google app?
Try this
/* Clear chart Panel */
var chartPanel = app.getElementById('chartPanel');
chartPanel.clear();
Reuse the "draw()" function. example :
/*************************************************************************/
/* Redraw charts on window resize (only if responsive option is TRUE */
angular.element($window).bind('resize', function () {
if (googleTreeChartsResponsive) {
$timeout(function () { googleChartsInstance.draw(data, googleTreeChartsOptions) }, 250);
}
});
From : http://codepen.io/vage/pen/KdoBRr (resize the window, the charts will be redraw() )