I'm new to canvas. I have a drop canvas shape and want to fill it as animation.
HTML
<canvas id="canvas" width="500" height="500"></canvas>
JS
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d");
context.beginPath();
context.moveTo(109,15);
context.bezierCurveTo(121,36,133,57,144,78);
context.bezierCurveTo(160,109,176,141,188,175);
context.bezierCurveTo(206,226,174,272,133,284);
context.bezierCurveTo(79,300,24,259,25,202);
context.bezierCurveTo(25,188,30,174,35,161);
context.bezierCurveTo(53,115,76,73,100,31);
context.bezierCurveTo(103,26,106,21,109,15);
context.lineWidth = 10;
context.strokeStyle="#0092f9";
context.stroke();
context.fillStyle="rgb(43,146,255)";
context.beginPath();
context.moveTo(181,229);
context.bezierCurveTo(179,232,178,235,176,238);
context.bezierCurveTo(171,247,165,254,158,260);
context.bezierCurveTo(150,266,141,269,132,272);
context.bezierCurveTo(126,274,119,275,112,275);
context.bezierCurveTo(108,276,104,275,100,275);
context.bezierCurveTo(92,274,84,272,76,269);
context.bezierCurveTo(67,265,60,259,53,251);
context.bezierCurveTo(48,245,43,238,39,231);
context.bezierCurveTo(39,230,38,230,39,229);
context.bezierCurveTo(39,228,40,229,40,229);
context.bezierCurveTo(52,230,63,231,75,230);
context.bezierCurveTo(79,229,84,228,89,228);
context.bezierCurveTo(97,227,104,227,112,229);
context.bezierCurveTo(116,230,120,230,124,230);
context.bezierCurveTo(130,231,137,231,143,231);
context.bezierCurveTo(148,231,153,230,158,230);
context.bezierCurveTo(165,229,173,228,181,229);
context.fill();
Drop shape start point as;
and shape end point as;
I want to fill it with animation, increase liquid slowly as in jquery animate function. How can I do this?
Code example
You can use context.clip to restrict your liquid to drawing only in the container.
Here is example code and a Demo: http://jsfiddle.net/m1erickson/jM4hW/
// draw the container
ctx.beginPath();
ctx.moveTo(109,15);
ctx.bezierCurveTo(121,36,133,57,144,78);
ctx.bezierCurveTo(160,109,176,141,188,175);
ctx.bezierCurveTo(206,226,174,272,133,284);
ctx.bezierCurveTo(79,300,24,259,25,202);
ctx.bezierCurveTo(25,188,30,174,35,161);
ctx.bezierCurveTo(53,115,76,73,100,31);
ctx.bezierCurveTo(103,26,106,21,109,15);
ctx.lineWidth=linewidth;
ctx.strokeStyle=strokestyle;
ctx.stroke();
// make the container a clipping region
// all subsequent drawings will only appear inside the container
ctx.clip();
// now draw the liquid
// the liquid will be drawn only where
// it is inside the clipping region (the container)
ctx.fillRect(0,150,canvas.width,500);
Related
For an assignment I need to animate something simple using CSS and JavaScript. I've been able to figure out the CSS but everything I read to make an object fade in using JavaScript just doesn't seem to work with the object I drew in JavaScript. I just wanted to draw a circle in JavaScript and then animate it to fade in in 5 seconds.
Here is the basic Code I have so far:
HTML:
<body onload="draw();">
<canvas id="circle" width="450" height="450"></canvas>
</body>
JavaScript:
<script>
function draw()
{
var canvas = document.getElementById('circle');
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
var X = canvas.width / 2;
var Y = canvas.height / 2;
var R = 45;
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 3;
ctx.strokeStyle = '#645862';
ctx.stroke();
}
}
</script>
As you can see I only have the circle part of the code. I have tried multiple versions of different fade in animations but I just can't quite get them to work. I'm not very good at JavaScript. It's the one language I have trouble understanding for some reason. I'm also really sick right now otherwise I would be troubleshooting more reasons as to why it isn't working.
To understand how a canvas works, you need to know that it's just a place to display something, and initially it doesn't do anything on its own. You've drawn the circle once, which is enough to display the circle, but not to animate it in any way.
If we want to move the circle in any direction, we must clear the canvas of the already drawn circle and draw the circle in a different place, changing its coordinates by N pixels. The same goes for transparency. We must change the transparency of the color of the circle in each frame, and draw the circle again and again.
This is how 2D and 3D canvas works, as well as all video games - they draw scenes 60 times per second, changing some values along the way, such as coordinates, values, color, transparency, height and width.
In order for this to work, we need two additional variables, opacity and the direction (fading) in which the opacity changes, to know whether the circle appears or disappears.
Also important is the recursive call to our draw() function. We will call it constantly, and we will constantly redraw our image on the canvas.
I also want to point out some conceptual mistakes in your code.
Dont use "var", it is deprecated. Use "let","const". Also don`t repeat "var","var","var" in every line. Use commas.
Dont use onload,onclick and others HTML on-attributes. They are only suitable for educational purposes, not for real work. Use script tag and document event listeners.
Dont name canvas id like "circle","box" etc. It is not a circle and a box, it is a canvas.
Use document.querySelector instead of document.getElementById. It is more modern
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas opacity animation</title>
</head>
<body>
<canvas id="canvas" width="450" height="450"></canvas>
<script>
document.addEventListener("DOMContentLoaded",()=>{
const OPACITY_SPEED = .005
let canvas = document.querySelector('canvas'),
context = canvas.getContext('2d'),
opacity = 1,
fading = true
draw()
function draw(){
// clear canvas for redrawing (important!)
context.clearRect(0, 0, canvas.width, canvas.height);
let circleX = canvas.width/2,
circleY = canvas.height/2,
radius = 45
// changing circle opacity
if(fading) opacity -= OPACITY_SPEED
else opacity += OPACITY_SPEED
// check if we need to fade in or to fade out
if(opacity >= 1) fading = true
if(opacity <= 0) fading = false
// draw circle
context.beginPath();
context.arc(circleX, circleY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 3;
context.strokeStyle = `rgba(0, 0, 0, ${opacity})`;
context.stroke();
// call draw() again and again
requestAnimationFrame(draw)
}
})
</script>
</body>
</html>
I'm using html5 canvas to make a game. I made a spritefont system to be able to draw text from a texture. Namely
.
Now I'd like to be able to change the white part of the text to any color I want. My guess is that I'll need to render the texture to a temporary canvas change the color and get the new texture and draw that instead.
However, I don't know how I can replace a color using the canvas's functions.
And I don't even know if this is the best way to do this. What should I do?
Since your spritefont is monochrome, you can use CanvasRenderingContext2D's 'multiply' globalCompositeOperation to apply color to the white part. But multiplying by a solid rectangle of color will wipe out the transparency, so you'll need to redraw the transparent parts with 'destination-atop'.
const FONT_COLOR = '#39f';
// Load up your spritefont
const spritefont = new Image();
spritefont.src = 'https://i.stack.imgur.com/mDvum.png';
// While waiting for the image to load,
// create a canvas to do the coloring work on
const fontCanvas = document.createElement('canvas');
const fontContext = fontCanvas.getContext('2d');
// Once the spritefont is loaded,
spritefont.addEventListener('load', function () {
// Resize the canvas to match the image's dimensions
fontCanvas.width = spritefont.width;
fontCanvas.height = spritefont.height;
// Draw your image on the canvas with a black background
// Without the background, you'll get tinting at the partially-transparent edges
fontContext.fillStyle = 'black';
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
fontContext.drawImage(spritefont, 0, 0);
// Multiply by the font color
// white * color = color, black * color = black
fontContext.globalCompositeOperation = 'multiply';
fontContext.fillStyle = FONT_COLOR;
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
// Restore the transparency
fontContext.globalCompositeOperation = 'destination-atop';
fontContext.drawImage(spritefont, 0, 0);
});
// Display the canvas in the snippet
document.body.append(fontCanvas);
/* just to prove that alpha is preserved */
canvas {background:0 0/32px 32px linear-gradient(45deg,#ccc 25%,transparent 25%,transparent 75%,#ccc 75%,#ccc),16px 16px/32px 32px linear-gradient(45deg,#ccc 25%,#999 25%,#999 75%,#ccc 75%,#ccc);}
If you plan to put the color-changing functionality in a function and reuse the canvas (which you should), make sure to set the context's globalCompositeOperation back to the default, 'source-over'.
HTML5 canvases follows draw and forget strategy. If you want any change (be it font color or change of shapes or text or lines etc) in what had been drawn earlier, you need to re-draw everything.
Mostly upto to my use of canvases, the whole re-drawing process is pretty fast and works without any lag or delay.
EDIT
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '20pt Verdana';
context.fillText('Some text', 50, 50);
context.strokeText('Some text', 50, 50);
context.fill();
context.stroke();
I have this canvas here:
http://jsbin.com/soserubafe
and CODE javascript:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cw=canvas.width;
var ch=canvas.height;
var fov = 250;
var pts = [{x:32,y:59.45},{x:136,y:66},{x:170,y:99},{x:171,y:114},{x:183,y:125},{x:218,y:144},{x:218,y:165},{x:226,y:193},{x:254,y:195},{x:283,y:195},{x:292,y:202},{x:325,y:213},{x:341,y:134},{x:397,y:245},{x:417,y:548}];
mimicSvg(pts);
function mimicSvg(pts){
// make caps & joins round
//ctx.lineCap='round';
ctx.lineJoin='round';
// draw the outside line with red shadow
ctx.shadowColor='red';
ctx.shadowBlur='2';
ctx.lineWidth='40';
ctx.scale(3,3);
// draw multiple times to darken shadow
drawPolyline(pts);
drawPolyline(pts);
drawPolyline(pts);
// stop shadowing
ctx.shadowColor='transparent';
// refill the outside line with pink
ctx.strokeStyle='yellowgreen';
drawPolyline(pts);
// draw the inside line
ctx.lineWidth=2;
ctx.strokeStyle='blue';
drawPolyline(pts);
}
function drawPolyline(pts){
ctx.beginPath();
ctx.moveTo(pts[0].x,pts[0].y);
for(var i=1;i<pts.length;i++){
ctx.lineTo(pts[i].x,pts[i].y);
}
ctx.stroke();
}
and HTML:
<canvas id="canvas" width=1000 height=800></canvas>
How I can add 3d perspective view of this canvas witout using css3, webGL and similar.
Is it possible to add 3d view on 2d canvas?
If you can draw 2d and do math and combine the 2 you can create 3d image (not easy though)
A quick google let me to: http://www.kevs3d.co.uk/dev/phoria/
And this : Possible to run/create 3d animation without need for webgl in HTML5? (so duplicate)
Just wondering if anyone could point me in a good direction to a way I could fill an irregular shape with particles, in rows, which would then be animatable.
This is the closest example i can find - http://www.wkams.com/#!/work/detail/coca-cola-music-vis
The two ways I can think would work is work out the density I want, map out how many particles would be needed for each row, and position accordingly. This way seems quite timely and not very robust.
The second way, which I can't seem to figure out how I would do it, is draw the shape in the canvas, then generatively fill the shape with particles, keeping them in the constraints of the shape.
Any general concept of how this could be done would be greatly appreciated.
Let me know if it doesn't make sense.
Cheers
You can use compositing to restrict your particles inside an irregular shape
For each loop of your animation:
Clear the canvas.
Draw your irregular shape on the canvas.
Set compositing to 'source-atop'. This will cause any new drawings to appear only if any newly drawn pixel is over an existing opaque pixel. This is the secret to restricting your particles to be drawn only inside your irregular shape.
Draw your rows of particles. All particles will appear only inside the shape.
Here's example code and a Demo. My example just animates the size of each particle row. You can apply your design requirements to change the size & position of each row.
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
//
ctx.fillStyle='skyblue';
var PI2=Math.PI*2;
//
var w=132;
var h=479;
//
var x1=29;
var x2=177;
var x3=327;
//
var nextTime=0;
var delay=16*2;
var isFading=true;
var isComplete=false;
var opacity=100;
var imgCount=2;
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/coke.png";
var label=new Image();label.onload=start;label.src="https://dl.dropboxusercontent.com/u/139992952/multple/label.png";
function start(){
console.log(imgCount);
if(--imgCount>0){return;}
requestAnimationFrame(animate);
$('#again').click(function(){
nextTime=0;
delay=16*2;
opacity=100;
isFading=true;
});
}
function overlay(clipX,x,alpha){
ctx.globalAlpha=alpha;
ctx.drawImage(img,clipX,0,w,h,x,0,w,h);
}
function fillParticles(radius,margin){
var rr=radius*2+margin;
ctx.save();
ctx.clearRect(0,0,cw,ch);
overlay(x3,50,1.00);
ctx.globalCompositeOperation='source-atop';
ctx.beginPath();
var rows=parseInt(ch/(rr))-2;
var cols=parseInt(cw/rr);
for(var r=0;r<rows;r++){
for(var c=0;c<cols;c++){
ctx.arc(c*rr,h-(r*rr),radius,0,PI2);
ctx.closePath();
}}
ctx.fill();
ctx.restore();
overlay(x2,50,1.00);
}
function animate(time){
if(!isComplete){ requestAnimationFrame(animate); }
if(time<nextTime){return;}
if(isFading){
if(--opacity>0){
ctx.clearRect(0,0,cw,ch);
overlay(x1,50,opacity/100);
overlay(x2,50,1.00);
}else{
isFading=false;
overlay(x2,50,1.00);
ctx.drawImage(label,70,210);
nextTime=time+1000;
}
}else{
delay=1000;
fillParticles(parseInt(Math.random()*8)+2,3);
ctx.drawImage(label,70,210);
nextTime=time+delay;
}
}
body{ background-color:white; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=again>Again</button>
<br>
<canvas id="canvas" width=250 height=500></canvas>
If I were to approach this problem, I would go about it in this way:
Create an object that can be used to "create" particles.
Create as many new instances of that object as is needed for the required density.
So, basically, all the work is done by one function constructor/object.
You want this object to provide methods to draw itself to the canvas, store its x and y coordinates, its velocity and direction.
Then you can create instances of this object with the new keyword and set their x and y coordinates to spread them across a grid.
I need your help , my question is can we adjust the transparency of drawn line on mouse move??
I wrote this code to draw tow lines and I added the addEventListener to get the coordinates of mouse but my problem is that I do not know how to adjust the transparency when the mouse is moving on the line.
<body>
<canvas id="drawImage" width="900" height="900" style="background-color:black"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("drawImage");
var cont = canvas.getContext("2d");
cont.beginPath();
cont.lineWidth=15;
cont.strokeStyle="red";
cont.moveTo(0,0);
cont.lineTo(100,100);
cont.stroke();
cont.save();
cont.beginPath();
cont.strokeStyle="yellow";
cont.moveTo(100,100);
cont.lineTo(100,150);
cont.stroke();
cont.save();
canvas.addEventListener("mousemove", function(event {});
</script>
</body>
thanx every body.
You can create a function that alters transparency with each stroke using .globalAlpha
A Demo: http://jsfiddle.net/m1erickson/dQFvm/
Example function:
function drawAlphaLine(x0,y0,x1,y1,strokeColor,alpha){
ctx.save();
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.lineTo(x1,y1);
ctx.globalAlpha=alpha;
ctx.strokeStyle=strokeColor;
ctx.stroke();
ctx.restore();
}