JOSÉ JUANAS

Facebook Gmail Linkedin
Galleta

Cookies

Utilizamos cookies propias y de terceros para mejorar nuestros servicios.

Aviso de Cookies

Canvas animados

Como os anticipe, al final de mi página canvas, tenía que hacer esta página, combinándo la etiqueta canvas, con animaciones implementadas, con un poco de javascript, ya que esta es una de las principales virtudes del elemento canvas.

Ejemplos de canvas animados de este sitio que os voy a ir mostrándo en contenedores de código, que he construido, como un web component, en los que podeís exáminar todo el código del ejemplo y la propia demo.

Cursor canvas

Para este canvas se emplean los eventos mousemove y mouseout, ya sabeís, similar al :hover, de CSS.

<body style="margin: 0;"> <canvas id="canvas"></canvas> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var radius = 15; function drawCircle(mouseX, mouseY){ // Resize to the screen if(canvas.width != window.innerWidth || canvas.width != window.innerWidth){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; } // Limpia el background c.clearRect(0, 0, canvas.width, canvas.height); // Dibuja el circulo c.beginPath(); c.arc(mouseX, mouseY, radius, 0 , 2 * Math.PI, false); // Relleno del circulo c.fillStyle = '#00F0FF'; c.fill(); // Borde (stroke) del circulo c.lineWidth = 2; c.strokeStyle = 'black'; c.stroke(); } // función que va redibujando el circulo al movimiento del ratón (cursor) canvas.addEventListener('mousemove',function(e){ drawCircle(e.clientX, e.clientY); }); // Limpia el canvas cuando el ratón sale del canvas canvas.addEventListener('mouseout',function(e){ c.clearRect(0, 0, canvas.width, canvas.height); }); // Dibuja un circulo en el centro inicialmente drawCircle(canvas.width / 2, canvas.height / 2);

Click ball

<body> <canvas id="canvas"></canvas> <script src="../js/requestAnimFrame.js"></script> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var radius = 32; var lineWidth = 4; var gravity = 0.1; var dampening = 0.995; var mousePullStrength = 0.005; var animate = false; var mouse = { x : 0, y : 0, down: false }; var circle = { x : canvas.width/2, y : canvas.height/2, vx: 0, // 'v' stands for 'velocity' vy: 0 }; function executeFrame(){ if(animate) requestAnimFrame(executeFrame); incrementSimulation(); c.clearRect(0, 0, canvas.width, canvas.height); drawBox(); drawCircle(); if(mouse.down) drawLineToMouse(); } function incrementSimulation(){ // Pull the circle toward the mouse if(mouse.down){ var dx = mouse.x - circle.x, dy = mouse.y - circle.y, distance = Math.sqrt(dx*dx + dy*dy), unitX = dx / distance, unitY = dy / distance, force = distance * mousePullStrength; circle.vx += unitX * force; circle.vy += unitY * force; } // Execute gravity circle.vy += gravity; // Execute dampening (slowing down) circle.vx *= dampening; circle.vy *= dampening; // Increment the position by the velocity circle.x += circle.vx; circle.y += circle.vy; // Bounce off the floor if(circle.y + radius > canvas.height){ circle.y = canvas.height - radius; circle.vy = - Math.abs(circle.vy); } // Bounce off the ceiling else if(circle.y - radius < 0){ circle.y = radius; circle.vy = Math.abs(circle.vy); } // Bounce off the right wall if(circle.x + radius > canvas.width){ circle.x = canvas.width - radius; circle.vx = - Math.abs(circle.vx); } // Bounce off the left wall else if(circle.x - radius < 0){ circle.x = radius; circle.vx = Math.abs(circle.vx); } } function drawBox(){ // Resize to the screen if(canvas.width != window.innerWidth || canvas.width != window.innerWidth){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; } c.lineWidth = 1; c.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1); } function drawCircle(){ c.beginPath(); c.arc(circle.x, circle.y, radius - lineWidth/2, 0 , 2 * Math.PI, false); c.fillStyle = '00F0FF'; c.fill(); c.lineWidth = 4; c.strokeStyle = 'black'; c.stroke(); } function drawLineToMouse(){ c.lineWidth = 2; c.moveTo(circle.x, circle.y); c.lineTo(mouse.x, mouse.y); c.stroke(); } canvas.addEventListener('mousedown',function(e){ mouse.down = true; mouse.x = e.pageX; mouse.y = e.pageY; }); canvas.addEventListener('mousemove', function(e){ mouse.x = e.pageX; mouse.y = e.pageY; }); canvas.addEventListener('mouseup', function(e){ mouse.down = false; }); // Start animating when the mouse enters the canvas canvas.addEventListener('mouseover', function(e){ animate = true; executeFrame(); }); // Stop animating when the mouse exits the canvas canvas.addEventListener('mouseout', function(e){ mouse.down = false; animate = false; }); // Draw the initial scene once, so something // is displayed before animation starts. executeFrame();

Click balls colision

<body> <canvas id="canvas"></canvas> <script src="../js/requestAnimFrame.js"></script> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var gravity = 0.1; var radius = 20; var numCircles = 10; var dampeningFactor = 0.99; var circles = []; var i, j, circle, circle2; var mouse = { x: 0, y: 0, down: false }; var circleUnderMouse; var ballMouseY, ballMouseX, pullForceY, pullForceX; var r, g, b; var animate = false; initializeCircles(); function executeFrame(){ if(animate) requestAnimFrame(executeFrame); iterateSimulation(); c.fillStyle = 'rgba(255,255,255,0.3)'; c.fillRect(0,0,canvas.width,canvas.height); drawCircles(); } function initializeCircles(){ circles = []; for(i = 0; i < numCircles; i++){ circle = { x: Math.random() * canvas.width, y: Math.random() * canvas.height, velocity:{x:0, y:0} }; circles.push(circle); } } function drawCircles(){ // Resize to the screen if(canvas.width != window.innerWidth || canvas.width != window.innerWidth){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; initializeCircles(); iterateSimulation(); } // draw rectangle border c.lineWidth = "3"; c.strokeRect(0,0,canvas.width,canvas.height); // draw circles for(i = 0; i < numCircles; i++){ circle = circles[i]; r = i*5; g = i*10; b = i*15; // draw connecting line from ball to mouse if(circle == circleUnderMouse){ c.beginPath(); c.moveTo(circle.x, circle.y); c.lineTo(mouse.x, mouse.y); c.lineWidth = "2"; c.strokeStyle="black"; c.stroke(); } c.beginPath(); c.arc(circle.x, circle.y, radius, 0, 2 * Math.PI); if(circle == circleUnderMouse){ c.fillStyle = "C1FF24"; c.lineWidth = "5"; c.stroke(); } else{ c.fillStyle = 'rgb('+r+', '+g+', '+b+')'; } c.fill(); } } function iterateSimulation(){ for(i = 0; i < numCircles; i++){ circle = circles[i]; // pull ball to mouse pullBallToMouse(); // Add gravity circle.velocity.y += gravity; // slows things down circle.velocity.x *= dampeningFactor; circle.velocity.y *= dampeningFactor; // Add velocity to position circle.x += circle.velocity.x; circle.y += circle.velocity.y; // Make them bounce off the floor if(circle.y > canvas.height - radius){ circle.y = canvas.height - radius; circle.velocity.y = - Math.abs(circle.velocity.y); } // bounce off ceiling if(circle.y < radius){ circle.y = radius; circle.velocity.y = Math.abs(circle.velocity.y); } // bounce off right wall if(circle.x > canvas.width - radius){ circle.x = canvas.width - radius; circle.velocity.x = -Math.abs(circle.velocity.x); } // bounce off left wall if(circle.x < radius){ circle.x = radius; circle.velocity.x = Math.abs(circle.velocity.x); } // REPULSION between circles for(j = i + 1; j < numCircles; j++){ circle2 = circles[j]; var dx = circle2.x - circle.x; var dy = circle2.y - circle.y; var d = Math.sqrt(dx*dx + dy*dy); if(d < 2*radius){ if(d === 0){ d = 0.1; } var unitX = dx/d; var unitY = dy/d; var force = -2; var forceX = unitX * force; var forceY = unitY * force; circle.velocity.x += forceX; circle.velocity.y += forceY; circle2.velocity.x -= forceX; circle2.velocity.y -= forceY; } } } } function pullBallToMouse(){ if(circle == circleUnderMouse){ ballMouseY = mouse.y - circle.y; ballMouseX = mouse.x - circle.x; pullForceY = ballMouseY * 0.02; pullForceX = ballMouseX * 0.02; circle.velocity.y += pullForceY; circle.velocity.x += pullForceX; } } canvas.addEventListener("mousemove", function(e){ mouse.x = e.x; mouse.y = e.y; }); canvas.addEventListener("mousedown", function(e){ mouse.down = true; mouse.x = e.x; mouse.y = e.y; for(i = 0; i < circles.length; i++){ var circle = circles[i]; // get circle out of array var dx = mouse.x - circle.x; var dy = mouse.y - circle.y; var d = Math.sqrt(dx*dx + dy*dy); if(d < radius){ circleUnderMouse = circle; break; // break (stop) the for loop } } }); canvas.addEventListener("mouseup", function(e){ mouse.down = false; circleUnderMouse = null; }); canvas.addEventListener("mouseout", function(e){ mouse.down = false; circleUnderMouse = null; }); // Kick off the animation when the mouse enters the canvas canvas.addEventListener('mouseover', function(e){ animate = true; executeFrame(); }); // Pause animation when the mouse exits the canvas canvas.addEventListener("mouseout",function(e){ animate = false; }); // Draw the first frame to start animation executeFrame();

Árbol canvas

<body> <canvas id="canvas" width="300" height="300"></canvas> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var centerX = canvas.width / 2; var trunkHeight = 100; var branchLengthRatio = 0.75; var branchAngleDifference = 0.27; var branchingDepth = 10; function drawTree(x1, y1, x2, y2, branchLength, branchAngle, depth){ if(depth == 0) return; else{ c.beginPath(); c.moveTo(x1, y1); c.lineTo(x2, y2); c.closePath(); c.stroke(); branchLength *= branchLengthRatio; function branch(angle){ var branchX2 = x2 + branchLength * Math.cos(angle); var branchY2 = y2 + branchLength * Math.sin(angle); drawTree(x2, y2, branchX2, branchY2, branchLength, angle, depth - 1); } // Right branch branch(branchAngle + branchAngleDifference); // Left branch branch(branchAngle - branchAngleDifference); } } function redrawTree(){ c.clearRect(0,0, canvas.width, canvas.height); var x1 = centerX; var y1 = canvas.height; var x2 = centerX; var y2 = canvas.height - trunkHeight; drawTree(x1, y1, x2, y2, trunkHeight, - Math.PI / 2, branchingDepth); } canvas.addEventListener("mousemove",function(e){ branchLengthRatio = e.x / 300; branchAngleDifference = e.y / canvas.height * Math.PI; redrawTree(); console.log("branchLengthRatio = "+branchLengthRatio); console.log("branchAngleDifference = "+branchAngleDifference); }); redrawTree();

Stars canvas

<body> <canvas id="canvas"></canvas> <button type="button" class="btn" id="fullscr">Go Fullscreen</button> <script src="../js/requestAnimFrame.js"></script> <script src="../js/fullscreen.js"></script> </body> #canvas { width: 100%; height: 100%; } .btn { position: fixed; bottom: 5%; right: 0px; transform: translateX(-50%); border: 1px solid #000; border-radius: 5px; font-size: 0.9rem; padding: 0.5rem 0.7em; background-color: transparent; color: #ffffff; font-family: Verdana, Geneva, Tahoma, sans-serif; -webkit-font-smoothing: antialiased; cursor: pointer; transition: all .3s; z-index: 100; } .btn:hover {background: #1B1734; color: #ffffff;} var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var numStars = 1000; var radius = 1; var focalLength = canvas.width; var centerX, centerY; var stars = [], star; var i; var animate = false; initializeStars(); function executeFrame(){ if(animate) requestAnimFrame(executeFrame); moveStars(); drawStars(); } function initializeStars(){ centerX = canvas.width / 2; centerY = canvas.height / 2; stars = []; for(i = 0; i < numStars; i++){ star = { x: Math.random() * canvas.width, y: Math.random() * canvas.height, z: Math.random() * canvas.width }; stars.push(star); } } function moveStars(){ for(i = 0; i < numStars; i++){ star = stars[i]; star.z--; if(star.z <= 0){ star.z = canvas.width; } } } function drawStars(){ var pixelX, pixelY, pixelRadius; // Condición para cuando se redimensione la ventana if(canvas.width != window.innerWidth || canvas.height != window.innerHeight){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; initializeStars(); } c.fillStyle = "black"; c.fillRect(0,0, canvas.width, canvas.height); c.fillStyle = "white"; for(i = 0; i < numStars; i++){ star = stars[i]; pixelX = (star.x - centerX) * (focalLength / star.z); pixelX += centerX; pixelY = (star.y - centerY) * (focalLength / star.z); pixelY += centerY; pixelRadius = radius * (focalLength / star.z); c.beginPath(); c.arc(pixelX, pixelY, pixelRadius, 0, 2 * Math.PI); c.fill(); } } canvas.addEventListener("mousemove",function(e){ focalLength = e.x; }); // Animación cuando el ratón entre en el canvas canvas.addEventListener('mouseover', function(e){ animate = true; executeFrame(); }); // Para la animación cuando el ratón sale del canvas canvas.addEventListener("mouseout",function(e){ // mouseDown = false; animate = false; }); // Dibuja el primer frame y comienza la animación executeFrame();

Click Ondas canvas

Este simulador de ondas esta basado ecuación de onda

<body> <canvas id="canvas"></canvas> <script src="../js/requestAnimFrame.js"></script> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var pullStrength = 0.01; var dampeningFactor = 0.99; var initialHeight = 0.5; var cells = []; var gridSize = 100; var conservationOfMassCorrection = 0; var cellWidth = 1 / (gridSize-1) * canvas.width; var mouseX, mouseY, mouseDown; var animate = false; // This function executes once per animation frame function executeFrame(){ if(animate) requestAnimFrame(executeFrame); clearCanvas(); drawCells(); iterateSimulation(); executeMouseInteraction(); } // Initialize the water height for(var i = 0; i < gridSize; i++){ cells.push({ // for a still initial surface //height: 0.5, // for an initial wave: height: i === Math.floor(gridSize*1/4) ? 1 : initialHeight, velocity: 0 }); } function clearCanvas(){ // resizes to full screen canvas.width = window.innerWidth; canvas.height = window.innerHeight; cellWidth = 1 / (gridSize-1) * canvas.width; } function drawCells(){ c.beginPath(); c.moveTo(canvas.width, canvas.height); c.lineTo(0, canvas.height); for(var i = 0; i < gridSize; i++){ var cell = cells[i]; var x = i / (gridSize-1) * canvas.width; var y = canvas.height - cell.height * canvas.height; c.lineTo(x,y); } c.closePath(); c.fill(); } // Increment the wave simulation: // Neighboring cells pull on one another. function iterateSimulation(){ var avgHeight = 0; for(var i = 0; i < gridSize; i++){ // center cell var c = cells[i]; // left neighbor var l = cells[((i - 1) + gridSize) % gridSize]; // right neighbor var r = cells[(i + 1) % gridSize]; // pull toward neighbors c.velocity += pullStrength * (l.height - c.height); c.velocity += pullStrength * (r.height - c.height); // increment velocity c.height += c.velocity; // ensure conservation of mass c.height += conservationOfMassCorrection; // apply dampening c.velocity *= dampeningFactor; avgHeight += c.height; } avgHeight /= (gridSize - 1); conservationOfMassCorrection = initialHeight - avgHeight; } // Pull the wave cell closest to the mouse function executeMouseInteraction(){ if(mouseDown){ for(var i = 0; i < gridSize; i++){ var x = i / (gridSize-1) * canvas.width; if(Math.abs(x - mouseX) < cellWidth){ var cell = cells[i]; cell.height = 1 - mouseY/canvas.height; cell.velocity = 0; } } } } // Record when the mouse is pressed canvas.addEventListener("mousedown",function(e){ mouseDown = true; mouseX = e.clientX; mouseY = e.clientY; }); // Record when the mouse is moved canvas.addEventListener("mousemove",function(e){ mouseX = e.clientX; mouseY = e.clientY; }); // Record when the mouse is released canvas.addEventListener("mouseup",function(e){ mouseDown = false; }); // Kick off the animation when the mouse enters the canvas canvas.addEventListener('mouseover', function(e){ animate = true; executeFrame(); }); // Pause animation when the mouse exits the canvas canvas.addEventListener("mouseout",function(e){ mouseDown = false; animate = false; }); // Draw the first frame executeFrame();

Ondas dos dimensiones

Este simulador de ondas esta basado ecuación de onda

<body> <canvas id="canvas"></canvas> <script src="../js/requestAnimFrame.js"></script> </body> var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); var pullStrength = 0.005; var dampeningFactor = 0.98; var initialHeight = 0.5; var cells = []; var gridSize = 50; var conservationOfMassCorrection = 0; var cellWidth = 1 / (gridSize-1) * canvas.width; var cellHeight = 1 / (gridSize-1) * canvas.height; var mouseX, mouseY, mouseDown; var animate = false; function executeFrame(){ if(animate) requestAnimFrame(executeFrame); clearCanvas(); drawCells(); iterateSimulation(); executeMouseInteraction(); }; // Store the color strings as an object re-use optimization. // (otherwise new string objects would be created for each color each frame) var grayStrings = []; for(var gray = 0;gray < 255; gray++){ // this transforms strings from 'rgb(255,190,201)' to '#FF564B' c.fillStyle = 'rgb('+gray+','+gray+','+gray+')'; // store the colors of the form '#FF564B' grayStrings.push(c.fillStyle); } for(var i = 0; i < gridSize; i++){ for(var j = 0; j < gridSize; j++){ // Raise a single cell so the simulation is // initialized with something that looks interesting var isRaisedCell = false; if(i === Math.floor(gridSize*1/4)) if(j === Math.floor(gridSize*1/4)) isRaisedCell = true; cells.push({ // for a still initial surface //height: 0.5, // for an initial wave: height: isRaisedCell ? 4 : initialHeight, velocity: 0 }); } } function clearCanvas(){ // resizes to full screen canvas.width = window.innerWidth; canvas.height = window.innerHeight; cellWidth = 1 / (gridSize-1) * canvas.width; cellHeight = 1 / (gridSize-1) * canvas.height; } function drawCells(){ for(var i = 0; i < gridSize; i++){ for(var j = 0; j < gridSize; j++){ var cell = cells[i + j * gridSize]; var x = i / (gridSize-1) * canvas.width; var y = j / (gridSize-1) * canvas.height; var gray = Math.floor(cell.height * 255); gray = gray > 255 ? 255 : gray < 0 ? 0 : gray; // This commented method of defining the colors // would create lots of new String objects. // Better to re-use existing objects so that // no memory is allocated/released each frame. //c.fillStyle = 'rgb('+gray+','+gray+','+gray+')'; c.fillStyle = grayStrings[gray]; c.fillRect(x,y,cellWidth+1,cellHeight+1); } } } function iterateSimulation(){ var avgHeight = 0; for(var i = 0; i < gridSize; i++){ for(var j = 0; j < gridSize; j++){ // center cell var c = cells[i + j * gridSize]; for(var di = -1; di <= 1; di++){ for(var dj = -1; dj <= 1; dj++){ if(di !== 0 || dj !== 0){ var ni = ((i + di) + gridSize) % gridSize; var nj = ((j + dj) + gridSize) % gridSize; var neighbor = cells[ni + nj * gridSize]; // pull toward neighbors c.velocity += pullStrength * (neighbor.height - c.height); } } } // increment velocity c.height += c.velocity; // ensure conservation of mass c.height += conservationOfMassCorrection; // apply dampening c.velocity *= dampeningFactor; avgHeight += c.height; } } avgHeight /= Math.pow(gridSize - 1,2); conservationOfMassCorrection = initialHeight - avgHeight; } function executeMouseInteraction(){ if(mouseDown){ var i = Math.floor((gridSize-1) * mouseX / canvas.width); var j = Math.floor((gridSize-1) * mouseY / canvas.height); var cell = cells[i + j * gridSize]; cell.height = 2; cell.velocity = 0; } } canvas.addEventListener("mousedown",function(e){ mouseDown = true; mouseX = e.offsetX; mouseY = e.offsetY; }); canvas.addEventListener("mousemove",function(e){ mouseX = e.offsetX; mouseY = e.offsetY; }); canvas.addEventListener("mouseup",function(e){ mouseDown = false; }); // Kick off the animation when the mouse enters the canvas canvas.addEventListener('mouseover', function(e){ animate = true; executeFrame(); }); // Pause animation when the mouse exits the canvas canvas.addEventListener("mouseout",function(e){ mouseDown = false; animate = false; }); // Iterate the simulation a couple of times // so the program shows something before animation starts. for(var i = 0; i < 7; i++) iterateSimulation(); // Draw the first frame executeFrame();

Pizarra multicolor canvas

<body> <canvas id="canvas"></canvas> <script src="../js/requestAnimFrame.js"></script> </body> var canvas = document.getElementById('canvas'); var c = canvas.getContext('2d'); canvas.width = innerWidth; canvas.height = innerHeight; c.fillRect(0,0,canvas.width, canvas.height); var paintColors = {}; var mouseId = 'mouse'; var mouseDown = false; function addMouseListeners(){ canvas.addEventListener('mousemove', function(e){ if(mouseDown){ c.fillStyle = paintColors[mouseId]; drawCircle(e.clientX, e.clientY); } }); canvas.addEventListener('mousedown', function(e){ mouseDown = true; setRandomPaintColor(mouseId); }); canvas.addEventListener('mouseup', function(e){ mouseDown = false; }); canvas.addEventListener('dblclick', function(e){ c.fillStyle = 'black'; c.fillRect(0,0,canvas.width, canvas.height); }); } function setRandomPaintColor(id){ function rand255(){ return Math.floor(Math.random()*255);} paintColors[id] = 'rgb('+rand255()+','+rand255()+','+rand255()+')'; } function drawCircle(x, y){ c.beginPath(); c.arc(x, y, 3, 0, 2 * Math.PI); c.fill(); } function addMultiTouchListeners(){ canvas.addEventListener('touchmove',function(e){ var i, touch; setRandomPaintColor(); for(i = 0; i < e.targetTouches.length; i++){ touch = e.targetTouches[i]; c.fillStyle = paintColors[touch.identifier]; drawCircle(touch.pageX, touch.pageY); } }); canvas.addEventListener('touchstart',function(e){ var i, touch; for(i = 0; i < e.changedTouches.length; i++){ touch = e.changedTouches[i]; setRandomPaintColor(touch.identifier); } }); canvas.addEventListener('touchend',function(e){ var i, touch; for(i = 0; i < e.changedTouches.length; i++){ touch = e.changedTouches[i]; console.log("removing "+touch.identifier); delete paintColors[touch.identifier]; } }); } // prevent scrolling document.body.addEventListener('touchmove', function(event) { event.preventDefault(); }, false); addMouseListeners(); addMultiTouchListeners();

Conclusión

Si has llegado hasta aquí, y has leido el código de los ejemplos que he mostrado, observarás que para trabajar con canvas, hay que aprender javascript, los eventos, los diferentes métodos para manejar y controlar el ancho (width) y el alto (height), tanto de la ventana (window), como de los elementos html, en nuestro caso canvas.

Contacto José Juanas
Datos del mensaje
 WEBMASTER  JOSE JUANAS