I am drawing a canvas.
I simplified my code.
There is a transparent circle.
The background is rgba 0,0,0,0.5.
I'd like to add "shadowblur" for the transparent circle. However, it's fail.
Is it possible?
I have another logic:
Create one circle with linear-gradient (rgba 0,0,0,0.5, transparent)
However, it seems no good.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="Preloader">
<canvas id="myCanvas"></canvas>
</div>
<style>
.Preloader {
background-color: #7bf;
}
</style>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = window.innerWidth;
c.height = window.innerHeight;
class ball {
constructor(x, y) {
this.position = {
x: x,
y: y
}
this.r = 100
}
draw() {
ctx.beginPath();
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, c.width, c.height);
ctx.fill();
ctx.closePath();
ctx.save();
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);
ctx.clip();
ctx.clearRect(0, 0, c.width, c.height);
ctx.shadowBlur = 0;
ctx.closePath();
ctx.restore();
}
update() {
this.draw()
this.position.x++
this.position.y++
}
}
var Ball = new ball(c.width / 2, c.height / 2)
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, c.width, c.height);
Ball.update();
};
animate();
</script>
</body>
</html>
If you mean that you want the edges of the clipping-area to be smoother, then you can use compositing to use any bitmap as a mask:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = window.innerWidth;
c.height = window.innerHeight;
class ball {
constructor(x, y) {
this.position = {
x: x,
y: y
}
this.r = 100
}
draw() {
// fillRect doesn't need beginPath(), and it does fill()
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, c.width, c.height);
// closePath encloses the current subpath
// it doesn't "end" the path declaration
// beginPath does that
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);
// we use compositing to create our hole, with shadow:
ctx.globalCompositeOperation = "destination-out";
ctx.shadowBlur = 30;
ctx.shadowColor = "black";
ctx.fillStyle = 'black';
ctx.fill();
// restore
ctx.shadowBlur = 0;
ctx.globalCompositeOperation = "source-over";
}
update() {
this.draw()
this.position.x++
this.position.y++
}
}
var Ball = new ball(c.width / 2, c.height / 2)
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, c.width, c.height);
Ball.update();
};
animate();
.Preloader {
background-color: #7bf;
}
<div class="Preloader">
<canvas id="myCanvas"></canvas>
</div>
This would also work with CanvasGradient instead of shadowBlur:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = window.innerWidth;
c.height = window.innerHeight;
class ball {
constructor(x, y) {
this.position = {
x: x,
y: y
}
this.r = 100
}
draw() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, c.width, c.height);
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = ctx.createRadialGradient(this.position.x, this.position.y, this.r, this.position.x, this.position.y, 0);
ctx.fillStyle.addColorStop(0, "transparent");
ctx.fillStyle.addColorStop(.25, "black");
ctx.fillRect(0, 0, c.width, c.height);
// restore
ctx.globalCompositeOperation = "source-over";
}
update() {
this.draw()
this.position.x++
this.position.y++
}
}
var Ball = new ball(c.width / 2, c.height / 2)
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, c.width, c.height);
Ball.update();
};
animate();
.Preloader {
background-color: #7bf;
}
<div class="Preloader">
<canvas id="myCanvas"></canvas>
</div>
Or even in Chrome and Firefox by using CSS blur filters:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = window.innerWidth;
c.height = window.innerHeight;
class ball {
constructor(x, y) {
this.position = {
x: x,
y: y
}
this.r = 100
}
draw() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, c.width, c.height);
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);
// we use compositing to create our hole, with shadow:
ctx.globalCompositeOperation = "destination-out";
ctx.filter = "blur(15px)";
ctx.fill();
// restore
ctx.filter = "none";
ctx.globalCompositeOperation = "source-over";
}
update() {
this.draw()
this.position.x++
this.position.y++
}
}
var Ball = new ball(c.width / 2, c.height / 2)
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, c.width, c.height);
Ball.update();
};
animate();
.Preloader {
background-color: #7bf;
}
<div class="Preloader">
<canvas id="myCanvas"></canvas>
</div>
Related
I have made an audio-player and it has a canvas for its seeklider.
The ctx is the pointer that tracks audio.currentTime.
I am trying to achieve an effect so that when the ctx is moving along the X axis, the canvas before that point should have globalAlpha set to 0.4, and canvas after the ctx set to globalAlpha = 0.6.
<div class="slider-container ">
<canvas id ="canvas" height ="90" width ="300"></canvas>
</div>
//Javascript
//Load canvasbackground image.
function drawbg(){
canvasbackground_index = playlist_index;
canvasbg.src = cdir+canvasbackground[canvasbackground_index]+png;
ctx.drawImage(canvasbg,0,0,canvas.width, canvas.height);
}
//calculate canvas.ctx position on X-axis relative to audio.currentTime
function ctxupdate() {
ct = audio.currentTime * (100 / audio.duration);
ctx.x = (ct/100) * canvas.width;
seekto = ctx.x;
}
//draw a thin vertical rectangle relative to audio.currentTime
function draw() {
ctx.fillStyle = "rgb(250,250,250)";
ctx.fillRect(ctx.x, 0, 1, 90);
ctx.x = ct;
}
//animate canvas
function canvasAnimate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(canvasAnimate);
drawbg();
ctxupdate();
draw();
}
canvasAnimate();
Would using js instead of css be ok. Something similar to this?
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
canvas.width = 300;
canvas.height= 100;
let pic = new Image();
pic.src="https://static.toiimg.com/photo/72975551.cms"
class Cursor {
constructor(x) {
this.x = x;
}
draw() {
ctx.strokeStyle = "white";
ctx.strokeRect(this.x ,0, 2, 100);
ctx.stroke();
}
update() {
this.x == canvas.width ? this.x = 0 : this.x++
this.draw();
}
}
let cursor = new Cursor(0);
function changeBG() {
ctx.drawImage(pic,0,0,canvas.width,canvas.height);
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
ctx.fillRect(0, 0, 0 + cursor.x, canvas.height);
ctx.fillStyle = "rgba(255, 255, 255, 0.6)";
ctx.fillRect(0, 0, cursor.x + canvas.width, canvas.height);
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
cursor.update();
changeBG();
requestAnimationFrame(animate);
}
animate();
<canvas id ="canvas" height ="90" width ="300"></canvas>
UPDATE: I took your ctxupdate() function and moved the contents of that to drawbg(). Then I added the fillRect and fillStyle code from above to drawbg(). The stopCanvasbg() is not used but I left it because you had it in there.
So from your sizeCanvas() to your canvasAnimate() here;s what it looks like
function sizecanvas() {
if(window.innerWidth >= 1469) {
canvas.width = 1469
canvas.clientWidth = canvas.width;
} else {
canvas.width = canvas.clientWidth;
}
}
function drawbg(){
ct = audio.currentTime * (100 / audio.duration);
//if (isNaN(ctx.x)) return;
ctx.x = (ct/100) * canvas.width;
seekto = ctx.x;
canvasbackground_index = playlist_index;
canvasbg.src = cdir+canvasbackground[canvasbackground_index]+png;
ctx.drawImage(canvasbg,0,0,canvas.width, canvas.height);
ctx.fillStyle = "rgba(255, 255, 255, 0.6)"
ctx.fillRect(0, 0, 0 + seekto, canvas.height);
ctx.fillStyle = "rgba(255, 255, 255, 0.2)";
ctx.fillRect(0, 0, seekto + canvas.width, canvas.height);
}
function stopCanvasbg(){
canvasbackground_index = (canvasbackground.length -1);
console.log(canvasbackground_index);
canvasbg.src = canvasbackground_index;
ctx.drawImage(canvasbg,0,0,canvas.width, canvas.height);
}
function canvasAnimate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawbg();
requestAnimationFrame(canvasAnimate);
}
canvasAnimate();
See if that works on your end.
I am currently trying to create a canvas that has a background and a crosshair like object that follows around your mouse, everything works besides the crosshair still showing where it was previously drawn. I'm not sure where to clear the canvas without everything on the canvas being cleared and not showing up here is my code.
canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
class Background {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawBackground() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");
backgroundSky.drawBackground();
backgroundGrass.drawBackground();
class Lens {
constructor(x, y, radius, color) {
this.x = x,
this.y = y,
this.radius = radius,
this.color = color
}
drawLens() {
ctx.lineWidth = 10;
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
ctx.stroke();
ctx.fillStyle = this.color;
ctx.fill();
}
}
class Cross {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawCross() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
addEventListener("mousemove", function(event) {
mouseX = event.clientX;
mouseY = event.clientY;
const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
const lens = new Lens(mouseX, mouseY, 250, "transparent");
crossX.drawCross();
crossY.drawCross();
lens.drawLens();
});
* {
margin: 0;
overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="index.js" async defer></script>
</body>
</html>
Clear the entire screen and redraw it per frame:
ctx.clearRect(0, 0, canvas.width, canvas.height);
backgroundSky.drawBackground();
backgroundGrass.drawBackground();
crossX.drawCross();
crossY.drawCross();
lens.drawLens();
Full code:
canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
class Background {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawBackground() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");
class Lens {
constructor(x, y, radius, color) {
this.x = x,
this.y = y,
this.radius = radius,
this.color = color
}
drawLens() {
ctx.lineWidth = 10;
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
ctx.stroke();
ctx.fillStyle = this.color;
ctx.fill();
}
}
class Cross {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawCross() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
addEventListener("mousemove", function(event) {
mouseX = event.clientX;
mouseY = event.clientY;
const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
const lens = new Lens(mouseX, mouseY, 250, "transparent");
ctx.clearRect(0, 0, canvas.width, canvas.height);
backgroundSky.drawBackground();
backgroundGrass.drawBackground();
crossX.drawCross();
crossY.drawCross();
lens.drawLens();
});
* {
margin: 0;
overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="index.js" async defer></script>
</body>
</html>
You could redraw the background just before drawing the crosshair.
Your mousemove event listener function would become:
addEventListener("mousemove", function(event) {
mouseX = event.clientX;
mouseY = event.clientY;
const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
const lens = new Lens(mouseX, mouseY, 250, "transparent");
backgroundSky.drawBackground(); // ⚠️
backgroundGrass.drawBackground(); // ⚠️
crossX.drawCross();
crossY.drawCross();
lens.drawLens();
});
canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
class Background {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawBackground() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");
backgroundSky.drawBackground();
backgroundGrass.drawBackground();
class Lens {
constructor(x, y, radius, color) {
this.x = x,
this.y = y,
this.radius = radius,
this.color = color
}
drawLens() {
ctx.lineWidth = 10;
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
ctx.stroke();
ctx.fillStyle = this.color;
ctx.fill();
}
}
class Cross {
constructor(x, y, width, height, color) {
this.x = x,
this.y = y,
this.width = width,
this.height = height,
this.color = color
}
drawCross() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
addEventListener("mousemove", function(event) {
mouseX = event.clientX;
mouseY = event.clientY;
const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
const lens = new Lens(mouseX, mouseY, 250, "transparent");
backgroundSky.drawBackground(); // ⚠️
backgroundGrass.drawBackground(); // ⚠️
crossX.drawCross();
crossY.drawCross();
lens.drawLens();
});
* {
margin: 0;
overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="index.js" async defer></script>
</body>
</html>
I want a ball falling, with gravity. But the background won't clear the previous circle. (the falling part isnt implemented yet) why doesnt it erase the last drawn object?
let c, ctx;
let met;
let colorArray = ["green", "yellow", "orange", "red"];
window.onload = function(){
c = document.getElementById("boom");
ctx = c.getContext("2d");
c.width = window.innerWidth - 165;
c.height = window.innerHeight;
setup();
draw();
}
function setup(){
met = new Meteor(200, 400, 10, 0, 5);
}
function draw(){
window.requestAnimationFrame(draw);
ctx.fillStyle = colorArray[Math.floor(Math.random() * colorArray.length)];
ctx.fillRect(0, 0, c.width, c.height);
met.draw();
met.fall();
};
class Meteor {
constructor(x, y, r, xSpeed, ySpeed){
this.xPos = x;
this.yPos = y;
this.radius = r;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.color = "blue";
this.acceleration = 0.5;
}
draw(){
ctx.fillStyle = this.color;
ctx.arc(this.xPos, this.yPos, this.radius, 0, 2 * Math.PI);
//ctx.fill();
ctx.stroke();
}
fall(){
this.yPos += (this.ySpeed);
}
}
Also, if you have any tips on how to make it have gravity, please don't hesitate to tell me. Ive been struggling with it for a while now.
In draw() add this before the call to met.draw():
ctx.clearRect(0, 0, window.innerWidth, window.innterHeight)
This will clear the screen every frame.
For gravity, add a dt parameter to your draw function, then pass it to met.draw() like this:
function draw(dt){
window.requestAnimationFrame(draw);
ctx.fillStyle = colorArray[Math.floor(Math.random() * colorArray.length)];
ctx.fillRect(0, 0, c.width, c.height);
ctx.clearRect(0, 0, window.innerWidth, window.innterHeight) // Clear screen here
met.draw(dt);
met.fall();
};
Then in the Meteor class, use the dt in the draw() function to calculate your y position based on velocity. Here dt will be your delta time for the calculation.
How can I stop filling my circle at some point?
Like only fill 50% of the circle or 25% of the circle and leave the left over. Just like progress bar.
below is the code Im using but it is filling entire circle.
Kindly please give me suggestions.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineCap = "round";
var y = ch - 10;
var drawingColor = "#0092f9";
animate();
function animate() {
if (y > 0) {
requestAnimationFrame(animate);
}
ctx.clearRect(0, 0, cw, ch);
ctx.save();
drawContainer(0, null, null);
drawContainer(15, drawingColor, null);
drawContainer(7, "white", "white");
ctx.save();
ctx.clip();
drawLiquid();
ctx.restore();
ctx.restore();
y--;
}
function drawLiquid() {
ctx.beginPath();
ctx.moveTo(0, y);
for (var x = 0; x < 300; x += 1) {
ctx.quadraticCurveTo(x + 5, y+5, x + 5, y);
}
ctx.lineTo(cw, ch);
ctx.lineTo(0, ch);
ctx.closePath();
ctx.fillStyle = drawingColor;
ctx.fill();
}
function drawContainer(linewidth, strokestyle, fillstyle) {
ctx.beginPath();
ctx.arc(cw/2, ch/2,cw/2-30,0,2*Math.PI);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokestyle;
ctx.stroke();
if (fillstyle) {
ctx.fillStyle = fillstyle;
ctx.fill();
}
}
<canvas id="canvas" width=200 height=200></canvas>
I know zit at javascript but: Just change the limit of y in animate. I put 100 instead of 0 and it fills half the circle.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineCap = "round";
var y = ch - 10;
var drawingColor = "#0092f9";
animate();
function animate() {
if (y > 100) {
requestAnimationFrame(animate);
}
ctx.clearRect(0, 0, cw, ch);
ctx.save();
drawContainer(0, null, null);
drawContainer(15, drawingColor, null);
drawContainer(7, "white", "white");
ctx.save();
ctx.clip();
drawLiquid();
ctx.restore();
ctx.restore();
y--;
}
function drawLiquid() {
ctx.beginPath();
ctx.moveTo(0, y);
for (var x = 0; x < 300; x += 1) {
ctx.quadraticCurveTo(x + 5, y+5, x + 5, y);
}
ctx.lineTo(cw, ch);
ctx.lineTo(0, ch);
ctx.closePath();
ctx.fillStyle = drawingColor;
ctx.fill();
}
function drawContainer(linewidth, strokestyle, fillstyle) {
ctx.beginPath();
ctx.arc(cw/2, ch/2,cw/2-30,0,2*Math.PI);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokestyle;
ctx.stroke();
if (fillstyle) {
ctx.fillStyle = fillstyle;
ctx.fill();
}
}
<canvas id="canvas" width=200 height=200></canvas>
I am attempting to animate an emoticon that was previously drawn in canvas. I am attempting to do a draw and clear using frames following a tutorial but am not getting results. I have 6 frames of the emoticon coded and am unsure how to include this within the code. This is what I have so far:
<!DOCTYPE html>
<html>
<head>
<title>Adding Animation</title>
<style>
canvas {
border: 3px #CCC solid;
}
</style>
</head>
<body>
<div id="container">
<canvas id="myCanvas" height="1200" width="900"></canvas>
</div>
<script>
var mainCanvas = document.querySelector("#myCanvas");
var mainContext = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
function drawCircle() {
mainContext.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
mainContext.fillStyle = "#EEEEEE";
mainContext.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
ctx.closePath();
//The eyes
//Left
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(850, 405, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
drawCircle();
</script>
</body>
</html>
I am unsure if I am even on the right track as I have a difficult time with animation. Does anyone have any suggestions they can give me guidance on?
You have 2 names for the context: mainContext & ctx.
Change it to a single name and your face is "smiley" ! :-)
...
To animate:
Use a requestAnimationFrame loop to change the scaleY value in scale(scaleX,scaleY) over time.
Here's annotated code and a Demo:
var mainCanvas = document.querySelector("#myCanvas");
var ctx = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
ctx.translate(-425,-275);
drawCircle(1);
// global var to hold pct the left eye is open
// 1==fully open, 0==fully closed
var scaley=1;
var direction=-1;
// request 1 animate() loop
requestAnimationFrame(animate);
function animate(time){
// draw smiley with the specified eye openness
drawCircle(scaley);
scaley+=.02*direction;
if(scaley<0){
scaley=0;
direction=1;
}
if(scaley>1){
scaley=1;
direction=-1;
}
requestAnimationFrame(animate);
}
function drawCircle(scaleY) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
ctx.fillStyle = "#EEEEEE";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
//The eyes
//Left
ctx.save();
// move the [0,0] origin to the left eye's centerpoint
ctx.translate(550,405);
// close the left eye by the specified scaleY
ctx.scale(0.65, scaleY);
ctx.beginPath();
// draw the left eye (arc) at 0,0 because
// we translated the origin to [550,405] earlier
ctx.arc(0, 0, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
<canvas id="myCanvas" height="1200" width="900"></canvas>
You never declared a ctx variable.
Change all your mainContext by ctx and it should be working fine.