HTML5 canvas height and width 100% distorts the game animation - javascript

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.

Related

What is the best way to scale an Canvas with css or js to the screen? And how do I make the width of the canvas equal to the height?

I want to make an TIC TAC TOE and im pretty new to js. I want to draw the x's and 0's to the canvas.
1. How do I make the height equal to the width of the canvas?
2. What is the best way to scale the canvas to use this for example also on phones and have the same experience?
You can make a full-screen canvas and use it to display your code.
Here is a boilerplate to get you started:
HTML
<canvas id="canvas"></canvas>
CSS
* {
margin: 0;
}
canvas {
display: block;
}
JS
window.onload = function() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
width = canvas.width = window.innerWidth,
height = canvas.height = window.innerHeight;
context.fillRect(0, 0, width, height);
};

HTML5 canvas, fit to (rest of) screen

I've made a little web game, I'm using this code below to scale the game to the page size.
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
// Attempt at auto-resize
function resize_canvas(){
if (canvas.width != window.innerWidth)
{
canvas.width = window.innerWidth;
}
if (canvas.height != window.innerHeight)
{
canvas.height = window.innerHeight;
}
}
window.addEventListener("resize", resize_canvas);
window.addEventListener("orientationchange", resize_canvas);
However, I'm now adding a menu in the top of the game using some CSS and I'm running into problems.
The game takes the size of the inner window, so anything displayed along with the game will cause the content not to fit into the browser.
How can I make the game "fill" the rest of the window?
(I've found questions on how to scale the game to the window, but I'd like the game to fill the window instead)
An image to demonstrate the problem below:
(Notice the scrollbars, which I'd like to eliminate)
Edit:
I'm quite new to web development, but I have the feeling CSS doesn't really work well on canvas.
And if you remove the nav height ?
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var menu = document.getElementById('nav')
resize_canvas();
document.body.appendChild(canvas);
// Attempt at auto-resize
function resize_canvas(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight - menu.offsetHeight;
}
window.addEventListener("resize", resize_canvas);
window.addEventListener("orientationchange", resize_canvas);
and
canvas {
position:relative;
}

Bad quality for 100% both width and height of canvas

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.

event.point not resizing with paper.js

This will drag my rectangle path. It works perfectly if the window hasn't resized.
function onMouseDrag(event) {
MyRectanglePath.position = event.point;
}
This will resize my game to be a square at either 100% width or 100% length of the browser window.
function OnResizeCalled() {
var gameWidth = window.innerWidth;
var gameHeight = window.innerHeight;
var scaleToFitX = gameWidth / 640;
var scaleToFitY = gameHeight / 640;
var currentScreenRatio = gameWidth / gameHeight;
var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
canvas.style.width = 640 * optimalRatio + "px";
canvas.style.height = 640 * optimalRatio + "px";
}
// Resize
window.addEventListener("resize", OnResizeCalled, false);
OnResizeCalled();
The smaller my browser window gets, the farther the rectangle is from my mouse when I drag it. How do I make event.point scale with the rest of the canvas?
Paper.js is not designed to support manual resizing of the canvas, since that will blow up the pixels and cause all kind of internal issues. It will also interfere with HiDPI handling on Retina screens.
but you can resize the canvas using:
paper.view.viewSize = [width, height];
I hope this helps!
Umm as Mr. Jürg Lehni stated before, Paper.js is not designed to support manual resizing of the canvas. when paper.view.setViewSize() extends/ shrink the canvas to that size.
If you want to scale the things inside the canvas (e.g. path), you had to apply transformation to every item (with right Matrix) using .transform();

Full Bleed Image Resize Calculation

I am trying to write a JavaScript function that will expand an image to fill a div always (so crop top or sides as needed). It is the JavaScript equivalent of the CSS3 code background-size: cover.
I can't for the life of me figure it out. This is what I have so far:
function full_bleed(box_width, box_height, new_width, new_height)
{
var aspect_ratio=new_width/new_height;
if(new_height<box_height) {
new_height=box_height;
new_width=Math.round(new_height*aspect_ratio);
}
if(new_width<box_width) {
new_width=box_width;
new_height=Math.round(new_width/aspect_ratio);
}
return {
width: new_width,
height: new_height
};
}
I figured one of you guys might have the equation lying around.
Thanks to the comment from Ben, I figured it out.
full_bleed: function(boxWidth, boxHeight, imgWidth, imgHeight)
{
// Calculate new height and width
var initW = imgWidth;
var initH = imgHeight;
var ratio = initH / initW;
imgWidth = boxWidth;
imgHeight = boxWidth * ratio;
if(imgHeight < boxHeight){
imgHeight = boxHeight;
imgWidth = imgHeight / ratio;
}
// Return new size
return {
width: imgWidth,
height: imgHeight
};
}
I made some changes on Drew's solution to better fit my needs.
function calculateCover(frame, sides) {
var ratio = sides[1] / sides[0],
cover = {
width: frame.width,
height: Math.ceil(frame.width * ratio)
};
if (cover.height <= frame.height) {
cover.height = frame.height;
cover.width = Math.ceil(frame.height / ratio);
}
return cover;
}
calculateCover({width: 1280, height: 822}, [16,9]);
The idea is the same, but the point here is to calculate the scaled up size without having an initial size of the media, instead using a given aspect ratio. I use it for video embeds, rather than images, where I load the video via YouTube API, for example, and I don't have any initial size, but I know the ratio and I want to stretch the video across the available space. (Of course, it can be changed back to calculate the ratio from the actual dimensions of the video or image.)
Also made some code simplifications.

Categories

Resources