Mousewheel smooth scroll - javascript

I'm looking for make a smooth scroll effect in my website, like these websites :
http://www.femmefatale.paris/fr/project/tati-express
http://onirim.com/photographers/olaf-wipperfurth/
I only found this script : https://github.com/fatlinesofcode/jquery.smoothwheel
But it doesn't work when you scroll your page in holding the scrollbar...
Here's my code I apply at the body :
https://jsfiddle.net/bLhs0fkn/1/
(function ($) {
var self = this, container, running=false, currentY = 0, targetY = 0, oldY = 0, maxScrollTop= 0, minScrollTop, direction, onRenderCallback=null,
fricton = 0.95, // higher value for slower deceleration
vy = 0,
stepAmt = 0.8,
minMovement= 0.3,
ts=0.1;
var updateScrollTarget = function (amt) {
targetY += amt;
vy += (targetY - oldY) * stepAmt;
oldY = targetY;
}
var render = function () {
if (vy < -(minMovement) || vy > minMovement) {
currentY = (currentY + vy);
if (currentY > maxScrollTop) {
currentY = vy = 0;
} else if (currentY < minScrollTop) {
vy = 0;
currentY = minScrollTop;
}
container.scrollTop(-currentY);
vy *= fricton;
// vy += ts * (currentY-targetY);
// scrollTopTweened += settings.tweenSpeed * (scrollTop - scrollTopTweened);
// currentY += ts * (targetY - currentY);
if(onRenderCallback){
onRenderCallback();
}
}
}
var animateLoop = function () {
if(! running)return;
requestAnimFrame(animateLoop);
render();
//log("45","animateLoop","animateLoop", "",stop);
}
var onWheel = function (e) {
e.preventDefault();
var evt = e.originalEvent;
var delta = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
var dir = delta < 0 ? -1 : 1;
if (dir != direction) {
vy = 0;
direction = dir;
}
//reset currentY in case non-wheel scroll has occurred (scrollbar drag, etc.)
currentY = -container.scrollTop();
updateScrollTarget(delta);
}
/*
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
/*
* http://jsbin.com/iqafek/2/edit
*/
var normalizeWheelDelta = function () {
// Keep a distribution of observed values, and scale by the
// 33rd percentile.
var distribution = [], done = null, scale = 30;
return function (n) {
// Zeroes don't count.
if (n == 0) return n;
// After 500 samples, we stop sampling and keep current factor.
if (done != null) return n * done;
var abs = Math.abs(n);
// Insert value (sorted in ascending order).
outer: do { // Just used for break goto
for (var i = 0; i < distribution.length; ++i) {
if (abs <= distribution[i]) {
distribution.splice(i, 0, abs);
break outer;
}
}
distribution.push(abs);
} while (false);
// Factor is scale divided by 33rd percentile.
var factor = scale / distribution[Math.floor(distribution.length / 3)];
if (distribution.length == 500) done = factor;
return n * factor;
};
}();
$.fn.smoothWheel = function () {
// var args = [].splice.call(arguments, 0);
var options = jQuery.extend({}, arguments[0]);
return this.each(function (index, elm) {
if(!('ontouchstart' in window)){
container = $(this);
container.bind("mousewheel", onWheel);
container.bind("DOMMouseScroll", onWheel);
//set target/old/current Y to match current scroll position to prevent jump to top of container
targetY = oldY = container.get(0).scrollTop;
currentY = -targetY;
minScrollTop = container.get(0).clientHeight - container.get(0).scrollHeight;
if(options.onRender){
onRenderCallback = options.onRender;
}
if(options.remove){
log("122","smoothWheel","remove", "");
running=false;
container.unbind("mousewheel", onWheel);
container.unbind("DOMMouseScroll", onWheel);
}else if(!running){
running=true;
animateLoop();
}
}
});
};
})(jQuery);
Thanks

The problem with your code is that you are trying to apply smoothWheel to your DOM body. What you can do instead is wrap all the div inside another div (id="wrapper") and apply the CSS and JS onto this div.
HTML
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js" type="text/javascript"></script>
<script src="http://fatlinesofcode.github.io/jquery.smoothwheel/src/jquery.smoothwheel.js" type="text/javascript"></script>
<div id="wrapper">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
JS
$(document).ready(function(){//alert('1')
$("#wrapper").smoothWheel();
});
CSS
#wrapper {
height:300px;
width:100%;
overflow:auto;
-webkit-overflow-scrolling: touch;
background: grey;
}
div {
height:100px;
width:100px;
background:lightblue;
margin-bottom : 50px;
}
Here is a Demo for the same.

Related

Scrollable board for HTML5 GAME should use SVG's or Canvas

I wish to create a simple webgame that involves a tiled board. I have a collection of svg's for the background of each square (i.e one for grass, one for stone, one for dirt etc). I also have svg's for items that will be displayed on the layer above the background (such as trees, wood, sword).
I have an in memory database of what the background for each square is and if and which item it contains.
I wish to be able to:
* Zoom in or out
* Scroll left or right
* Scolll up or down
* Have items displayed above the background for that square
Only needs to work in recent versions of modern browsers
What is the best approach for this:
1. Have a canvas object. Get the current zoom, top most XY, canvas width and canvas height. Loop though the squares in the in memory database and print the corresponding SVG's in the correct locations. Each time it is scrolled or zoomed reprint the entire board.
2. Have a div. Get the current zoom, top most XY, canvas width and canvas height. Loop though the squares in the in memory database and create SVG's in the correct locations.
Each time the board scrolls add new SVGs as they become visible, delete SVGs as they move of the board. Translate all the existing SVGs by the appropriate amount.
Each time the board zooms enlarge or shrink all the existing SVGs based on the new zoom level.
3. Some third approach that I am unaware of.
The example below uses two modules svg to load images (Any image format will work) & board which handles panning, zooming & rendering. It also provides an onClick event which will give you an object that describes the tile that has been clicked on.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: 30px auto 0px auto;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
var svg = function() {
"use strict";
var svgImages = [];
var areImagesLoaded = true;
var isPageLoaded = false;
addEventListener("load",function() { isPageLoaded = true; isFinished(); });
var exports = {
onload: function() {},
request: null,
get: null
};
function isFinished() {
if (isPageLoaded && areImagesLoaded) {
exports.onload();
}
}
function onSvgError() {
this.isDone = true;
console.warn("SVG " + this.src + " failed to load.");
}
function onSvgLoaded() {
this.isDone = true;
for (var id in svgImages) {
if (!svgImages[id].isDone) {
return;
}
}
areImagesLoaded = true;
isFinished();
}
function request(id,path) {
if (svgImages[id]) {
return;
}
areImagesLoaded = false;
var img = document.createElement("img");
img.onerror = onSvgError;
img.onload = onSvgLoaded;
img.isDone = false;
img.id = id;
img.src = path;
svgImages[id] = img;
}
function get(id) {
return svgImages[id];
}
exports.request = request;
exports.get = get;
return exports;
}();
var board = function() {
"use strict";
var canvasWidth = 0;
var canvasHeight = 0;
var canvas = null;
var ctx = null;
var frameRequested = false;
var tileWidth = 0;
var tileHeight = 0;
var tileTypes = [];
var boardWidth = 0;
var boardHeight = 0;
var board = [];
var hasInitialized = false;
var camera = {
x: 0.0,
y: 0.0,
zoom: 1.0
};
function mapToBoard(x,y) {
var invZoom = 1.0 / camera.zoom;
return [
(x - (canvasWidth >> 1)) * invZoom - camera.x,
(y - (canvasHeight >> 1)) * invZoom - camera.y
];
}
var isMouseDragging = false;
var mouseStartX = 0;
var mouseStartY = 0;
var mouseLastX = 0;
var mouseLastY = 0;
var tileEvent = {
background: "",
foreground: "",
x: 0,
y: 0
};
function onTileSelected(e) {
}
function onMouseDown(e) {
isMouseDragging = true;
var bounds = canvas.getBoundingClientRect();
mouseStartX = mouseLastX = e.clientX - bounds.left;
mouseStartY = mouseLastY = e.clientY - bounds.top;
}
function onMouseUp(e) {
isMouseDragging = false;
var bounds = canvas.getBoundingClientRect()
var x = e.clientX - bounds.left - mouseStartX;
var y = e.clientY - bounds.top - mouseStartY;
var l = Math.sqrt(x * x + y * y);
if (l < 2.0) {
[x,y] = mapToBoard(e.clientX - bounds.left,e.clientY - bounds.top);
if (x > 0 && y > 0 && x < boardWidth * tileWidth && y < boardHeight * tileHeight) {
x = (x / tileWidth) | 0;
y = (y / tileHeight) | 0;
var tile = board[x + y * boardWidth];
tileEvent.background = tile.background;
tileEvent.foreground = tile.foreground;
tileEvent.x = x;
tileEvent.y = y;
} else {
tileEvent.background = "";
tileEvent.foreground = "";
tileEvent.x = -1;
tileEvent.y = -1;
}
onTileSelected(tileEvent);
}
}
function onMouseMove(e) {
if (hasInitialized && isMouseDragging) {
var bounds = canvas.getBoundingClientRect();
var x = e.clientX - bounds.left;
var y = e.clientY - bounds.top;
camera.x += (x - mouseLastX) / camera.zoom;
camera.y += (y - mouseLastY) / camera.zoom;
mouseLastX = x;
mouseLastY = y;
requestDraw();
}
}
function onWheel(e) {
if (Math.sign(e.deltaY) === -1) {
camera.zoom *= 1.1;
} else {
camera.zoom *= 0.9;
}
requestDraw();
}
function draw() {
ctx.fillStyle = "gray";
ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
var _tileWidth = tileWidth * camera.zoom;
var _tileHeight = tileHeight * camera.zoom;
var _ox = camera.x * camera.zoom;
var _oy = camera.y * camera.zoom;
var _x = _ox;
var _y = _oy;
for (var x = 0; x <boardWidth; ++x) {
for (var y = 0; y < boardHeight; ++y) {
var index = x + y * boardWidth;
var tile = board[index];
var background = tileTypes[tile.background];
var foreground = tileTypes[tile.foreground];
if (background) {
ctx.drawImage(
background,
_x,
_y,
_tileWidth,
_tileHeight
);
}
if (foreground) {
ctx.drawImage(
foreground,
_x,
_y,
_tileWidth,
_tileHeight
);
}
_y += _tileHeight;
}
_y = _oy;
_x += _tileWidth;
}
frameRequested = false;
}
function requestDraw() {
if (!frameRequested) {
frameRequested = true;
requestAnimationFrame(draw);
}
}
return {
BACKGROUND: 0,
FOREGROUND: 1,
set canvas(canvasID) {
if (!hasInitialized) {
canvas = document.getElementById(canvasID);
canvas.onmousedown = onMouseDown;
canvas.onmouseup = onMouseUp;
canvas.onmousemove = onMouseMove;
canvas.onwheel = onWheel;
ctx = canvas.getContext("2d");
}
},
set canvasWidth(w) {
if (!hasInitialized && canvas) {
canvasWidth = canvas.width = w;
}
},
set canvasHeight(h) {
if (!hasInitialized && canvas) {
canvasHeight = canvas.height = h;
}
},
set tileWidth(w) {
if (!hasInitialized) {
tileWidth = w;
}
},
set tileHeight(h) {
if (!hasInitialized) {
tileHeight = h;
}
},
set width(w) {
if (!hasInitialized) {
boardWidth = w;
}
},
set height(h) {
if (!hasInitialized) {
boardHeight = h;
}
},
set onTileSelected(callback) {
onTileSelected = callback;
},
get width() {
return boardWidth;
},
get height() {
return boardHeight;
},
get onTileSelected() {
return onTileSelected;
},
defineTileTypes: function(types) {
if (types.length % 2 !== 0) {
return;
}
for (var i = 0; i < types.length; i += 2) {
var id = types[i];
var img = types[i + 1];
tileTypes[id] = img;
}
},
init: function() {
camera.x = -(boardWidth >> 1) * tileWidth;
camera.y = -(boardHeight >> 1) * tileHeight;
ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
board.length = boardWidth * boardHeight;
for (var i = 0; i < board.length; ++i) {
board[i] = {
background: "",
foreground: ""
};
}
hasInitialized = true;
requestAnimationFrame(draw);
},
set: function(type,id,x,y) {
if (hasInitialized
&& tileTypes[id]
&& x > -1
&& x < boardWidth
&& y > -1
&& y < boardHeight) {
var index = x + y * boardWidth;
if (type === this.BACKGROUND) {
board[index].background = id;
} else {
board[index].foreground = id;
}
requestDraw();
}
}
};
}();
void function() {
"use strict";
svg.request("grass","https://i.stack.imgur.com/CkvU7.png");
svg.request("water","https://i.stack.imgur.com/an6a5.png");
svg.onload = function() {
board.canvas = "canvas";
board.canvasWidth = 180;
board.canvasHeight = 160;
board.tileWidth = 25;
board.tileHeight = 25;
board.width = 20;
board.height = 20;
board.defineTileTypes([
"GRASS",svg.get("grass"),
"WATER",svg.get("water")
]);
board.init();
for (var x = 0; x < board.width; ++x) {
for (var y = 0; y < board.height; ++y) {
board.set(board.BACKGROUND,"WATER",x,y);
if (Math.random() > 0.2) {
board.set(board.BACKGROUND,"GRASS",x,y);
} else {
board.set(board.BACKGROUND,"WATER",x,y);
}
}
}
}
board.onTileSelected = function(e) {
if (e.background === "GRASS") {
board.set(board.BACKGROUND,"WATER",e.x,e.y);
} else {
board.set(board.BACKGROUND,"GRASS",e.x,e.y);
}
}
}();
</script>
</body>
</html>

How to move character in two speeds without one affecting the other?

OK, so this is a little hard to explain. I'm making a canvas-based point-and-click 2d game. You can look around (move the environment) by dragging the mouse horizontally across the screen. And move the character by clicking where you want him to go. Kinda like This War of Mine. Here's a simplified version of what I got...
MOUSE ACTIONS:
var held, mouseX, mouseXInitial;
window.addEventListener('mousedown',function(e){
held = true;
mouseXInitial = mouseX;
});
window.addEventListener('mouseup',function(e){
held = false;
});
window.addEventListener('mousemove',function(e){
mouseX = e.clientX;
});
mouseEvents();
LOOKING AROUND (dragging across the screen to look around the environment):
var sharedParentObject = {
scrolledAmount: null,
scrolling: function(){
if (held){
this.scrolledAmount = mouseX - mouseXInitial;
this.x = this.xInitial + this.scrolledAmount;
}
},
inputShared: function(){
var that = this;
window.addEventListener('mousedown',function(e){
that.xInitial = that.x;
});
window.addEventListener('mousemove',function(e){
that.scrolling();
});
}
}
MOVING THE CHARACTER:
function Character(){
this.speed = 2;
this.target = null;
this.input = function(){
var that = this;
window.addEventListener('mouseup',function(e){
that.target = that.mouseXInitial;
that.target += that.scrolledAmount;
});
}
this.update = function(){
if (this.target){
//moving right
if (this.x + this.w/2 < this.target){
this.x += this.speed;
}
//moving left
if (this.x + this.w/2 > this.target){
this.x -= this.speed;
}
}
}
}
Character.prototype = Object.create(sharedParentObject);
This works but the problem is that once I start dragging across the screen to look around, while the character is already walking, it gets all weird and jittery. I understand why this is happening. The character's x is getting changed in both the character class and the parent class at the same time. Is there a way to have it so the character can keep walking towards the target, while still getting moved as I scroll the environment? Kinda doing both, without one affecting the other..
All you need to do is track the distance the mouse have moved between the onmousedown and onmouseup events. If the distance is very small, then the user has clicked on one spot, if the distance is larger then they are trying to pan the scene.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// ES5 Friendly class functions
// (Supports overloading & single inheritance)
var _class = (function() {
"use strict";
/*
All a class is in JS is a function that
acts as a constructor and an object (prototype)
that holds the properties shared across all
instances (static vars, constants & functions).
*/
function _class(constructor,prototype) {
prototype.base = null;
prototype.super = constructor;
constructor.prototype = prototype;
return constructor;
}
_class.extends = function(base,constructor,prototype) {
for (var property in base.prototype) {
if (!prototype[property]) {
prototype[property] = base.prototype[property];
}
}
function bundledConstructor() {
base.apply(this,arguments);
constructor.apply(this,arguments);
}
prototype.base = base;
prototype.super = bundledConstructor;
bundledConstructor.prototype = prototype;
return bundledConstructor;
}
return _class;
})();
void function() {
"use strict";
// Classes
// Encapsulate canvas element
var Viewport = _class(
function(canvasID,width,height,bgColour) {
this.canvas = document.getElementById(canvasID) || null;
this.width = width || 1.0;
this.height = height || 1.0;
this.bgColour = bgColour || "gray";
this.hWidth = this.width >> 1;
this.hHeight = this.height >> 1;
this.canvas.width = this.width;
this.canvas.height = this.height;
this.ctx = this.canvas.getContext("2d");
this.ctx.translate(this.hWidth,this.hHeight);
var bounds = this.canvas.getBoundingClientRect();
this.leftMargin = bounds.left;
this.topMargin = bounds.top;
},{
clear: function() {
var ctx = this.ctx;
ctx.fillStyle = this.bgColour;
ctx.fillRect(-this.hWidth,-this.hHeight,this.width,this.height);
}
}
);
// This is a class used to encapsulate
// the scene's panning/zooming.
var Camera = _class(
// Constructor Function
function(viewport,x,y) {
this.viewport = viewport || null;
this.x = x || 0.0;
this.y = y || 0.0;
this.scale = 1.0;
this.invScale = 1.0 / this.scale;
this.allowUserInput = false;
this.mouseDown = false;
this.mouseLastX = 0.0;
this.mouseLastY = 0.0;
viewport.canvas.addEventListener("wheel",this.onwheel.bind(this));
viewport.canvas.addEventListener("mousedown",this.onmousedown.bind(this));
viewport.canvas.addEventListener("mouseup",this.onmouseup.bind(this));
viewport.canvas.addEventListener("mousemove",this.onmousemove.bind(this));
},
// Prototype (constant values & functions go here)
{
scaleCoordinates: function(x,y) {
return [
(x - this.viewport.hWidth) * this.invScale + this.x,
(y - this.viewport.hHeight) * this.invScale + this.y
];
},
scaleDimensions: function(width,height) {
return [
width * this.invScale,
height * this.invScale
];
},
pan: function(deltaX,deltaY) {
this.x += deltaX;
this.y += deltaY;
},
zoom: function(deltaScale) {
this.scale += deltaScale;
this.scale = Math.max(0.0,this.scale);
this.invScale = 1.0 / this.scale;
},
onwheel: function(e) {
if (this.allowUserInput) {
var deltaY = -Math.sign(e.deltaY) * (e.deltaY / e.deltaY) * 0.25;
this.zoom(deltaY);
}
},
onmousedown: function(e) {
this.mouseDown = true;
[
this.mouseLastX,
this.mouseLastY
] = this.scaleCoordinates(
e.clientX - this.viewport.leftMargin,
e.clientY - this.viewport.topMargin
);
},
onmouseup: function(e) {
this.mouseDown = false;
},
onmousemove: function(e) {
if (this.allowUserInput && this.mouseDown) {
var [
mouseX,
mouseY
] = this.scaleCoordinates(
e.clientX - this.viewport.leftMargin,
e.clientY - this.viewport.topMargin
);
this.pan(
this.mouseLastX - mouseX,
this.mouseLastY - mouseY
);
}
}
}
);
// Contains basic behaviour all game objects will have
var GameObject = _class(
function(x,y,width,height,colour) {
this.x = x || 0.0;
this.y = y || 0.0;
this.width = width || 1.0;
this.height = height || 1.0;
this.colour = colour || "darkblue";
this.dx = 0.0;
this.dy = 0.0;
this._draw_x = 0.0;
this._draw_y = 0.0;
this._draw_width = 0.0;
this._draw_height = 0.0;
},{
updateDrawParameters: function(camera) {
this._draw_width = this.width * camera.scale;
this._draw_height = this.height * camera.scale;
this._draw_x = ((this.x - camera.x) * camera.scale) - this._draw_width * 0.5;
this._draw_y = ((this.y - camera.y) * camera.scale) - this._draw_height * 0.5;
},
tick: function() {
},
render: function(viewport) {
var ctx = viewport.ctx;
ctx.fillStyle = this.colour;
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.rect(this._draw_x,this._draw_y,this._draw_width,this._draw_height);
ctx.fill();
ctx.stroke();
}
}
);
// A more specialized type of game object that
// can move to a specific location
var MoveAgent = _class.extends(GameObject,
function(x,y,width,height,colour) {
this.currentState = this.STATE_IDLE;
this.targetX = 0.0;
this.targetY = 0.0;
},{
STATE_IDLE: 1000,
STATE_MOVING_TO_TARGET: 1001,
MOVE_SPEED: 1.0,
GOAL_TOLERANCE: 5.0, // How close is 'good enough' to the target
moveTo: function(x,y) {
this.targetX = x || 0.0;
this.targetY = y || 0.0;
this.currentState = this.STATE_MOVING_TO_TARGET;
},
tick: function() {
switch(this.currentState) {
case this.STATE_IDLE:
break;
case this.STATE_MOVING_TO_TARGET:
var x = this.targetX - this.x;
var y = this.targetY - this.y;
var l = x * x + y * y;
if (l < this.GOAL_TOLERANCE * this.GOAL_TOLERANCE) {
this.currentState = this.STATE_IDLE;
} else {
l = 1.0 / Math.sqrt(l);
this.dx = x * l * this.MOVE_SPEED;
this.dy = y * l * this.MOVE_SPEED;
this.x += this.dx;
this.y += this.dy;
}
break;
}
}
}
);
var ControlledMoveAgent = _class.extends(MoveAgent,
function(x,y,width,height,colour,camera) {
this.camera = camera || null;
this.mouseDown = false;
this.mouseX = 0.0;
this.mouseY = 0.0;
viewport.canvas.addEventListener("mousedown",this.onmousedown.bind(this));
viewport.canvas.addEventListener("mouseup",this.onmouseup.bind(this));
viewport.canvas.addEventListener("mousemove",this.onmousemove.bind(this));
},{
MOVE_TOLLERANCE: 5.0,
onmousedown: function(e) {
if (e.button === 0) {
this.mouseDown = true;
this.mouseX = e.clientX;
this.mouseY = e.clientY;
}
},
onmouseup: function(e) {
if (e.button === 0 && this.mouseDown) {
this.mouseDown = false;
var x = e.clientX - this.camera.viewport.leftMargin;
var y = e.clientY - this.camera.viewport.topMargin;
[x,y] = this.camera.scaleCoordinates(x,y);
this.moveTo(x,y);
}
},
onmousemove: function(e) {
if (this.mouseDown) {
var x = this.mouseX - e.clientX;
var y = this.mouseY - e.clientY;
var l = Math.sqrt(x * x + y * y);
if (l > this.MOVE_TOLLERANCE) {
this.mouseDown = false;
}
}
}
}
);
// Vars
var camera = null;
var viewport = null;
var scenery = [];
var character = null;
// Functions
function loop() {
// Tick
for (var i = 0; i < scenery.length; ++i) {
scenery[i].updateDrawParameters(camera);
}
character.tick();
character.updateDrawParameters(camera);
// Render
viewport.clear();
for (var i = 0; i < scenery.length; ++i) {
scenery[i].render(viewport);
}
character.render(viewport);
//
requestAnimationFrame(loop);
}
// Entry Point
onload = function() {
viewport = new Viewport("canvas",180,160,"gray");
camera = new Camera(viewport,0,0);
camera.allowUserInput = true;
camera.zoom(0.25);
for (var i = 0; i < 10; ++i) {
scenery[i] = new GameObject(
180 * Math.random() - 90,
160 * Math.random() - 80,
10 + Math.random() * 10,
10 + Math.random() * 10,
"#" + ((Math.random() * 255) | 0).toString(16)
+ ((Math.random() * 255) | 0).toString(16)
+ ((Math.random() * 255) | 0).toString(16)
);
}
character = new ControlledMoveAgent(0,0,10,10,"darkred",camera);
loop();
}
}()
</script>
</body>
</html>

How can I get this GIF from another website?

I'm creating a website and I want a certain gif background that runs automatically on page load, here is the link of the website
http://contact-festival.com/
And I want to use the moving star-background on the artist line up list
I checked my developer tools and the network , but can't seem to find a source
These are not gifs . These are made with canvas tags and javascript coding.
So here is an example below that you can use.
window.onload = function () {
var element = "starfield";
var bgColor = "#030304";
var FPS = 30;
var displacementRate = 5;
var accelerationRate = 10;
var maxSpeed = 100;
var maxStars = 1000;
var speedUp = setInterval(function(){
if (accelerationRate > maxSpeed) {
clearInterval(speedUp);
}
accelerationRate = accelerationRate * 1.1;
},100);
var Star = function() {
this.x = 0;
this.y = 0;
this.z = 0;
this.maxDepth = 0;
this.alpha = 0;
this.radius = 0;
this.dx = 0;
this.dy = 0;
this.dz = 0;
this.ddx = 0;
this.ddy = 0;
this.drawInContext = function(ctx, deltaX, deltaY) {
ctx.beginPath();
ctx.fillStyle = "rgba(255, 255, 255," + this.alpha + ")";
ctx.arc(this.x + deltaX, this.y + deltaY, this.radius, 0, Math.PI * 2, false);
ctx.fill();
};
};
var requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000 / FPS);
};
function isCanvasSupported(element) {
return !!(element.getContext && element.getContext("2d"));
}
function backingScale(context) {
if ('devicePixelRatio' in window) {
if (window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
}
return 1;
}
function StarField(canvasID) {
this.canvas = document.getElementById(canvasID);
if (!isCanvasSupported(this.canvas)) {
this.canvas.className = "inactive";
this.canvas.width = window.innerWidth;
this.isCanvasEnabled = false;
return this;
}
this.isCanvasEnabled = true;
this.ctx = this.canvas.getContext("2d");
this.scaleFactor = backingScale(this.ctx);
this.stars = new Array();
function newStar() {
var star = new Star();
star.x = Math.random() * this.canvas.width - this.originX;
star.y = Math.random() * this.canvas.height - this.originY;
star.z = star.max_depth = Math.max(this.canvas.width, this.canvas.height);
star.alpha = Math.random();
star.radius = Math.random();
var xcoeff = star.x > 0 ? 1 : -1;
var ycoeff = star.y > 0 ? 1 : -1;
if (Math.abs(star.x) > Math.abs(star.y)) {
star.dx = 1.0;
star.dy = Math.abs(star.y / star.x);
} else {
star.dx = Math.abs(star.x / star.y);
star.dy = 1.0;
}
star.dx *= xcoeff * (displacementRate / 10);
star.dy *= ycoeff * (displacementRate / 10);
star.dz = -1;
star.ddx = (accelerationRate * star.dx) / 10;
star.ddy = (accelerationRate * star.dy) / 10;
return star;
}
function move(star) {
star.x += star.dx;
star.y += star.dy;
star.z += star.dz;
star.dx += star.ddx;
star.dy += star.ddy;
}
function updateStars(ctx, stars) {
for (var i=0; i<stars.length; i++) {
move(stars[i]);
if (stars[i].x < -this.originX || stars[i].x > this.originX || stars[i].y < -this.originY || stars[i].y > this.originY) {
// Remove
stars[i] = newStar();
} else {
// Paint
var deltaX = this.originX;
var deltaY = this.originY;
stars[i].drawInContext(ctx, deltaX, deltaY);
}
}
}
this.configureGeometry = function() {
// Ensure we are always at full width
this.canvas.width = window.innerWidth;
this.canvas.style.backgroundColor = bgColor;
var ratio = 1;
// Retina support
// See http://www.html5rocks.com/en/tutorials/canvas/hidpi/
if (this.scaleFactor > 1) {
var devicePixelRatio = this.scaleFactor;
var context = this.ctx;
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
ratio = devicePixelRatio / backingStoreRatio;
// Upscale the canvas if the two ratios don't match
if (devicePixelRatio !== backingStoreRatio) {
var canvas = this.canvas;
var oldWidth = canvas.width;
var oldHeight = canvas.height;
canvas.width = oldWidth * ratio;
canvas.height = oldHeight * ratio;
canvas.style.width = oldWidth + 'px';
canvas.style.height = oldHeight + 'px';
// Now scale the context to counter the fact that we've manually scaled our canvas element
context.scale(ratio, ratio);
}
}
// Starting origin of stars
var logicalWidth = this.canvas.width / ratio;
var logicalHeight = this.canvas.height / ratio;
this.originX = logicalWidth / 2;
this.originY = logicalHeight / 2;
var numStars = logicalWidth / 2;
this.numStars = numStars > maxStars ? maxStars : numStars;
}
this.render = function() {
setTimeout(function() {
// Drawing
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
updateStars(this.ctx, this.stars);
requestAnimationFrame(render);
}, 1000 / FPS);
};
// Configure origin and frames before creating initial batch of stars
this.configureGeometry();
for (var i=0; i<this.numStars; i++) {
this.stars.push(newStar());
}
return this;
}
var starfield = StarField(element);
if (starfield.isCanvasEnabled) {
starfield.render();
}
// Make sure we adjust the canvas whenever the window resizes
// Don't rely on CSS rules for 100% width because that causes rendering issues
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
if (starfield.isCanvasEnabled) {
starfield.configureGeometry();
} else {
starfield.canvas.width = window.innerWidth;
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="starfield" width="100%" height="400px"></canvas>

how to fill particles inside rectangle?

I'm looking to draw a rectangle basically text but just for clearing insight I'm working it with rectangle with small particles inside rectangle the basic I idea I got from https://yalantis.com/ but in my attempt I'm stuck here with solid filled rectangle with a color I have specified for particles. Please help me.. :)
Thanks here is my code:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Off Screen Canvas</title>
<script>
function createOffscreenCanvas() {
var offScreenCanvas = document.createElement('canvas');
offScreenCanvas.width = '1360';
offScreenCanvas.height = '400';
var context = offScreenCanvas.getContext("2d");
var W=200;
var H=200;
particleCount = 200;
particles = []; //this is an array which will hold our particles Object/Class
function Particle() {
this.x = Math.random() * W;
this.y = Math.random() * H;
this.direction ={"x": -1 + Math.random()*2, "y": -1 + Math.random()*2};
this.vx = 2 * Math.random() + 4 ;
this.vy = 2 * Math.random() + 4;
this.radius = .9 * Math.random() + 1;
this.move = function(){
this.x += this.vx * this.direction.x;
this.y += this.vy * this.direction.y;
};
this.changeDirection = function(axis){
this.direction[axis] *= -1;
};
this.draw = function() {
context.beginPath();
context.fillStyle = "#0097a7";
context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
context.fill();
};
this.boundaryCheck = function(){
if(this.x >= W){
this.x = W;
this.changeDirection("x");
}
else if(this.x <= 0){
this.x = 0;
this.changeDirection("x");
}
if(this.y >= H){
this.y = H;
this.changeDirection("y");
}
else if(this.y <= 0){
this.y = 0;
this.changeDirection("y");
}
};
}
function createParticles(){
for (var i = particleCount-1; i >= 0; i--) {
p = new Particle();
particles.push(p);
}
}// end createParticles
function drawParticles(){
for (var i = particleCount-1; i >= 0; i--){
p = particles[i];
p.draw();
}
} //end drawParticles
function updateParticles(){
for(var i = particles.length - 1; i >=0; i--){
p = particles[i];
p.move();
p.boundaryCheck();
}
}//end updateParticle
createParticles();
var part=drawParticles();
context.fillStyle=part;
context.fillRect(W-190, H-190, W, H);
context.fill();
return offScreenCanvas;
}
function copyToOnScreen(offScreenCanvas) {
var onScreenContext=document.getElementById('onScreen').getContext('2d');
var offScreenContext = offScreenCanvas.getContext('2d');
var image=offScreenContext.getImageData(10,10,200,200);
onScreenContext.putImageData(image,offScreenCanvas.width/2,offScreenCanvas.height/4);
}
function main() {
copyToOnScreen(createOffscreenCanvas());
}
</script>
<style>
canvas {
border: 1px solid red;
}
</style>
</head>
<body onload="main()">
<canvas id="onScreen" width="1360" height="400"></canvas>
</body>
</html>
I see you have not found what you are looking for yet. Below is something quick to get you on your way. There is a whole range of stuff being used from canvas,mouse,particles, etc most of which is without comments. There is no load balancing or compliance testing and because it uses babel to be compatible with IE11 I have no clue how it runs on those browsers.
I will add to this answer some other time but for now I am a little over it.
const textList = ["1","2","3","Testing","text","to","particles"];
var textPos = 0;
function createParticles(text){
createTextMap(
text, // text to display
40, // font size
"Arial", // font
{ // style fot rendering font
fillStyle : "#6AF",
strokeStyle : "#F80",
lineWidth : 2,
lineJoin : "round",
},{ // bounding box to find a best fit for
top : 0,
left : 0,
width : canvas.width,
height : canvas.height,
}
)
}
// This function starts the animations
var started = false;
function startIt(){
started = true;
const next = ()=>{
var text = textList[(textPos++ ) % textList.length];
particles.mouseFX.dist = canvas.height / 8;
createParticles(text);
setTimeout(moveOut,text.length * 100 + 3000);
}
const moveOut = ()=>{
particles.moveOut();
setTimeout(next,2000);
}
setTimeout(next,0);
}
function setStyle(ctx,style){
Object.keys(style).forEach(key => ctx[key] = style[key]);
}
// the following function create the particles from text using a canvas
// the canvas used is dsplayed on the main canvas top left fro referance.
var tCan = createImage(100, 100); // canvas used to draw text
function createTextMap(text,size,font,style,fit){
// function to conver to colour hex value
const hex = (v)=> (v < 16 ? "0" : "") + v.toString(16);
// set up font so we can find the size.
tCan.ctx.font = size + "px " + font;
// get size of text
var width = Math.ceil(tCan.ctx.measureText(text).width + size);
// resize the canvas to fit the text
tCan.width = width;
tCan.height = Math.ceil(size *1.2);
// c is alias for context
var c = tCan.ctx;
// set up font
c.font = size + "px " + font;
c.textAlign = "center";
c.textBaseline = "middle";
// set style
setStyle(c,style);
// only do stroke and fill if they are set in styles object
if(style.strokeStyle){
c.strokeText(text, width / 2, tCan.height / 2);
}
if(style.fillStyle){
c.fillText(text, width / 2, tCan.height/ 2);
}
// prep the particles
particles.empty();
// get the pixel data
var data = c.getImageData(0,0,width,tCan.height).data;
var x,y,ind,rgb,a;
// find pixels with alpha > 128
for(y = 0; y < tCan.height; y += 1){
for(x = 0; x < width; x += 1){
ind = (y * width + x) << 2; // << 2 is equiv to * 4
if(data[ind + 3] > 128){ // is alpha above half
rgb = `#${hex(data[ind ++])}${hex(data[ind ++])}${hex(data[ind ++])}`;
// add the particle
particles.add(Vec(x, y), Vec(x, y), rgb);
}
}
}
// scale the particles to fit bounding box
var scale = Math.min(fit.width / width, fit.height / tCan.height);
particles.each(p=>{
p.home.x = ((fit.left + fit.width) / 2) + (p.home.x - (width / 2)) * scale;
p.home.y = ((fit.top + fit.height) / 2) + (p.home.y - (tCan.height / 2)) * scale;
})
.findCenter() // get center used to move particles on and off of screen
.moveOffscreen() // moves particles off the screen
.moveIn(); // set the particles to move into view.
}
// vector object a quick copy from other code.
function Vec(x,y){ // because I dont like typing in new
return new _Vec(x,y);
}
function _Vec(x = 0,y = 0){
this.x = x;
this.y = y;
return this;
}
_Vec.prototype = {
setAs(vec){
this.x = vec.x;
this.y = vec.y;
},
toString(){
return `vec : { x : ${this.x}, y : ${this.y} );`
}
}
// basic particle
const particle = {
pos : null,
delta : null,
home : null,
col : "black",
}
// array of particles
const particles = {
items : [], // actual array of particles
mouseFX : { // mouse FX
power : 20,
dist : 100,
curve : 3, // polynomial power
on : true,
},
fx : {
speed : 0.4,
drag : 0.15,
size : 4,
jiggle : 8,
},
// direction 1 move in -1 move out
direction : 1,
moveOut(){this.direction = -1; return this},
moveIn(){this.direction = 1; return this},
length : 0, // Dont touch this from outside particles.
each(callback){ // custom iteration
for(var i = 0; i < this.length; i++){
callback(this.items[i],i);
}
return this;
},
empty(){ // empty but dont dereference
this.length = 0;
return this;
},
deRef(){ // call to clear memory
this.items.length = 0;
this.length = 0;
},
add(pos,home,col){ // adds a particle
var p;
if(this.length < this.items.length){
p = this.items[this.length++];
// p.pos.setAs(pos);
p.home.setAs(home);
p.delta.x = 0;
p.delta.y = 0;
p.col = col;
}else{
this.items.push(
Object.assign(
{},
particle,
{
pos,
home,
col,
delta : Vec()
}
)
);
this.length = this.items.length
}
return this;
},
draw(){ // draws all
var p, size, sizeh;
sizeh = (size = this.fx.size) / 2;
for(var i = 0; i < this.length; i++){
p = this.items[i];
ctx.fillStyle = p.col;
ctx.fillRect(p.pos.x - sizeh, p.pos.y - sizeh, size, size);
}
},
update(){ // update all particles
var p,x,y,d;
var mP = this.mouseFX.power;
var mD = this.mouseFX.dist;
var mC = this.mouseFX.curve;
var fxJ = this.fx.jiggle;
var fxD = this.fx.drag;
var fxS = this.fx.speed;
for(var i = 0; i < this.length; i++){
p = this.items[i];
p.delta.x += (p.home.x - p.pos.x ) * fxS + (Math.random() - 0.5) * fxJ;
p.delta.y += (p.home.y - p.pos.y ) * fxS + (Math.random() - 0.5) * fxJ;
p.delta.x *= fxD;
p.delta.y *= fxD;
p.pos.x += p.delta.x * this.direction;
p.pos.y += p.delta.y * this.direction;
if(this.mouseFX.on){
x = p.pos.x - mouse.x;
y = p.pos.y - mouse.y;
d = Math.sqrt(x * x + y * y);
if(d < mD){
x /= d;
y /= d;
d /= mD;
d = (1-Math.pow(d,mC)) * mP;
p.pos.x += x * d;
p.pos.y += y * d;
}
}
}
return this;
},
findCenter(){ // find the center of particles maybe could do without
var x,y;
y = x = 0;
this.each(p => {
x += p.home.x;
y += p.home.y;
});
this.center = Vec(x / this.length, y / this.length);
return this;
},
moveOffscreen(){ // move start pos offscreen
var dist,x,y;
dist = Math.sqrt(this.center.x * this.center.x + this.center.y * this.center.y);
this.each(p => {
var d;
x = p.home.x - this.center.x;
y = p.home.y - this.center.y;
d = Math.max(0.0001,Math.sqrt(x * x + y * y)); // max to make sure no zeros
p.pos.x = p.home.x + (x / d) * dist;
p.pos.y = p.home.y + (y / d) * dist;
});
return this;
},
}
function onResize(){ // called from boilerplate
if(!started){
startIt();
}
}
/** SimpleFullCanvasMouse.js begin **/
// the following globals are available
// w, h, cw, ch, width height centerWidth centerHeight of canvas
// canvas, ctx, mouse, globalTime
//MAIN animation loop
function display() { // call once per frame
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.clearRect(0, 0, w, h);
if(tCan){
// ctx.drawImage(tCan,0,0);
}
particles.update();
particles.draw();
}
/******************************************************************************
The code from here down is generic full page mouse and canvas boiler plate
code. As I do many examples which all require the same mouse and canvas
functionality I have created this code to keep a consistent interface. The
Code may or may not be part of the answer.
This code may or may not have ES6 only sections so will require a transpiler
such as babel.js to run on legacy browsers.
*****************************************************************************/
// V2.0 ES6 version for Stackoverflow and Groover QuickRun
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0;
// You can declare onResize (Note the capital R) as a callback that is also
// called once at start up. Warning on first call canvas may not be at full
// size.
;(function(){
const RESIZE_DEBOUNCE_TIME = 100;
var resizeTimeoutHandle;
var firstRun = true;
function createCanvas () {
var c,cs;
cs = (c = document.createElement("canvas")).style;
cs.position = "absolute";
cs.top = cs.left = "0px";
cs.zIndex = 1000;
document.body.appendChild(c);
return c;
}
function resizeCanvas () {
if (canvas === undefined) { canvas = createCanvas() }
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals() }
if (typeof onResize === "function") {
clearTimeout(resizeTimeoutHandle);
if (firstRun) { onResize() }
else { resizeTimeoutHandle = setTimeout(onResize, RESIZE_DEBOUNCE_TIME) }
firstRun = false;
}
}
function setGlobals () {
cw = (w = canvas.width) / 2;
ch = (h = canvas.height) / 2;
}
mouse = (function () {
function preventDefault(e) { e.preventDefault() }
var m; // alias for mouse
var mouse = {
x : 0, y : 0, w : 0, // mouse position and wheel
alt : false, shift : false, ctrl : false, // mouse modifiers
buttonRaw : 0,
over : false, // true if mouse over the element
buttonOnMasks : [0b1, 0b10, 0b100], // mouse button on masks
buttonOffMasks : [0b110, 0b101, 0b011], // mouse button off masks
active : false,
bounds : null,
eventNames : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(","),
event(e) {
var t = e.type;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left - scrollX;
m.y = e.pageY - m.bounds.top - scrollY;
m.alt = e.altKey;
m.shift = e.shiftKey;
m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.buttonOnMasks[e.which - 1] }
else if (t === "mouseup") { m.buttonRaw &= m.buttonOffMasks[e.which - 1] }
else if (t === "mouseout") { m.over = false }
else if (t === "mouseover") { m.over = true }
else if (t === "mousewheel") {m.w = e.wheelDelta }
else if (t === "DOMMouseScroll") { m.w = -e.detail }
if (m.callbacks) { m.callbacks.forEach(c => c(e)) }
if ((m.buttonRaw & 2) && m.crashRecover !== null) {
if (typeof m.crashRecover === "function") { setTimeout(m.crashRecover, 0) }
}
e.preventDefault();
},
addCallback(callback) {
if (typeof callback === "function") {
if (m.callbacks === undefined) { m.callbacks = [callback] }
else { m.callbacks.push(callback) }
}
},
start(element) {
if (m.element !== undefined) { m.remove() }
m.element = element === undefined ? document : element;
m.eventNames.forEach(name => document.addEventListener(name, mouse.event) );
document.addEventListener("contextmenu", preventDefault, false);
m.active = true;
},
remove() {
if (m.element !== undefined) {
m.eventNames.forEach(name => document.removeEventListener(name, mouse.event) );
document.removeEventListener("contextmenu", preventDefault);
m.element = m.callbacks = undefined;
m.active = false;
}
}
}
m = mouse;
return mouse;
})();
function done() { // Clean up. Used where the IDE is on the same page.
window.removeEventListener("resize", resizeCanvas)
mouse.remove();
document.body.removeChild(canvas);
canvas = ctx = mouse = undefined;
}
function update(timer) { // Main update loop
if(ctx === undefined){ return }
globalTime = timer;
display(); // call demo code
requestAnimationFrame(update);
}
setTimeout(function(){
canvas = createCanvas();
mouse.start(canvas, true);
resizeCanvas();
if(typeof Groover !== "undefined" && Groover.ide){ mouse.crashRecover = done }; // Requires Ace.js and GrooverDev.js. Prevents
window.addEventListener("resize", resizeCanvas);
requestAnimationFrame(update);
},0);
})();
/** SimpleFullCanvasMouse.js end **/
/** CreateImage.js begin **/
// creates a blank image with 2d context
function createImage(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
/** CreateImage.js end **/
canvas {
background : black;
}
well after all the attempts like hell I finally got my answer thanks to moƔois answer to my post using particle slider. here is the code. Thanks everyone for your help :)

How to add fade onclick event to specific particle (data object) within canvas system?

I want to click on one of the floating particles, upon clicking it, I want the particle colour to change from light grey to blue and then fade. Particle quantity is set as 100, as particles are clicked on to fade away particle quantity decreases. I'm unfamiliar with js, just started learning about canvas and particle systems yesterday, this is code from a pen that I've changed a bit and would like to add more changes to by adding the fade onclick event. I know that the particles within canvas are under one variable that defines them altogether, I don't know how to isolate one particle in the canvas to work with as I would need to know it's exact x,y coordinates.
Would I then have to find the coordinates for all 100 particles and add elements to each individual particle- and how do I do this?
$(document).ready(function() {
var PARTICLE_QUANT = 100;
var FPS = 60;
var BOUNCE = -1;
var PARTICLE_COLOR = '#ced4d4';
var ARC_RADIUS = 12;
var Particles = function($element) {
if ($element.length === 0) {
return;
}
this.$element = $element;
this.lastTimeStamp = null;
this.particles = [];
this.init();
};
var proto = Particles.prototype;
proto.init = function() {
this.createChildren()
.layout()
.enable();
};
proto.createChildren = function() {
this.canvas = this.$element[0];
this.context = this.canvas.getContext('2d');
this.canvasWidth = this.canvas.width;
this.canvasHeight = this.canvas.height;
this.lastTimeStamp = new Date().getTime();
return this;
};
proto.layout = function() {
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
})();
return this;
};
proto.removeChildren = function() {
this.context = null;
this.canvasWidth = null;
this.canvasHeight = null;
this.lastTimeStamp = null;
return this;
};
proto.enable = function() {
this.createParticleData();
this.renderLoop();
};
proto.createParticleData = function() {
var i = 0;
var l = PARTICLE_QUANT;
for (; i < l; i++) {
this.particles[i] = {};
this.setParticleData(this.particles[i]);
}
};
proto.setParticleData = function(particle) {
particle.x = Math.random() * this.canvasWidth;
particle.y = Math.random() * this.canvasHeight;
particle.vx = (Math.random()) - 0.5;
particle.vy = (Math.random()) - 0.5;
};
proto.update = function() {
var i = 0;
var l = PARTICLE_QUANT;
for (; i < l; i++) {
var particle = this.particles[i];
particle.x += particle.vx;
particle.y += particle.vy;
if (particle.x > this.canvasWidth) {
particle.x = this.canvasWidth;
particle.vx *= BOUNCE;
} else if (particle.x < 0) {
particle.x = 0;
particle.vx *= BOUNCE;
}
if (particle.y > this.canvasHeight) {
particle.y = this.canvasHeight;
particle.vy *= BOUNCE;
} else if (particle.y < 0) {
particle.y = 0;
particle.vy *= BOUNCE;
}
}
};
proto.draw = function() {
var i = 0;
if (!this.context) {
return;
}
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.context.fillStyle = PARTICLE_COLOR;
for (; i < PARTICLE_QUANT; i++) {
var particle = this.particles[i];
this.context.save();
this.context.beginPath();
this.context.arc(particle.x, particle.y, ARC_RADIUS, 0, Math.PI * 2);
this.context.fill();
this.context.restore();
}
};
proto.renderLoop = function() {
requestAnimationFrame(this.renderLoop.bind(this));
this.update();
this.draw();
};
var particles = new Particles($('#js-particles'));
//Everything above works, it is what comes next (below), is this the right approach?
var elem = document.getElementById('js-particles'),
elemLeft = elem.offsetLeft,
elemTop = elem.offsetTop,
context = elem.getContext('2d'),
elements = [];
// Add event listener for `click` events.
elem.addEventListener('click', function(event) {
var x = event.pageX - elemLeft,
y = event.pageY - elemTop;
// Collision detection between clicked offset and element.
elements.forEach(function(element) {
if (y > element.top && y < element.top + element.height && x > element.left && x < element.left + element.width)
});
}, false);
// Add element.
elements.push({
colour: '#05EFFF',
width: 150,
height: 100,
top: 20,
left: 15
});
// Render elements.
elements.forEach(function(element) {
context.fillStyle = element.colour;
context.fillRect(element.left, element.top, element.width, element.height);
});
<canvas id="js-particles" class="particles" width="960" height="960">
<p>text appears if browser doesn 't support canvas</p>
</canvas>

Categories

Resources