How to scale my canvas in reason, with the zoom scale? - javascript

I am working on a multiple web game using JavaScript. My canvas is currently set to the width and the height of my screen.
html
<canvas id = "canvas"></canvas>
javascript
var c=document.getElementById("canvas");
var ctx = c.getContext("2d");
//Making canvas scale;
c.width = window.innerWidth;
c.height = window.innerHeight;
function resize(){
//Add some code
}
My problem is, I do not want my players to zoom out, well not by default. It will make the game look bad and give the players an edge over everyone else. So I need to add some code to go into the resize method, that regardless of scale, the canvas will not be zoomed out. If the end result is something blurry at 300%+ that is fine.
IMPORTANT: the resize function cannot remove or reset the canvas back to default.

There are various ways to scale a canvas.
First off, there are 2 main parameters for the canvas size:
-Canvas Pixel Count. Set via canvas.width = 1000
-Canvas Display Pixel Size. Set via canvas.style.width = '1000px'
If you want all players to see a 1000x1000 region but displaying it fullscreen:
canvas.width = 1000;
canvas.height = 1000;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
There is also another option with canvas.style.transform = 'scale(2,2)'.
This method is the closest thing to the browser zoom done via Ctrl+ or Ctrl-.
The big advantage of transform is that the scaling is applied to all DOM children elements. If your game is using HTML for its interface, then this is the way to go. (By applying the scaling on the div containing the canvas + HTML interface.

Related

Resizing canvas size gives advantage to larger screens. Not sure how to keep the functionality while making it fair

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 :)

HTML Canvas Not Displaying Correctly When Resized to Fit Parent Div with 'offsetWidth'

I'm working on a sketchpad application using html canvas and javascript (trying to stay away from jQuery). The canvas needs to be responsive and I've found several methods to do so, but each one stretches out the canvas and makes the sketchpad unusable. It's hard to explain without seeing the problem. Here's the CodePen. Try drawing inside the canvas and you'll see what I'm talking about. The current method I'm using to resize the canvas incorporates offsetWidth and offsetHeight like so:
var sketchpadContainer = [
document.getElementById('container').offsetWidth,
document.getElementById('container').offsetHeight]
var canvas = document.getElementById('sketchpad');
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
Is there a way to make the canvas responsive while at the same time keeping the dimensions of the sketch intact?
The CSS width and height properties are NOT the same as the width and height attributes on a Canvas element.
If you absolutely need to use css to set width/height, keep a scale factor of your default canvas size, then multiple the target x and y positions of your mouse position by the inverse of the x/y scale factors (or just divide the target position by them).
Using css to resize your canvas is a bit too hacky imo (and will leave your lines blurry), I highly recommend you instead simlpy change with width/height attributes of your canvas and use CanvasRenderingContext2D.scale() to change the size of your lines (A scale factor will still need to be used to calculate your true mouse pos, however)
Simply change
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
to
canvas.height = sketchpadContainer[1];
canvas.width = sketchpadContainer[0];
Apply CanvasRenderingContext2D.scale() when you first get your context, and then do as I mentioned above. (ctx.lineTo(x,y); -> ctx.lineTo(x/scaleFactorX,y/scaleFactorY); & lastX=x; -> lastX=x/scaleFactorX;)
I.E See HERE

What is the best way to scale contents of a realtime whiteboard

I am making a whiteboard with angularjs, socketio an node.js.
As long as I use a fixed width/height for the canvas everywhere I can just broadcast the coordinates of the mouse/touch event and recreate the graphic in realtime. However, the problem I am facing is when trying to make the canvas have different sizes across different platforms (think desktop and a smartphone), the canvas has to be scaled and so does the graphic, but this makes things pretty slow.
The approach I am currently taking is to draw the graphic in a temporary hidden canvas of original size, then when there is a pause in the drawing stream (in other words the user has stopped doodling), I scale and copy it to the main canvas. The problem with this is, it doesn't feel very realtime at all, especially when a user keeps doodling without a pause for a while. Another approach I could try is to push all the coordinates in an array, apply 2d affine transformation on it, then redraw the entire thing. Though this too doesn't seem like a good solution for when the array size increases, repeatedly trying to apply transformations in realtime can easily eat up a lot of resources.
Is there any better way to achieve this?
do it with css scale transform. Scale the canvas to fit the size of the device be it a mobile, desktop, or tablet, or whatever.
Have your canvas be fixed width across all devices. Say it's 640px by 480px. Now we'll resize it to fit whatever window.
$(window).resize(function() {
var w = 640; // $('#mycanvas').width();
var h = 480; // $('#mycanvas').height();
var newWidth = $(window).width(); // this could be either smaller or bigger than the canvas
var newHeight = $(window).height(); // same here
var scaleX = newWidth / w;
var scaleY = newHeight / h;
$('#mycanvas').css('transform','scale(' + scaleX + ',' + scaleY +')');
$('#mycanvas').css('-webkit-transform','scale(' + scaleX + ',' + scaleY +')');
});
note: mycanvas could also be a container if any kind that holds the canvas and other divs or whatever. just make sure that w is the width of that container, etc.
note: if someone uses their fingers to draw across the screen, you may need to convert it from scaled coordinates to fixed width (640x480) coordinates.
Btw, I found a different way to do this that might be better. not sure:
Scaling canvas element with static resolution

Update HTML canvas width and height attributes automatically

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.

Resizing the canvas

I'm trying to design a web using flex-boxes in order to fit it to any kind of screen size. My main screen has a canvas, so... which is the best way to resize the canvas during the inizialitation?
I have tried these two ways. My first way was to use CSS and set a percentage for its size. For example, width=100% and height=100%. Despite the design worked, I found that there were a lot of issues when playing with the coords of my canvas. For example, when dragging an item, my mouse coords where amplified by ten times or so.
Despite I could manage that, I think it's not the best approach.
The second way was to set a fixed size when the onload and onresize events when they are fired. I was doing something like this:
window.initHeight = window.screen.height;
window.initWidth = window.screen.width;
/*The height of the navbar.*/
navbar.height = document.getElementById('navbar').offsetHeight;
canvas = document.getElementById('canvasStage');
canvas.width = window.initWidth;
canvas.height = window.initHeight - navbar.height;
canvas.setAttribute("width", canvas.width);
canvas.setAttribute("height", canvas.height);
The problem is that the height seems to be too big:
http://i.imgur.com/WI0jGH2.png
How could I fit the screen exactly through this way?
The third way, but I'll try to avoid it, is to set a fixed size and let the small screens to scroll on the page.
Thanks!
UPDATED:
This is my JSFiddle:
http://i.imgur.com/NRTykLv.png
window.screen.width and window.screen.height returns the width and height of the screen which includes all bars (evrything you see on your screen).So you have to use window.innerHeight and window.innerWidth in order to get the view port height and width
Replace
window.initHeight = window.screen.height;
window.initWidth = window.screen.width;
with
window.initHeight = window.innerHeight;
window.initWidth = window.innerWidth;

Categories

Resources