Circles are not bouncing back - javascript

A few of my circle objects are not bouncing back, even though I have tried to take care of the edge cases.
I followed everything from here -
https://www.youtube.com/watch?v=yq2au9EfeRQ
I've tried different ways of passing the Window width and height and changing them in different ways using the radius:
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var iW = window.innerWidth;
var iH = window.innerHeight;
var c = canvas.getContext('2d');
function Circle(x, y, dx, dy, radius) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.draw = function() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = "orange";
c.stroke();
}
this.update = function() {
if (this.x + this.radius > iW || this.x - this.radius < 0) {
this.dx = ~this.dx;
}
if (this.y + this.radius > iH || this.y - this.radius < 0) {
this.dy = ~this.dy;
}
this.x += this.dx;
this.y += this.dy;
this.draw();
}
}
var circleArray = [];
for (var i = 0; i < 100; i++) {
var radius = 30;
var x = Math.random() * (iW - radius * 2) + radius;
var y = Math.random() * (iH - radius * 2) + radius;
var dx = Math.random() * 5;
var dy = Math.random() * 5;
circleArray.push(new Circle(x, y, dx, dy, radius));
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, iW, iH);
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
animate();
canvas { border : 1px solid black; }
body { margin :0; }
<canvas>abcd</canvas>
The circles are getting stuck and then are going out of the window after vibrating where they get stuck. They should bounce back but only a few are bouncing back. I am using brackets and also am getting an undefined error I don't know if that error is what is causing this problem.

You are not negating the dx and dy values. Instead you are flipping all their binary bits. But then note how ~(-1) === 0. This roughly explains the problem you see: circles that only move with -1 in either direction, will "bounce" to a move of 0 in that same direction. Consequently they are bouncing again on the next cycle, where they start moving with -1 again, ... and so they wiggle off the canvas.
So just use the minus operator:
this.dx = -this.dx;
this.dy = -this.dy;

Related

I will try to print 100 of circle and make them go anywhere on the screen

class Circle {
constructor(x, y, dx, dy, radius) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
}
draw() {
c.beginPath()
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
c.strokeStyle = "blue"
c.stroke()
}
update() {
if (this.x + this.radius > innerWidth || this.x - this.radius < 0) {
this.dx = - this.dx
}
if (this.y + this.radius > innerHeight || this.y - this.radius < 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y -= this.dy
circleArray.draw()
}
}
let circleArray = []
// let circle = [];
for (let i = 0 ; i < 100; i++){
let radius = 30
let x = Math.random() * innerWidth
let y = Math.random() * innerHeight
let dx = (Math.random() - 0.5 * 5)
let dy = (Math.random() - 0.5 * 5)
// circle = new Circle(x,y,dx,dy,radius)
circleArray =(new Circle(x,y,dx,dy,radius))
console.log(circleArray)
// console.log(circleArray)
}
function animation() {
requestAnimationFrame(animation)
c.clearRect(0, 0, innerWidth, innerHeight)
for(let i = 0;i < circleArray.length; i++){
circleArray[i].update()
// console.log(circle[i])
}
}
animation()
i will try to print 100 circle by using html canvas and Class in javascript but nothing happend
then i try to push new class in empty array they give me a error and them i call dray method with empyt array variable the give a error and say this is not a function and them i try to use both
empty array and a new variable so they give me a typeerror and say this is undefind
There were two issues in your snippet:
circleArray =(new Circle(x,y,dx,dy,radius))
This assigns a single circle instance to the circleArray variable. You probably meant to write circleArray.push(new Circle(...))
circleArray.draw()
This might have worked because of the mistake in (1), but should now be this.draw() instead.
Here's a snippet that has these issues fixed:
const innerWidth = 256;
const innerHeight = 256;
const cvs = document.createElement("canvas");
cvs.width = 256;
cvs.height = 256;
const c = cvs.getContext("2d");
class Circle {
constructor(x, y, dx, dy, radius) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
}
draw() {
c.beginPath()
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
c.strokeStyle = "blue"
c.stroke()
}
update() {
if (this.x + this.radius > innerWidth || this.x - this.radius < 0) {
this.dx = -this.dx
}
if (this.y + this.radius > innerHeight || this.y - this.radius < 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y -= this.dy
this.draw();
}
}
let circleArray = []
// let circle = [];
for (let i = 0; i < 100; i++) {
let radius = 30
let x = Math.random() * innerWidth
let y = Math.random() * innerHeight
let dx = (Math.random() - 0.5 * 5)
let dy = (Math.random() - 0.5 * 5)
circleArray.push(new Circle(x, y, dx, dy, radius))
}
function animation() {
requestAnimationFrame(animation)
c.clearRect(0, 0, innerWidth, innerHeight)
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update()
}
}
document.body.appendChild(cvs);
animation();

Determine if a Selection Marquee is over a Rotated Rectangle

I have a Rectangle class for drawing to HTML Canvas. It has a rotation property that gets applied in its draw method. If the user drags within the canvas, a selection marquee is being drawn. How can I set the Rectangle's active attribute to true when the Rectangle is within the selection marquee using math? This is a problem I'm having in another language & context so I do not have all of Canvas' methods available to me there (e.g. isPointInPath).
I found a StackOverflow post about finding Mouse position within rotated rectangle in HTML5 Canvas, which I am implementing in the Rectangle method checkHit. It doesn't account for the selection marquee, however. It's just looking at the mouse X & Y, which is still off. The light blue dot is the origin around which the rectangle is being rotated. Please let me know if anything is unclear. Thank you.
class Rectangle
{
constructor(x, y, width, height, rotation) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.xOffset = this.x + this.width/2;
this.yOffset = this.y + ((this.y+this.height)/2);
this.rotation = rotation;
this.active = false;
}
checkHit()
{
// translate mouse point values to origin
let originX = this.xOffset;
let originY = this.yOffset;
let dx = marquee[2] - originX;
let dy = marquee[3] - originY;
// distance between the point and the center of the rectangle
let h1 = Math.sqrt(dx*dx + dy*dy);
let currA = Math.atan2(dy,dx);
// Angle of point rotated around origin of rectangle in opposition
let newA = currA - this.rotation;
// New position of mouse point when rotated
let x2 = Math.cos(newA) * h1;
let y2 = Math.sin(newA) * h1;
// Check relative to center of rectangle
if (x2 > -0.5 * this.width && x2 < 0.5 * this.width && y2 > -0.5 * this.height && y2 < 0.5 * this.height){
this.active = true;
} else {
this.active = false;
}
}
draw()
{
ctx.save();
ctx.translate(this.xOffset, this.yOffset);
ctx.fillStyle = 'rgba(255,255,255,1)';
ctx.beginPath();
ctx.arc(0, 0, 3, 0, 2 * Math.PI, true);
ctx.fill();
ctx.rotate(this.rotation * Math.PI / 180);
ctx.translate(-this.xOffset, -this.yOffset);
if (this.active)
{
ctx.fillStyle = 'rgba(255,0,0,0.5)';
} else {
ctx.fillStyle = 'rgba(0,0,255,0.5)';
}
ctx.beginPath();
ctx.fillRect(this.x, this.y, this.width, this.y+this.height);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var raf;
var rect = new Rectangle(50,50,90,30,45);
var marquee = [-3,-3,-3,-3];
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var start_x,start_y;
let draw = () => {
ctx.clearRect(0,0, canvas.width, canvas.height);
//rect.rotation+=1;
rect.draw();
ctx.fillStyle = "rgba(200, 200, 255, 0.5)";
ctx.fillRect(parseInt(marquee[0]),parseInt(marquee[1]),parseInt(marquee[2]),parseInt(marquee[3]))
ctx.strokeStyle = "white"
ctx.lineWidth = 1;
ctx.rect(parseInt(marquee[0]),parseInt(marquee[1]),parseInt(marquee[2]),parseInt(marquee[3]))
ctx.stroke()
raf = window.requestAnimationFrame(draw);
}
let dragStart = (e) =>
{
start_x = parseInt(e.clientX-offsetX);
start_y = parseInt(e.clientY-offsetY);
marquee = [start_x,start_y,0,0];
canvas.addEventListener("mousemove", drag);
}
let drag = (e) =>
{
let mouseX = parseInt(e.clientX-offsetX);
let mouseY = parseInt(e.clientY-offsetY);
marquee[2] = mouseX - start_x;
marquee[3] = mouseY - start_y;
rect.checkHit();
}
let dragEnd = (e) =>
{
marquee = [-10,-10,-10,-10];
canvas.removeEventListener("mousemove", drag);
}
canvas.addEventListener('mousedown', dragStart);
canvas.addEventListener('mouseup', dragEnd);
raf = window.requestAnimationFrame(draw);
body
{
margin:0;
}
#canvas
{
width: 360px;
height: 180px;
border: 1px solid grey;
background-color: grey;
}
<canvas id="canvas" width="360" height="180"></canvas>
Do convex polygons overlap
Rectangles are convex polygons.
Rectangle and marquee each have 4 points (corners) that define 4 edges (lines segments) connecting the points.
This solution works for all convex irregular polygons with 3 or more sides.
Points and edges must be sequential either Clockwise CW of Count Clockwise CCW
Test points
If any point of one poly is inside the other polygon then they must overlap. See example function isInside
To check if point is inside a polygon, get cross product of, edge start to the point as vector, and the edge as a vector.
If all cross products are >= 0 (to the left of) then there is overlap (for CW polygon). If polygon is CCW then if all cross products are <= 0 (to the right of) there is overlap.
It is possible to overlap without any points inside the other poly.
Test Edges
If any of the edges from one poly crosses any of the edges from the other then there must be overlap. The function doLinesIntercept returns true if two line segments intercept.
Complete test
Function isPolyOver(poly1, poly2) will return true if there is overlap of the two polys.
A polygon is defined by a set of Point's and Lines's connecting the points.
The polygon can be irregular, meaning that each edge can be any length > 0
Do not pass polygons with an edge of length === 0 or will not work.
Added
I added the function Rectangle.toPoints that transforms the rectangle and returning a set of 4 points (corners).
Example
Example is a copy of your code working using the above methods.
canvas.addEventListener('mousedown', dragStart);
canvas.addEventListener('mouseup', dragEnd);
requestAnimationFrame(draw);
const Point = (x = 0, y = 0) => ({x, y, set(x,y){ this.x = x; this.y = y }});
const Line = (p1, p2) => ({p1, p2});
const selector = { points: [Point(), Point(), Point(), Point()] }
selector.lines = [
Line(selector.points[0], selector.points[1]),
Line(selector.points[1], selector.points[2]),
Line(selector.points[2], selector.points[3]),
Line(selector.points[3], selector.points[0])
];
const rectangle = { points: [Point(), Point(), Point(), Point()] }
rectangle.lines = [
Line(rectangle.points[0], rectangle.points[1]),
Line(rectangle.points[1], rectangle.points[2]),
Line(rectangle.points[2], rectangle.points[3]),
Line(rectangle.points[3], rectangle.points[0])
];
function isInside(point, points) {
var i = 0, p1 = points[points.length - 1];
while (i < points.length) {
const p2 = points[i++];
if ((p2.x - p1.x) * (point.y - p1.y) - (p2.y - p1.y) * (point.x - p1.x) < 0) { return false }
p1 = p2;
}
return true;
}
function doLinesIntercept(l1, l2) {
const v1x = l1.p2.x - l1.p1.x;
const v1y = l1.p2.y - l1.p1.y;
const v2x = l2.p2.x - l2.p1.x;
const v2y = l2.p2.y - l2.p1.y;
const c = v1x * v2y - v1y * v2x;
if(c !== 0){
const u = (v2x * (l1.p1.y - l2.p1.y) - v2y * (l1.p1.x - l2.p1.x)) / c;
if(u >= 0 && u <= 1){
const u = (v1x * (l1.p1.y - l2.p1.y) - v1y * (l1.p1.x - l2.p1.x)) / c;
return u >= 0 && u <= 1;
}
}
return false;
}
function isPolyOver(p1, p2) { // is poly p2 under any part of poly p1
if (p2.points.some(p => isInside(p, p1.points))) { return true };
if (p1.points.some(p => isInside(p, p2.points))) { return true };
return p1.lines.some(l1 => p2.lines.some(l2 => doLinesIntercept(l1, l2)));
}
const ctx = canvas.getContext("2d");
var dragging = false;
const marquee = [0,0,0,0];
const rotate = 0.01;
var startX, startY, hasSize = false;
const BB = canvas.getBoundingClientRect();
const offsetX = BB.left;
const offsetY = BB.top;
class Rectangle {
constructor(x, y, width, height, rotation) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.rotation = rotation;
this.active = false;
}
toPoints(points = [Point(), Point(), Point(), Point()]) {
const xAx = Math.cos(this.rotation) / 2;
const xAy = Math.sin(this.rotation) / 2;
const x = this.x, y = this.y;
const w = this.width, h = this.height;
points[0].set(-w * xAx + h * xAy + x, -w * xAy - h * xAx + y);
points[1].set( w * xAx + h * xAy + x, w * xAy - h * xAx + y);
points[2].set( w * xAx - h * xAy + x, w * xAy + h * xAx + y);
points[3].set(-w * xAx - h * xAy + x, -w * xAy + h * xAx + y);
}
draw() {
ctx.setTransform(1, 0, 0, 1, this.x, this.y);
ctx.fillStyle = 'rgba(255,255,255,1)';
ctx.strokeStyle = this.active ? 'rgba(255,0,0,1)' : 'rgba(0,0,255,1)';
ctx.lineWidth = this.active ? 3 : 1;
ctx.beginPath();
ctx.arc(0, 0, 3, 0, 2 * Math.PI, true);
ctx.fill();
ctx.rotate(this.rotation);
ctx.beginPath();
ctx.rect(-this.width / 2, - this.height / 2, this.width, this.height);
ctx.stroke();
}
}
function draw(){
rect.rotation += rotate;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
rect.draw();
drawSelector();
requestAnimationFrame(draw);
}
function drawSelector() {
if (dragging && hasSize) {
rect.toPoints(rectangle.points);
rect.active = isPolyOver(selector, rectangle);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillStyle = "rgba(200, 200, 255, 0.5)";
ctx.strokeStyle = "white";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.rect(...marquee);
ctx.fill();
ctx.stroke();
} else {
rect.active = false;
}
}
function dragStart(e) {
startX = e.clientX - offsetX;
startY = e.clientY - offsetY;
drag(e);
canvas.addEventListener("mousemove", drag);
}
function drag(e) {
dragging = true;
const x = e.clientX - offsetX;
const y = e.clientY - offsetY;
const left = Math.min(startX, x);
const top = Math.min(startY, y);
const w = Math.max(startX, x) - left;
const h = Math.max(startY, y) - top;
marquee[0] = left;
marquee[1] = top;
marquee[2] = w;
marquee[3] = h;
if (w > 0 || h > 0) {
hasSize = true;
selector.points[0].set(left, top);
selector.points[1].set(left + w, top);
selector.points[2].set(left + w, top + h);
selector.points[3].set(left , top + h);
} else {
hasSize = false;
}
}
function dragEnd(e) {
dragging = false;
rect.active = false;
canvas.removeEventListener("mousemove", drag);
}
const rect = new Rectangle(canvas.width / 2, canvas.height / 2, 90, 90, Math.PI / 4);
body
{
margin:0;
}
#canvas
{
width: 360px;
height: 180px;
border: 1px solid grey;
background-color: grey;
}
<canvas id="canvas" width="360" height="180"></canvas>

How do I resize my canvas with my elements in it?

Background Information
I'm currently working on a project and I want the background to be a blank canvas with balls bouncing off the walls.
I've managed so far, but I've come across a problem.
Whenever I resize my browser window, neither my canvas or the balls in it follow through. I have no clue what I'm doing wrong.
codepen
Code
const canvas = document.querySelector('#responsive-canvas')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let c = canvas.getContext('2d');
function Circle(x, y, dx, dy, radius, colour) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
this.draw = function() {
this.getNewColour = function() {
let symbols, colour;
symbols = "0123456789ABCDEF";
colour = "#";
for (let i = 0; i < 6; i++) {
colour += symbols[Math.floor(Math.random() * 16)];
}
c.strokeStyle = colour;
c.fillStyle = colour;
}
this.getNewColour();
this.x = x;
this.y = y;
this.radius = radius;
//this.getNewColour().colour = colour;
c.beginPath();
c.arc(x, y, radius, 0, Math.PI * 2, false);
// c.strokeStyle = 'blue';
c.stroke();
//c.fill();
}
this.update = function() {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
if (x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
if (y + radius > innerHeight || y - radius < 0) {
dy = -dy;
}
x += dx;
y += dy;
this.draw();
}
}
let circleArr = [];
for (let i = 0; i < 23; i++) {
let radius = 50;
let x = Math.random() * (innerWidth - radius * 2) + radius;
let y = Math.random() * (innerHeight - radius * 2) + radius;
let dx = (Math.random() - 0.5);
let dy = (Math.random() - 0.5);
circleArr.push(new Circle(x, y, dx, dy, radius));
};
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight)
for (var i = 0; i < circleArr.length; i++) {
circleArr[i].update();
}
};
animate();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* BODY
*/
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<link rel="stylesheet" href="../dist/css/style.css">
<body>
<canvas id="responsive-canvas"></canvas>
</body>
<script src="js/canvas.js"></script>
</html>
you can use
ctx.scale(x,y);
to scale everything on the canvas by the given factor, the X and Y are scalling on X and Y axis respectively.
You might want to reset the canvas using
ctx.resetTransform() or ctx.setTransform(1,0,0,1,0,0);
Then draw your background from 0,0 to canvas.width and canvas.height
Then draw everything (all of the circles) and finally set the scalling to your desired value.
If you want the width and height to change, you just need to add the width and height in the same CSS area that the `{border-box} is in.
but if you want to make the images inside it to not be stretched, you would need to access the heigh specifically in the canvas using the above comments methods.
Preferably using:
width:() => document.documentElement.clientWidth
First you must fix your collision logic, then you can safely change the canvas size as needed.
Always resolve the collisions fully.
An unresolved collision means that your sim is in an impossible state (eg ball inside a wall). From that point the following states will be meaning less.
Fix
The reason why the balls move out of the canvas is because you are not moving them back onto the canvas if they are outside.
Also when you change the ball direction when it hits the side you do not ensure that the direction is the correct sign.
// if the dx = 1 and x > innerWidth + 1000 then dx becomes -1
// Next tine x is still > innerWidth + 1000 and you flip the sign of dx again to 1,
// Then dx to -1 and so on. You never move the ball
if(x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
Be systematic in the collision testing so that when the playfield (canvas) changes size you don't get unexpected results
When you update, first move then check for collisions. If there is a collision, move the ball again to ensure not magic ball in wall thing happening.
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
Resize the canvas
With the collision problem solved you can now change the canvas size whenever you need to. One way is to do it inside the animate function.
If the canvas size does not match the page size change the canvas size to match.
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// ... do stuff
requestAnimationFrame(animate);
}
Note that changing the canvas size also clears the canvas, that is why the clear is on the else clause.
Copy paste demo
There were many bad points in the code. You can copy paste the snippet below into code pen or use the information above to modify your code in your style.
const canvas = document.querySelector('#responsive-canvas')
canvas.width = innerWidth;
canvas.height = innerHeight;
// Set constants in one place so you can make changes quickly and easily
const DEFAULT_RADIUS = 50;
const MAX_SPEED = 5;
const CIRCLE_COUNT = 100;
Math.TAU = Math.PI * 2
// Use function to do repetitive code
Math.rand = (min, max) => Math.random() * (max - min) + min; //
function randomHexColor() {
return "#" + ((Math.random() * 0xFFFFFF | 0).toString(16).padStart(6,"0"));
}
// pulral names for arrays and variables that do not change should be constants
const circles = [];
const ctx = canvas.getContext('2d');
requestAnimationFrame(animate); // start frame renderer with a request, dont call it directly
function Circle( // using default params to set random values
radius = Math.rand(DEFAULT_RADIUS/4, DEFAULT_RADIUS), // radius must be first argument as its used to set random x, and y
x = Math.rand(radius, ctx.canvas.width - radius),
y = Math.rand(radius, ctx.canvas.height - radius),
dx = Math.rand(-MAX_SPEED, MAX_SPEED),
dy = Math.rand(-MAX_SPEED, MAX_SPEED),
colour = randomHexColor()
) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
}
// Define Circle functions as prototype outside the function Circle (runs faster)
Circle.prototype = {
draw() {
ctx.strokeStyle = ctx.fillStyle = this.colour;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.TAU);
ctx.stroke();
},
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
};
for (let i = 0; i < CIRCLE_COUNT; i++) { circles.push(new Circle()) }
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// use for of loop (saves having to mess with index)
for (const circle of circles) {
circle.update(); // seperate update and draw
circle.draw()
}
requestAnimationFrame(animate);
}

Model html5 canvas with SVG

The solution that I'm trying to achieve is to have a html5 canvas with bouncing balls inside. But the thing is that this balls need to bounce WITHIN the bound a certain shape (say a SVG map).
I've used Sketch.js to create my bouncing particles, and this can be illustrated in this pen. But I can't set the SVG element as the container for the sketch.
So, here the question stands: how can I do that? Is there a way using sketch? Or there is another framework that allows this behavior? Or even any known live example of this?
My JS code, which is a fork on one of rglazebrook's works, is
var particles = [],
particleCount = 150;
Particle = function(x, y) {
this.x = x;
this.y = y;
this.radius = random(7, 20);
this.rgba = 'rgba(' + floor(random(0, 255)) + ',' + floor(random(0, 255)) + ',' + floor(random(0, 255)) + ',' + random(.1, .8) + ')';
this.vx = random(-1, 1);
this.vy = random(-1, 1);
// Draw our particle to the canvas.
this.draw = function(ctx) {
ctx.fillStyle = this.rgba;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, TWO_PI);
ctx.fill();
};
// Update our position.
this.update = function(ctx) {
this.x += this.vx;
this.y += this.vy;
// Bounce off edges.
if (this.x + this.radius > ctx.width) {
this.vx *= -1;
this.x = ctx.width - this.radius;
}
if (this.x - this.radius < 0) {
this.vx *= -1;
this.x = this.radius;
}
if (this.y + this.radius > ctx.height) {
this.vy *= -1;
this.y = ctx.height - this.radius;
}
if (this.y - this.radius < 0) {
this.vy *= -1;
this.y = this.radius;
}
}
};
var sketch = Sketch.create({
container: document.getElementById("brazil"),
fullscreen: false,
width: 500,
height: 500,
setup: function() {
var i = particleCount;
while (i--) {
var p = new Particle(random(0, this.width), random(0, this.height));
particles.push(p);
}
},
update: function() {
var i = particleCount;
while (i--) {
particles[i].update(this);
}
},
draw: function() {
var i = particleCount;
while (i--) {
particles[i].draw(this);
}
}
});

How to make the canvas background transparent

I am a newbie on using html5 canvas.
And I'd like to use canvas generate a smoke animation and place it on top of a cigarette image.
The follow code is a sample code of a smoke generator but i don't know how to make the background of the canvas transparent.
I have try different globalCompositeOperation but it seem that i go into a wrong direction.(I don't know much about canvas
I need some help.
Sorry for my poor English.
The following is my code.
And the link is the sample code i used.
http://codepen.io/CucuIonel/pen/hFJlr
function start_smoke( smoke_id ) {
var canvas = document.getElementById(smoke_id);
var w = canvas.width = 200,
h = canvas.height = 150;
var c = canvas.getContext('2d');
var img = new Image();
img.src = 'http://oi41.tinypic.com/4i2aso.jpg';
var position = {x: w / 2, y: h};
var particles = [];
var random = function (min, max) {
return Math.random() * (max - min) * min;
};
function Particle(x, y) {
this.x = x;
this.y = y;
this.velY = -2;
this.velX = (random(1, 10) - 5) / 10;
this.size = random(3, 5) / 10;
this.alpha = 0.3;
this.update = function () {
this.y += this.velY;
this.x += this.velX;
this.velY *= 0.99;
if (this.alpha < 0)
this.alpha = 0;
c.globalAlpha = this.alpha;
c.save();
c.translate(this.x, this.y);
c.scale(this.size, this.size);
c.drawImage(img, -img.width / 2, -img.height / 2);
c.restore();
this.alpha *= 0.96;
this.size += 0.02;//
};
}
var draw = function () {
var p = new Particle(position.x, position.y);
particles.push(p);
while (particles.length > 500) particles.shift();
c.globalAlpha = 1;
c.fillRect(0, 0, w, h);
for (var i = 0; i < particles.length; i++) {
particles[i].update();
}
};
setInterval(draw, 1000 / 20);
}
$(function(){
start_smoke("main_censer_smoke");
});
Canvas transparent by default.
But anyway this question could have a pretty easy solution, which not using globalAlpha, and not using a rgba() color. The simple, effective answer is:
context.clearRect(0,0,width,height);

Categories

Resources