I want to use HTML5 canvas with flexbox. I need to set canvas.width and canvas.height automatically when user resizes window. I have tried to use jQuery for it:
$(".cnvs").attr("width", $(".cnvs").width());
$(".cnvs").attr("height", $(".cnvs").height());
but it keeps increasing actual width of canvas so it almost fills entire screen. I have put it on jsfiddle - try to resize output window with separator.
Is there any reasonable way how to do it? Thanks.
Edit: Just to be clear: I don't want to fill entire screen with that canvas. I want UI where I have:
<div class="container">
<div class="control"></div>
<canvas></canvas>
<div class="control"></div>
</div>
then use flexbox to put those three elements beside eachother, while canvas will be twice as wide as the other. This works without problem, but canvas.width and canvas.height doesn't get updated, so whenever I render something onto that canvas, it is rendered as if that canvas was 320x140 px.
Edit 2: I am sorry, but (perhaps because of my poor English) I am not clear enough. I will try to explain it once again:
Actual width of canvas element is correct (even without using any JavaScript code) only by using flexbox. My problem is that although width is correct (and $(".cnvs").width() returns correct value of width), it doesn't have any "width" attribute, it is still:
<canvas>
</canvas>
and I need to provide width argument by myself (because it renders badly when it's not set). When I try to use my code or proposed:
...
var rect = canvas.parentNode.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
...
it behaves weirdly, canvas's width keeps increasing with every resize, but too much (it erases both control divs almost immediately).
Update 2
If I understand the question correct: the canvas has a flex CSS set (not shown in the question right now). It defines the canvas to be 2x the size of the other two elements, but since the canvas is resized and not its bitmap, the drawings are stretches as well and you want the bitmap to adopt dynamically.
If so, do this change to the code -
This update will leave the CSS rules of the canvas element alone and let flexbox handle it. It will read the actual pixel size of the element and then apply it to the bitmap so that data isn't stretched:
$(window).on("resize", function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}
Additionally, since resizing the window can produce a lot of events, you may want to consider "debouncing" so that you only deal with the more recent resize:
var timerID;
$(window).on("resize", function() {
clearTimeout(timerID);
timerID = setTimeout(function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}, 180); // adjust at will
}
This will delay the resizing/redrawing until 180ms has passed.
You don't even have to load jQuery, it is simple:
var canvas = document.querySelector("canvas");
window.addEventListener("resize", function(){
canvas.setAttribute("width", window.innerWidth);
canvas.setAttribute("height", window.innerHeight)
})
You have to add a listener to the resize event on the window object.
If your looking for a jquery solution.
$( window ).resize(function() {
$(".cnvs").attr("width", $(window).width());
$(".cnvs").attr("height", $(window).height());
});
This should work just fine.
Related
So I am trying to learn javascript by making a game where you click on a canvas to move a circle and you have to dodge multiple other circles coming in your direction. I am close to the final result but I just realized that the larger your screen is, the easier it is for you to play.
The reason is that the enemies spawn at the edges of the canvas, so if the canvas is bigger, you have more time to react to them since their speed doesn't change. The game is supposedly refreshing around 60fps and each time it resizes the canvas depending on if you change your window size. The only thing I can think of is increasing the speed of enemies with the size increase but I don't know if there's any other way to go about this. Maybe I could increase the size of the of the player and the enemies to accommodate the change in window size but I don't know which is better or how to make sure I am consistent with the ratio increase.
Any suggestions would be much appreciated. Thanks for your time
Here's my full code: https://jsfiddle.net/r2f6eb89/2/
It doesn't actually run on this site so it's just a reference for my logic.
Here are the resizing functions:
/*
function setCanvasSize() {
//c.width = window.innerWidth-100;
//c.height = window.innerHeight-100;
if (window.innerWidth < window.innerHeight) {
c.width = window.innerWidth - 150;
c.height = window.innerWidth - 150;
} else {
c.width = window.innerHeight - 150;
c.height = window.innerHeight - 150;
}
}
*/
function setCanvasSize() {
c.width = 600;
c.height = 600;
}
There's actually two kinds of "width" and "height" property. One is the width and height you can actually see in your website, that is, the one you can change by the property on your html file element. The other one is the width and height you set in the javascript file, for setting the coordinate you use to print image or draw in the canvas.
Example for first type of the width/height property:
<canvas id="my_canvas" width="500" height="200"></canvas>
Example for second type of the width/height property:
var canvas = document.getElementById("my_canvas");
canvas.width=500;
canvas.height=200;
It seems like you are changing the second type of the width/height property each refresh. If that's not what you want, try modifying the first type of width/height. It seems like a simpler solution to your question. To modify the first type of property, the CSS property in javascript, here's the code:
canvas.style.width="500px";
canvas.style.height="200px";
Hope that helps :)
I'm using EaselJs to build my game and I would like to catch the onresize event of the browser in order to resize the stage and all images it contains.
I've tried this code:
window.addEventListener('resize', resize, false);
init() {
createjs.Ticker.addEventListener('tick', handleTick);
resize();
}
function handleTick(event) {
stage.update();
}
function resize() {
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
}
But it didn't really work...Any ideas?
Thank you.
If you resize the canvas contents with JavaScript, then you are adding more pixels to the canvas element. The contents will not resize to fit.
canvas.width = window.innerWidth;
If you resize with CSS, then you are transforming the element, so it has the same number of pixels, but is stretched.
canvas.style.width = window.innerWith;
If you want to scale the contents to fit on more pixels, you need to scale the stage, or better, put your contents inside a container and scale that.
Here is a quick sample I made to answer a similar question, which should get you started.
https://jsfiddle.net/lannymcnie/4yy08pax/
From what I know canvas should maintain their ratio automatically if you set their width using relative units (e.g. 100 %). Obviously children elements should be relative as well to achieve a fluid layout.
If you want to use javascript to obtain the same result you should use the correct events listener
window.onresize
I have the following cropper app:
var canvas = $('#selector')[0]
//works
**canvas.width=image.width
canvas.height=image.height**
//doesn't work
**//$(canvas).width($(image).width())
//$(canvas).height($(image).height())**
//both seem to do the exact same thing
$('#selector').css('left','30px')
var ctx = $('#selector')[0].getContext("2d");
ctx.fillStyle="rgba(210,220,255,0.6)";
var cropinit=false;
//the cropped section will not be resizeable after the user finishes, but the user can create a new cropped section
canvas.addEventListener("mousedown", function setP1(event) {
//allows you to find the height and width by imagining a rectangle around it
//get bounding selector parameters
var selector_position = $('#selector').position()
xOff=selector_position.left
yOff=selector_position.top
console.log(xOff)
console.log(yOff)
p1=[event.clientX-xOff, event.clientY-yOff];
ctx.fillRect(80,54,40,40)
console.log(p1)
cropinit=true;
});
//so that if the user releases the mouse after it leaves the canvas, the crop completes
canvas.addEventListener("mouseleave", function() {
cropinit=false;
});
canvas.addEventListener("mousemove", function drawBox(event) {
if (cropinit) {
p2=[event.clientX-xOff, event.clientY-yOff]
setBox();
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(corner[0],corner[1],boxW,boxH);
//console.log(p2)
//console.log(corner[0]+" "+corner[1]+" "+boxW+" "+boxH);
}
});
canvas.addEventListener("mouseup", function finishBox(event) {
p2=[event.clientX-xOff, event.clientY-yOff];
setBox();
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(corner[0],corner[1],boxW,boxH);
cropinit=false;
});
The code works when I use the normal JavaScript code for setting the canvas width and height in **. However, when I use jQuery to set the width and height in the ** with comments. The rectangle is not drawn at the start and ending point of the user's mouse. The jQuery and normal JS version seem to produce the same canvas width and height, yet the rectangle is drawn in different places. They seem to do the exact same thing. What is the difference?
JavaScript element.width and jQuery width() are not equivalent.
element.width changes HTML attribute.
element.style.width changes CSS style value.
jQuery width() changes CSS style value, and is equivalent to the previous one.
Talking about canvas, its width and height attributes define an actual drawing size. At the same time, width and height CSS properties control the scale of image.
Note further that the height and width are the logical canvas dimensions used for drawing and are different from the style.height and style.width CSS attributes. If you don't set the CSS attributes, the intrinsic size of the canvas will be used as its display size; if you do set the CSS attributes, and they differ from the canvas dimensions, your content will be scaled in the browser.
There is a good Stackoverflow article, explaining the meaning of width and height of canvas with examples.
jQuery width() result
So, as I said, jQuery width() function changes the inline style of an object.
$("canvas").width(500).height(400);
document.body.innerText = document.getElementsByTagName("canvas")[0].outerHTML;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
element.width result
However, every item in this jQuery array is a DOM element:
var canvas = $("#selector")[0]; // HTML element object
canvas.width = 500; // changing the HTML element object's properties
When you change height and width properties of canvas, it actually changes its attributes:
document.getElementsByTagName("canvas")[0].width = 500;
document.getElementsByTagName("canvas")[0].height = 400;
document.body.innerText = document.getElementsByTagName("canvas")[0].outerHTML;
<canvas></canvas>
Conclusion
So, in case of canvas, you need to change HTML attributes, but not style rules, and jQuery width() and height() functions are just not suitable for this.
At the same time, you can use jQuery in the following way:
$("canvas").prop({"height": 500, "width": 400});
However, it will do absolutely the same as your pure JS code.
What I'd like to do is create a 15 by 15 pixel sized canvas with jQuery and I am looking for an elegant way to do it.
I currently create a canvas with jQuery like this:
var canvasNode = $('<canvas />', {
style:'display:block',
width:15,
});
// canvasNode[0].width=15;
canvasNode[0].height=15;
An oddity is that the width:15 in that has no effect while the currently commented out line below does what I'd like to do. I also tried style:'display:block;width:15px;' but while that displays the canvas at 15px width the canvas itself stays at its large default size so its just being scaled so that's not what I seek.
In case you are really worried about performance, this is the fastest way (untested, but I'm sure it is):
var canvas = document.createElement("canvas");
canvas.width = 15;
canvas.height = 15;
That is, no jQuery at all.
Note that sending in an object with a width property will set the css width to 15px (basically just scaling the canvas), the canvas will still be created with the default number of pixels in width if no width attribute is specified, which is usually 300 pixels.
Just set the width and height attributes:
$('<canvas />', {
style:'display:block'
}).attr('width', 15).attr('height', 15);
I'm creating a HTML Canvas object using this javascript code:
var Canvas = document.createElement("canvas");
Canvas.style.width = "500px";
and then i'm drawing text upon it.
When the canvas is displayed, the whole canvas has been scaled up (including content) to to match the 500px width, which results in ugly resampling. What i really want, is that the content stay the same size, only the canvas itself made bigger.
Any ideas?
Try changing the element’s width instead of its CSS width.
Canvas.width = 500;
Thomas' answer is correct, but it sound's like you also want to keep the existing content on the canvas. When you change the canvas size, it automatically gets cleared and reset to it's default state. Because of that, you will either need to redraw the contents, or copy the contents to another canvase (using drawImage), resize the canvas, then copy the contents back (again, using drawImage).