We need to implement a screen saver which should have 3 images.
The bottom image should be fixed.
Middle image will be moving.
Top image will be moving at relatively higher speed.
We created 3 divs to handle the images as below.
<!DOCTYPE html>
<html>
<head>
<title>Moving Screen Saver</title>
<style>
html, body {
position: relative;
height: 100%;
width: 100%;
}
#bgimg {
background-image: url("background/moon_bg.png");
position: absolute;
background-repeat: no-repeat;
background-size: cover;
width: 100%;
height: 100%;
}
.animator {
width: 100vw;
height: 100vh;
}
#poster {
background-image: url("posters/gladiator.png");
position: absolute;
background-position:right 20px bottom 20px;
background-repeat: no-repeat;
width: 100%;
height: 100%;
background-color: transparent;
}
</style>
</head>
<body>
<div id="bgimg"></div>
<div class="animator"></div>
<div id="poster"></div>
<script>
var poster = document.getElementById('poster');
var animate;
function moveRight()
{
poster.style.left = poster.style.left || 0;
poster.style.left = parseInt(poster.style.left) - 10 + 'px';
requestAnimationFrame(moveRight);
}
moveRight();
function rollAnimate(element, url) {
if(!element instanceof HTMLElement)
return;
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
var x = 0;
var pattern;
var framesPerSec = 10;
img.onload = startDrawing;
img.onerror = console.error;
img.src = url;
canvas.style.cssText = 'position:absolute;'
function startDrawing() {
element.insertBefore(canvas, element.firstChild);
pattern = ctx.createPattern(img, 'repeat');
resize();
anim();
window.addEventListener('resize', resize, {passive: true});
}
function anim() {
x = (x - 1) % img.width;
ctx.setTransform(1,0,0,1,x,(canvas.height) - (img.height));
ctx.fill();
setTimeout(function() {
requestAnimationFrame(anim);
}, 1000 / framesPerSec);
}
function resize(evt) {
canvas.width = element.offsetWidth;
canvas.height = element.offsetHeight;
ctx.fillStyle = pattern;
ctx.rect(0, canvas.height - img.height, canvas.width, img.height);
ctx.globalCompositeOperation = 'copy';
}
}
rollAnimate(document.querySelector('.animator'), 'buildings/mod_cropped.png');
</script>
</body>
</html>
lower image - bgimg
middle image - animator
top image - poster
We are able to see lower image which is fixed and middle image which is moving. But poster image is not visible. We are thinking that this is because when we are trying to paint middle image it is replacing top image. Can any one please help me to fix this issue.
Below is jsfiddle page
https://jsfiddle.net/n76epste/10/
So when I look, you are actually getting all 3 images. Your issue is the poster moves off screen super fast and never returns.
bgimg is static and covered by animator (you can see this by deleting animator)
animator is animated and repeating and cover bgimage
poster is given an ever updating style="left: -***px" where * is an increasing number. (You can see this for a split second when loading the page if you hide bgimg and animator with css)
This is because of Z-index. I changed z-index of poster dev tp the highest to fix the problem.
I want to create a media control bar for a video player with the controls blurring the background. Currently I can get the glassy look but I can't get blurring to work.
I tried following this guide: https://medium.com/#AmJustSam/how-to-do-css-only-frosted-glass-effect-e2666bafab91 but it seems like it only works on static images.
Here's an example of what I want:
I also saw the webkit backdrop-filter which looks perfect but it's only stable on safari so I can't use that. Any advice for frosted glass on dynamic videos?
I was able to accomplish this by copying the bottom part of the video to a canvas every frame and blurring the canvas via CSS. It seems to work well in Chrome, but flashes sometimes in Firefox. Doing the blur programmatically in the canvas with something like Superfast Blur might be more performant, but that's an experiment for another day. Tomorrow, probably.
function initControls (player, blurRadius, controlHeight, videoWidth, videoHeight) {
// crop player to video size
let video = player.querySelector('video');
videoWidth = videoWidth || video.clientWidth;
videoHeight = videoHeight || video.clientHeight;
player.style.width = videoWidth + 'px';
player.style.height = videoHeight + 'px';
// crop control bar to video size
let controlBar = player.querySelector('.control-bar');
controlBar.style.width = videoWidth + 'px';
controlBar.style.height = controlHeight + 'px';
// canvas needs to be slightly taller than what gets displayed
// to blur cleanly
let canvas = player.querySelector('canvas');
canvas.width = videoWidth;
canvas.height = 2 * blurRadius + controlHeight;
canvas.style.filter = `blur(${blurRadius}px)`;
canvas.style.top = -2 * blurRadius + 'px';
// copy video to canvas
let ctx = canvas.getContext('2d');
let videoCropY = videoHeight - canvas.height;
function updateCanvas () {
ctx.drawImage(
video,
0, videoCropY, canvas.width, canvas.height,
0, 0, canvas.width, canvas.height
);
}
// update the canvas only when necessary
let hovering = false;
function renderLoop () {
updateCanvas();
if (hovering && !video.paused) {
window.requestAnimationFrame(renderLoop);
}
}
// no point in rendering to a canvas you can't see
player.addEventListener('mouseenter', () => {
hovering = true;
renderLoop();
});
player.addEventListener('mouseleave', () => { hovering = false; });
video.addEventListener('play', renderLoop);
}
document.addEventListener('DOMContentLoaded', event => {
// do the magic
initControls(document.querySelector('.player'), 4, 50, 320, 240);
// basic play button functionality
document.querySelector('.play-button').addEventListener('click', event => {
let v = event.target.closest('.player').querySelector('video');
if (v.ended) v.currentTime = 0;
if (v.paused) {
v.play();
} else {
v.pause();
}
});
});
/* styling required for blurred control background */
.player {
position: relative;
}
.player > video {
margin: 0;
display: block;
}
.control-bar > canvas {
margin: 0;
display: block;
left: 0;
position: absolute;
}
.control-bar {
margin: 0;
overflow: hidden;
position: absolute;
bottom: 0;
/* height of control bar is specified in javascript, sorry about that */
}
/* simple control-hiding mechanism; other methods also work */
/* javascript relies on mouseover and mouseout to decide whether to update canvas */
.player > .control-bar {
display: none;
}
.player:hover > .control-bar {
display: block;
}
/* styling actual controls; adjust to taste */
.play-button {
height: 30px;
line-height: 30px;
width: 100px;
color: white;
border: 1px solid white;
position: absolute;
top: 10px;
left: 50%;
margin-left: -50px;
text-align: center;
}
<div class="player">
<video src="https://archive.org/download/MedicalA1950/MedicalA1950_512kb.mp4"></video>
<div class="control-bar">
<canvas></canvas>
<div class="play-button">PLAY/PAUSE</div>
</div>
</div>
How can I automatically scale the HTML5 <canvas> element to fit the page?
For example, I can get a <div> to scale by setting the height and width properties to 100%, but a <canvas> won't scale, will it?
I believe I have found an elegant solution to this:
JavaScript
/* important! for alignment, you should make things
* relative to the canvas' current width/height.
*/
function draw() {
var ctx = (a canvas context);
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
//...drawing code...
}
CSS
html, body {
width: 100%;
height: 100%;
margin: 0;
}
Hasn't had any large negative performance impact for me, so far.
The following solution worked for me the best. Since I'm relatively new to coding, I like to have visual confirmation that something is working the way I expect it to. I found it at the following site:
http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/
Here's the code:
(function() {
var
// Obtain a reference to the canvas element using its id.
htmlCanvas = document.getElementById('c'),
// Obtain a graphics context on the canvas element for drawing.
context = htmlCanvas.getContext('2d');
// Start listening to resize events and draw canvas.
initialize();
function initialize() {
// Register an event listener to call the resizeCanvas() function
// each time the window is resized.
window.addEventListener('resize', resizeCanvas, false);
// Draw canvas border for the first time.
resizeCanvas();
}
// Display custom canvas. In this case it's a blue, 5 pixel
// border that resizes along with the browser window.
function redraw() {
context.strokeStyle = 'blue';
context.lineWidth = '5';
context.strokeRect(0, 0, window.innerWidth, window.innerHeight);
}
// Runs each time the DOM window resize event fires.
// Resets the canvas dimensions to match window,
// then draws the new borders accordingly.
function resizeCanvas() {
htmlCanvas.width = window.innerWidth;
htmlCanvas.height = window.innerHeight;
redraw();
}
})();
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
/* Disable scrollbars */
display: block;
/* No floating content on sides */
}
<canvas id='c' style='position:absolute; left:0px; top:0px;'></canvas>
The blue border shows you the edge of the resizing canvas, and is always along the edge of the window, visible on all 4 sides, which was NOT the case for some of the other above answers. Hope it helps.
Basically what you have to do is to bind the onresize event to your body, once you catch the event you just need to resize the canvas using window.innerWidth and window.innerHeight.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Canvas Resize</title>
<script type="text/javascript">
function resize_canvas(){
canvas = document.getElementById("canvas");
if (canvas.width < window.innerWidth)
{
canvas.width = window.innerWidth;
}
if (canvas.height < window.innerHeight)
{
canvas.height = window.innerHeight;
}
}
</script>
</head>
<body onresize="resize_canvas()">
<canvas id="canvas">Your browser doesn't support canvas</canvas>
</body>
</html>
Setting the canvas coordinate space width and height based on the browser client's dimensions requires you to resize and redraw whenever the browser is resized.
A less convoluted solution is to maintain the drawable dimensions in Javascript variables, but set the canvas dimensions based on the screen.width, screen.height dimensions. Use CSS to fit:
#containingDiv {
overflow: hidden;
}
#myCanvas {
position: absolute;
top: 0px;
left: 0px;
}
The browser window generally won't ever be larger than the screen itself (except where the screen resolution is misreported, as it could be with non-matching dual monitors), so the background won't show and pixel proportions won't vary. The canvas pixels will be directly proportional to the screen resolution unless you use CSS to scale the canvas.
A pure CSS approach adding to solution of #jerseyboy above.
Works in Firefox (tested in v29), Chrome (tested in v34) and Internet Explorer (tested in v11).
<!DOCTYPE html>
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
canvas {
background-color: #ccc;
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.fillRect(25,25,100,100);
ctx.clearRect(45,45,60,60);
ctx.strokeRect(50,50,50,50);
}
</script>
</body>
</html>
Link to the example: http://temporaer.net/open/so/140502_canvas-fit-to-window.html
But take care, as #jerseyboy states in his comment:
Rescaling canvas with CSS is troublesome. At least on Chrome and
Safari, mouse/touch event positions will not correspond 1:1 with
canvas pixel positions, and you'll have to transform the coordinate
systems.
function resize() {
var canvas = document.getElementById('game');
var canvasRatio = canvas.height / canvas.width;
var windowRatio = window.innerHeight / window.innerWidth;
var width;
var height;
if (windowRatio < canvasRatio) {
height = window.innerHeight;
width = height / canvasRatio;
} else {
width = window.innerWidth;
height = width * canvasRatio;
}
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
};
window.addEventListener('resize', resize, false);
Set initial size.
const canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Update size on window resize.
function windowResize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.addEventListener('resize', windowResize);
2022 answer
The recommended way in 2022 to check if an element resized is to use ResizeObserver
const observer = new ResizeObserver(myResizeTheCanvasFn);
observer.observe(someCanvasElement);
It's better than window.addEventListener('resize', myResizeTheCanvasFn) or onresize = myResizeTheCanvasFn because it handles EVERY case of the canvas resizing, even when it's not related to the window resizing.
Similarly it makes no sense to use window.innerWidth, window.innerHeight. You want the size of the canvas itself, not the size of the window. That way, no matter where you put the canvas you'll get the correct size for the situation and won't have to re-write your sizing code.
As for getting the canvas to fill the window
html, body {
height: 100%;
}
canvas {
width: 100%;
height: 100%;
display: block; /* this is IMPORTANT! */
}
The reason you need display: block is because by default the canvas is inline which means it includes extra space at the end. Without display: block you'll get a scrollbar. Many people fix the scrollbar issue by adding overflow: hidden to the body of the document but that's just hiding the fact that the canvas's CSS was not set correctly. It's better to fix the bug (set the canvas to display: block than to hide the bug with overflow: hidden
Full example
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const observer = new ResizeObserver((entries) => {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
});
observer.observe(canvas)
// not import but draw something just to showcase
const hsla = (h, s, l, a) => `hsla(${h * 360}, ${s * 100}%, ${l * 100}%, ${a})`;
function render(time) {
const {width, height} = canvas;
ctx.clearRect(0, 0, width, height);
ctx.save();
ctx.translate(width / 2, height / 2);
ctx.rotate(time * 0.0001);
const range = Math.max(width, height) * 0.8;
const size = 64 + Math.sin(time * 0.001) * 50;
for (let i = 0; i < range; i += size) {
ctx.fillStyle = hsla(i / range * 0.3 + time * 0.0001, 1, 0.5, 1);
ctx.fillRect( i, -range, size, range * 2);
ctx.fillRect(-i, -range, size, range * 2);
}
ctx.restore();
requestAnimationFrame(render)
}
requestAnimationFrame(render)
html, body {
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display: block;
}
<canvas></canvas>
Note: there are other issues related to resizing the canvas. Specifically if you want to deal with different devicePixelRatio settings. See this article for more.
Unless you want the canvas to upscale your image data automatically (that's what James Black's answer talks about, but it won't look pretty), you have to resize it yourself and redraw the image. Centering a canvas
If your div completely filled the webpage then you can fill up that div and so have a canvas that fills up the div.
You may find this interesting, as you may need to use a css to use percentage, but, it depends on which browser you are using, and how much it is in agreement with the spec:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#the-canvas-element
The intrinsic dimensions of the canvas
element equal the size of the
coordinate space, with the numbers
interpreted in CSS pixels. However,
the element can be sized arbitrarily
by a style sheet. During rendering,
the image is scaled to fit this layout
size.
You may need to get the offsetWidth and height of the div, or get the window height/width and set that as the pixel value.
CSS
body { margin: 0; }
canvas { display: block; }
JavaScript
window.addEventListener("load", function()
{
var canvas = document.createElement('canvas'); document.body.appendChild(canvas);
var context = canvas.getContext('2d');
function draw()
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.moveTo(0, 0); context.lineTo(canvas.width, canvas.height);
context.moveTo(canvas.width, 0); context.lineTo(0, canvas.height);
context.stroke();
}
function resize()
{
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
draw();
}
window.addEventListener("resize", resize);
resize();
});
If you're interested in preserving aspect ratios and doing so in pure CSS (given the aspect ratio) you can do something like below. The key is the padding-bottom on the ::content element that sizes the container element. This is sized relative to its parent's width, which is 100% by default. The ratio specified here has to match up with the ratio of the sizes on the canvas element.
// Javascript
var canvas = document.querySelector('canvas'),
context = canvas.getContext('2d');
context.fillStyle = '#ff0000';
context.fillRect(500, 200, 200, 200);
context.fillStyle = '#000000';
context.font = '30px serif';
context.fillText('This is some text that should not be distorted, just scaled', 10, 40);
/*CSS*/
.container {
position: relative;
background-color: green;
}
.container::after {
content: ' ';
display: block;
padding: 0 0 50%;
}
.wrapper {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
canvas {
width: 100%;
height: 100%;
}
<!-- HTML -->
<div class=container>
<div class=wrapper>
<canvas width=1200 height=600></canvas>
</div>
</div>
Using jQuery you can track the window resize and change the width of your canvas using jQuery as well.
Something like that
$( window ).resize(function() {
$("#myCanvas").width($( window ).width())
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;">
Here's a tiny, complete Code Snippet that combines all the answers. Press: "Run Code Snippet" then press "Full Page" and resize the window to see it in action:
function refresh(referenceWidth, referenceHeight, drawFunction) {
const myCanvas = document.getElementById("myCanvas");
myCanvas.width = myCanvas.clientWidth;
myCanvas.height = myCanvas.clientHeight;
const ratio = Math.min(
myCanvas.width / referenceWidth,
myCanvas.height / referenceHeight
);
const ctx = myCanvas.getContext("2d");
ctx.scale(ratio, ratio);
drawFunction(ctx, ratio);
window.requestAnimationFrame(() => {
refresh(referenceWidth, referenceHeight, drawFunction);
});
}
//100, 100 is the "reference" size. Choose whatever you want.
refresh(100, 100, (ctx, ratio) => {
//Custom drawing code! Draw whatever you want here.
const referenceLineWidth = 1;
ctx.lineWidth = referenceLineWidth / ratio;
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.arc(50, 50, 49, 0, 2 * Math.PI);
ctx.stroke();
});
div {
width: 90vw;
height: 90vh;
}
canvas {
width: 100%;
height: 100%;
object-fit: contain;
}
<div>
<canvas id="myCanvas"></canvas>
</div>
This snippet uses canvas.clientWidth and canvas.clientHeight rather than window.innerWidth and window.innerHeight to make the snippet run inside a complex layout correctly. However, it works for full window too if you just put it in a div that uses full window. It's more flexible this way.
The snippet uses the newish window.requestAnimationFrame to repeatedly resize the canvas every frame. If you can't use this, use setTimeout instead. Also, this is inefficient. To make it more efficient, store the clientWidth and clientHeight and only recalculate and redraw when clientWidth and clientHeight change.
The idea of a "reference" resolution lets you write all of your draw commands using one resolution... and it will automatically adjust to the client size without you having to change the drawing code.
The snippet is self explanatory, but if you prefer it explained in English: https://medium.com/#doomgoober/resizing-canvas-vector-graphics-without-aliasing-7a1f9e684e4d
A bare minimum setup
HTML
<canvas></canvas>
CSS
html,
body {
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display: block;
}
JavaScript
const canvas = document.querySelector('canvas');
const resizeObserver = new ResizeObserver(() => {
canvas.width = Math.round(canvas.clientWidth * devicePixelRatio);
canvas.height = Math.round(canvas.clientHeight * devicePixelRatio);
});
resizeObserver.observe(canvas);
For WebGL
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const resizeObserver = new ResizeObserver(() => {
canvas.width = Math.round(canvas.clientWidth * devicePixelRatio);
canvas.height = Math.round(canvas.clientHeight * devicePixelRatio);
gl.viewport(0, 0, canvas.width, canvas.height);
});
resizeObserver.observe(canvas);
Notice that we should take device pixel ratio into account, especially for HD-DPI display.
I think this is what should we exactly do: http://www.html5rocks.com/en/tutorials/casestudies/gopherwoord-studios-resizing-html5-games/
function resizeGame() {
var gameArea = document.getElementById('gameArea');
var widthToHeight = 4 / 3;
var newWidth = window.innerWidth;
var newHeight = window.innerHeight;
var newWidthToHeight = newWidth / newHeight;
if (newWidthToHeight > widthToHeight) {
newWidth = newHeight * widthToHeight;
gameArea.style.height = newHeight + 'px';
gameArea.style.width = newWidth + 'px';
} else {
newHeight = newWidth / widthToHeight;
gameArea.style.width = newWidth + 'px';
gameArea.style.height = newHeight + 'px';
}
gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';
var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;
}
window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
(function() {
// get viewport size
getViewportSize = function() {
return {
height: window.innerHeight,
width: window.innerWidth
};
};
// update canvas size
updateSizes = function() {
var viewportSize = getViewportSize();
$('#myCanvas').width(viewportSize.width).height(viewportSize.height);
$('#myCanvas').attr('width', viewportSize.width).attr('height', viewportSize.height);
};
// run on load
updateSizes();
// handle window resizing
$(window).on('resize', function() {
updateSizes();
});
}());
This worked for me.
Pseudocode:
// screen width and height
scr = {w:document.documentElement.clientWidth,h:document.documentElement.clientHeight}
canvas.width = scr.w
canvas.height = scr.h
Also, like devyn said, you can replace "document.documentElement.client" with "inner" for both the width and height:
**document.documentElement.client**Width
**inner**Width
**document.documentElement.client**Height
**inner**Height
and it still works.