How do I keep the canvas in the this demo centered at all times (including when the scrollbars appear) when the window is resized? The canvas element should always fill the window.
I tried playing around with settings like left, margin-left, etc. (including negative values) but to no avail.
Is this what you wanted?
This is a refactored version of your code that resizes the canvas to the smallest dimension of the window (width or height) on window resize. It also sets the display of the canvas to block and uses margin: 0 auto to center it.
Here is the demo.
UPDATE 1 I've refactored with comments to show where to change the code to resize the canvas to the largest dimension between the window height and width.
UPDATE 2 I've refactored to fit the canvas so the crosshairs are always centered by setting the width and height to the exact window.
I've also updated the CSS to remove all padding and margins.
The canvas is redrawn on window.onresize.
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
function setSize() {
var w = window.innerWidth;
var h = window.innerHeight;
//var size = (h > w) ? h : w; //<<<< resize to largest between height and width
//var size = (h < w) ? h : w; //<<<< resize to smallest between height and width
//canvas.width = size;
//canvas.height = size;
canvas.width = w; //<<<< exact resizing to width
canvas.height = h; //<<<< exact resizing to height
}
function draw() {
var context = canvas.getContext('2d');
context.fillRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = 'red';
context.moveTo(canvas.width/2, 0);
context.lineTo(canvas.width/2, canvas.height);
context.moveTo(0, canvas.height/2);
context.lineTo(canvas.width, canvas.height/2);
context.stroke();
}
setSize();
draw();
window.onresize = function(e) {
setSize();
draw();
};
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
margin: 0 auto;
}
Did you try overflow: hidden;?
JSFiddle
body {
overflow: hidden;
}
You can do something like
canvas{
position: fixed;
top: -500px;
}
To make the canvas resize with the page, try adding a window resize listener:
window.addEventListener("resize", function () {
canvas.width = window.innerWidth;
canvas.width = window.innerHeight;
});
If you want to remove margins so the canvas fills the entire page, try adding the following CSS to your page:
body {
margin: 0 !important;
padding: 0 !important;
}
After much fiddling, I think I figured it out. Here's the working demo (fullscreen version). I ended up using the following loop:
function render() {
requestAnimationFrame(render);
window.scrollTo(
document.documentElement.scrollWidth/2 - window.innerWidth/2,
document.documentElement.scrollHeight/2 - window.innerHeight/2
);
}
requestAnimationFrame(render);
which automatically scrolls the window to the middle of the entire scrollable area (including the non-visible portions) minus half the size of the viewing area itself.
Thanks to everyone for your help!
Related
i was testing some code with javascript, about resizing the html5 canvas. i've asked similar question before, when i was testing the same thing with jquery. and i've got the desired solution that time, reference (eg_1). in this (eg_1), the result was, canvas element was resizing in every frame because of requestAnimationFrame($.fn.animate); is taking place in a recursive form.the visual result for that is here the width attribute updates when i resize the console window. and if i close the console the canvas resizes automatically, i don't need to reload the window, to update the attribute values. means canvas is full screen, all time. but i am having problem with the same thing, in javascript. if i close the console, the width of the console cuts (or resizes) the canvas with a white space. here is the visual result the white space is my problem. i've to reload the window, to make the canvas full screen again. in short i'm not having the same effect as (eg_1). here i tried so far, reference (eg_2).
(eg_1)
html : <canvas></canvas>
css :
* {
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
background-color: turquoise;
}
jquery :
$(document).ready(function() {
var view = $(window),
canvas = $("canvas"),
ctx = canvas[0].getContext("2d"),
width = view.width(),
height = view.height();
$.fn.windowResize = function() {
var width = view.width();
height = view.height();
canvas.attr("width", width);
canvas.attr("height", height);
};
view.on("resize", $.fn.windowResize);
canvas.attr("width", width);
canvas.attr("height", height);
$.fn.animate = function() {
requestAnimationFrame($.fn.animate);
ctx.clearRect(0, 0, width, height);
// start here
};
$.fn.animate();
});
(eg_2)
var canvas = document.querySelectorAll("canvas")[0];
var context = canvas.getContext("2d");
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
function resize() {
setInterval(resize, 5);
clearInterval(resize);
canvas.width = windowWidth;
canvas.height = windowHeight;
}
resize();
Answer:
Your initial issue:
You need to get the updated values of window.innerWidth and window.innerHeight.
To do this you can turn the variables into functions that request the current values.
Example:
var canvas = document.querySelectorAll("canvas")[0];
var context = canvas.getContext("2d");
var windowWidth = () => window.innerWidth;
var windowHeight = () => window.innerHeight;
function resize() {
setInterval(resize, 5);
clearInterval(resize);
canvas.width = windowWidth();
canvas.height = windowHeight();
}
resize();
* {
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
background-color: turquoise;
}
<canvas></canvas>
Other issues:
Your use of Timers is incorrect. clearInterval(resize) isn't going to clear anything, because resize is not a timer itself.
Secondly you shouldn't be using any timers when rendering to Canvas. It can often lead to things like the above( multiple timers ) or issues with constant, unnecessary, re-processing.
Instead of resizing perpetually you may want to just do so when the resize event is dispatched. Even if you were using requestAnimationFrame - which would effectively stop the render if anything else takes precedence or if you switch tabs, it's an unnecessary process in that you're constantly re-rendering the same thing without cause. Canvas Apps tend to get big real quick when you add in multiple rendering functions, so you'll want to mitigate unnecessary steps.
You can do this by attaching to appropriate events and creating requestAnimationFrame helpers like in the following example:
var canvas = document.querySelectorAll("canvas")[0];
var context = canvas.getContext("2d");
var windowWidth = () => window.innerWidth;
var windowHeight = () => window.innerHeight;
var request = fn => requestAnimationFrame(fn),
requestHandler = fn => () => request(fn);
function resize() {
canvas.width = windowWidth();
canvas.height = windowHeight();
}
request(resize);
window.addEventListener("resize", requestHandler(resize) );
* {
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
background-color: turquoise;
}
<canvas></canvas>
I'm quite a noob with Pixi.js so here comes the noob question.
I'm trying to display a square in the middle of the screen. When I resize the window, the square should stay in the middle.
When drawing the square I'm using
const square = new PIXI.Graphics();
square.beginFill(0xff0000, 1);
square.drawRect(app.renderer.width /2, app.renderer.height / 2, 50, 50);
square.endFill();
app.stage.addChild(square);
Then, I understand that the x and y properties of square are relative to the initial drawing position. So square.x = 0 will keep the square in the middle.
But then, how do I reset the center of the window (and so the position of the square) when I resize it?
This can be your solution. This is diametric resize response.
I use something like :
getWidthByPer : function (per) {
return window.innerWidth / 100 * per
}
console.log = function(){};
var app = new PIXI.Application({
autoResize: true,
resolution: 1.77
});
document.querySelector("#MYAPP").appendChild(app.view);
const rect = new PIXI.Graphics()
.beginFill(0x55faaf)
.drawRect(-50, -50, 100, 100);
app.stage.addChild(rect);
window.addEventListener('resize', resize);
function resize() {
const parent = app.view.parentNode;
app.renderer.resize(parent.clientWidth, parent.clientHeight);
rect.position.set(
app.screen.width / 2 ,
app.screen.height / 2
);
}
window.onload = function(){
resize();
};
canvas {
display:block;
}
#MYAPP {
position: absolute;
overflow: hidden;
top:0%;
left:0%;
width: 100%;
height: 100%;
}
<script src="https://pixijs.download/v4.7.0/pixi.min.js"></script>
<div id="MYAPP"></div>
I made adaptive-scale to reuse common resizing needs for multiple projects
I've been trying to make a parallax-esque effect using HTML5 canvas, for various reasons. I've been using the window.scrollY property to determine how far down the user has scrolled and therefore can calculate the transformations using this value.
I suppose this is best explained through an example:
function draw() {
scrollOffset = window.scrollY;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "#000";
ctx.fillRect((width/2) - (size/2), ((height/2) - (size/2)) + scrollOffset, size, size);
requestAnimationFrame(draw);
}
As you can see, depending on what browser you use, there will be a varying level of "glitchiness" caused by you scrolling. The square in the center should remain in the same place the entire time, however there are issues with keeping up with how far the user has scrolled.
How noticeable this problem is depends on what browser you are using; Chrome is only noticeable if you change your scrolling direction in rapid succession whereas Firefox and Edge are noticeable regardless of how slowly you scroll.
Would there be a better way to go about this?
Note: Not a solution but a suggestion
The parallax should happen only when one scrolls on the page. Should be something like the snippet below:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let width;
let height;
window.addEventListener("resize", resizeCanvas);
function resizeCanvas() {
width = canvas.width = document.documentElement.clientWidth;
height = canvas.height = document.documentElement.clientHeight;
}
resizeCanvas();
let scrollOffset;
let size = 50;
function draw() {
scrollOffset = window.scrollY;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "#000";
ctx.fillRect((width/2) - (size/2), ((height/2) - (size/2)) + scrollOffset, size, size);
}
draw();
window.onscroll = function (e)
{
draw();
}
html, body {
margin: 0;
}
canvas {
display: block;
}
#padder {
height: 100vh;
background-color: #F00;
}
<canvas id="canvas"></canvas>
<section id="padder"></section>
Also, since it's browser specific, for Firefox, check scrolling options in the advanced settings or you shall try changing the mouseWheel scrolling behavior in about:config
I am not sure, how i can be more specific, but i am putting my best effort to explain it.I am trying to understand, what should i be looking for to be more specific, so this is all i have got at this moment.
I was exploring HTML5 JavaScript games, and I noticed, that making the canvas height and width 100% distorts the animation within.
a simple example that i got from here.
If i change the canvas size to 100% (in the example I have provided) it breaks the animation of the game(for example the asteroid).
I would like to know, which property of HTML5 is responsible for this behaviour and what should I be looking for to get the HTML5 animation fit the complete screen size?
EDIT
I tried to run cordova to build the game to native platform,but the 1st problem i am encountering is that the canvas was not fitting the screen size. (that's why i wanted it to completely fit the browser screen, but i see a complete misfit when a canvas made for the browser screen is rendered to the native using cordova).
I explored phaser, about how they are solving this problem, and found this game which is using something called a ScalingManager.
So, my questions are
1. What is scaling a Game?
2. How is the scaling-manager of phaser working
3. without using the scaling manager why will a game not fit the moile screen size even though the canvas height and width are properly mentioned?
4. is there a small experment (without using any phaser or similar javascript game framework) that i can do to understand the need for scaling with simple HTML5 javasctipt and cordova?
A canvas has two distinct sizes:
the size of the element on the page
the size in pixel of the canvas
To avoid distortion and get a pixel-perfect graphic you need to ensure they end up equal... for example:
function redraw() {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
...
}
For single-page HTML games where you just want to draw everything in a canvas a simple approach is:
<!DOCTYPE html>
<html>
<head>
<style type='text/css'>
* {
margin: 0;
padding: 0;
border: none;
}
body,html {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<script>
var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
var body = document.body;
body.insertBefore(canvas, body.firstChild);
var context = canvas.getContext('2d');
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = context.webkitBackingStorePixelRatio
|| context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio
|| context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;
var ratio = devicePixelRatio / backingStoreRatio;
redraw();
window.addEventListener('resize', redraw, false);
window.addEventListener('orientationchange', redraw, false);
function redraw() {
width = (window.innerWidth > 0 ? window.innerWidth : screen.width);
height = (window.innerHeight > 0 ? window.innerHeight : screen.height);
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
width *= ratio;
height *= ratio;
if (canvas.width === width && canvas.height === height) {
return;
}
canvas.width = width;
canvas.height = height;
}
//draw things
</script>
</body>
</html>
You will also need to check for changes in innerWidth / innerHeight if your app has parts in which you're just waiting for user interaction (not looping on calling redraw) and the user instead resizes the browser window or tilts the phone/tab.
With Phaser 3, I succeeded by adding window.innerWidthand window.innerHeightto the Scale object into my config :
config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-game',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: window.innerWidth,
height: window.innerHeight
},
scene: [MainScene],
parent: 'gameContainer',
physics: {
default: 'arcade',
arcade: {
gravity: {y: 0}
}
}
};
For the moment I don't see any problem, it makes the trick.
I have done a very tiny example with canvas, it's available on JsFiddle:
http://jsfiddle.net/yPtr5/
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
#myCanvas {
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<canvas id="myCanvas">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var canvas = document.getElementById( "myCanvas" );
var context = canvas.getContext( "2d" );
context.id = "myContext";
context.beginPath();
context.arc( 95, 50, 40, 0, 2 * Math.PI );
context.stroke();
setTimeout( function() {
var rectWidth = 150;
var rectHeight = 75;
context.fillStyle = "blue";
context.fillRect( rectWidth / -2, rectHeight / -2, rectWidth, rectHeight );
}, 2000 );
</script>
</body>
</html>
As you are able to see, the rendering result has a very low quality:
So, I'm wondering, how can I draw various figures using Canvas in a good quality, I don't want to draw in small size, I want to draw in 100% size of page.
So, maybe I didn't define some anti aliasing filter or something else?
Thanks!
Problem
In most general cases we should avoid using CSS to set the canvas size.
The default size of canvas is 300 x 150 pixels (bitmap). If you set the size using CSS we'll just end up scaling those 300 x 150 pixels meaning the browser will start interpolating and smoothing the image, which is why you end up with a blurry result.
Solution
Remove these from the CSS-rule:
#myCanvas {
/*width: 100%;
height: 100%;*/
display: block;
}
and set the size in JavaScript like this:
var canvas = document.getElementById( "myCanvas" );
canvas.width = window.innerWidth; // equals window dimension
canvas.height = window.innerHeight;
You can of course set any other size you need (in pixels). You probably want to define position (i.e. fixed or absolute) for the canvas' CSS as well if your goal is full window size.
Hope this helps.
The height and width need to be set on the height and width attributes of the canvas tag and not in CSS. Any CSS sizing of the canvas element merely stretches the canvas and does not size it properly.
<canvas id="canvas" width="500px" height="500px">
Have a look at this project that I posted on my site: Creating an HTML5 Paint App
It includes a functionto resize the canvas when the browser window size changes (which you would have to modify):
this.onScreenSizeChanged = function (forceResize) {
if (forceResize || (this.canvas.width != window.innerWidth /*||
this.canvas.height != window.innerHeight*/)) {
var image = this.context.getImageData(0, 0,
this.canvas.width, this.canvas.height);
this.canvas.width = (window.innerWidth);
this.canvas.height = (window.innerHeight);
this.context.putImageData(image, 0, 0);
}
}
this.onScreenSizeChanged(true);
In my case, it was a problem with the screen pixel ratio.
To solve it, I created a canvas with a higher pixel ratio as follows:
function createHiPPICanvas(w, h) {
let ratio = window.devicePixelRatio;
let cv = document.createElement("canvas");
cv.width = w * ratio;
cv.height = h * ratio;
cv.style.width = w + "px";
cv.style.height = h + "px";
cv.getContext("2d").scale(ratio, ratio);
return cv;
}
Then I also increased accordingly the pixel ratio of the images used inside of the canvas.