How to make my drawing move inside HTML5 canvas? - javascript

I have a HTML5 canvas and Javascript. How can I make it move like move it's arms and feet?
I tried Googling for some tutorials but failed.
Attached here is my image and my codes:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="canvascss.css">
</head>
<body>
<div>
<canvas id="canvas" width="400px" height="300px" >
Your browser does not support HTML5 Canvas element
</canvas>
</div>
<script>
var canvas = document.getElementById("canvas");
if (canvas.getContext("2d")) { // Check HTML5 canvas support
context = canvas.getContext("2d"); // get Canvas Context object
context.beginPath();
context.fillStyle = "black"; // #ffe4c4
context.arc(200, 50, 30, 0, Math.PI * 2, true); // draw circle for head
context.fill();
context.beginPath();
context.strokeStyle = "black"; // color
context.lineWidth = 3;
context.arc(200, 50, 20, 0, Math.PI, false); // draw semicircle for smiling
context.stroke();
// eyes
context.beginPath();
context.fillStyle = "black"; // color
context.arc(190, 45, 3, 0, Math.PI * 2, true); // draw left eye
context.fill();
context.arc(210, 45, 3, 0, Math.PI * 2, true); // draw right eye
context.fill();
// body
context.beginPath();
context.moveTo(200, 80);
context.lineTo(200, 180);
context.strokeStyle = "black";
context.stroke();
// arms
context.beginPath();
context.strokeStyle = "black"; // blue
context.moveTo(200, 80);
context.lineTo(150, 130);
context.moveTo(200, 80);
context.lineTo(250, 130);
context.stroke();
// legs
context.beginPath();
context.strokeStyle = "black";
context.moveTo(200, 180);
context.lineTo(150, 280);
context.moveTo(200, 180);
context.lineTo(250, 280);
context.stroke();
}
</script>
</body>
</html>
Result:

From HTML5 Canvas Animation with requestAnimFrame:
To create an animation using HTML5 Canvas, we can use the
requestAnimFrame shim which enables the browser to determine the
optimal FPS for our animation. For each animation frame, we can
update the elements on the canvas, clear the canvas, redraw the
canvas, and then request another animation frame.
In short your point of departure is the following:
requestAnimationFrame
You will need a javascript function to CHANGE aspects of your starting image, and then to call that javascript code at regular intervals.
setInterval is another key word to google and learn from.

Related

How do I copy line segment on HTML5 CANVAS tag rotate it and place it next to the original segment?

Firstly I have tried to find solution to my problem but I do not think that I know how to search online for solutions.
Okay so I have this image that is drawn via line segments : moveTo, lineTo etc.
As you can see we could divide the image into 4 parts that are essentially the same but rotated and placed next to other elements. What I mean by this if you draw 4 lines from the center with 90 angle you can notice the same pattern.
Basically what I am trying to do is to have one part of the canvas drawn manually by inserting moveTo and the rest to somehow generate to save some time ofc.
Not sure if I explained well my problem, excuse me this is my first stackoverflow question posted.
I mean I found a way to do this by having 4 different CANVAS elements and then rotate each canvas. I am looking for a way to do everything in one CANVAS element. But not sure if that is possible.
My code below:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Model 1</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body onload="draw();">
<canvas id="canvas_id" width="150" height="150" style="border:1px solid #000000;"></canvas>
<!-- 1---->
<script type="text/javascript">
function draw() {
var canvas = document.getElementById('canvas_id');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
//top left square
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(10, 40);
ctx.lineTo(40, 40);
ctx.lineTo(40, 10);
ctx.lineTo(10, 10);
ctx.fillStyle = "red";
ctx.fill();
//down left square
ctx.beginPath();
ctx.moveTo(10, 100);
ctx.lineTo(10, 130);
ctx.lineTo(40,130);
ctx.lineTo(40, 100);
ctx.lineTo(10, 100);
ctx.fillStyle = "red";
ctx.fill();
//top right square
ctx.beginPath();
ctx.moveTo(100, 10);
ctx.lineTo(130, 10);
ctx.lineTo(130, 40);
ctx.lineTo(100, 40);
ctx.lineTo(100, 10);
ctx.fillStyle = "red";
ctx.fill();
//down right square
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(130, 100);
ctx.lineTo(130, 130);
ctx.lineTo(100, 130);
ctx.lineTo(100, 100);
ctx.fillStyle = "red";
ctx.fill();
//center figure
//1
ctx.beginPath();
ctx.moveTo(70, 10);
ctx.lineTo(10, 70);
ctx.lineTo(70, 130);
ctx.lineTo(130, 70);
ctx.lineTo(70, 10);
// inside
ctx.moveTo(70, 30);
ctx.lineTo(30, 70);
ctx.lineTo(70, 110);
ctx.lineTo(110, 70);
ctx.lineTo(70, 30);
//square 1
ctx.moveTo(60, 60);
ctx.lineTo(80, 60);
ctx.lineTo(80, 80);
ctx.lineTo(60, 80);
ctx.lineTo(60, 60);
//square 2
ctx.moveTo(50, 50);
ctx.lineTo(90, 50);
ctx.lineTo(90, 90);
ctx.lineTo(50, 90);
ctx.lineTo(50, 50);
ctx.stroke();
}
}
</script>
</body>
</html>
I hope that I understood well what you need.
You can either parametrize your draw function with an angle, and a x, y position parameters, or copy, rotate and paste a part of the canvas. I assumed you would prefer the second solution.
Basically, copy your canvas, rotate it, draw something, then restore your changes.
You can use this function:
function draw(canvas, ctx, x, y, angle) {
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(angle * Math.PI / 180);
ctx.translate(-(canvas.width / 2), -(canvas.height / 2));
// drawing begin
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(10, 40);
ctx.lineTo(40, 40);
ctx.lineTo(40, 10);
ctx.lineTo(10, 10);
ctx.lineTo(30, 30);
ctx.strokeStyle = "red";
ctx.stroke();
// drawing end
ctx.restore();
}
You can use it like this:
// draw something with a 90° angle
draw(canvas, ctx, 0, 0, 90);
// draw something with a 180° angle
draw(canvas, ctx, 0, 0, 180);
The x and y coordinates are the ones of the rotated canvas, so 0, 0 will be in the angle each time.
Here's a fiddle: https://jsfiddle.net/nmerinian/kt3f782o/19/

Overlapping clipping issue

I have an issue where I am grabbing a users displayAvatar() and then I use an arc to make the image round. This works fine, however, I need to place a circle on top of that image, but it is getting cut in half because of the previous clip()
Without clip() : https://i.gyazo.com/b474c656f33a1f004f5e3becffcef527.png
With clip() : https://i.gyazo.com/da13377cd3f6dc7516c2b8fd1f0f8ac9.png
I know that in the 'With clip()' image, it appears as if the arc border is showing outside of the clip, but that is hardcoded into the image, I put it as a guide with an image editor.
I tried moving around the code, I removed the line ctx.clip() and saw that my circle displays fine on top of the image.
// circle around avatar
ctx.beginPath();
ctx.arc(122.5, 141.8, 81, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
const avatar = await Canvas.loadImage(
message.author.displayAvatarURL({ format: 'png' })
);
ctx.strokeStyle = '#ffffff';
ctx.strokeRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(avatar, 41.5, 60.5, 162, 162);
// presence circle
ctx.beginPath();
ctx.arc(184.5, 193.5, 19, 0, Math.PI * 2, true);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fillStyle = userStatusColor;
ctx.fill();
Take a look at the canvas clip() definition:
https://www.w3schools.com/tags/canvas_clip.asp
Tip: Once a region is clipped, all future drawing will be limited to the clipped region (no access to other regions on the canvas). You can however save the current canvas region using the save() method before using the clip() method, and restore it (with the restore() method) any time in the future.
Below is an example using the save and restore
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(90, 90, 81, 0, Math.PI * 2, true);
ctx.stroke();
ctx.save();
ctx.clip();
ctx.beginPath();
ctx.arc(150, 50, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#0000ff';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.arc(170, 99, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#ff0000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
<canvas id="canvas"></canvas>

How to rotate a rectangle in Javascript

Hi guys, I am working on an assignment where I need to draw an image of an emoticon face.
function sadFace() {
//Drawing the sad face
context.beginPath();
context.fillStyle = "rgb(255,255,0)" //Drawing the face in yellow colour
context.lineWidth = 3;
context.arc(300,300,200,0,Math.PI*4,true);
context.fill();
context.stroke();
//Left Eyebrow
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(170,180,90,15);
context.fill();
context.stroke();
This is my current code. How can I rotate the 'eyebrow' of the image firstly, and also rotate the eyebrow without rotating the whole image? Thanks!
You can use affine transformation, like rotation, translation, scale.
First save the current context
context.save()
Set rotation and translation see document
Restore the state
context.restore()
const canvas = document.getElementById("canvas")
const context = canvas.getContext("2d");
context.beginPath();
context.fillStyle = "rgb(255,255,0)" //Drawing the face in yellow colour
context.lineWidth = 3;
context.arc(300,300,200,0,Math.PI*4,true);
context.fill();
context.stroke();
//Left Eyebrow
context.save();
context.translate(210, 188);
context.rotate(30 * Math.PI / 180);
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(-45,-8,90,15);
context.fill();
context.stroke();
context.restore();
context.save();
context.translate(380, 188);
context.rotate(-30 * Math.PI / 180);
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(-45,-8,90,15);
context.fill();
context.stroke();
context.restore();
<canvas id="canvas" width="500" height="500" />
Explanation:
Since rotating is rotate around the coordinator (O (0, 0), we need to translate first to the position we want to draw:
context.translate(eyeBrowX, eyeBrowY); // eyebrow position here
Then do a rotation:
context.rotate(angleInRadian);
Then draw the rectangle so that the center of the rectangle is O (0, 0) - then it would rotate around its center.
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(-width / 2, -height / 2, width, height);
context.fill();
context.stroke();
You don't have to rotate anything. Instead of creating rect just use lines to draw the eyebrows. Tell the line to go get drawn in a diagonal path like this
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext("2d");
context.beginPath();
context.fillStyle = "rgb(255,255,0)" //Drawing the face in yellow colour
context.lineWidth = 3;
context.arc(300,300,200,0,Math.PI*4,true);
context.fill();
context.stroke();
//Left Eyebrow
context.beginPath();
context.moveTo(170,180);
context.lineTo(260,195);
context.lineWidth = 10
context.fillStyle = "rgb(0,0,0)";
context.fill();
context.stroke();
<canvas id="myCanvas" width="800" height="800"></canvas>
In this way you don't need to save the context. By the way the canvas does not allow you to change things individually. You need to clear and redraw. (that how it works for animations for example). If you want more control, and modify things individually you need a rendering library like Pixi.js

How to scale a canvas image larger and smaller in a continuous loop?

I created a cloud shape in canvas, and I'm wondering how I can scale the shape back and forth between larger and smaller. Like I want the cloud to get bigger, than smaller, then bigger then smaller, etc.
I was able to be able to move a separate canvas image up and down using a when-then method, but I don't think that method will work by increasing the canvas size because the actual image stays to scale.
Here is my canvas code:
<script>
var canvas = document.getElementById('hardware-cloud');
var context = canvas.getContext('2d');
// begin cloud shape-Hardware
context.beginPath();
context.moveTo(180, 80);
context.bezierCurveTo(150, 132, 143, 165, 203, 154);
context.bezierCurveTo(203, 154, 180, 200, 260, 175);
context.bezierCurveTo(297, 231, 352, 198, 344, 185);
context.bezierCurveTo(344, 185, 372, 215, 374, 175);
context.bezierCurveTo(473, 165, 462, 132, 429, 110);
context.bezierCurveTo(473, 44, 407, 33, 374, 55);
context.bezierCurveTo(352, 10, 275, 22, 275, 55);
context.bezierCurveTo(210, 20, 165, 22, 180, 80);
// complete cloud shape-Hardware
context.closePath();
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
//font inside hardware cloud
context.beginPath();
context.font = 'bold 15pt Calibri';
context.textAlign = 'center';
context.fillStyle ="navy"; // <-- Text colour here
context.fillText('Why not the electronic store?', 300, 120);
context.lineWidth = 2;
context.strokeStyle = 'grey';
context.stroke();
context.closePath();
//top hardware circle
context.beginPath();
context.arc(380, 220, 13, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();
//middle hardware circle
context.beginPath();
context.arc(398, 253, 10, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();
//bottom hardware circle
context.beginPath();
context.arc(425, 273, 7, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();
</script>
And here is my attempt at the jQuery. The first part of it is to get the div region to slide into view. The second part is an attempt to scale up and down.:
$(document).ready(function(){
$('#hardware').hide();
$('#hardware').show("slide", {direction: "left"}, 400 );
ani();
function ani(){
$.when(
$('#hardware-cloud').effect({
scale: "120"},700),
$('#hardware-cloud').effect({
scale: "100"},700)
.then(ani));}
});
You can use scale and translate to change the size of the shape.
All transforms works for the next drawn shape and doesn't affect already drawn shapes.
So for it to work you'll need to clear the canvas, transform and then redraw the shape.
For example, re-factor the code so that you can call shape() to draw the cloud, then:
Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height);
Apply scale ctx.scale(scaleX, scaleY);
Optionally translate the shape using ctx.translate(deltaX, deltaY);
Redraw shape shape();
Repeat using for example requestAnimationFrame() in a loop.
Scale value is 1 = 1:1, 0.5 = half etc. Just remember these transforms are accumulative (you can use setTransform() to set absolute transforms each time).
Update
Here is one way you can do this:
var maxScale = 1, // for demo, this represents "max"
current = 0, // angle (in radians) used to scale smoother
step = 0.02, // speed
pi2 = Math.PI; // cached value
// main loop clears, transforms and redraws shape
function loop() {
context.clearRect(0, 0, canvas.width, canvas.height);
transform();
drawShape();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
// set scale based on rotation
function transform() {
current += step;
current %= pi2;
// just play around with different combinations here
var s = (maxScale * Math.abs(Math.sin(current))) / maxScale + 0.5;
// set absolute scale
context.setTransform(s, 0, 0, s, 0, 0);
}
// wrap shape calls in a function so it can be reused
function drawShape() {
// begin cloud shape-Hardware
context.beginPath();
... rest goes here...
Online demo
In addition you can use translate() to re-position the shape linked to the rotation value.
Hope this helps!

Javascript code display text

Have code for a rectangle with a line through it, I would like to display text under the rectangle. How do I add this into my code? Or can someone point me in the right direction?
<canvas id="main" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("main");
var context = canvas.getContext('2d');
context.fillStyle = "#008000";
context.rect(0,0,300,300);
context.fill();
context.beginPath();
context.lineWidth = 10;
context.strokeStyle = "blue";
context.lineCap = "round";
context.moveTo( 50, 150);
context.lineTo (250, 150);
context.stroke();
context.closePath();
You can draw text using fillText:
context.fillText("Hello, world!", 50, 50);
For more information, see this article on the Mozilla Developer Network.
I believe you want the fillText function:
context.font="30px Arial";
context.fillText("Hello World",10,50);

Categories