javascript svg animation - javascript

How would I write script that would move a shape in svg linearly with javascript. I want to use requestanimframe.
Here is an example using canvas. I just want to do the same thing except with svg.
The script obtains a context to the canvas then it uses javascript to draw a shape with the properties of the context. Then it manages the animation of the shape on the canvas in a linear motion. I just want to use svg for the shape instead of the canvas context properties.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
window.requestAnimFrame = (function(callback){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(lastTime, myRectangle){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// update
var date = new Date();
var time = date.getTime();
var timeDiff = time - lastTime;
var linearSpeed = 100; // pixels / second
var linearDistEachFrame = linearSpeed * timeDiff / 1000;
var currentX = myRectangle.x;
if (currentX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myRectangle.x = newX;
}
lastTime = time;
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// draw
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = "#8ED6FF";
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = "black";
context.stroke();
// request new frame
requestAnimFrame(function(){
animate(lastTime, myRectangle);
});
}
window.onload = function(){
var myRectangle = {
x: 0,
y: 50,
width: 100,
height: 50,
borderWidth: 5
};
var date = new Date();
var time = date.getTime();
animate(time, myRectangle);
};
</script>
</head>
<body onmousedown="return false;">
<canvas id="myCanvas" width="578" height="200">
</canvas>
</body>

Probably the easiest way to move an element in SVG with JavaScript is to modify the transform attribute of the element. This isn't the best method in terms of performance, but it is very readable and simple.
Most simply:
var el = document.getElementById( "mySVGElement" );
for( var i = 0; i < 100; i++ )
{
setTimeout( function( ) {
el.setAttribute( "transform", "translate( " + i + ", 0 )" );
}, 200 + i );
}
Or if you want a function to do it:
function translateElement( element, distance )
{
var x, y;
for( var i = 0; i < 100; i++ )
{
setTimeout( function( ) {
x = parseInt( distance.x * i / 100 );
y = parseInt( distance.y * i / 100 );
element.setAttribute( "transform", "translate( " + x + ", " + y + " )" );
}, 20 + i );
}
}
or per Erik's advice:
function translateElement( element, distance )
{
var x, y;
for( var i = 0; i < 100; i++ )
{
setTimeout( function( ) {
x = distance.x * i / 100;
y = distance.y * i / 100;
element.transform.baseVal.getItem( 0 ).setTranslate( x, y );
}, 20 + i );
}
}
Where element is the element you're moving and distance is an object of the form:
{
x: xOffset,
y: yOffset
}

Related

Js, HTML, and CSS to make matrix rainbow rain not working

https://codepen.io/deathshadow8123/pen/KKNaLXq That is my pen from codepen, however when I create an html doc, and put the js into a tag and the css into a tag it doesn't show up on the webpage I also put the in there. Pls help me I do not know how to make this work. Any ideas?
if you can't access codepen here is my code:
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
chars: '\1234567890ìqwertyuiopè+asdfghjklòàù<zxcvbnm,.-|!"£$%&/()=?^QWERTYUIOPé*ASDFGHJKLç°§>ZXCVBNM;:_[]##€{}'.split(''), // every key in the italian keyboard layout. It sucks, we don't even have a backtick!
font: '12px monospace',
charSize: 14,
lineHeight: 14,
hueSpeed: 1,
repaintAlpha: .1,
stripesParXxY: .1,
stripeSpeed: .5,
beforeSpawning: 50
},
tick = 0,
endX = ( w / opts.charSize + 1 ) |0,
endY = ( h / opts.lineHeight + 1 ) |0,
sum = w + h,
stripes = [];
ctx.font = opts.font;
ctx.fillStyle = '#111';
ctx.fillRect( 0, 0, w, h );
function loop() {
window.requestAnimationFrame( loop );
tick += opts.hueSpeed;
ctx.fillStyle = 'rgba(0,0,0,alp)'.replace( 'alp', opts.repaintAlpha );
ctx.fillRect( 0, 0, w, h );
stripes.map( function( stripe ){ stripe.step(); } );
}
function Stripe(){
this.reset();
}
Stripe.prototype.reset = function() {
this.x = ( Math.random() * endX ) |0;
this.y = -Math.random() * opts.beforeSpawning;
}
Stripe.prototype.step = function() {
this.y += opts.stripeSpeed;
drawLetter( this.x, this.y|0 );
if( this.y > endX )
this.reset();
}
function drawLetter( x, y ){
x *= opts.charSize;
y *= opts.lineHeight;
ctx.fillStyle = 'hsl(hue,80%,50%)'.replace( 'hue', ( x + y ) / sum * 360 + tick );
ctx.fillText( opts.chars[ ( Math.random() * opts.chars.length ) |0 ], x, y );
}
for( var i = 0; i < endX*endX * opts.stripesParXxY; ++i )
stripes.push( new Stripe );
loop();
window.addEventListener( 'resize', function(){
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
ctx.fillStyle = '#111';
ctx.fillRect( 0, 0, w, h );
ctx.font = opts.font;
endX = ( w / opts.charSize + 1 ) |0;
endY = ( h / opts.lineHeight + 1 ) |0;
sum = w + h;
stripes.length = 0;
for( var i = 0; i < endX*endY * opts.stripesParXxY; ++i )
stripes.push( new Stripe );
})
canvas {
position: absolute;
top: 0;
left: 0;
}
<canvas id=c></canvas>
Once the DOM is loaded, you need to get a reference to your canvas DOM element at the top of your script or load handler function.
const c = document.getElementById("c");
Also its best to use quotes in your html.
e.g.
<canvas id="c"></canvas>
The problem of your code is that you have not put your canvas' id inside "", putting t
I have seen the code. There is a small error in html file and this is the cause of the project not working. It is simple, Just put your canvas id in "" doublequotes.
<canvas id="c"></canvas>
Thanks, Hope it helps

PIXI Graphics "Out of Memory"

I tried to modify the following code (that draws splash animations on canvas directly):
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var particles = [];
canvas.onmousemove = function(e)
{
for (var i = 0; i < 36 * 2; i++)
{
particles.push({
x: e.clientX,
y: e.clientY,
angle: i * 5,
size: 5 + Math.random() * 3,
life: 200 + Math.random() * 50
});
}
}
canvas.onmouseup = function()
{
//ctx.clearRect(0, 0, 600, 600);
}
var delta = 0;
var last = Date.now();
function animate()
{
delta = Date.now() - last;
last = Date.now();
for (var i = 0; i < particles.length; i++)
{
var p = particles[i];
p.x += Math.cos(p.angle) * 4 + Math.random() * 2 - Math.random() * 2;
p.y += Math.sin(p.angle) * 4 + Math.random() * 2 - Math.random() * 2;
p.life -= delta;
p.size -= delta / 50;
if (p.size <= 0)
{
p.life = 0;
}
if (p.life <= 0)
{
particles.splice(i--, 1);
continue;
}
}
}
function render()
{
ctx.fillStyle = '#' + (Math.floor(Math.random() * (0xFFFFFF + 1))).toString(16);
for (var i = 0; i < particles.length; i++)
{
if (Math.random() < 0.1)
{
continue;
}
var p = particles[i];
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2, false);
ctx.fill();
}
}
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
(function animloop(){
requestAnimFrame(animloop);
animate();
render();
})();
...to draw using PIXI.Graphics:
const app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x1099bb,
resolution: window.devicePixelRatio || 1,
resizeTo: window
});
document.body.appendChild(app.view);
const graphics = new PIXI.Graphics();
app.stage.addChild(graphics);
ctx = {
beginPath: function() {
graphics.beginFill(0x00ff00);
},
arc: function() {
graphics.arc(...arguments);
},
fill: function() {
graphics.endFill();
}
};
//var canvas = document.getElementById("canvas");
//var ctx = canvas.getContext("2d");
var particles = [];
window.onmousemove = function(e)
{
for (var i = 0; i < 36 * 2; i++)
{
particles.push({
x: e.clientX,
y: e.clientY,
angle: i * 5,
size: 5 + Math.random() * 3,
life: 200 + Math.random() * 50
});
}
}
window.onmouseup = function()
{
//ctx.clearRect(0, 0, 600, 600);
}
var delta = 0;
var last = Date.now();
function animate()
{
delta = Date.now() - last;
last = Date.now();
for (var i = 0; i < particles.length; i++)
{
var p = particles[i];
p.x += Math.cos(p.angle) * 4 + Math.random() * 2 - Math.random() * 2;
p.y += Math.sin(p.angle) * 4 + Math.random() * 2 - Math.random() * 2;
p.life -= delta;
p.size -= delta / 50;
if (p.size <= 0)
{
p.life = 0;
}
if (p.life <= 0)
{
particles.splice(i--, 1);
continue;
}
}
}
function render()
{
ctx.fillStyle = "#00FF00";
for (var i = 0; i < particles.length; i++)
{
if (Math.random() < 0.1)
{
continue;
}
var p = particles[i];
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2, false);
ctx.fill();
}
}
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
(function animloop(){
requestAnimFrame(animloop);
animate();
render();
})();
It seems to work, however after a few splashes it starts lagging and eventually crashes the browser with "Out of Memory" error.
The original code draws on mouse click, but I tried and it works on mouse move too.
My idea is that PIXI.Graphics creates too much cache causing the crash.
Does anybody know the reason of the crash and maybe a way to fix it?
Any ideas are appreciated!
Codepen HTML for testing:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
<title>PIXI Splash Test</title>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
height: 100vh;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js"></script>
</body>
</html>
Is better to use more small "Graphics" objects - instead of one "Graphics" object with many shapes inside it. Please read second part of this answer" (after "Update 2020-03-15) : https://stackoverflow.com/a/60686761/3174731
Remove unneded objects / containers from "Pixi stage" when you dont need to use them anymore. When you remove the particles (when you do particles.splice(i--, 1);) you should also call app.stage.removeChild(somePixiContainer) (Graphics object is a PIXI.Container too - see "Extends" in https://pixijs.download/dev/docs/PIXI.Graphics.html )

Code crashes because object's .rad property becomes undefined

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>

Could I modify my DOM from within a class?

It's really very simple, but I can't seem to figure out how to do this. I get "Uncaught TypeError: this.resizeCanvas is not a function" from the console in Chrome. The code is meant to resize the canvas in which I draw an analog clock.
<edit>
Pasting the entirety of the code, not just the protion giving me headache
</edit>
JAVASCRIPT
function Hands(canvas)
{
this.angle = 0;
this.beginX = canvas.width / 2;
this.beginY = canvas.height / 2;
this.endX = 0;
this.endY = 0;
this.radius = 0;
this.length = 0;
this.modLength = 0;
this.color = '';
this.lineCap = '';
this.lineWidth = 0;
this.rotation = ( Math.PI * 2 ) / 4;
this.draw = function(ctx)
{
this.length = this.radius - this.modLength;
this.endX = this.beginX + Math.cos( this.angle - this.rotation ) * this.length;
this.endY = this.beginY + Math.sin( this.angle - this.rotation ) * this.length;
ctx.beginPath();
ctx.moveTo( this.beginX, this.beginY );
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.color;
ctx.lineCap = this.lineCap;
ctx.lineTo( this.endX, this.endY );
ctx.stroke();
};
}
function AnalogClock()
{
this.canvas = document.getElementById( "clockface" );
this.context = this.canvas.getContext('2d');
this.margin = 30;
this.rotation = (Math.PI * 2) / 4; // Rotate 0 rad to be at top of circle
this.centerX = this.canvas.width / 2;
this.centerY = this.canvas.height / 2;
this.secondHand = new Hands(this.canvas);
this.secondHand.lineWidth = 3;
this.secondHand.modLength = 100;
this.secondHand.beginX = this.centerX;
this.secondHand.beginY = this.centerY;
this.secondHand.color = '#ff0000';
this.secondHand.radius = this.canvas.height / 2.031;
this.minuteHand = new Hands(this.canvas);
this.minuteHand.lineWidth = 10;
this.minuteHand.modLength = 100;
this.minuteHand.beginX = this.centerX;
this.minuteHand.beginY = this.centerY;
this.minuteHand.color = '#101010';
this.minuteHand.radius = this.canvas.height / 2.031;
this.hourHand = new Hands(this.canvas);
this.hourHand.lineWidth = 16;
this.hourHand.modLength = 175;
this.hourHand.beginX = this.centerX;
this.hourHand.beginY = this.centerY;
this.hourHand.color = '#101010';
this.hourHand.radius = this.canvas.height / 2.031;
this.drawSecondHand = function( s )
{
this.secondHand.angle = ( Math.PI * 2 ) * ( s / 60 );
this.secondHand.draw( this.context );
};
this.drawMinuteHand = function( m )
{
this.minuteHand.angle = ( Math.PI * 2 ) * ( m / 60 );
this.minuteHand.draw( this.context );
};
this.drawHourHand = function( h )
{
this.hourHand.angle = ( Math.PI * 2 ) * ( h / 12 );
this.hourHand.draw( this.context );
};
this.drawDot = function( x, y, radius, radians, color )
{
this.context.beginPath();
this.context.arc( x, y, radius, 0, Math.PI * 2, false );
this.context.fillStyle = color;
this.context.fill();
};
this.drawClockFace = function()
{
var distance = this.centerY - 80;
for( i = 0; i < 60; i++ )
{
var targetX = this.centerX + Math.cos( ( ( Math.PI * 2 ) * ( i / 60 ) ) - this.rotation ) * distance;
var targetY = this.centerY + Math.sin( ( ( Math.PI * 2 ) * ( i / 60 ) ) - this.rotation ) * distance;
this.drawDot( targetX, targetY, 3, this.minuteHand.color);
}
for( i = 0; i < 12; i++ )
{
var targetX = this.centerX + Math.cos( ( ( Math.PI * 2 ) * ( i / 12 ) ) - this.rotation ) * distance;
var targetY = this.centerY + Math.sin( ( ( Math.PI * 2 ) * ( i / 12 ) ) - this.rotation ) * distance;
this.drawDot( targetX, targetY, 8, this.hourHand.color );
}
};
this.resizeCanvas = function()
{
this.canvas.width = window.innerWidth - this.margin;
this.canvas.height = window.innerHeight - this.margin;
};
this.draw = function()
{
var now = new Date();
this.resizeCanvas();
this.drawClockFace();
this.drawHourHand( now.getHours() );
this.drawMinuteHand( now.getMinutes() );
this.drawSecondHand( now.getSeconds() );
this.drawDot( this.centerX, this.centerY, 10, this.secondHand.color ); // Center dot
};
}
/********
LOAD APP
*********/
// ctx.translate(0.5, 0.5); // Anti-aliasing
var analogClock = new AnalogClock();
function tick()
{
setInterval( analogClock.draw, 1000 );
analogClock.draw();
}
document.addEventListener("DOMContentLoaded", function(){ tick(); });
HTML
<!DOCTYPE html>
<html>
<head>
<style>
body {
background: #fefefe;
}
canvas {
background: #fefefe;
}
</style>
</head>
<body id="root">
<canvas id="clockface"></canvas>
<script src="clock.js"></script>
</body>
</html>
You need to code your tick more like this...
function tick() {
analogClock.draw();
//setInterval(tick, 1000); - WRONG
setTimeout(tick, 1000); // Or preferably use requestAnimationFrame.
}
window.addEventListener("load", function() {
tick();
});
However, when I do this, it runs very poorly in Firefox. Perhaps requestAnimationFrame will work better, but there's something that's locking it up that I can't quite put my finger on. However, this does resolve your current issue of resizeCanvas coming back as undefined. When you remove the tick and just call resizeCanvas or draw directly, they work fine. And once the tick is looping correctly, it also works fine.
I suspect the performance issue is being caused by the resize of the canvas being called on EVERY tick. You probably don't want to be doing that. You only need to call that, if the window is resized.
And the resultant clock is upside down BTW. In your Hands object, this corrects it...
this.rotation = -Math.PI / 2;
The root of your problem is that functions called by setTimeout and setInterval always have a this object of the current window. When using either of these functions on an object's method, you must either use a wrapper function or use apply()
//wrapper
setTimeout(function(){analogClock.draw();}, 1000);
or
//apply
setTimeout(function(){analogClock.draw.apply(analogClock), 1000);
Instead you should write:
function tick()
{
analogClock.draw();
}
document.addEventListener("DOMContentLoaded", function(){ setInterval(tick, 1000); })
or
function tick()
{
analogClock.draw();
setInterval( analogClock.draw.apply(analogClock), 1000 );
}
document.addEventListener("DOMContentLoaded", function(){ tick(); });
Change clock.resize() to myClock.resize().

"parseInt from form" and "clearing canvas on start()"

Greeting Everyone,
I already asked for some help with this assignment but the help I got was rather fruitless..
hope this time some1 would be to assist me :( ..
I have to draw on an id'd canvas everytime i click on a button,
however after some modification I get the result on my screen but I lost some functionalties,
parsing integer wont work since I get an error:
Uncaught ReferenceError: pGame is not defined
Although it is identified and it used to work at an early stage.
another issue is clearing the canvas everytime I click start:
function start()
{
//tried making a counter, if its the first time to click
//start then do nothing else restore
// context.restore();
if (shouldClear==0) {
setInterval(rotateShape, 30);
var degrees = 0.0;
shouldClear = 1;
}
else{
rotateShape();
shouldClear-1;
}
}
For reference pursposes here is my full code:
<!DOCTYPE HTML>
<html>
<head><title>Rectangles</title></head>
<body>
<script>
var i = 0;
var rectArrayStartX,rectArrayStartY,rectArrayDimY, rectArrayDimX;
var RotatingRectangle = function(x, y, width, height, rot, r,g,b){
var rotation = rot;
var rotationState = 0;
this.draw = function(ctx){
rotationState += rotation;
ctx.save();
ctx.translate(x+(width/2), y+(height/2));
ctx.rotate(rotationState);
var randomRed = Math.floor( Math.random() * 256 );
var randomGreen = Math.floor( Math.random() * 256 );
var randomBlue = Math.floor( Math.random() * 256 );
ctx.fillStyle = "rgb(" + randomRed + ", " + randomGreen + ", " + randomBlue +")";
ctx.fillRect(0-(width/2), 0-(height/2), width, height);
ctx.restore();
}
}
var shouldClear = 0;
function start()
{
//tried making a counter, if its the first time to click
//start then do nothing else restore
// context.restore();
if (shouldClear==0) {
setInterval(rotateShape, 30);
var degrees = 0.0;
shouldClear = 1;
}
else{
rotateShape();
shouldClear-1;
}
}
function construct()
{
var count = 25;
var count = parseInt(pGame.box.value);
var allShapes = [];
for (i=0; i < count; ++i) {
var rotation = Math.random()*.10
var x = Math.floor(Math.random() * 640);
var y = Math.floor(Math.random() * 480);
var randomRed = Math.floor( Math.random() * 256 );
var randomGreen = Math.floor( Math.random() * 256 );
var randomBlue = Math.floor( Math.random() * 256 );
var rect = new RotatingRectangle(x, y, 50, 50, rotation, "rgb(" + randomRed + ", " + randomGreen + ", " + randomBlue +")");
allShapes.push(rect);
}
return allShapes;
}
var allShapes = construct();
function rotateShape()
{
var canvas = document.getElementById('gameId');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 640, 480);
for (i=0; i < allShapes.length; ++i) {
allShapes[i].draw(ctx);
}
if (shouldClear==1) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 640, 480);
for (i=0; i < allShapes.length; ++i) {
allShapes[i].draw(ctx);
}
}
}
}
</script>
<div id="rectangles" STYLE = "background-color: #fff68f; width: 600px; height: 420px;
border-style: outset;position: absolute;">
<form name="pGame">
<center>
<b>Canvas Application</b><br>
<input type= "button" value= "Start" onclick= "start()" />
<input id="box" type="text" size="2" value="10" style="border-style:inset;
color:red; background-color: black" />
</center>
</form>
<canvas id="gameId" width="598" height="300"
STYLE = "border:1px solid; background-color: #fff68f; position: absolute;">
</canvas>
</div>
</body>
</html>
The form pGame hasn't been created when you try to access it.
Place your script under the form so that the form will be created before the script is executed or call your script when the DOMContentLoaded event triggers.

Categories

Resources