I'm using this code to draw something like waiting progress on page:
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Preloaders</title>
<link rel="stylesheet" href="css/index.css" />
<link rel="stylesheet" href="css/preloaders.css" />
<script src="js/lib/requestAnimFrame.js"></script>
<script src="js/lib/timer.js"></script>
<script src="js/lib/preloaders.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div id="preloader1"></div>
</body>
</html>
index.css:
html, body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
preloader.css:
#preloader1 {
display: block;
width: 100%;
height: 15px;
margin: 0;
padding: 0;
}
requestAnimFrame.js:
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
timer.js:
var Timer = function(){
"use strict";
var prev = new Date().getTime();
var speed = 1;
this.start = function(){
prev = new Date().getTime();
}
this.setSpeed = function ( s ) {
speed = s;
}
this.getDelta = function( inSeconds ){
var now = new Date().getTime();
var delta = (now - prev) * speed;
if (inSeconds) delta /= 1000;
prev = now;
return delta;
}
}
preloaders.js:
var PRELOADERS = {
waiting1: function ( el ) {
"use strict";
var width = el.offsetWidth;
var height = el.offsetHeight;
var speed = 1;
var v = [0, 0, 0, 0]; // values
var e = [0, -0.5, -1, -1.5]; // elapsed
var canvas = document.createElement( "canvas" )
canvas.style.display = "block";
canvas.width = width;
canvas.height = height;
el.appendChild( canvas );
var ctx = canvas.getContext('2d');
var c = [ // colours
[255,60,60], // red
[255,200,60], // yellow
[80,220,40], // green
[40,120,220] // blue
]
var o = [0,1,2,3]; // order
var drawRect = function ( w /* width: 0..1 */, c /* colour: [r,g,b | a] */ ) {
if (c.length == 4) ctx.fillStyle = "rgba("+c[0]+","+c[1]+","+c[2]+","+c[3]+")";
else ctx.fillStyle = "rgb("+c[0]+","+c[1]+","+c[2]+")";
var hw = width / 2; // half-width
ctx.fillRect( hw-hw*w, 0, width*w, height );
}
var easing = function ( val ) {
return -val*(val -2)
}
var next = function ( ) {
var ot = o.slice(0);
o = [ot[1], ot[2], ot[3], ot[0]];
}
this.update = function ( delta ) {
for (var i = 0; i < 4; i++) {
e[i] += delta * speed;
if (e[i] > 2) {
e[i] = 0;
next();
}
v[i] = easing( Math.min(1, Math.max(0, e[i])) );
drawRect( v[o[i]], c[o[i]] );
}
}
this.setSpeed = function ( s ) {
speed = s;
}
}
}
app.js:
var init = function( ){
"use strict";
var timer = new Timer();
var preloader1 = new PRELOADERS.waiting1( document.getElementById( "preloader1" ) );
// preloader1.setSpeed(0.1);
var animate = function( ) {
render( );
requestAnimFrame( animate );
}
var render = function( ){
var delta = timer.getDelta( true );
preloader1.update( delta );
}
animate();
}
window.onload = init;
But sometimes rectangles on canvas are blinking.
Help me to catch this bug please.
The problem was in update function.
drawRect shoud be called in separate loop after all calculations:
this.update = function ( delta ) {
for (var i = 0; i < 4; i++) {
e[i] += delta * speed;
if (e[i] > 2) {
e[i] = 0;
next();
}
v[i] = easing( Math.min(1, Math.max(0, e[i])) );
}
for (i = 0; i < 4; i++) {
drawRect( v[o[i]], c[o[i]] );
}
}
Related
I am creating an ecosystem with my code consisting of plants, herbivores, and carnivores being represented through circles. For some reason, my code has been crashing after a certain amount of time ranging from 30 seconds to 8 minutes but no more than that.
After doing some digging I have found out that the crash is a result of my object's .rad property becoming undefined for some reason. It's probably a result of me improperly setting up my functions but I haven't been able to find a solution.
var plantSpawn = 5;
var herbSpawn = 3;
var carnSpawn = 2;
var myPlants = new Array();
var myCarns = new Array();
var myHerbs = new Array();
//////////////PLANTS//////////////////
function createPlants() {
reproducePlants();
setInterval(reproducePlants, 5000);
}
function reproducePlants() {
for(var p=0; p<plantSpawn; p++){
var rr = Math.round(Math.random() * 150);
var gg = Math.round(Math.random() * 255);
var bb = Math.round(Math.random() * 150);
var plant = new Object();
plant.x = Math.random() * canvas.width;
plant.y = Math.random() * canvas.height;
plant.rad = 2 + Math.random()*2;
plant.skin = 'rgba('+rr+','+gg+','+bb+', 1)';
myPlants.push(plant);
}
}
function drawPlants(){
var plantAmt = myPlants.length;
for(var j=0; j<plantAmt; j++) {
if (myPlants[j].x + myPlants[j].rad >= canvas.width) {
myPlants[j].x -= 10;
}
if (myPlants[j].y + myPlants[j].rad >= canvas.height) {
myPlants[j].y -= 10;
}
context.beginPath();
context.arc(myPlants[j].x, myPlants[j].y, myPlants[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myPlants[j].skin;
context.fill();
}
}
function killPlants() {
plantDeath();
setInterval(plantDeath, 30000); //play with inc
}
function plantDeath() {
myPlants.splice(0,5);
}
//////////////HERBS//////////////////
function herbsLife(){
reproduceHerbs();
setInterval(reproduceHerbs, 10000);
herbsDeath();
setInterval(herbsDeath, 90000); //1.5 minutes
setInterval(herbsStarve, 10000); //10 seconds
}
function reproduceHerbs() {
for (var h=0; h<herbSpawn; h++){
var gg = Math.round(Math.random() * 100);
var bb = Math.round(Math.random() * 255);
var herbivore = new Object();
herbivore.x = Math.random() * canvas.width;
herbivore.y = Math.random() * canvas.height;
herbivore.rad = 5 + Math.random()*3;
herbivore.skin = 'rgba(0,'+gg+','+bb+', 1)';
herbivore.speedH = -3 + Math.random()*1.2;
herbivore.speedV = -3 + Math.random()*1.2;
herbivore.dirH = 1;
herbivore.dirV = 1;
myHerbs.push(herbivore);
}
}
function drawHerbs() {
var herbAmt = myHerbs.length;
for(var j=0; j<herbAmt; j++) {
var hX = myHerbs[j].x;
var hY = myHerbs[j].y;
//HERB MOVEMENT//
myHerbs[j].x += myHerbs[j].dirH * myHerbs[j].speedH;
if (myHerbs[j].x > canvas.width + myHerbs[j].rad || myHerbs[j].x < 0){
myHerbs[j].dirH *= -1;
}
myHerbs[j].y += myHerbs[j].dirV * myHerbs[j].speedV;
if (myHerbs[j].y > canvas.height + myHerbs[j].rad || myHerbs[j].y < 0){
myHerbs[j].dirV *= -1;
}
context.beginPath();
context.arc(myHerbs[j].x, myHerbs[j].y, myHerbs[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myHerbs[j].skin;
context.fill();
}
}
function herbsDeath() {
myHerbs.splice(0,3);
}
function herbsEat() {
for (var k=0; k<myPlants.length; k++){
var pX = myPlants[k].x;
var pY = myPlants[k].y;
for (var h=0; h<myHerbs.length; h++){
var hX = myHerbs[h].x;
var hY = myHerbs[h].y;
var eX = hX - pX;
var eY = hY - pY;
var dist = Math.sqrt(Math.pow(eX,2) + Math.pow(eY,2));
if (dist < myPlants[k].rad*2) {
myPlants.splice(k,1);
myHerbs[h].rad += 1;
}
}
}
}
function herbsStarve() {
for (var s=0; s<myPlants.length; s++){
myHerbs[s].rad -= 1;
if (myHerbs[s].rad <= 2) {
myHerbs.splice(s,1);
}
}
}
//////////////CARNS//////////////////
function carnsLife() {
reproduceCarns();
setInterval(reproduceCarns, 20000); //20 seconds
carnsDeath();
setInterval(carnsDeath, 60000); //50 seconds
setInterval(carnsStarve, 7500); //10 seconds
}
function reproduceCarns() {
for (var c=0; c<carnSpawn; c++){
var rr = Math.round(Math.random() * 255);
var gg = Math.round(Math.random() * 100);
var carnivore = new Object();
carnivore.x = Math.random() * canvas.width;
carnivore.y = Math.random() * canvas.height;
carnivore.rad = 7 + Math.random()*3;
carnivore.skin = 'rgba('+rr+','+gg+',0, 1)';
//bigger random = slower//
carnivore.speedH = -3 + Math.random()*2;
carnivore.speedV = -3 + Math.random()*2;
carnivore.dirH = 1;
carnivore.dirV = 1;
myCarns.push(carnivore);
}
}
function drawCarns() {
var carnAmt = myCarns.length;
for(var j=0; j<carnAmt; j++) {
//CARN MOVEMENT//
myCarns[j].x += myCarns[j].dirH * myCarns[j].speedH;
if (myCarns[j].x > canvas.width + myCarns[j].rad || myCarns[j].x < 0){
myCarns[j].dirH *= -1;
}
myCarns[j].y += myCarns[j].dirV * myCarns[j].speedV;
if (myCarns[j].y > canvas.height + myCarns[j].rad || myCarns[j].y < 0){
myCarns[j].dirV *= -1;
}
context.beginPath();
context.arc(myCarns[j].x, myCarns[j].y, myCarns[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myCarns[j].skin;
context.fill();
}
}
function carnsDeath() {
myCarns.splice(0,2);
}
function carnsEat() {
for (var k=0; k<myCarns.length; k++){
var cX = myCarns[k].x;
var cY = myCarns[k].y;
for (var h=0; h<myHerbs.length; h++){
var hX = myHerbs[h].x;
var hY = myHerbs[h].y;
var eX = cX - hX;
var eY = cY - hY;
var dist = Math.sqrt(Math.pow(eX,2) + Math.pow(eY,2));
if (dist < myCarns[k].rad*1.2 && myCarns[k].rad > myHerbs[h].rad) {
myHerbs.splice(h,1);
myCarns[k].rad += 1;
}
}
}
}
function carnsStarve() {
for (var q=0; q<myPlants.length; q++){
myCarns[q].rad = myCarns[q].rad - 1;
if (myCarns[q].rad <= 5) {
myCarns.splice(q,1);
}
}
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title> Ecosystem </title>
<!-- import external .js scripts here -->
<script type="text/javascript" src="Creatures.js" ></script>
<!-- modify CSS properties here -->
<style type="text/css">
body,td,th {
font-family: Monaco, "Courier New", "monospace";
font-size: 14px;
color: rgba(255,255,255,1);
}
body {
background-color: rgba(0,0,0,1);
}
#container {
position: relative;
text-align: left;
width: 95%;
height: 800px;
}
#fmxCanvas {
position: relative;
background-color:rgba(255,255,255,1);
border: rgba(255,255,255,1) thin dashed;
cursor: crosshair;
display: inline-block;
}
</style>
</head>
<body>
<div id="container">
<!-- START HTML CODE HERE -->
<canvas id="fmxCanvas" width="800" height="800"></canvas>
<div id="display"></div>
<!-- FINISH HTML CODE HERE -->
</div>
<script>
///////////////////////////////////////////////////////////////////////
// DECLARE requestAnimFrame
var rAF = window.requestAnimFrame ||
window.mozRequestAnimFrame ||
window.webkitRequestAnimFrame ||
window.msRequestAnimFrame;
var fps = 30;
window.requestAnimFrame = (
function(callback) {
return rAF ||
function(callback) {
window.setTimeout(callback, 1000 / fps);
};
})();
///////////////////////////////////////////////////////////////////////
// DEFINE GLOBAL VARIABLES HERE
var canvas;
var context;
canvas = document.getElementById("fmxCanvas");
context = canvas.getContext("2d");
var canvas1;
var context1;
canvas1 = document.createElement("canvas");
context1 = canvas1.getContext("2d");
canvas1.width = canvas.width;
canvas1.height = canvas.height;
var display;
display = document.getElementById('display');
var counter;
///////////////////////////////////////////////////////////////////////
// DEFINE YOUR GLOBAL VARIABLES HERE
///////////////////////////////////////////////////////////////////////
// CALL THE EVENT LISTENERS
window.addEventListener("load", setup, false);
//////////////////////////////////////////////////////////////////////
// ADD EVENT LISTENERS
canvas.addEventListener("mousemove", mousePos, false);
//////////////////////////////////////////////////////////////////////
// MOUSE COORDINATES
var stage, mouseX, mouseY;
function mousePos(event) {
stage = canvas.getBoundingClientRect();
mouseX = event.clientX - stage.left;
mouseY = event.clientY - stage.top;
}
/////////////////////////////////////////////////////////////////////
// INITIALIZE THE STARTING FUNCTION
function setup() {
/////////////////////////////////////////////////////////////////////
// DECLARE STARTING VALUES OF GLOBAL VARIABLES
counter = 0;
mouseX = canvas.width/2;
mouseY = canvas.height/2;
/////////////////////////////////////////////////////////////////////
// CALL SUBSEQUENT FUNCTIONS, as many as you need
createPlants();
killPlants();
herbsLife();
carnsLife();
clear(); // COVER TRANSPARENT CANVAS OR CLEAR CANVAS
draw(); // THIS IS WHERE EVERYTHING HAPPENS
}
////////////////////////////////////////////////////////////////////
// CLEAR THE CANVAS FOR ANIMATION
// USE THIS AREA TO MODIFY BKGD
function clear() {
context.clearRect(0,0,canvas.width, canvas.height);
context1.clearRect(0,0,canvas.width, canvas.height);
// clear additional contexts here if you have more than canvas1
}
////////////////////////////////////////////////////////////////////
// THIS IS WHERE EVERYTHING HAPPENS
function draw() {
counter += 0.1; // EASIER FOR SINE COSINE FUNCTIONS
//if (counter > Math.PI*200) { counter = 0; } // RESET COUNTER
clear(); // USE THIS TO REFRESH THE FRAME AND CLEAR CANVAS
////////////////////////////////////////////////////////////////////
// >>>START HERE>>>START HERE>>>START HERE>>>START HERE>>>START HERE
drawPlants();
drawHerbs();
drawCarns();
herbsEat();
carnsEat();
// <<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// HTML DISPLAY FIELD FOR TESTING PURPOSES
display.innerHTML =
// mouseX + " || " + mouseY +
" || Minutes = " + Math.trunc(counter/180) +
" || Seconds = " + Math.round(counter/3) +
"<br><br>" +
"Plants = " + myPlants.length +
"<br>" +
"Herbivores = " + myHerbs.length +
"<br>" +
"Carnivores = " + myCarns.length;
/////////////////////////////////////////////////////////////////
// LAST LINE CREATES THE ANIMATION
requestAnimFrame(draw); // CALLS draw() every nth of a second
}
</script>
</body>
</html>
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>
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>
I'm studying javascript.
I don't know how input from First source can be used as input to Second Source of TextBox?
How should I go about it?
############### First Source ##################
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
#container canvas{
position: absolute;
}
#land{
background-color: #ececec;
}
#temp{
display: none;
}
</style>
</head>
<body>
<div id="container">
<canvas id="land" width="800" height="600"></canvas>
<canvas id="sky" width="800" height="600"></canvas>
<canvas id="temp" width="800" height="600"></canvas>
</div>
<script src="lib/jquery.js"></script>
<script src="src/vec.js"></script>
<script src="src/vecoper.js"></script>
<script>
var land = document.getElementById( 'land' );
var landc = land.getContext( '2d' );
var sky = document.getElementById( 'sky' );
var skyc = sky.getContext( '2d' );
var temp = document.getElementById( 'temp' );
var tempc = temp.getContext( '2d' );
var PI2 = 2*Math.PI;
var Land = {
init:function(){
this.vtx = 20;
this.tempColor = 'blue'
this.pixelmap = [];
var x = 0;
var y = land.height / 1.1;
var l = land.width / this.vtx;
var d;
var h;
landc.save();
landc.fillStyle = '#cccccc';
landc.beginPath();
landc.moveTo( x, y );
for( var i=0, count=this.vtx ; i<count ; i+=1 ){
x+=l;
h = Math.random() * 20;
d = Math.round( Math.random() );
if( d){ y-=h; }
else{ y+=h; }
landc.lineTo( x, y );
}
landc.lineTo( x, land.height );
landc.lineTo( 0, land.height );
landc.closePath();
landc.fill();
landc.restore();
this.updatePixelmap();
},
updatePixelmap:function(){
tempc.drawImage( land, 0, 0 );
this.pixelmap = tempc.getImageData( 0,0, temp.width, temp.height ).data;
},
isCollision:function( bomb ){
temp.width = temp.width;
var x = bomb.ltx;
var y = bomb.lty;
var targetPixelData = landc.getImageData( x, y, bomb.size*2, bomb.size*2).data;
for( var i= 0, count=bomb.pixelmap.length ; i<count ; i+=4 ){
a = bomb.pixelmap[ i+3 ];
if( a != 0 && targetPixelData[ i+3 ] != 0 && targetPixelData[ i ] != 0 || targetPixelData[ i+1 ] != 0 || targetPixelData[ i+2 ] != 0 ){
return true;
}
}
return false;
},
destroy:function( bomb ){
landc.save();
landc.globalCompositeOperation = "destination-out";
landc.beginPath();
landc.arc( bomb.x, bomb.y, bomb.power, 0, Math.PI*2, false );
landc.fill();
landc.restore();
}
};
var Bomb = function(){
this.init();
};
Bomb.prototype = {
init:function(){
this.x = Math.random() * sky.width;
this.y = Math.random() * -200;
this.speed = Math.random() + 5;
this.size = ( Math.random() * 10 ) + 5;
this.power = this.size*3;
this.pixelmap = [];
this.color = '#cccccc';
this.tempColor = 'red';
this.updatePixelmap();
},
updatePixelmap:function(){
this.pixelmap = [];
var size = this.size;
var size2 = this.size*2;
temp.width = temp.width;
tempc.save();
tempc.fillStyle = this.tempColor;
tempc.beginPath();
tempc.arc( size, size, size, 0, PI2, false );
tempc.fill();
tempc.restore();
this.pixelmap = tempc.getImageData(0,0, size2, size2).data;
},
update:function(){
this.y += this.speed;
this.ltx = this.x-this.size;
this.lty = this.y-this.size;
skyc.save();
skyc.fillStyle = this.color;
skyc.beginPath();
skyc.arc( this.x, this.y, this.size, 0, PI2, false );
skyc.fill();
skyc.restore();
},
exp:function(){
this.speed = 0;
}
};
var World = {
loopId:null,
land:Land,
bombs:( function(){
var result = [];
for( var i= 0, count=10 ; i<count ; i+=1 ){ result.push( new Bomb() ); }
return result;
}()),
init:function(){
land.width = land.width;
sky.width = sky.width;
this.land.init();
},
update:function(){
sky.width = sky.width;
skyc.save();
var bomb;
for( var i= 0, count=this.bombs.length ; i<count ; i+=1 ){
bomb = this.bombs[ i];
bomb.update();
if( !this.land.isCollision(bomb)) {
if( this.land.isCollision( bomb ) ){
this.land.destroy( bomb );
bomb.exp();
bomb.init();
}
}else{
console.log( bomb.y+bomb.size/2, land.height );
if( bomb.y+bomb.size/2 > land.height ){
bomb.init();
}
}
}
skyc.restore();
},
start:function(){
var self = this;
this.stop();
this.loopId = setInterval( function(){
self.update();
}, 1000/40 )
},
stop:function(){
clearInterval( this.loopId );
}
};
World.init();
World.start();
</script>
</body>
</html>
############### secound source #################
enter code here
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
* {
margin: 0;
padding: 0;
}
#wrapper {
position: relative;
width: 800px;
height: 600px;
background: red;
}
#myCanvas {
width: 800px;
height: 600px;
background: blue;
}
#stop {
position: absolute;
}
#write {
position: absolute;
width: 200px;
height: 24px;
left: 50%;
margin-left: -100px;
margin-top: -50px;
}
</style>
<script>
$(function(){
var canvas=document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");
var write = document.getElementById('write');
document.addEventListener('keydown', function(e) {
if (e.keyCode == 13) {
write.focus();
}
});
write.addEventListener('keydown', function(e) {
if (e.keyCode == 13) {
console.log(write.value);
write.value = '';
}
});
// a flag to let you stop the animation
var ok2animate=true;
// a Drop pseudo-class
// Properties: current x,y & the speed at which this drop falls
function Drop(){
this.x=Math.random()*(canvas.width-20);
this.y=-Math.random()*20;
this.fallRate=1;
}
// draw this drop on the canvas
Drop.prototype.draw=function(){
ctx.beginPath();
ctx.moveTo(this.x-5,this.y);
ctx.lineTo(this.x,this.y-7);
ctx.lineTo(this.x+5,this.y);
ctx.arc(this.x,this.y,5,0,Math.PI);
ctx.closePath();
ctx.fill();
return(this);
}
// make this drop "fall"
Drop.prototype.fall=function(){
this.y+=this.fallRate;
return(this);
}
// an animation loop to make some test drops fall
function animate(){
// request another animation frame
if(ok2animate){
requestAnimationFrame(animate);
}
// fill the canvas with the orange background
// ctx.fillStyle="orange";
// ctx.fillRect(0,0,canvas.width,canvas.height)
var img=new Image();
img.onload = function(){
ctx.drawImage(img,0,0);
};
img.src="Game_Background.jpg";
// make all drops fall and then redraw them
ctx.fillStyle="red";
for(var i=0;i<drops.length;i++){
drops[i].fall().draw();
}
}
// let the user stop the animation
$("#stop").click(function(){
ok2animate=false;
});
// an array of objects each representing 1 drop
var drops=[];
// add some test drops
for(var i=0;i<10;i++){
drops.push(new Drop());
}
// start the animation
requestAnimationFrame(animate);
}); // end $(function(){});
</script>
</head>
<body>
<div id="wrapper">
<button id="stop">Stop</button>
<canvas id="myCanvas" width=800 height=600></canvas>
<input type="text" id="write">
</div>
</body>
</html>
Copying values between input-type-text's
Get a reference to #first and #second: document.getElementById
Read #first's .value: var theValue=tbFirst.value
Write the value to #second: tbSecond.value=theValue
Here's example code and a Demo:
// get reference to textboxes
var tbFirst=document.getElementById('first');
var tbSecond=document.getElementById('second');
// button to call firstToSecond function
document.getElementById('movetext').onclick=function(){
firstToSecond();
};
// copy #first's text value to #second
function firstToSecond(){
// read tbFirst and copy to tbSecond
tbSecond.value=tbFirst.value;
// optionally, clear #first
tbFirst.value='';
}
<h4>Type in #First. Click button to move to #Second</h4>
First:<input type="text" id="first">
<button id='movetext'>First-to-second</button>
<br>
Second:<input type="text" id="second">
I am aiming to attach a slider onto this codepen animation, so the user can edit the speed of the animation.
At the moment, I am not getting any errors, but I am not getting the value from the input slider passed through to the animation.
this.speed = dotSpeed;
I am aiming to take the value from the slider, create a variable and put it through the "function Circle" properties.
var dotArray = [];
function threeDotSliderChangeSpeed (value) {
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" onchange="threeDotSliderChangeSpeed(3)"/>
<br /> <br />
<script src="js/index.js"></script>
</body>
</html>
Here is a video of another one I got going, using the same method.
https://www.youtube.com/watch?v=vjZ6CfQ2WrY&feature=youtu.be
To get the value from the slider you need to get the value from the element
by using document.getElementById('rg').value on change event
js:
var dotArray = [];
function threeDotSliderChangeSpeed () {
var value = document.getElementById('rg').value;
alert(value);
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
Html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" id="rg" onchange="threeDotSliderChangeSpeed(3)"/>
<br />
<br />
<script src="js/index.js"></script>
</body>
</html>
i am able to get the slider value on alert
you can see output in codepin
http://codepen.io/anon/pen/aOOjXE