So, I have a browser game which is run by a canvas with dynamic dimensions(it scales to the user's window's dimensions) which takes images at various sizes, scales them according to the user's window dimensions and draws them:
(example of my resizing algo:)
https://jsfiddle.net/8o3sn9mh/55/
var
canvas = document.getElementById('c'),
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var flower = new Image();
//the src is actually local, but i put a url for example's sake
flower.src = "http://plainicon.com/dboard/userprod/2803_dd580/prod_thumb/plainicon.com-46129-128px-af2.png"
flower.onload = function(){
ctx.drawImage(flower,0,0,128,128, 0, 0, window.innerWidth / 2, window.innerHeight / 2);
}
as you can see, I am drawing a 128x128px image and I resize it to half's the user's window. So, I was thinking - my game may do this operation every single render execution, and it may take unnecessary resizing time to perform it every time. So:
1) Does performing this resizing take more time since I use it every requestAnimationFrame?
2) Is there a way to resize my image one time, save it into a var and use it in order to save that time?
Regardless I'd like a way to save the resized image into a var in order to fit it inside canvas' createPattern method:
pattern = ctx.createPattern(resizedFlower, 'repeat'); //resizedFlower should be the original flower resized into half's the user's window's width + height
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 50, 50);
You can save your image to a canvas and then use drawImage with that canvas. For instance:
var canvas = document.getElementById('c'),
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var flowerCanvas = document.createElement('canvas');
flowerCanvas.width = window.innerWidth;
flowerCanvas.height = window.innerHeight;
flowerCtx = flowerCanvas.getContext('2d');
var flower = new Image();
//the src is actually local, but i put a url for example's sake
flower.src = "http://plainicon.com/dboard/userprod/2803_dd580/prod_thumb/plainicon.com-46129-128px-af2.png"
flower.onload = function(){
flowerCtx.drawImage(flower,0,0,128,128, 0, 0, window.innerWidth / 2, window.innerHeight / 2);
ctx.drawImage(flowerCanvas,0,0);
}
Now you can reuse flowerCanvas and it will be whatever size you initially drew it at. You probably won't see much of a performance gain between resizing vs not resizing, although you should benchmark it to be sure.
Also you shouldn't resize everything everyframe, you can listen for a window resize event, and resize when that event fires.
Related
thank you for taking a look.
What I am trying to do here is... load image from computer (by using FileReader), put img tag's src to the file. Then draw canvas with that image.
function previewFile(){
var preview = document.querySelector('img'); //selects the query named img
var file = document.querySelector('input[type=file]').files[0]; //sames as here
var reader = new FileReader();
reader.onload = function () {
preview.src = reader.result;
drawCanvas();
}
if (file) {
reader.readAsDataURL(file); //reads the data as a URL
} else {
preview.src = "sample.jpg";
}
}
previewFile(); //calls the function named previewFile
window.onload = function () {drawCanvas(); };
function drawCanvas() {
var img = document.querySelector("img");
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
ctx.filter = window.getComputedStyle(document.querySelector("img")).filter;
ctx.drawImage(img, 0, 0);
}
Problem is when I load another image file. It loads in the canvas, but not fit in the canvas size. It keeps the original image size and "part" of the image is shown in the canvas.
In order to solve it, I tried following:
ctx.drawImage(img, 0, 0, document.getElementById('canvas').width,
document.getElementById('canvas').height);
It works, however the image quality becomes really bad... since it is not original image size. It is adjusted to the certain height and forced to be resized.
All I want to do is... keep the original canvas size (width: some px; height: auto), so when I load the image, it fits to the canvas width and adjusted height.
Would you please help me? Thank you.
Added
I researched myself and found following:
I came up with an idea - change the image size first based on the current width of the canvas.
var img = document.querySelector("img");
var canvas = document.getElementById("image");
var ratio = img.height / img.width;
img.width = canvas.offsetWidth;
img.height = img.width * ratio;
Then draw with the edited image.
var ctx = canvas.getContext('2d');
ctx.filter = window.getComputedStyle(img).filter;
ctx.drawImage(img, 0, 0, img.width, img.height);
Then I found the problem. I checked "img.height" variable is 199px. But canvas's height becomes 150px somehow. I checked and there is no css applied to the canvas at all.
So this time, I set canvas width, before drawImage().
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
ctx.filter = window.getComputedStyle(img).filter;
ctx.drawImage(img, 0, 0);
And again, the original image coming back... and "part" of the image is shown in the canvas. The canvas's size is what I wanted though...
Thank you so much for taking a look the issue. Especially #Kaiido who tried to help. Thank you. I am really new to this stackoverflow... so I didn't know how to create demo.
I found the solution. Well... it was really basic knowledge of the Canvas,,, but I think many people will forget / miss following:
var ctx = canvas.getContext('2d');
ctx.canvas.width = 1000;
ctx.canvas.height = 1000;
ctx.drawImage(img, 0, 0, 800, 800);
ctx.canvas.width is canvas's width. ctx.canvas.height is canvas's height.
In drawImage, those 800s are width and height of the image will be drawn, not the canvas's size!! So if you set... let's say 1000, 1000 in drawImage, the image will be resized to the size and it will be drawn into the canvas. If it is bigger than the canvas size, it will show only "part" of your image.
So what I did was... get the div width size where I want to put my canvas. Then calculate the ratio of the image first ( ratio = image's height / image's width ). Then set canvas size to following ( ctx.canvas.width = div width size, ctx.canvas.height = div width size * ratio ). Then draw canvas with canva's width and height ( ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height) ).
Hope this helps someone new like me :) Thank you.
This is pretty simple!
try this.
getting the ratio, setting the height, drawing the image
var ratio = img.naturalWidth / img.naturalHeight;
var width = canvas.width;
var height = width / ratio;
ctx.drawImage(img, 0, 0, width, height);
this worked for me, try this.
see the line
var width = canvas.width;
you can replace the canvas.width by any other value.
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;
}
I'm trying to load an image from a URL into a HTML canvas at a 1:1 scale. I load the image, and set the canvas DOM element to the appropriate dimensions, but for some reason the image in the canvas is significantly upscaled and therefore only the top left hand corner is drawn.
This is demonstrated by the following JSFiddle: http://jsfiddle.net/KdrYr/1/
var img = new Image();
var cv = document.getElementById('thecanvas');
img.src = 'http://www.photographyblogger.net/wp-content/uploads/2009/12/Picture-in-a-picture4.jpg';
img.onload = function() {
var ctx = cv.getContext('2d');
cv.style.width = img.width + 'px';
cv.style.height = img.height + 'px';
ctx.drawImage(img, 0, 0);
};
For example, I'm trying to draw this (sorry about the big images :/)
But end up with this
What could be causing this?
You need to assign the canvas actual width and height, not via its style:
cv.width = img.width;
cv.height = img.height;
Live test case.
As for the why, well, it's explained already here.
I'm trying to create a HTML5 canvas using Windows 8 / WinJS. Here's what I have:
var body = document.getElementById("body");
var canvas = document.createElement("canvas");
canvas.id = "myCanvas";
body.appendChild(canvas);
var canvasContext = canvas.getContext("2d");
canvas.width = document.width;
canvas.height = document.height;
canvasContext.fillStyle = "#f00";
canvasContext.fillRect(canvas.width - 100, canvas.height - 50, 100, 50);
console.log("canvas width " + canvas.width + ", height " + canvas.height);
Most of this is directly from a tutorial, but for all the tutorials I've seen, the width and height are set to hard coded numbers, for example:
canvas.width = 800;
canvas.height = 600;
Admittedly that does work, but I want the canvas to be as big as the screen, whatever the resolution. How do I achieve this?
You can just use the viewport with and viewport height CSS values to do this (see some information on these here)
In this specific case you could just do:
canvas.style.width = "100vw";
canvas.style.height = "100vh";
The advantage of this solution is that you don't have to load 3rd party libraries, e.g. JQuery to size to the full width / height.
By "screen", do you mean the browser window size?
If so, you can use window.outerWidth and window.outerHeight instead of document.width and document.height. Or if you use jQuery: $(window).width() and $(window).height().
Also, you want to listen to the resize event on the window so that you can reinitialize the canvas when the browser is resized.
I have created a basic shape in HTML canvas element which works fine.
The problem occurs when I resize the canvas, all the drawing in the canvas disappears. Is this the normal behavior? or is there a function that can be used to stop this?
One way to fix this could be to call drawing function again on canvas resize however this may not be very efficient if there is huge content to be drawn.
What's the best way?
Here is the link to sample code https://gist.github.com/2983915
You need to redraw the scene when you resize.
setting the width or height of a canvas, even if you are setting it to the same value as before, not only clears the canvas but resets the entire canvas context. Any set properties (fillStyle, lineWidth, the clipping region, etc) will also be reset.
If you do not have the ability to redraw the scene from whatever data structures you might have representing the canvas, you can always save the entire canvas itself by drawing it to an in-memory canvas, setting the original width, and drawing the in-memory canvas back to the original canvas.
Here's a really quick example of saving the canvas bitmap and putting it back after a resize:
http://jsfiddle.net/simonsarris/weMbr/
Everytime you resize the canvas it will reset itself to transparant black, as defined in the spec.
You will either have to:
redraw when you resize the canvas, or,
don't resize the canvas
One another way is to use the debounce if you are concerned with the performance.
It doesnt resize or redraw every position you are dragging. But it will resize only when the it is resized.
// Assume canvas is in scope
addEventListener.("resize", debouncedResize );
// debounce timeout handle
var debounceTimeoutHandle;
// The debounce time in ms (1/1000th second)
const DEBOUNCE_TIME = 100;
// Resize function
function debouncedResize () {
clearTimeout(debounceTimeoutHandle); // Clears any pending debounce events
// Schedule a canvas resize
debounceTimeoutHandle = setTimeout(resizeCanvas, DEBOUNCE_TIME);
}
// canvas resize function
function resizeCanvas () { ... resize and redraw ... }
I had the same problem. Try following code
var wrapper = document.getElementById("signature-pad");
var canvas = wrapper.querySelector("canvas");
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
It keeps the drawing as it is
One thing that worked for me was to use requestAnimationFrame().
let height = window.innerHeight;
let width = window.innerWidth;
function handleWindowResize() {
height = window.innerHeight;
width = window.innerWidth;
}
function render() {
// Draw your fun shapes here
// ...
// Keep this on the bottom
requestAnimationFrame(render);
}
// Canvas being defined at the top of the file.
function init() {
ctx = canvas.getContext("2d");
render();
}
I had the same problem when I had to resize the canvas to adjust it to the screen.
But I solved it with this code:
var c = document.getElementById('canvas');
ctx = c.getContext('2d');
ctx.fillRect(0,0,20,20);
// Save canvas settings
ctx.save();
// Save canvas context
var dataURL = c.toDataURL('image/jpeg');
// Resize canvas
c.width = 50;
c.height = 50;
// Restore canvas context
var img = document.createElement('img');
img.src = dataURL;
img.onload=function(){
ctx.drawImage(img,20,20);
}
// Restote canvas settings
ctx.restore();
<canvas id=canvas width=40 height=40></canvas>
I also met this problem.but after a experiment, I found that Resizing the canvas element will automatically clear all drawings off the canvas!
just try the code below
<canvas id = 'canvas'></canvas>
<script>
var canvas1 = document.getElementById('canvas')
console.log('canvas size',canvas1.width, canvas1.height)
var ctx = canvas1.getContext('2d')
ctx.font = 'Bold 48px Arial'
var f = ctx.font
canvas1.width = 480
var f1 = ctx.font
alert(f === f1) //false
</script>