Moving a canvas element around on webpage - javascript

I have a local web server on a raspberry pi that I am using as a kiosk for rotating photos. I am also trying to include the coolclock.js script on the page which I do have working, but I would like the canvas that the clock lives in to move when the photo changes so it doesn't get burned in on the TV that the pi is hooked up to. I cannot get the clock to move on the page though...
function rotateImages() {
var canvas = document.getElementById('clockid');
alert(canvas.style.top);
alert(canvas.style.left);
if(last==1){
document.body.style.backgroundImage='url('+preloads2.src+')';
num=Math.floor(Math.random()*preloads.length);
preloads1.src=preloads[num];
last=2;
canvas.style.top = '0px';
canvas.style.left = '0px';
}
else{
document.body.style.backgroundImage='url('+preloads1.src+')';
num=Math.floor(Math.random()*preloads.length);
preloads2.src=preloads[num];
last=1;
canvas.style.top = '500px';
canvas.style.left = '500px';
}
}
var myVar=setInterval(function(){rotateImages()}, speed);
</script>
<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
<script src="coolclock.js" type="text/javascript"></script>
<script src="moreskins.js" type="text/javascript"></script>
</head>
<body onload="CoolClock.findAndCreateClocks()">
<canvas id="clockid" class="CoolClock::50::-4"></canvas>
</body>
</html>
The clock works, the images rotate, and the alerts show that the style.left and top are changing the way I would expect, but the clock doesn't budge. Do I have to update or refresh something in order to activate the new position? I've found lots of things that explain how to move elements around that are coded (i think) the same as I have, but no examples of canvases specifically - so maybe a canvas doesn't work this way?
Thanks!

You have to make sure that you canvas has style position, and its value should be fixed, absolute or relative, so the style.left/right/top/bottom would work. If you don't assign any position value to the canvas's style, it's default is static. And the top, right, bottom, left and z-index properties do not apply on elements whose position is static.
I've created a snippet to show how that works. You can find more from MDN-style-position
var i;
var cv, ctx, grd;
for (i = 1; i <= 3; ++i) {
cv = document.getElementById('move' + i);
ctx = cv.getContext('2d');
grd = ctx.createRadialGradient(75, 75, 10, 75, 75, 75);
grd.addColorStop(0, 'red');
grd.addColorStop(0.2, 'red');
grd.addColorStop(0.4, 'yellow');
grd.addColorStop(0.6, 'green');
grd.addColorStop(0.8, 'blue');
grd.addColorStop(1, 'purple');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 150, 150);
}
var last = false;
// Alter each canvas' top style to change its position.
setInterval(function(){
var cv, ctx, grd;
var top = last ? '300px': '';
last = !last;
for (i = 1; i <= 3; ++i) {
cv = document.getElementById('move' + i);
cv.style.top = top;
}
}, 1000);
#move1 {}
#move2 {
position: relative;
}
#move3 {
position: absolute;
}
<canvas id="move1" width="150" height="150"></canvas><!-- position is default: static -->
<canvas id="move2" width="150" height="150"></canvas><!-- position is relative-->
<canvas id="move3" width="150" height="150"></canvas><!-- position is absolute -->

Related

how to hide dynamically created canvas objects after reaching the end of the screen

I've created HTML5 canvas objects dynamically, by cloning them at a set interval of time. Now, I need to make each of them disappear after they reach the end of the screen. This is the code I've used to create the canvas objects.
HTML code
<html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8" src="cordova-1.7.0.js"></script>
<br><br>
<script src="myjs1.js"></script>
<canvas id="test" class="test"></canvas>
</body>
</html>
MYJS1.JS file
$(document).ready(function(){
var c = document.getElementById("test");
var ctx=c.getContext("2d");
var h=ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)';
ctx.fillRect(20, 20, 150, 100);
ctx.font="30px Arial";
ctx.fillText(0,250,75);
ctx.stroke();
setInterval(function() {
var el = $("#test"),
newone = el.clone(true);
el.before(newone);
},5000);
var i=0;
setInterval(function() {
i++;
var e = document.getElementById("test");
var ctx2 = e.getContext("2d");
ctx2.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)';
ctx2.fillRect(20, 20, 150, 100);
ctx2.font="30px Arial";
ctx2.fillText(i,250,75 );
ctx2.stroke();
},5000);
});
If I use the following code, it's stopping the blocks from being created after the given condition, not making the first created block disappear.
if(i>10){
$('#test:first').remove();
}
'#test:last' also gives the same result.
Can someone please help me out.

Hide divs under blackness and reveal items below with a gradient circle when hover

I have this idea, in which you can only see blackness on the site, but when you hover on it with your mouse it shows a radial gradient white circle that reveals the menu items beneath it, such as "contact", "info", and "products". And when you click on "products" all the items on the page appears, but still they are hidden under the blackness and only show when you hover on it. If you click on any of the products, you can go to product page through the a tag link.
So I get the both parts - 1) reveal things with gradient circle, and 2) products shown after clicking on "products" - to work, but the canvas part with the gradient just get stuck when the products appear. That's probably because I tried to do it in a hacky way by separating these two interactions, as follows:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/normalize.css">
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
</head>
<body>
<div id="menu">
<div class="menu-item" id="products"><a>Products</a></div>
<div class="menu-item" id="contact">News</div>
</div>
<script>
// create a full screen canvas
var canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.left = "0px";
canvas.style.top = "0px";
canvas.style.zIndex = 10;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
// var to hold context
var ctx;
// load an image
var image = new Image();
image.src = "./assets/images/white.jpg";
// add resize event
var resize = function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext("2d");
}
// add mouse event. Because it is full screen no need to bother with offsets
var mouse = function(event){
posX = event.clientX;
posY = event.clientY;
}
// incase the canvas size is changed
window.addEventListener("resize",resize);
// listen to the mouse move
canvas.addEventListener("mousemove",mouse);
// Call resize as that gets our context
resize();
// define the gradient
var cirRadius = 300;
var posX = 100; // this will be set by the mouse
var posY = 100;
var RGB = [11,11,11] ; // black any values from 0 to 255
// var alphas = [0,0,0.2,0.5,0.9,0.95,1]; // zero is transparent one is not
var alphas = [0,0,0.1,0.5,1];
// the update function
var update = function(){
if(ctx){ // make sure all is in order..
if(image.complete){ // draw the image when it is ready
ctx.drawImage(image,0,0,canvas.width,canvas.height)
}else{ // while waiting for image clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
}
// create gradient
var grad = ctx.createRadialGradient(posX,posY,0,posX,posY,cirRadius);
// add colour stops
var len = alphas.length-1;
alphas.forEach((a,i) => {
grad.addColorStop(i/len,`rgba(${RGB[0]},${RGB[1]},${RGB[2]},${a})`);
});
// set fill style to gradient
ctx.fillStyle = grad;
// render that gradient
ctx.fillRect(0,0,canvas.width,canvas.height);
}
requestAnimationFrame(update); // keep doing it till cows come home.
}
// start it all happening;
requestAnimationFrame(update);
</script>
<script>
$("#products").click(function(){
$("#products").remove();
var diagram = document.createElement("div");
diagram.style.position = "absolute";
diagram.style.left = "0px";
diagram.style.top = "0px"
diagram.style.zIndex = 100;
diagram.style.width = window.innerWidth + "px";
diagram.style.height = window.innerHeight + "px";
document.body.appendChild(diagram);
var products = [{
titleShort: "Black",
mainImage: "N/A",
link: "./black.html"
}, {
titleShort: "White",
mainImage: "N/A",
link: "./white.html"
}, {
titleShort: "Red",
mainImage: "N/A",
link: "./red.html"
}, {
titleShort: "Blue",
mainImage: "N/A",
link: "./blue.html"
}]
for (var i = 0; i < products.length; i++) {
var product = document.createElement("div");
diagram.appendChild(product);
productstyle.position = "absolute";
product.style.width = "120px";
product.style.height = "50px";
product.style.top = i * 100 + "px";
product.style.left = i * 100 + "px";
product.style.textAlign = "center";
var circle = document.createElement("a");
circle.style.width = "15px";
circle.style.height = "15px";
circle.style.borderRadius = "50%";
circle.style.backgroundColor = "black";
circle.style.marginLeft = "auto";
circle.style.marginRight = "auto";
circle.href = products[i].link;
product.appendChild(circle);
}
});
</script>
</body>
</html>
Note: all the products are just represented by the dots/circles for sake of convenience.
It's probably best if I merge two parts into one canvas. For example, right now we have that white image as the background for the canvas, if in some ways we can update the image with the products? But I'm very new to canvas and therefore not sure how to do this. Any other suggestions welcome as well.
You could use a div (a) with display none, border radius 50%, an insanely high value for border (solid, black), position fixed and a high z-index. Then use a second div (b) with width 100%, height 100%, background black and also position fixed and a high z-index.
Your "hotspots" have a mouseon handler on it on which you set the position of "a" to the position of the hotspot, set it to display block and set "b" to display none.
A mouseout event then does everything backwards.
Now most people would mislike the idea of a imense border, but hey: it's not like it takes more traffic than any other border and it should be way more performant than to use canvases aswell as way less code.
P.s.: sry i can't provide any code samples since I'm on mobile. This also explains the typos. If you like the idea I (or someone in the comments) can write you a quick fiddle. Also if you are using a js library (like jQuery for example) we can consider this in the snippets.
Edit 1: sorry, I didn't noticed your code already contained the jQuery include. This should make the js part just a few lines...
Also with a little extra code you can have transitions, gradients,.... any fancyness you like

Javascript canvas animating

I want to make a loading bar for my web application and I want to use a html canvas for this. This is the script that I use to fill up the canvas:
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
var xPos = 0;
draw = function() {
if(xPos < 300){
c.rect(0, 0, xPos, 30);
c.fill(255,0,0);
xPos += 0.5;
}
};
</script>
I tested this code on a online code converter (khan academy) and it worked (of course without the first 2 lines and c. in front of most things), and that is also my trouble I don't know where I have to put c. in front of?
I simplified the page a little bit:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<canvas id="bar"></canvas>
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#ff0000"
draw = function(){
if(xPos < 300){
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
}
};
</script>
</body>
</html>
Whatever you are trying to draw... this:
draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
}
};
... it is a definition of variable in global context (context of window object), then assigning a function to it. That's all - it only defines the behavior.
What you need also needs to execute that (a sidenote: to execute it after the canvas is actually created - when you put code in a script tag after canvas tag - it's sufficient and you did it already).
To execute the function use:
draw();
Or don't wrap code in function at all (unless it's to be called multiple times).
Or use a syntax construct to execute the function created in place like this:
(draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
setTimeout(draw,15); // use this to achieve animation effect
}
})();
var xPos = 0;
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#FF0000";
var draw;
(draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
setTimeout(draw,15);
}
})();
#bar {
width: 300px;
height: 50px;
}
<canvas id="bar"></canvas>
Edit: I've been thinking of what you might need, as it's not entirely abvious what you want. I have created this jsfiddle. Maybe it'll be of any help.
Hmmm...
You got some things mixed up. Try this:
<html>
<canvas id = "cvs1" width = "300" height = "30"></canvas>
</html>
And for the script:
var c = document.getElementById("cvs1").getContext("2d");
c.fillStyle = "#ff0000" //Set Fill Color(Set to red)
if(xPos < 300){
c.fillRect(xPos, 0, 30, 30);
xPos += 0.5;
}
If not:
What you did was use fill and rect seperately. You need to set the color, and then use the fillRect() function to draw the rectangle.
EDIT: You got the x,y,width,height as width,height,x,y. Fixed answer.
Good luck!
You need to call draw for every animation step. You could do this using setTimeout, setInterval or requestAnimationFrame :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<canvas id="bar"></canvas>
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#ff0000";
xPos=0;
draw = function(){
if(xPos < 300){
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
requestAnimationFrame(draw);
}
};
requestAnimationFrame(draw);
</script>
</body>
</html>

html5 canvas context .fillStyle not working

Just giving canvas a go for the first time with the intention of creating a game. I have an image displaying but oddly the fillStyle method doesn't seem to be working. ( At least the canvas background is still white in google chrome.)
Note that in my code the canvas var is actually the canvas elements 2d context, maybe that's where i'm getting myself confused? i can't see the problem, would appreciate if anyone else could.
LD24.js:
const FPS = 30;
var canvasWidth = 0;
var canvasHeight = 0;
var xPos = 0;
var yPos = 0;
var smiley = new Image();
smiley.src = "http://javascript-tutorials.googlecode.com/files/jsplatformer1-smiley.jpg";
var canvas = null;
window.onload = init; //set init function to be called onload
function init(){
canvasWidth = document.getElementById('canvas').width;
canvasHeight = document.getElementById('canvas').height;
canvas = document.getElementById('canvas').getContext('2d');
setInterval(function(){
update();
draw();
}, 1000/FPS);
}
function update(){
}
function draw()
{
canvas.clearRect(0,0,canvasWidth,canvasHeight);
canvas.fillStyle = "#FFAA33"; //orange fill
canvas.drawImage(smiley, xPos, yPos);
}
LD24.html:
<html>
<head>
<script language="javascript" type="text/javascript" src="LD24.js"></script>
</head>
<body>
<canvas id="canvas" width="800" height="600">
<p> Your browser does not support the canvas element needed to play this game :(</p>
</canvas>
</body>
</html>
3 notes:
fillStyle does not cause your canvas to be filled. It means that when you fill a shape it will be filled with that color. Therefore you need to write canvas.fillRect( xPos, yPos, width, height).
Wait until your image actually loads, otherwise the rendering may be inconsistent or buggy.
Careful of cross-domain images used in your canvas - most browsers will throw a security exception and stop executing your code.
Wait till image loads as well:
var img = new Image();
img.onload = function() {
handleLoadedTexture(img);
};
img.src = "image.png";
function handleLoadedTexture(img) {
//call loop etc that uses image
};
Or maybe you were just missing
canvas.fill();
after
canvas.drawImage(smiley, xPos, yPos);

Use <canvas> as a CSS background

Can I use the canvas element as a css background?
This has been possible in WebKit since 2008, see here.
<html>
<head>
<style>
div { background: -webkit-canvas(squares); width:600px; height:600px; border:2px solid black }
</style>
<script type="application/x-javascript">
function draw(w, h) {
var ctx = document.getCSSCanvasContext("2d", "squares", w, h);
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, 55, 50);
}
</script>
</head>
<body onload="draw(300, 300)">
<div></div>
</body>
</html>
Currently, Firefox 4 contains a feature, which allows you to use any element (including canvas) as a CSS background, in this fashion:
<p id="myBackground1" style="background: darkorange; color: white; width: 300px; height: 40px;">
This element will be used as a background.
</p>
<p style="background: -moz-element(#myBackground1); padding: 20px 10px; font-weight: bold;">
This box uses #myBackground1 as its background!
</p>
See Mozilla hacks for specifics.
Yes!!!! You can put a canvas in CSS background.
var Canvas = document.createElement("canvas");
... do your canvas drawing....
$('body').css({'background-image':"url(" + Canvas.toDataURL("image/png")+ ")" });
I know this is a pretty old question but I felt like posting my answer for people who'd visit this page because this is the correct answer, in just one line of code, using the .toDataURL function. It works in every browser that supports canvas.
I think the closest you could get is to render into a canvas, call toDataUrl() on it to retrieve the contents as an image, and assignment that result to the desired element's background-image property. This will only give a static background, though. If you want to be able to further update the canvas, however, then you'll need to instead position the canvas behind another element, as Johan has already suggested.
I've been triying to achieve this same feature past weeks, the best solution I've found its the same proposed by bcat:
Render canvas (visible or hidden)
Get canvas image with "canvas.toDataURL"
Asign this image-data as background image for the element (I use MooTools)
The bad news, for static images works great, but with animation in Chrome sometimes "blinks", and in Firefox blinks-a-lot. Maybe someone knows a workaround to get rid of this "nasty blinking".
Best regards.
P:.
<!DOCTYPE html>
<html>
<head>
<title>Asign canvas to element background</title>
<script type="text/javascript" src="/js/mootools.1.2.4.js"></script>
<style type="text/css">
* {
outline:0;
padding:0;
margin:0;
border:0;
}
body {
color:#fff;
background:#242424;
}
</style>
<script>
window.addEvent('domready',function() {
//GET BODY
var mibodi = $('mibodi');
var viewportSize = mibodi.getSize();
//GET CANVAS
var micanvas = $('micanvas');
var ctx = micanvas.getContext('2d');
var playAnimation = true;
//GET DIV
var midiv = $('midiv');
//VARIABLES
var rotate_angle = 0;
var rotate_angle_inc = 0.05;
//FUNCIÓN DE INICIALIZACIÓN
function init(){
ctx.clearRect (0, 0, 512, 512); //CLEAR CANVAS
ctx.fillStyle = 'rgba(128,128,128,1)';
ctx.strokeStyle = 'rgba(255,255,255,1)';
if (playAnimation) {
setInterval(draw,100);//
}
} //INIT
//FUNCIÓN DE DIBUJADO
function draw() {
//CLEAR BACKGROUND
ctx.clearRect (0, 0, 512, 512);
//DRAW ROTATING RECTANGLE
ctx.save();
ctx.translate( micanvas.width / 2, micanvas.height / 2 );
ctx.rotate( rotate_angle );
ctx.fillRect(0, 0, 100, 100);
ctx.restore();
//GET CANVAS IMAGE
var dataURL = micanvas.toDataURL("image/png");
//SET IMAGE AS BACKGROUND OF THE ELEMENTS
midiv.setStyle('background-image', 'url(' + dataURL + ')');
mibodi.setStyle('background-image', 'url(' + dataURL + ')');
//ANGLE INCREMENT
rotate_angle = rotate_angle + rotate_angle_inc;
} //DRAW
//BEGIN TO DRAW
init();
});//domeady
</script>
</head>
<body id="mibodi" >
<canvas id="micanvas" width="512" height="512" style="float:left;" style="display:none;">
Este texto se muestra para los navegadores no compatibles con canvas.
<br>
Por favor, utiliza Firefox, Chrome, Safari u Opera.
</canvas>
<div id="midiv" style="width:512px;height:512px;background:#f00;float:left;">
Sample
</div>
</body>
</html>
Try -moz-element(#id) for CSS background in Firefox.
And -webkit-canvas(name) for CSS background in WebKit based browsers.
You can use CSS Paint API
.elem {
backgound: paint(squares);
}
See more details here:
Blog posts:
https://vitaliy-bobrov.github.io/blog/exploring-the-css-paint-api/
https://vitaliy-bobrov.github.io/blog/css-paint-in-action-bar-chart/
Demos: https://vitaliy-bobrov.github.io/css-paint-demos/
You can emulate this behavior quickly without the performance drop of toDataURL() using z-index (granted, it's a workaround, since CSS images 4 / CSS Houdini hasn't implemented "background: element(#mycanvas)" as of 2017))
Working JSFiddle here. I didn't write this, all credit goes to Derek Leung:
http://jsfiddle.net/DerekL/uw5XU/
Unable to comment so I will create my own answer for this.
This answer is based off of #livedo, #Eric Rowell, and #shabunc
http://jsfiddle.net/MDooley47/yj26psdb/
window.i = 0;
function draw(w, h) {
window.i+=5;
if (window.webkitURL != null) {
var ctx = document.getCSSCanvasContext("2d", "squares", 100, 100);
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, w, h);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, w, h);
}
else {
var ctxmozc = document.getElementById("squares");
var ctxmoz = ctxmozc.getContext("2d");
ctxmoz.fillStyle = "rgb(200,0,0)";
ctxmoz.fillRect (10, 10, w, h);
ctxmoz.fillStyle = "rgba(0, 0, 200, 0.5)";
ctxmoz.fillRect (30, 30, w, h);
}
}
setInterval(function(){draw(window.i, window.i);}, 500);
div {
background: -webkit-canvas(squares);
background: -moz-element(#squares) repeat-x;
width:575px;
height:475px;
border:2px solid black
}
<body>
<div></div>
<canvas id="squares" name="squaresmoz" style="display: none;" ></canvas>
</body>

Categories

Resources