HTML5 circle and arrow with gradient background - html

I need a function in HTML5 that with given context, x1, y1, x2, y2 would draw me a circle (at beginning of this vector) with arrow that represents the vector itself, that would have gradient background. Left image is what I got - I am not pleased with the result... right image is visualisation of what I would like to make.
Could anybody help me with that please?
This is my arrow function (circle is obvious):
function arrow(context, fromx, fromy, tox, toy){
var headlen = 10;
var angle = Math.atan2(toy-fromy,tox-fromx);
context.moveTo(fromx, fromy);
context.lineTo(tox, toy);
context.lineTo(tox-headlen*Math.cos(angle-Math.PI/6),toy-headlen*Math.sin(angle-Math.PI/6));
context.moveTo(tox, toy);
context.lineTo(tox-headlen*Math.cos(angle+Math.PI/6),toy-headlen*Math.sin(angle+Math.PI/6));
}

Ok, I'll bite...
If your arrow function is working fine now, you can also draw a circle in that function.
This modified arrow() will draw both the circle and arrow in gray.
Since you want to change the context state ( change fill/stroke to gray ) you should wrap the path drawing commands in context.save and context.restore.
You should (must!) begin all atomic path drawings with context.beginPath. This prevents path drawings from being inadvertently repeated.
This refactoring of your arrow uses context transforms to set the rotation point at x1,y1 and then draws the circle and then draws the arrow to x2,y2.
A Demo: http://jsfiddle.net/m1erickson/87T8d/
Example arrow function:
function arrow(x1,y1,x2,y2){
var dx=x2-x1;
var dy=y2-y1;
var radians=Math.atan2(dy,dx);
var length=Math.sqrt(dx*dx+dy*dy);
// save the unrotated context state
ctx.save();
// set the rotation point as x1,y1
ctx.translate(x1,y1);
// rotate the canvas by the angle of the vector
ctx.rotate(radians);
// draw the circle
ctx.beginPath();
ctx.arc(0,0,8,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="gray"; // or gradient if you prefer
ctx.fill();
// draw the arrow
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(length,0);
ctx.lineTo(length-7,-4);
ctx.lineTo(length-7,4);
ctx.lineTo(length,0);
ctx.closePath();
ctx.fillStyle="gray";
ctx.fill();
ctx.strokeStyle="gray";
ctx.stroke();
// restore the context to its unrotated state
ctx.restore();
}

Related

html5 canvas text slide in behind nothing

I want to have html5 canvas text slide in behind nothing, its an effect where text appears like coming out behind some obstacle, but the obstacle is invisible.
Here is some youtube video showing how to do it in after effect:
https://www.youtube.com/watch?v=KIYMy7vLLRo
I know how to slide a text along canvas, and one idea I got is having two canvases on top of each other, and top canvas is smaller and contains the text that is initially out of canvas and slides in. But if there is a way to do it with just one canvas that would be great.
You can using a clipping path to mask out part of the text.
Save the existing clipping path using the save() method. Create a shape/path and make it the new clipping path using the clip() method. Draw your text. Store the previous clipping path using the restore() method.
For example, suppose your canvas is 100 pixels by 100 pixels. The following will draw text on only the left side of the canvas.
context.save();
context.rect(0, 0, 50, 100);
context.clip();
context.fillText("Draw some text.", 30, 50);
context.restore();
jsFiddle : https://jsfiddle.net/CanvasCode/vgpov2yk/3
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
// Positions for the text startint off
var xText = -100;
var yText = 150;
// This will update the canvas as fast as possible (not good)
setInterval(function () {
// Clear the canvas
ctx.fillStyle = "#F0F";
ctx.fillRect(0, 0, c.width, c.height);
ctx.save()
// We create a clip rect
ctx.rect(200,0,400,400);
ctx.clip();
// Draw text
ctx.fillStyle = "#FFF";
ctx.font = "30px Arial";
ctx.fillText("Hello World", xText, yText);
ctx.restore();
// Increase the text x position
if (xText < 200) {
xText += 0.5;
}
}, 15);
All you have to do is use a clip rect which is like a mask in image editing.

Using globalCompositeOperation in few phases

I'm drawing many things on my context. Shapes, texts, images..
I want to use achieve the same effect i'm getting using the clip method on the context with globalCompositeOperation (Using the clip is harder for me to perform and i don't know if possible for texts)
The user can draw few shapes. and then start a mask phase. to draw some more shapes, texts.. which would draw into the mask and then the next draw will be clipped in the masked phase. and then continue to regular drawing...
For ex.
The user draw this drawing
Then started masked mode and drew this 2 red lines
Then he stopped drawing into the mask, and start drawing rectangle to consider the mask
And finally applied the mask clipping and the result should look like this
I've managed to clip the rectangle with the lines if there were no earlier drawings.
// Starting the mask phase
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(240, 140);
ctx.moveTo(80, 20);
ctx.lineTo(300, 140);
ctx.stroke();
ctx.globalCompositeOperation = 'source-out';
ctx.fillStyle = 'cyan';
ctx.fillRect(50, 70, 250, 20);
// Setting the composition back
ctx.globalCompositeOperation = 'source-over';
but when i'm adding my drawings in the beginning of the code, the composition considering it as well.
ctx.fillStyle = 'brown';
ctx.beginPath();
ctx.arc(80, 80, 50, 50, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'yellow';
ctx.fillRect(80, 60, 150, 40);
ctx.fillStyle = 'black';
ctx.font = '40pt arial';
ctx.fillText('Hello', 130, 110);
// How to tell the context to start from here the compisition ???
How to tell the context to start composition from a certain point, if possible ?
I could create another canvas and draw the mask there.. and then draw the new canvas on the main canvas. But there is better solution ?
You can change the compositing mode at any point in the drawing flow by changing .globalCompositeOperation. But, as you've discovered, any new compositing mode will also affect existing canvas content.
Your intuition is correct about using a second "staging canvas" to do compositing that won't destroy your existing content.
You can use an in-memory canvas to do compositing and create your rect-with-erased-lines. Then you can drawImage this in-memory canvas to your main canvas. Since the compositing was done on your in-memory canvas, your existing circle-hello content is not undesirably affected by compositing.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// create an in-memory canvas to do compositing
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/temp6a.png";
function start(){
ctx.drawImage(img,0,0);
addCompositedRectangle();
ctx.drawImage(c,0,0);
}
function addCompositedRectangle(){
// resize the in-memory canvas
// Note: this automatically clears any previous content
// and also resets any previous compositing modes
c.width=300; // largest width;
c.height=140; // largest height;
// Starting the mask phase
cctx.strokeStyle = 'red';
cctx.lineWidth = 5;
cctx.beginPath();
cctx.moveTo(20, 20);
cctx.lineTo(240, 140);
cctx.moveTo(80, 20);
cctx.lineTo(300, 140);
cctx.stroke();
cctx.globalCompositeOperation = 'source-out';
cctx.fillStyle = 'cyan';
cctx.fillRect(50, 70, 250, 20);
// Setting the composition back
cctx.globalCompositeOperation = 'source-over';
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

Canvas Chart fill the space between lines

I'm developing a simple chart using html5 Canvas. The idea is to draw two lines - one for min values and another one for max values, which I managed to do AND fill the space between those two line with some colour. Wonder how do I do the last part?
to fill the space you have to:
//get the context of the canvas
var context = canvas.getContext("2d");
//begin to draw
context.beginPath();
//draw all the lines you need to do the path....
context.moveTo(x, y);
context.lineTo(x1,y1);
context.lineTo(x2,y2);
//end of draw
context.closePath();
//to fill the space in the shape
context.fillStyle = "#FF00FF";
context.fill();
//to draw a border
context.lineWidth = 5;
context.strokeStyle = "#FF0000";
context.stroke();
UPDATE: to fill the space between 2 lines, is drawing a square:
I asume the lines are defined as:
line1: from (x1,y1) to (x2,y2)
line2: from (x3,y3) to (x4,y4)
then the square to draw to fill the space:
from (x1,y1) -> (x2,y2) -> (x3,y3) -> (x4,y4) and closepath();
then:
context.beginPath();
context.moveTo(x1,y1); //go to first point
context.lineTo(x2,y2); //draw to second point
context.lineTo(x3,y3); //draw to third point
context.lineTo(x4,y4); //draw to last point
context.closePath(); //draw to first point
context.fill(); //fill the area

CSS Radial Clip

I have a image of a circle (png) and I'd like to use clip to mask a portion of it. Is there such a type of radial clip? (Say I wanted to convert the circle to a pie chart e.g 32% only) with the clip mask
Edit: Perhaps tips on a SVG overlay would be nice if this isnt possible?
Using canvas (and a very small bit of jquery to get node references):
var ctx = $( '#canvasTag' )[0].getContext( '2d' );
// draw your image
ctx.drawImage( $( '#imgTag' )[0], x, y );
// change composite operation so that only the image below the arc below shows
ctx.globalCompositeOperation = 'destination-in';
// draw part of a circle
ctx.beginPath();
ctx.arc( x, y, radius, startAngle, endAngle, false ); // draw outer arc
ctx.lineTo( x, y ); // draw to center
ctx.closePath();
ctx.fill();

HTML5 : drawing round corner rectangle as animation

I'm able to draw a rectangle with rounded corner with following code. What I'm looking is I want to form this as an animation - starting from one point and draw the line which ends at the beginning point. (like drawing with pencil) Any ideas?
ctx.beginPath();
ctx.moveTo(x,y+radius);
ctx.lineTo(x,y+height-radius);
ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
ctx.lineTo(x+width-radius,y+height);
ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
ctx.lineTo(x+width,y+radius);
ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
ctx.lineTo(x+radius,y);
ctx.quadraticCurveTo(x,y,x,y+radius);
ctx.stroke();
Canvases are double-buffered. You'll need to defer each step of the animation using setTimeout() to give the canvas a chance to draw your changes. Update: See requestAnimationFrame as an alternative to setTimeout().
I've created one example for you that draws each of your rectangle's segments by calling the context method and pausing. I think I know the particular animation you're looking for and this isn't it, but hopefully it gives you a good start.
Code below and a demo is here: http://jsfiddle.net/q8GcR/
function animateRoundRect(ctx, x, y, width, height, radius, delay) {
commands = [
['moveTo', x,y+radius],
['lineTo', x,y+height-radius],
['quadraticCurveTo', x,y+height,x+radius,y+height],
['lineTo', x+width-radius,y+height],
['quadraticCurveTo', x+width,y+height,x+width,y+height-radius],
['lineTo', x+width,y+radius],
['quadraticCurveTo', x+width,y,x+width-radius,y],
['lineTo', x+radius,y],
['quadraticCurveTo', x,y,x,y+radius]
];
function draw() {
var args = commands.shift();
var method = args.shift();
ctx[method].apply(ctx, args);
ctx.stroke();
if (commands.length) {
setTimeout(draw, delay);
}
}
ctx.beginPath();
draw();
}
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.lineWidth = 3;
ctx.strokeStyle = '#f00';
animateRoundRect(ctx, 20, 20, 250, 100, 10, 500);
some defects like - outline is crude, code might not be upto mark, the last clearing is making the canvas entirly white. Can somebody enhance this code ?. Pls run the code in firefox or chrome.
code : http://jsfiddle.net/XnzhQ/1/