This question title is relatively self explanatory. I'd like the canvas to be in the background of the page while the page's content starts where it normally would. I tried making a DIV for each with their own Z-index but this didn't do anything.
I need to figure out a way to send the canvas back, I've made the body background colour red so there only needs to be two layers (snow and content) rather than the three (background included).
I just need it so that the content displays on top as it would with any normal page, the snow should be a background element that goes along with the scrolling of the page.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
var flakes = [],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
flakeCount = 400,
mX = -100,
mY = -100
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function snow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = flakes[i],
x = mX,
y = mY,
minDist = 150,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
}
ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(snow);
};
function reset(flake) {
flake.x = Math.floor(Math.random() * canvas.width);
flake.y = 0;
flake.size = (Math.random() * 3) + 2;
flake.speed = (Math.random() * 1) + 0.5;
flake.velY = flake.speed;
flake.velX = 0;
flake.opacity = (Math.random() * 0.5) + 0.3;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = Math.floor(Math.random() * canvas.width),
y = Math.floor(Math.random() * canvas.height),
size = (Math.random() * 3) + 2,
speed = (Math.random() * 1) + 0.5,
opacity = (Math.random() * 0.5) + 0.3;
flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
opacity: opacity
});
}
snow();
};
canvas.addEventListener("mousemove", function(e) {
mX = e.clientX,
mY = e.clientY
});
window.addEventListener("resize",function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
})
init();
body, html{
margin:0;
padding:0;
overflow-x: hidden;
user-select: none;
-moz-appearance: none;
-webkit-appearance: none;
background-color: #E71D36;
}
.page {
min-width: 100%;
max-width: 100%;
z-index: -1;
}
.contentwrap {
min-width: 100%;
max-width: 100%;
z-index: 1;
}
.content {
min-width: 50%;
max-width: 50%;
margin-left: auto;
margin-right: auto;
text-align: center;
z-index: 1;
}
#media only screen and (max-width: 500px) {
.content {
min-width: 90%;
max-width: 90%;
margin-left: auto;
margin-right: auto;
text-align: center;
z-index: 1;
}
}
.canvas-holder {
z-index: 0;
}
.canvas {
z-index: -1;
}
<div class="page">
<div class-"canvas-holder">
<canvas id="canvas">
</canvas>
</div>
<div class="content">
<h1>Content is below the canvas</h1>
</div>
</div>
Any tips would be appreciated.
Use position: absolute for the canvas and content. I've made some other changes to .content css to center the text (and added class="canvas" to the canvas html). I also removed z-index as it's not needed if you use absolute positioning.
You asked in a comment:
Any ideas how to make the canvas the height of the page, not just the
window. That'd be appreciated too
One option is to use position: fixed which will keep the canvas position fixed as the page scrolls.
Please see updated snippet.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
var flakes = [],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
flakeCount = 400,
mX = -100,
mY = -100
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function snow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = flakes[i],
x = mX,
y = mY,
minDist = 150,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
}
ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(snow);
};
function reset(flake) {
flake.x = Math.floor(Math.random() * canvas.width);
flake.y = 0;
flake.size = (Math.random() * 3) + 2;
flake.speed = (Math.random() * 1) + 0.5;
flake.velY = flake.speed;
flake.velX = 0;
flake.opacity = (Math.random() * 0.5) + 0.3;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = Math.floor(Math.random() * canvas.width),
y = Math.floor(Math.random() * canvas.height),
size = (Math.random() * 3) + 2,
speed = (Math.random() * 1) + 0.5,
opacity = (Math.random() * 0.5) + 0.3;
flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
opacity: opacity
});
}
snow();
};
canvas.addEventListener("mousemove", function(e) {
mX = e.clientX,
mY = e.clientY
});
window.addEventListener("resize",function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
})
init();
body, html{
margin:0;
padding:0;
overflow-x: hidden;
user-select: none;
-moz-appearance: none;
-webkit-appearance: none;
background-color: #E71D36;
}
.page {
min-width: 100%;
max-width: 100%;
}
.contentwrap {
min-width: 100%;
max-width: 100%;
}
.content {
min-width: 100%;
max-width: 100%;
margin-left: auto;
margin-right: auto;
text-align: center;
position: absolute;
left: 0;
right: 0;
}
#media only screen and (max-width: 500px) {
.content {
min-width: 90%;
max-width: 90%;
margin-left: auto;
margin-right: auto;
text-align: center;
}
}
.canvas-holder {
}
.canvas {
position: fixed;
}
<div class="page">
<div class="canvas-holder">
<canvas id="canvas" class="canvas">
</canvas>
</div>
<div class="content">
<h1>Content is below the canvas</h1>
<p style="height: 900px;"></p>
</div>
</div>
Related
I am creating an animation using java script & canvas. I am using a fiddle as a reference, currently object are generating randomly & falling from top right corner to bottom left corner which is okay. but the issue is speed the objects are generating & falling in high speed. I want to make animation flow little slow & smooth.
I am new canvas programming, any help will be very useful.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
var particleArr = [],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
flakeCount = 700,
mouseX = -100,
mouseY = -100,
xMultiplier = 0.015
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function getRandomColor() {
// Random Color Generate
const colorArr = ["rgba(215,88,69, 1)", "rgba(117, 161, 199, 1)"]; // Blue & Orange Color
const randomColor = colorArr[Math.floor(Math.random() * colorArr.length)];
return randomColor;
}
function flow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = particleArr[i],
x = mouseX,
y = mouseY,
minDist = 150,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
}
ctx.fillStyle = getRandomColor();
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(flow);
};
function reset(flake) {
let temp = (Math.random() * 1) + 0.5;
flake.x = canvas.width;
flake.y = 50;
flake.size = (Math.random() * 3) + 5;
flake.speed = (Math.random() * 7) + 0.5;
flake.velY = flake.speed;
flake.velX = -xMultiplier * canvas.width * temp;
// flake.opacity = (Math.random() * 0.5) + 0.3;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = canvas.width,
y = 50,
size = (Math.random() * 3) + 5,
// speed = (Math.random() * 1) + 0.5;
speed = 0;
// opacity = (Math.random() * 0.5) + 0.3;
particleArr.push({
speed: speed,
velY: speed,
velX: -xMultiplier * canvas.width * speed,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
angle: 360
// opacity: opacity
});
}
flow();
};
canvas.addEventListener("mousemove", function(e) {
mouseX = e.clientX,
mouseY = e.clientY
});
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
init();
canvas {
background-color: #000000 !important;
}
body {
margin: 0;
overflow: hidden;
}
<canvas id="canvas"></canvas>
Could not work out what it was you wanted to slow down as there are several FX and interactions in the code.
I rewrote from the ground up as your code is a little old school.
Rather than play with the constants you had OI added the global variable rate (at the ver top of the source) is used to control the rate at which the animation plays, including the user interaction.
I have added two button to slow or speed up the animation.
Hope this helps :)
var rate = 1;
slower.addEventListener("click", () => rate *= 1 / 1.2);
faster.addEventListener("click", () => rate *= 1.2);
const flakes = [], flakeCount = 700, xMultiplier = 0.015;
const minDist = 150, minDistSqr = minDist * minDist;
const colors = ["#F99","#F83","#AF9","#ED9","#AC8","#FA9" ];
const ctx = canvas.getContext("2d");
const mouse = {x: -100, y: -100};
const randPick = (arr, len = arr.length) => arr[Math.random() * len | 0];
Math.rand = (min, range) => Math.random() * range + min;
function Flake() {
this.reset();
this.stepSize = Math.random() / 30;
this.step = 0;
}
Flake.prototype = {
reset() {
this.x = canvas.width;
this.y = 50;
this.size = Math.rand(5, 3);
this.speed = Math.rand(0.5, 7);
this.velY = this.speed;
this.velX = -xMultiplier * canvas.width * Math.rand(0.5, 1);
this.col = randPick(colors);
},
draw() {
ctx.fillStyle = this.col;
const s = this.size, sh = -s / 2;
ctx.fillRect(this.x + sh, this.y + sh, s, s);
},
update(w, h) {
const f = this;
const dx = f.x - mouse.x;
const dy = f.y - mouse.y;
const distSqr = dx * dx + dy * dy;
if (distSqr < minDistSqr) {
const deltaV = 2 * minDist * rate / distSqr ** 1.5;
f.velX -= deltaV * dx;
f.velY -= deltaV * dy;
} else {
f.velX -= 0.1 * rate * f.velX;
if (f.velY <= f.speed ) { f.velY = f.speed }
f.velX += Math.cos(f.step += 0.05 * rate) * f.stepSize * rate;
}
f.y += f.velY * rate;
f.x += f.velX * rate;
if (f.y >= h || f.y <= 0 || f.x >= w || f.x <= 0) { this.reset() }
else { this.draw() }
}
};
init();
mainLoop();
function mainLoop() {
if (innerWidth !== canvas.width || innerHeight !== canvas.height) { resize() }
else { ctx.clearRect(0, 0, canvas.width, canvas.height) }
for (const f of flakes) { f.update(canvas.width, canvas.height) }
requestAnimationFrame(mainLoop);
}
function init() {
var i = flakeCount;
while (i--) { flakes.push(new Flake()) }
}
canvas.addEventListener("mousemove", e => { mouse.x = e.clientX; mouse.y = e.clientY });
function resize() { canvas.width = innerWidth; canvas.height = innerHeight }
canvas {
background-color: #000;
}
body {
margin: 0;
}
.buttons {
position: absolute;
top: 12px;
left: 12px;
color: #000;
background-color: #AAA;
}
.buttons > div {
margin: 3px;
padding: 3px;
background-color: #EEE;
cursor: pointer;
}
.buttons > div:hover {
background-color: #DEF;
}
<canvas id="canvas"></canvas>
<div class = "buttons">
<div id="slower">Slower</div>
<div id="faster">Faster</div>
</div>
That requestAnimationFrame() function that calls flow() every frame is designed to run as fast as possible for whoever's computer it's running on. I wouldn't mess with your actual render loop.
Try messing with the flake.speed or the xMultiplier. Those are two of the main variables affecting the speed of your particles. You can see how each time through the flow() loop you're adjusting each particle's position based on their velocity properties and position. Then finally rendering the arc with ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
So any variable passed to ctx.arc() affects the particle's position. And many of those variables are recalculated each time through the loop.
I'm no expert here, but maybe try fiddling with your variables.
https://codepen.io/nitwit/pen/XWXJNaJ
https://jsfiddle.net/z6r8h5de/
if the issue is there are too many flakes on the screen, turn the count down from 700.
flakeCount = 100,
I have the following canvas:
Codepen link
What I want: Equal margin on both sides of canvas without any horizontal scroll bars.
Problem: margin-right property does not to work. I have seen some solutions that solve this problem by specifying a fixed width, but I cannot have a fixed width in my case. I want my canvas to adjust its width height according to the size of the window.
The following Javascript takes care of that:
window.addEventListener('resize' , resizeCanvas , false);
function resizeCanvas(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight/1.2;
}
So is there a different solution?
For the overflow problem, if I put overflow-x: hidden inside the body then only the scrollbar disappears but the problem persists. The canvas still extends past the screen hence the right border of the canvas is No longer visible.
See here
Here is my code:
HTML
<body onload="start()">
<canvas id="myCanvas"></canvas>
</body>
CSS
body{
}
canvas{
border: 1px solid black;
border-radius: 5px;
background-color: #fff;
margin: auto 50px auto 50px; /* works for left margin but not for right */
}
Thanks!
Another thing:
I have not set width: 100% for the canvas because it distorts the content inside it.
As Chris is saying you need to set the width of the canvas lower than the full width of the page:
canvas.width = window.innerWidth - 100;
Note that you need to take the border-width of the canvas and in your codepen the body also has a margin of 8px into account as well:
canvas.width = window.innerWidth - 118;
CSS calc() method is what you need. Just subtract the margins from 100% and you get the desired result. See the demo below. CSS calc() reference
function start() {
var canvas = document.getElementById('myCanvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 1.2;
var ctx = canvas.getContext('2d');
function rand(min, max) {
return parseInt(Math.random() * (max - min + 1), 10) + min;
}
function get_random_color() {
var h = rand(1, 360);
var s = rand(30, 100);
var l = rand(30, 70);
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var balls = [];
var ballCount = getRandomInt(2, 10);
//document.getElementById('ballCountInfo').innerHTML = ballCount;
//document.getElementById('box').innerHTML = ballCount;
var startpointX = 100;
var startpointY = 50;
for (var i = 0; i < ballCount; i++) {
var randValue = getRandomInt(20, 30);
balls.push({
x: startpointX,
y: startpointY,
vx: getRandomInt(3, 3) * direction(),
vy: getRandomInt(1, 1) * direction(),
radius: randValue,
mass: randValue,
color: get_random_color(),
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
});
startpointX = startpointX + 50;
startpointY = startpointY + 40;
}
function direction() {
var chosenValue = Math.random() < 0.5 ? 1 : -1;
return chosenValue;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < ballCount; i++) {
balls[i].draw();
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
if ((balls[i].y + balls[i].vy + balls[i].radius) > canvas.height || (balls[i].y + balls[i].vy - balls[i].radius) < 0) {
balls[i].vy = -balls[i].vy;
}
if ((balls[i].x + balls[i].vx + balls[i].radius) > canvas.width || (balls[i].x + balls[i].vx - balls[i].radius) < 0) {
balls[i].vx = -balls[i].vx;
}
}
// onBoxTouched();
//collision check
for (var i = 0; i < ballCount; i++) {
for (var j = i + 1; j < ballCount; j++) {
var distance = Math.sqrt(
(balls[i].x - balls[j].x) * (balls[i].x - balls[j].x) +
(balls[i].y - balls[j].y) * (balls[i].y - balls[j].y)
);
if (distance < (balls[i].radius + balls[j].radius)) {
var ax = (balls[i].vx * (balls[i].mass - balls[j].mass) + (2 * balls[j].mass * balls[j].vx)) / (balls[i].mass + balls[j].mass);
var ay = (balls[i].vy * (balls[i].mass - balls[j].mass) + (2 * balls[j].mass * balls[j].vy)) / (balls[i].mass + balls[j].mass);
balls[j].vx = (balls[j].vx * (balls[j].mass - balls[i].mass) + (2 * balls[i].mass * balls[i].vx)) / (balls[i].mass + balls[j].mass);
balls[j].vy = (balls[j].vy * (balls[j].mass - balls[i].mass) + (2 * balls[i].mass * balls[i].vy)) / (balls[i].mass + balls[j].mass);
balls[i].vx = ax;
balls[i].vy = ay;
}
}
}
raf = window.requestAnimationFrame(draw);
}
function onBoxTouched() {
for (var i = 0; i < ballCount; i++) {
if (balls[i].x + balls[i].radius > 600 && balls[i].x + balls[i].radius < 750 &&
balls[i].y + balls[i].radius > 200 && balls[i].y + balls[i].radius < 350) {
//var ele = document.getElementById("box");
ele.style.backgroundColor = balls[i].color;
balls.splice(i, 1);
ballCount = ballCount - 1;
if (ballCount == 0) {
ele.style.fontSize = "x-large";
ele.innerHTML = "Over";
} else {
ele.innerHTML = ballCount;
}
//document.getElementById('ballCountInfo').innerHTML=" "+ballCount;
}
}
}
window.requestAnimationFrame(draw);
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 1.2;
}
}
* {}
html,
body {}
canvas {
border: 1px solid black;
border-radius: 5px;
background-color: #fff;
width: calc(100% - 40px);
/*substract the total margin from 100% and will automoatically adjuts accordint to your need*/
margin: auto 20px auto 20px;
/* works for left margin but not for right */
}
#box {
width: 150px;
height: 150px;
background-color: plum;
border-radius: 5px;
position: absolute;
top: 200px;
left: 600px;
font-size: 72px;
font-weight: bold;
color: white;
line-height: 150px;
text-align: center;
}
#info {
float: left;
font-size: 24px;
color: #6D8390;
margin-top: 20px;
}
<body onload="start()">
<canvas id="myCanvas"></canvas>
</body>
Hope it helps :)
instead of messing around with margins, just change the width of your canvas and center it.
CSS
canvas {
border: 1px solid black;
border-radius: 5px;
background-color: #fff;
width: 90%!important;
}
HTML
<body onload="start()">
<center>
<canvas id="myCanvas"></canvas>
</center>
</body>
https://codepen.io/anon/pen/GEmLPL
I'm using the following code to move a ball around the screen when my mobile phone is rotated:
HTML
<html>
<head>
<meta charset="utf-8">
<title>Gyro_Ball</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/main.js"></script>
</head>
<body onload="init()">
<div id="ball"></div>
</body>
</html>
SCRIPT
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 );
};
} )();
}
var ball;
var w;
var h;
function init()
{
ball = document.getElementById("ball");
w = window.innerWidth;
h = window.innerHeight;
ball.style.left = (w/2)-50+"px";
ball.style.top = (h/2)-50+"px";
ball.velocity = {x:0,y:0}
ball.position = {x:0,y:0}
if (window.DeviceOrientationEvent) {
window.addEventListener("deviceorientation", function(event)
{
ball.velocity.y = Math.round(event.beta);
ball.velocity.x = Math.round(event.gamma);
}
)
};
update();
}
function update()
{
ball.position.x += ball.velocity.x;
ball.position.y += ball.velocity.y;
if(ball.position.x > (w-100) && ball.velocity.x > 0)
{
ball.position.x = w-100;
}
if(ball.position.x < 0 && ball.velocity.x < 0)
{
ball.position.x = 0;
}
if(ball.position.y > (h-100) && ball.velocity.y > 0)
{
ball.position.y = h-100;
}
if(ball.position.y < 0 && ball.velocity.y < 0)
{
ball.position.y = 0;
}
ball.style.top = ball.position.y + "px"
ball.style.left = ball.position.x + "px"
requestAnimationFrame(update);//KEEP ANIMATING
}
CSS
body {
padding:0;
margin:0;
background-color: #32c9d6;
}
#ball
{
-webkit-transition: all;
transition: all;
position:absolute;
width:100px;
height:100px;
border-radius: 50%;
background: white;
}
It works great! BUT I need to slow the ball down when I rotate my mobile....any ideas?
HERE IS A DEMO (Use Your mobile to view it):
http://inkfood.github.io/Gyro_Ball2/
JSFIDDLE (Use Your mobile to view it):
https://jsfiddle.net/qq74w6a3/6/
I just need to slow that ball down when tilting left to right so it doesn't zoom across so fast...there must be a delay or acceleration or FPS I can use to slow it down?
I tried getting this to work on mobile, but I couldn't. But I did add a mouse event which uses the mouse delta to slow the ball.
I calculate how far the mouse is away from the ball center and then use that percentage to adjust the velocity. I think you could use this to find how far the ball center is from the oriented side. i.e. the bottom.
Run the embedded script and move your mouse around. The ball should slow as it gets closer to the mouse position.
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = (function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
window.setTimeout(callback, 1000 / 60);
};
})();
}
var ball;
var dbg;
var w;
var h;
var my = 0;
var mx = 0;
function update() {
ball.position.x += ball.velocity.x;
ball.position.y += ball.velocity.y;
if (ball.position.x > (w - 100) && ball.velocity.x > 0) {
ball.position.x = w - 100;
}
if (ball.position.x < 0 && ball.velocity.x < 0) {
ball.position.x = 0;
}
if (ball.position.y > (h - 100) && ball.velocity.y > 0) {
ball.position.y = h - 100;
}
if (ball.position.y < 0 && ball.velocity.y < 0) {
ball.position.y = 0;
}
ball.style.top = ball.position.y + "px";
ball.style.left = ball.position.x + "px";
requestAnimationFrame(update); //KEEP ANIMATING
}
function init() {
ball = document.getElementById("ball");
dbg = document.getElementById("debug");
w = window.innerWidth;
h = window.innerHeight;
ball.style.left = (w / 2) - 50 + "px";
ball.style.top = (h / 2) - 50 + "px";
ball.velocity = {
x: 0,
y: 0
};
ball.position = {
x: 0,
y: 0
};
if (window.DeviceOrientationEvent) {
window.addEventListener("deviceorientation", function(event) {
ball.velocity.y = Math.round(event.beta);
ball.velocity.x = Math.round(event.gamma);
});
} else {
window.addEventListener("mousemove", function(event) {
my = event.clientY;
mx = event.clientX;
});
window.setInterval(function() {
var wy = window.outerHeight;
var wx = window.outerWidth;
var bcy = ball.position.y + 50; //ball center Y
var bcx = ball.position.x + 50; // ball center X
var dy = Math.round(((my - bcy) * 100 / wy) * 10000) / 10000;
var dx = Math.round(((mx - bcx) * 100 / wx) * 10000) / 10000;
ball.velocity.y = dy;
ball.velocity.x = dx;
dbg.innerHTML = 'deltaY:' + dy + ' deltaX:' + dx;
}, 100);
}
update();
}
init();
#ball {
-webkit-transition: all;
transition: all;
position: absolute;
width: 100px;
height: 100px;
border-radius: 50%;
background: red;
}
#debug {
position: absolute;
top: 5px;
left: 5px;
display: inline-block;
width: auto;
height: auto;
padding: 5px 10px;
z-index: 2;
color: rgb(255, 255, 255);
background: rgba(0, 0, 0, 0.75);
font-family: monospace;
font-size: 11px;
}
<div id="ball"></div>
<div id="debug">x:0 y:0</div>
$(document).ready(function(){
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d'),
img = new Image;
img.onload = draw;
img.src = 'http://fariskassim.com/stage/strip/v3/img/before1.jpg';
function draw() {
//drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height, 0.1, 0.5);
}
ERASE_W=150;
ERASE_H=70;
rzr=$("#razor2");
RAZOR_W=rzr.width();
RAZOR_H=rzr.height();
/**
* By Ken Fyrstenberg Nilsen
*
* drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
*
* If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
/// default offset is center
offsetX = typeof offsetX === 'number' ? offsetX : 0.5;
offsetY = typeof offsetY === 'number' ? offsetY : 0.5;
/// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, /// new prop. width
nh = ih * r, /// new prop. height
cx, cy, cw, ch, ar = 1;
/// decide which gap to fill
if (nw < w) ar = w / nw;
if (nh < h) ar = h / nh;
nw *= ar;
nh *= ar;
/// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
/// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
/// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
});
var hand = $('#razor2')[0];
(function() {
var origin = {
x: $(window).height(),
y: $(window).width()
}
window.onmousemove = handleMouseMove;
function handleMouseMove(event) {
event = event || window.event; // IE-ism
// event.clientX and event.clientY contain the mouse position
hand.style.left = event.clientX-92+"px";
hand.style.top = event.clientY-5+"px";
var leftSide = false;
var d = {
x: origin.x - event.clientX,
y: origin.y - event.clientY
};
var angle = Math.atan2(d.x, d.y) * 90 / Math.PI * -1;
if (leftSide) {
//angle = angle * -1;
}
hand.style["-webkit-transform"] = "rotate("+parseInt(angle,10)+"deg)";
hand.style["transform"] = "rotate("+parseInt(angle,10)+"deg)";
}
})();
function erase(e){
var cvxw = ctx.canvas.width;
var parentOffset = $("#razor2").parent().offset();
//or $(this).offset(); if you really just want the current element's offset
var relX = e.pageX + 0;
var relY = e.pageY + 0;
ctx.clearRect((relX-(RAZOR_W/2)),(relY-(RAZOR_H/2)),ERASE_W,ERASE_H);
}
function draw_razor(e){
var parentOffset = $("#razor2").parent().offset();
//or $(this).offset(); if you really just want the current element's offset
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
rzr.show();
rzr.css('margin-top','-'+(RAZOR_H/2)+'px');
rzr.css('margin-left','-'+(RAZOR_W/2)+'px');
rzr.css('left',relX+'px');
rzr.css('top',relY+'px');
};
$(document).mousemove(function(e){
draw_razor(e);
});
$('#razor2').bind('mousedown', function(e){
$('#razor2').bind('mousemove', function(e){
erase(e);
hand.className = "active";
});
$('#razor2').bind('mouseup',function(){
$('#razor2').unbind('mousemove')
hand.className = "";
});
});
$('#razor2').on('dragstart', function(e) {
e.preventDefault();
});
* {
padding: 0;
margin: 0;
}
#game {
position: relative;
display: block;
width: 100vw;
font-size: 0;
-webkit-box-shadow: 3px 3px 7px 1px rgba(0, 0, 0, 0.8);
box-shadow: 3px 3px 7px 1px rgba(0, 0, 0, 0.8);
margin:0;
overflow:hidden;
}
body {
background-color: navajo;
background-position: center top;
background-repeat: no-repeat;
margin:0;
}
.canvas_wrap {
width: 100%;
height: 0;
padding-bottom: 50%;
position:relative;
overflow: hidden;
}
canvas {
/*cursor: none;*/
position: absolute;
background: transparent;
top:0;
left: 0;
z-index: 3;
width:100%;
height: 100%;
object-fit: cover;
}
#kitten{
width: 100%;
height: 100%;
object-fit: cover;
position:absolute;
top:0;
left: 0;
z-index: 2;
}
#razor2 {
background-image:url(http://fariskassim.com/stage/strip/v3/img/razor.png);
/*cursor: none;*/
position: absolute;
z-index: 98;
width: 800px;
height: 476px;
margin-top: -200px !important;
margin-left: -200px !important;
background-size: cover;
object-position: -99999px 99999px;
}
#razor2.active {
background-position: 0 100% !important;
}
#razor {
height: 0;
width: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="game">
<img id="razor" src="img/razor.png">
<div id="razor2"></div>
<div class="canvas_wrap">
<canvas id="canvas" width="1730" height="870">Los ti browser!</canvas>
<img id="kitten" src="http://fariskassim.com/stage/strip/v3/img/after1.jpg">
</div>
</div>
As you'll see, when you start dragging your mouse across the canvas, you'll see that the clearRect (shaving hair) is not taking place on the mouse position. its a little off to the left
i believe this is because i scaled the canvas to make it responsive.
Anyone knows how i modify my code to make the clearRect work on the position of the mouse?
I visited the Stack Exchange Winter Bash website and I love the falling snow! My question is, how can I recreate a similar effect that looks as nice. I attempted to reverse engineer the code to see if I could figure it out but alas no luck there. The JS is over my head. I did a bit of googling and came across some examples but they were not as elegant as the SE site or did not look very good.
Can anyone provide some instructions on how to replicate what the SE Winter Bash site creates or a place where I might learn how to do this?
Edit: I would like to replicate the effect as close as possible, IE: falling snow with snowflakes, and being able to move the mouse and cause the snow to move or swirl with the mouse moments.
Great question, I actually wrote a snow plugin a while ago that I continually update see it in action. Also a link to the pure js source
I noticed you tagged the question html5 and canvas, however you can do it without using either, and just standard elements with images or different background colors.
Here's two really simple ones I put together just now for you to mess with. The key in my opinion is using sin to get the nice wavy effect as the flakes fall. The first one uses the canvas element, the 2nd one uses regular dom elements.
Since I'm absolutely addicted to canvas here's a canvas version that performs quite nicely in my opinion.
Canvas version
Full Screen
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
var flakes = [],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
flakeCount = 200,
mX = -100,
mY = -100
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function snow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = flakes[i],
x = mX,
y = mY,
minDist = 150,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
}
ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(snow);
};
function reset(flake) {
flake.x = Math.floor(Math.random() * canvas.width);
flake.y = 0;
flake.size = (Math.random() * 3) + 2;
flake.speed = (Math.random() * 1) + 0.5;
flake.velY = flake.speed;
flake.velX = 0;
flake.opacity = (Math.random() * 0.5) + 0.3;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = Math.floor(Math.random() * canvas.width),
y = Math.floor(Math.random() * canvas.height),
size = (Math.random() * 3) + 2,
speed = (Math.random() * 1) + 0.5,
opacity = (Math.random() * 0.5) + 0.3;
flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
angle: 180,
opacity: opacity
});
}
snow();
};
canvas.addEventListener("mousemove", function(e) {
mX = e.clientX,
mY = e.clientY
});
init();
Standard element version
var flakes = [],
bodyHeight = getDocHeight(),
bodyWidth = document.body.offsetWidth;
function snow() {
for (var i = 0; i < 50; i++) {
var flake = flakes[i];
flake.y += flake.velY;
if (flake.y > bodyHeight - (flake.size + 6)) {
flake.y = 0;
}
flake.el.style.top = flake.y + 'px';
flake.el.style.left = ~~flake.x + 'px';
flake.step += flake.stepSize;
flake.velX = Math.cos(flake.step);
flake.x += flake.velX;
if (flake.x > bodyWidth - 40 || flake.x < 30) {
flake.y = 0;
}
}
setTimeout(snow, 10);
};
function init() {
var docFrag = document.createDocumentFragment();
for (var i = 0; i < 50; i++) {
var flake = document.createElement("div"),
x = Math.floor(Math.random() * bodyWidth),
y = Math.floor(Math.random() * bodyHeight),
size = (Math.random() * 5) + 2,
speed = (Math.random() * 1) + 0.5;
flake.style.width = size + 'px';
flake.style.height = size + 'px';
flake.style.background = "#fff";
flake.style.left = x + 'px';
flake.style.top = y;
flake.classList.add("flake");
flakes.push({
el: flake,
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: 2,
stepSize: (Math.random() * 5) / 100,
step: 0
});
docFrag.appendChild(flake);
}
document.body.appendChild(docFrag);
snow();
};
document.addEventListener("mousemove", function(e) {
var x = e.clientX,
y = e.clientY,
minDist = 150;
for (var i = 0; i < flakes.length; i++) {
var x2 = flakes[i].x,
y2 = flakes[i].y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
if (dist < minDist) {
rad = Math.atan2(y2, x2), angle = rad / Math.PI * 180;
flakes[i].velX = (x2 / dist) * 0.2;
flakes[i].velY = (y2 / dist) * 0.2;
flakes[i].x += flakes[i].velX;
flakes[i].y += flakes[i].velY;
} else {
flakes[i].velY *= 0.9;
flakes[i].velX
if (flakes[i].velY <= flakes[i].speed) {
flakes[i].velY = flakes[i].speed;
}
}
}
});
init();
function getDocHeight() {
return Math.max(
Math.max(document.body.scrollHeight, document.documentElement.scrollHeight), Math.max(document.body.offsetHeight, document.documentElement.offsetHeight), Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
I've created a pure HTML 5 and js snowfall.
Check it out on my code pen here: https://codepen.io/onlintool24/pen/GRMOBVo
// Amount of Snowflakes
var snowMax = 35;
// Snowflake Colours
var snowColor = ["#DDD", "#EEE"];
// Snow Entity
var snowEntity = "•";
// Falling Velocity
var snowSpeed = 0.75;
// Minimum Flake Size
var snowMinSize = 8;
// Maximum Flake Size
var snowMaxSize = 24;
// Refresh Rate (in milliseconds)
var snowRefresh = 50;
// Additional Styles
var snowStyles = "cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;";
/*
// End of Configuration
// ----------------------------------------
// Do not modify the code below this line
*/
var snow = [],
pos = [],
coords = [],
lefr = [],
marginBottom,
marginRight;
function randomise(range) {
rand = Math.floor(range * Math.random());
return rand;
}
function initSnow() {
var snowSize = snowMaxSize - snowMinSize;
marginBottom = document.body.scrollHeight - 5;
marginRight = document.body.clientWidth - 15;
for (i = 0; i <= snowMax; i++) {
coords[i] = 0;
lefr[i] = Math.random() * 15;
pos[i] = 0.03 + Math.random() / 10;
snow[i] = document.getElementById("flake" + i);
snow[i].style.fontFamily = "inherit";
snow[i].size = randomise(snowSize) + snowMinSize;
snow[i].style.fontSize = snow[i].size + "px";
snow[i].style.color = snowColor[randomise(snowColor.length)];
snow[i].style.zIndex = 1000;
snow[i].sink = snowSpeed * snow[i].size / 5;
snow[i].posX = randomise(marginRight - snow[i].size);
snow[i].posY = randomise(2 * marginBottom - marginBottom - 2 * snow[i].size);
snow[i].style.left = snow[i].posX + "px";
snow[i].style.top = snow[i].posY + "px";
}
moveSnow();
}
function resize() {
marginBottom = document.body.scrollHeight - 5;
marginRight = document.body.clientWidth - 15;
}
function moveSnow() {
for (i = 0; i <= snowMax; i++) {
coords[i] += pos[i];
snow[i].posY += snow[i].sink;
snow[i].style.left = snow[i].posX + lefr[i] * Math.sin(coords[i]) + "px";
snow[i].style.top = snow[i].posY + "px";
if (snow[i].posY >= marginBottom - 2 * snow[i].size || parseInt(snow[i].style.left) > (marginRight - 3 * lefr[i])) {
snow[i].posX = randomise(marginRight - snow[i].size);
snow[i].posY = 0;
}
}
setTimeout("moveSnow()", snowRefresh);
}
for (i = 0; i <= snowMax; i++) {
document.write("<span id='flake" + i + "' style='" + snowStyles + "position:absolute;top:-" + snowMaxSize + "'>" + snowEntity + "</span>");
}
window.addEventListener('resize', resize);
window.addEventListener('load', initSnow);
body{
background: skyblue;
height:100%;
width:100%;
display:block;
position:relative;
}
<span id="flake0" style="cursor: default; user-select: none; position: absolute; font-family: inherit; font-size: 19px; color: rgb(221, 221, 221); z-index: 1000; left: 226px; top: 561px;">•</span>
The falling snow is simple: Create a canvas, create a bunch of snowflakes, draw them.
You can create a snowflake class like so:
function Snowflake() {
this.x = Math.random()*canvas.width;
this.y = -16;
this.speed = Math.random()*3+1;
this.direction = Math.random()*360;
this.maxSpeed = 4;
}
Or something like that. Then you have a timer that, each step, adjusts each snowflake's direction by a small amount, and then calculates its new X and Y by factoring in the Speed and Direction.
It's hard to explain, but actually quite basic.