I have a canvas into which I draw content. The width of the content is constant, but the height changes. This is kind of a list - a map legend. The problem is I don't know how many items will I get beforehand, neither their size.
If I set height to eg. 800 it's fine for longer lists, but for lists that have just a few of elements, it's way too high and a lot of whitespace remains at the bottom, plus an unnecessary scroll (it's placed in div with overflow: auto, so I can scroll when a longer legend appears).
But I know the last pixel Y-position after I draw every element. Is it possible to somehow trim the remaining space or force adjust canvas size?
Edit: code
<div class="legend">
some stuff here
<div id="canvas">
<canvas id="cv"></canvas>
</div>
</div>
#canvas {
width: 100%;
max-height: 100%;
}
And I set #canvas height using:
document.getElementById('canvas').style.height = finalSize
after knowing the total height.
If you're already holding the canvas in a div for overflow, you could just adjust the div height based on list length. It'd be easier (and cheaper on resources) to obscure the part you don't need, rather than draw the canvas all over again. Depending on your use case, the canvas might even be totally unnecessary (it could be more efficient to just prerender a few key aspects, i.e. use images), but I can't say any more on that without additional details.
It is not possible to resize a canvas not clearing all its content.
As a workaround I can suggest to create 2nd canvas to keep the content of main one while you resize it.
const mainCanvas = ...;
const mainCtx = mainCanvas.getContext('2d');
const hiddenCanvas = document.createElement('canvas');
const hiddenCtx = hiddenCanvas.getContext('2d');
function render() {
// render the list and keep last Y position
// copy content of main canvas to the 2nd one
hiddenCanvas.width = mainCanvas.width;
hiddenCanvas.height = mainCanvas.height;
hiddenCtx.drawImage(mainCanvas, 0, 0);
// resize main canvas and restore its content
mainCanvas.height = lastYPosition;
mainCtx.drawImage(hiddenCanvas, 0, 0);
}
Edit:
As pointed out in comments: you can even render the list directly to the 2nd canvas.
const mainCanvas = ...;
const mainCtx = mainCanvas.getContext('2d');
const hiddenCanvas = document.createElement('canvas');
const hiddenCtx = hiddenCanvas.getContext('2d');
function render() {
// render the list on hidden canvas
// and keep last Y position
// resize and copy
mainCanvas.width = hiddenCanvas.width;
mainCanvas.height = lastYPosition;
mainCtx.drawImage(hiddenCanvas, 0, 0);
}
Related
I am really new to javascript, css, and html, but i want to learn. The problem is, its not clear the direction i should head in. I want to make a game site that can play a few games. Im trying to make a game board that will have a dynamic size based on the height and/or width of the browser while maintaining the aspect ratio of its original. It is going to have elements inside of it which must also decrease their size proportionately to its parent. I have tried using bootstrap 4, with its col, row, and container classes. I am struggling to make it work with the container class. I have recently come across the , which I saw someone use to achieve this. can anyone give me a better idea whats going on here?
one example is this website https://colonist.io/ just click play game, at the top, manipulate the browser height and width, you will see how it resizes, and all child elements. this is the exact effect i am looking for.
thanks.
Well.. maybe this will suit your needs better
var scale = {}, isInitial = true;
window.onresize = function() {
// make sure the ctx variable is global or visible in current scope in your code
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
if (isInitial) {
isInitial = false;
scale.width = ctx.canvas.width;
scale.height = ctx.canvas.height;
} else {
scale.x = window.innerWidth / scale.width, scale.y = window.innerHeight / scale.height;
ctx.scale(scale.x, scale.y);
// redraw your canvas graphics
}
}
Please ensure that:
Your canvas position id fixed
Canvas top and left properties set to 0
ctx variable is globally accessible
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 want to add my image to a canvas, and position and scale it.
I know how to position it, but every time I scale it, it disappears from my canvas.
My current code looks similar to this:
function init() {
var canvas = new createjs.Stage("canvas");
var image = new createjs.Bitmap("assets/image.png");
image.scale(600, 600);
canvas.addChild(image);
canvas.update(image);
}
My image does not appear on the canvas unless I remove image.scale(600, 600).
According to the documentation, the scale property is the scale factor. For example, a scale of 2 means that the image is two times as large. You're making the image 600 times as large. So a 64x64px image would become a 38400x38400px image. You'll need to calculate the factor from the image's dimensions:
const imageBounds = image.getBounds()
image.scaleX = 600 / imageBounds.width;
image.scaleY = 600 / imageBounds.height;
Notice also that scale is a property, you can also directly assign to it:
image.scale = 1.6;
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.
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).