I have a WWWeb page with stacked <canvas> elements. The goal is to draw something persistent in the lower canvas and draw, clear, and redraw, repeatedly, in the upper canvas. According to w3.org and this StackOverflow article (How do I make a transparent canvas in html5?), canvas elements are, by default, transparent. What I am seeing is that not only are they not transparent, but that overlaying via z-index is not working. Here's a "vanilla" version of the page's code (complete and used to generate the images):
<html>
<head>
<title>Canvas Stack</title>
<script>
function doStuff() {
drawStuff(document.getElementById("lowerCanvas"), 0, 1);
drawStuff(document.getElementById("upperCanvas"), 1, 0);
}
function drawStuff(cvs, p0X, p1X) {
var ctx = cvs.getContext("2d");
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.strokeStyle = cvs.style.color;
ctx.beginPath();
ctx.moveTo(p0X * cvs.width, 0);
ctx.lineTo(p1X * cvs.width, cvs.height);
ctx.stroke();
}
</script>
</head>
<body onload="doStuff();" style="border:solid;">
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
</body>
</html>
and here's the result:
If I swap the order of the canvas elements
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />
the result is
It seems as if the z-index has been ignored and that the order of declaration has primacy.
What I want is
(synthetic image)
The behavior is identical in Chrome, Edge, Firefox, and Internet Explorer under Windows 10. That makes me confident that I'm just missing some detail rather than experiencing an anomaly. However, I'm getting a flattened forehead from whacking my head against a wall and would really appreciate some guidance, here.
Thank you, all!
Some notes (maybe irrelevant; maybe not):
style="position:absolute;... (without the left and top entries) seems to do the same thing as style="left:0;position:absolute;top:0;...
In similar fashion, style="position:inherit;... is probably necessary if the canvas is to reside within a table's <td> and that <td> is other than the first one in a <tr>.
<html>
<head>
<title>Canvas Stack</title>
<script>
function doStuff() {
drawStuff(document.getElementById("lowerCanvas"), 0, 1);
drawStuff(document.getElementById("upperCanvas"), 1, 0);
}
function drawStuff(cvs, p0X, p1X) {
var ctx = cvs.getContext("2d");
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.strokeStyle = cvs.style.color;
ctx.beginPath();
ctx.moveTo(p0X * cvs.width, 0);
ctx.lineTo(p1X * cvs.width, cvs.height);
ctx.stroke();
}
</script>
</head>
<body onload="doStuff();" style="border:solid;">
<div style="position:relative;min-height:200px">
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:absolute;top:0;width:300px;z-index:0;"></canvas>
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:absolute;top:0;width:300px;z-index:1;"></canvas>
</body>
</html>
You need to close your canvas elements explicitly. Simply close it with:
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;"></canvas>
instead of the embedded close "/>"
I also enclosed them in a div and used position:absolute so that they actually overlap...
Related
For an assignment I need to animate something simple using CSS and JavaScript. I've been able to figure out the CSS but everything I read to make an object fade in using JavaScript just doesn't seem to work with the object I drew in JavaScript. I just wanted to draw a circle in JavaScript and then animate it to fade in in 5 seconds.
Here is the basic Code I have so far:
HTML:
<body onload="draw();">
<canvas id="circle" width="450" height="450"></canvas>
</body>
JavaScript:
<script>
function draw()
{
var canvas = document.getElementById('circle');
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
var X = canvas.width / 2;
var Y = canvas.height / 2;
var R = 45;
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 3;
ctx.strokeStyle = '#645862';
ctx.stroke();
}
}
</script>
As you can see I only have the circle part of the code. I have tried multiple versions of different fade in animations but I just can't quite get them to work. I'm not very good at JavaScript. It's the one language I have trouble understanding for some reason. I'm also really sick right now otherwise I would be troubleshooting more reasons as to why it isn't working.
To understand how a canvas works, you need to know that it's just a place to display something, and initially it doesn't do anything on its own. You've drawn the circle once, which is enough to display the circle, but not to animate it in any way.
If we want to move the circle in any direction, we must clear the canvas of the already drawn circle and draw the circle in a different place, changing its coordinates by N pixels. The same goes for transparency. We must change the transparency of the color of the circle in each frame, and draw the circle again and again.
This is how 2D and 3D canvas works, as well as all video games - they draw scenes 60 times per second, changing some values along the way, such as coordinates, values, color, transparency, height and width.
In order for this to work, we need two additional variables, opacity and the direction (fading) in which the opacity changes, to know whether the circle appears or disappears.
Also important is the recursive call to our draw() function. We will call it constantly, and we will constantly redraw our image on the canvas.
I also want to point out some conceptual mistakes in your code.
Dont use "var", it is deprecated. Use "let","const". Also don`t repeat "var","var","var" in every line. Use commas.
Dont use onload,onclick and others HTML on-attributes. They are only suitable for educational purposes, not for real work. Use script tag and document event listeners.
Dont name canvas id like "circle","box" etc. It is not a circle and a box, it is a canvas.
Use document.querySelector instead of document.getElementById. It is more modern
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas opacity animation</title>
</head>
<body>
<canvas id="canvas" width="450" height="450"></canvas>
<script>
document.addEventListener("DOMContentLoaded",()=>{
const OPACITY_SPEED = .005
let canvas = document.querySelector('canvas'),
context = canvas.getContext('2d'),
opacity = 1,
fading = true
draw()
function draw(){
// clear canvas for redrawing (important!)
context.clearRect(0, 0, canvas.width, canvas.height);
let circleX = canvas.width/2,
circleY = canvas.height/2,
radius = 45
// changing circle opacity
if(fading) opacity -= OPACITY_SPEED
else opacity += OPACITY_SPEED
// check if we need to fade in or to fade out
if(opacity >= 1) fading = true
if(opacity <= 0) fading = false
// draw circle
context.beginPath();
context.arc(circleX, circleY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 3;
context.strokeStyle = `rgba(0, 0, 0, ${opacity})`;
context.stroke();
// call draw() again and again
requestAnimationFrame(draw)
}
})
</script>
</body>
</html>
today i've got a problem regarding JavaScript.
I was given an exercise which consists on create a circle on the screen, using JavaScript, and then make it move to the right.
So the problem comes when i put in the function animate().
The code by itself works, it creates a circle, but when i insert the function animate() , put the code in it, and then try to recall it with requestFrameAnimation(animate), it just doesn't draw on the screen.
Code right down here. I've tried everything i am capable of, but couldn't fix it.
Thanks for the replies.
HTML:
<head>
<style type="text/css">
canvas{
border:1px solid black;
}
body{
margin:0px;
background-color:red;
</style>
</head>
<body>
<canvas></canvas>
<script src="canvas.js"></script>
</script>
</body>
JS:
canvas = document.querySelector('canvas'); //CANVAS SELECTOR
canvas.width = window.innerWidth; //MATCHING THE CANVAS WIDTH WITH THE WINDOW WIDTH
canvas.height = window.innerHeight; //********************HEIGHT***************HEIGHT
context=canvas.getContext("2d");
var x=200;
function animate(){ //Starting the function
context.beginPath(); //Initializing a Path of drawings
context.arc(x,200,100,0,Math.PI*2, true); //drawing the circle
context.fillStyle="rgba(120,10,200,0.5)"; //filling the circle
context.fill();
context.strokeStyle = 'blue'; //giving the circle a strokeline
context.stroke();
x+=1; //increasing the circle x so that it keeps moving towards right
requestAnimationFrame(animate); //calling back to the function so it keeps drawing infinitely.
}
I need your help , my question is can we adjust the transparency of drawn line on mouse move??
I wrote this code to draw tow lines and I added the addEventListener to get the coordinates of mouse but my problem is that I do not know how to adjust the transparency when the mouse is moving on the line.
<body>
<canvas id="drawImage" width="900" height="900" style="background-color:black"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("drawImage");
var cont = canvas.getContext("2d");
cont.beginPath();
cont.lineWidth=15;
cont.strokeStyle="red";
cont.moveTo(0,0);
cont.lineTo(100,100);
cont.stroke();
cont.save();
cont.beginPath();
cont.strokeStyle="yellow";
cont.moveTo(100,100);
cont.lineTo(100,150);
cont.stroke();
cont.save();
canvas.addEventListener("mousemove", function(event {});
</script>
</body>
thanx every body.
You can create a function that alters transparency with each stroke using .globalAlpha
A Demo: http://jsfiddle.net/m1erickson/dQFvm/
Example function:
function drawAlphaLine(x0,y0,x1,y1,strokeColor,alpha){
ctx.save();
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.lineTo(x1,y1);
ctx.globalAlpha=alpha;
ctx.strokeStyle=strokeColor;
ctx.stroke();
ctx.restore();
}
I have a multipage site that the main home page simply has a single image logo on it. When this page is visited I need the image to move around like a screensaver. When any touch is registered the page will go to a second page. That second page has other data and info but nothing is touched for ten minutes it will default and go back to the entry page and the screensaver.
So, two things.
One, move an image around like a screensaver using jQuery.
Two, the other page has a timeout of ten minutes if no touch is registered that knocks the person back to the first page that has the screensaver.
This is an HTML5 page so if jQuery will not work, something using HTML5 and Canvas might.
This is for a site that will be used as a kiosk and a touch screen.
On the screensaver page:
You can use an html canvas that floats your logo image around the screen. Here's a link:
http://jsfiddle.net/m1erickson/E3Qda/
On the second page:
How about starting a 10 minute setTimeout when the page first loads.
If the user triggers a touch event before 10 minutes, (1) clearTimeout the original timeout (2) setTimeout for a new 10 minutes.
Here's example code for the screensaver page:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
img{border:1px solid purple;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var ball;
var ballX=60;
var ballY=150;
var ballRadius=50;
var image=new Image();
image.onload=function(){
// resize the image to fit inside the ball's radius
var c=document.createElement("canvas");
var cctx=c.getContext("2d");
// calc the max side length of a square that fits the ball
var maxSide=Math.sqrt(2*ballRadius*ballRadius);
// calc the max rect size that fits in the ball
var iw=image.width;
var ih=image.height;
var maxW,maxH;
if(iw>=ih){
maxW=maxSide;
maxH=maxSide*iw/ih;
}else{
maxW=maxSide*ih/iw;
maxH=maxSide;
}
// size the temp canvas to the max rect size
c.width=maxW;
c.height=maxH;
// draw the image to the temp canvas
cctx.drawImage(image,0,0,iw,ih,0,0,maxW,maxH);
var ballimg=new Image();
ballimg.onload=function(){
ball={x:ballX,y:ballY,r:ballRadius,img:ballimg,imgSide:maxSide,directionX:1,directionY:1};
drawBall(ball);
}
ballimg.src=c.toDataURL();
requestAnimationFrame(animate);
}
image.src="ship.png";
function drawBall(ball){
// clip image inside ball
ctx.save();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.clip();
ctx.fillStyle="white";
ctx.fillRect(ball.x-ball.r,ball.y-ball.r,ball.r*2,ball.r*2);
ctx.drawImage(ball.img, ball.x-ball.imgSide/2,ball.y-ball.imgSide/2);
ctx.restore();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="lightgray";
ctx.lineWidth=2;
ctx.stroke();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r+2,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="gray";
ctx.lineWidth=2;
ctx.stroke();
}
function animate(time) {
requestAnimationFrame(animate);
// move with collision detection
ball.x+=ball.directionX;
if(ball.x-ball.r<0 || ball.x+ball.r>canvas.width){
ball.directionX*=-1;
ball.x+=ball.directionX;
}
ball.y+=ball.directionY;
if(ball.y-ball.r<0 || ball.y+ball.r>canvas.height){
ball.directionY*=-1;
ball.y+=ball.directionY;
}
// Draw
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall(ball);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
I am making a loading spinner with html5 canvas. I have my graphic on the canvas but when i rotate it the image rotates off the canvas. How do I tell it to spin the graphic on its center point?
<!DOCTYPE html>
<html>
<head>
<title>Canvas test</title>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas && drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
//Load the image object in JS, then apply to canvas onload
var myImage = new Image();
myImage.onload = function() {
context.drawImage(myImage, 0, 0, 27, 27);
}
myImage.src = "img/loading.png";
context.rotate(45);
}
}
</script>
</head>
<body>
<canvas id="myDrawing" width="27" height="27">
</canvas>
</body>
</html>
Here is the complete working example:)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Cog</title>
<script type="text/javascript">
var cog = new Image();
function init() {
cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path
setInterval(draw,10);
}
var rotation = 0;
function draw(){
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.clearRect(0,0,27,27);
ctx.translate(13.5,13.5); // to get it in the origin
rotation +=1;
ctx.rotate(rotation*Math.PI/64); //rotate in origin
ctx.translate(-13.5,-13.5); //put it back
ctx.drawImage(cog,0,0);
ctx.restore();
}
init();
</script>
</head>
<body>
<canvas width="27" height="27" id="myCanvas"></canvas>
</body>
</html>
rotate turns the canvas(?) around your current position, which is 0, 0 to start. you need to "move" to your desired center point, which you can accomplish with
context.translate(x,y);
after you move your reference point, you want to center your image over that point. you can do this by calling
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
this tells the browser to start drawing the image from above and to the left of your current reference point, by have the size of the image, whereas before you were starting at your reference point and drawing entirely below and to the right (all directions relative to the rotation of the canvas).
since your canvas is the size of your image, your call to translate will use the same measurement, (27/2), for x and y coordinates.
so, to put it all together
// initialization:
context.translate(27/2, 27/2);
// onload:
context.rotate(Math.PI * 45 / 180);
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
edit: also, rotation units are radians, so you'll need to translate degrees to radians in your code.
edits for rearranging stuff.
For anyone else looking into something like this, you might want to look at this script which does exactly what was originally being requested:
http://projects.nickstakenburg.com/spinners/
You can find the github source here:
https://github.com/staaky/spinners
He uses rotate, while keeping a cache of rectangles which slowly fade out, the older they are.
I find another way to do html loading spinner. You can use sprite sheet animation. This approach can work both by html5 canvas or normal html/javascript/css. Here is a simple way implemented by html/javascript/css.
It uses sprite sheet image as background. It create a Javascript timer to change the background image position to control the sprite sheet animation. The example code is below. You can also check the result here: http://jmsliu.com/1769/html-ajax-loading-spinner.html
<html>
<head><title></title></head>
<body>
<div class="spinner-bg">
<div id="spinner"></div>
</div>
<style>
.spinner-bg
{
width:44px;
height:41px;
background: #000000;
}
#spinner
{
width: 44px;
height: 41px;
background:url(./preloadericon.png) no-repeat;
}
</style>
<script>
var currentbgx = 0;
var circle = document.getElementById("spinner");
var circleTimer = setInterval(playAnimation, 100);
function playAnimation() {
if (circle != null) {
circle.style.backgroundPosition = currentbgx + "px 0";
}
currentbgx -= 44; //one frame width, there are 5 frame
//start from 0, end at 176, it depends on the png frame length
if (currentbgx < -176) {
currentbgx = 0;
}
}
</script>
</body>