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>
Related
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.
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 created a new image but I'm trying to resize it and add some transformations to it. How ever, they are not taking effect.
Example: https://jsfiddle.net/chung9ey/3/
img.onload = function(){
img.style.width = "500";
img.style.height = "300";
img.style.transform = "perspective(500px) rotateZ(30deg)";
context.drawImage(img, 0 ,0);
}
Styles change properties, not attributes. In order to change the actual attributes you would need to use
img.height = 300;
//or by native API
img.setAttribute("height",300);
and so on for each attribute you wanted to change. Note that attributes are part of the html element and not necessarily part of the css definition (more on that here: https://www.w3.org/TR/CSS21/cascade.html#preshint).
Try using this.
document.getElementById("imageID").style.height="300px";
document.getElementById("imageID").style.width="500px";
That should change the element's style width and height to what you want.
In the HTML script, it'd be
<img src="source.jog" id="imageID"/>
Based on this Stack Overflow answer, change your JS to:
var img = new Image();
var canvas = document.getElementById("hello");
var context = canvas.getContext("2d");
img.onload = function(){
context.save(); // Saves current canvas state (includes transformations)
context.rotate(30); // This rotates canvas context around its top left corner...
context.translate(-275, 125); // ...so you need to make a correction.
context.drawImage(img, 0, 0, 500, 300);
context.restore(); // Restore canvas state
};
img.src = "https://www.enterprise.com/content/dam/global-vehicle-images/cars/CHRY_200_2015.png";
This essentially rotates the canvas's contents after the image is drawn on it.
Part of the image is off-canvas as a result of this rotation, so you may also want to scale the canvas to fit the rotated image.
https://jsfiddle.net/Lcyksjoz/
i would change the image size in the canvas and then manipulating the canvas through id
var img = new Image(100, 100);
var canvas = document.getElementById("hello");
var context = canvas.getContext("2d");
var width = 500;
var height = 300;
img.onload = function(){
img.style.transform = "perspective(200px) rotateZ(30deg)";
context.drawImage(img, 0 ,0, width,height);
}
img.src = "https://www.enterprise.com/content/dam/global-vehicle-images/cars/CHRY_200_2015.png";
document.getElementById("hello").style.width="300px";
https://jsfiddle.net/chung9ey/27/
I am using javascript to draw a rectangle around DOM elements in a website.
The problem is that the rectangles are drawn in the wrong positions.
I know that canvas, work like a real canvas so you have to "predraw" everything before filling the canvas, otherwise the elements will be on top of each other, in the orders you drew them.
That's why I'm defining canvas, and context outside of the loop.
This is my code:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
//Set canvas width/height
canvas.style.width='100%';
canvas.style.height='100%';
//Set canvas drawing area width/height
canvas.width = document.width;
canvas.height = document.height;
//Position canvas
canvas.style.position='absolute';
canvas.style.left=0;
canvas.style.top=0;
canvas.style.zIndex=100000;
canvas.style.pointerEvents='none'; //Make sure you can click 'through' the canvas
document.body.appendChild(canvas); //Append canvas to body element
var listingsRect = Array.prototype.map.call(document.querySelectorAll('.rc'), function(e) {
return e.getBoundingClientRect();
});
listingsRect.forEach(function(listingRect) {
var x = listingRect.left;
var y = listingRect.top;
var width = listingRect.width;
var height = listingRect.height;
//Draw rectangle
context.rect(x, y, width, height);
context.fillStyle = 'yellow';
context.fill();
});
However, when I change
canvas.width and canvas.height to window.innerWidth and window.innerHeight respectively, then canvas draws the rectangles in the right positions, however it only draws them in the visible area of the website (obviously).
Can somebody tell me what's wrong with my code?
Here's a JS bin:
http://jsbin.com/elUToGO/1
The x,y in context.rect(x,y,width,height) are relative to the canvas element not to the browser window.
So if your canvas element is absolutely positioned at 50,75 and you want a rect at window position 110,125 you would draw your rect like this:
context.rect( 110-50, 125-75, width, height );
A few other things:
If you set the canvas element width/height and then position absolutely, you don't need canvas.style.width/height.
document.width/height are deprecated (& not supported in IE) . Use this instead:
//Set canvas drawing area width/height
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
When setting style.left/top, you might want to pass a string with "px" in case you later set >0.
canvas.style.left="0px";
canvas.style.top="0px";
.pointerEvents='none' is supported in most browsers (but not in IE<11)
I'm playing around with a node/socket.io Pictionary game. I apologize in advance, I am a designer and not too keen with js.
I'm just trying to re-size the canvas so it will be the entire width and height of a browser window without scaling up the stroke path? Right now, the Javascript sets the canvas to 500px.
Here is the relevant code:
// ================================================
// canvas drawing section
// ================================================
var canvas = $('#canvas'),
context = canvas[0].getContext('2d');
socket.on('drawCanvas', function(canvasToDraw) {
if(canvasToDraw) {
canvas.width(500);
context.lineJoin = 'round';
context.lineWidth = 2;
// ...
}
});
canvas[0].width = $(window).width();
canvas[0].height = $(window).height();
worked great.
You're using jQuery to change the dimensions, and that won't work well with canvas (it will scale the canvas contents too). Set the dimensions directly on the canvas element:
canvas[0].width = 500;
// Or:
canvas.get(0).width = 500;
To set the canvas to the full window dimensions, try this:
canvas[0].width = $(window).width();
canvas[0].height = $(window).height();
Use clientWidth and clientHeight property of canvas
if (canvas[0].width != canvas[0].clientWidth || canvas[0].height != canvas[0].clientHeight) {
canvas[0].width = canvas[0].clientWidth;
canvas[0].height = canvas[0].clientHeight;
}
and set the css for canvas width and height to 100%;