Coordinates of a scaled canvas element - javascript

I already made use of a search engine, but I did not get the information I wanted, so I want to ask whether someone has a good method/trick for using a self-made coordinate system in a HTML5 canvas element.
I want to develop a 2D game in HTML5 using the canvas element, which should adapt to the whole browser window, like so:
<canvas style="width: 100%; height: 100%;">
No support for your browser, unfortunately...
</canvas>
The problem is that I do not know how I should manage the coordinates of my game.
In my game the player e.g. moves 32px to the right immediately when the user presses the right arrow key, but what happens, if I resize the canvas element?
Logically the "blocks" of the game will change their size too, so the unit of the coordinates will not be pixels anymore.
Are there other units I could use or what would you suggest me to do?

Set canvas width and height attributes to game area size
<canvas id="mycanvas" width="400" height="300"/>
And set its style to the desired display size on screen.
#mycanvas {
width: 100%
height: 100%
display: block
}
Now you can always assume in the code that canvas is 400x300 and when drawing ignore the actual physical pixel size on screen.
You need to scale the mouse clicks to correspond the actual location on game coordinates. So if you get mouse click on canvas at (x, y) you get location on game coordinates by x = ( x / $('#mycanvas').width()) * 400 and y likewise. If canvas is not full screen, use the $('#mycanvas').offset() to get delta for click coordinates.

Never ever ever use CSS sizing for the canvas, they will make things very ugly.
What you wrote does not make your canvas the width of the page, it makes it 300 pixels wide by 150 pixels tall (the default) and then warps that until its the width and height of the page.
Stick to the width and height attributes that Canvas has instead of using CSS.
If you want to make it the size of the page you have other options, such as putting the canvas inside a div and then making canvas.width equal to the div.style.clientWidth.
For working with different (fullscreen or not) window sizes, see my answer talking about "model coordinates" here: Working with canvas in different screen sizes

Related

Dynamically resize canvas on window resize

I am attempting to resize a canvas chart when a user resizes their browser window. The problem with changing it directly, or so I've found...is that the image disappears during the resizing. Here are some screenshots to help you understand my problem.
This is the chart before resizing.
This is the chart during the resizing. (without targeting the DOM element)
I've identified the chart overflowing on the right hand side.
Chart being resized and targeting the canvas width.
As you can see, the chart disappears.
let canvas = document.getElementById('canvas');
this.canvas.width = ${
event.target.innerWidth - (window.innerWidth / 100) * 2
};
Please let me know what options I have for dynamically resizing canvas charts. Thanks!
P.S. I'm using AngularJs for this particular project.
Update 12/30/2020
Discovered that the obvious reason for the chart disappearing is that the canvas is based on coordinates which originate from a set height/width. So the solution was re-mapping the strokes/fills as the canvas is resizing.
New challenge:
Using clearRect (0, 0, width, height) doesn't clear the canvas. Re-mapping results in an inifite mapping of charts on top of one another. As shown in the photo below.
Is this the solution I get paid a million dollars for? No. But...
After hours of spinning around thoughts as to why the creators never made an easy solution for resizing a canvas, I've finally found an option that works for resizing the charts. Note that if you're scaling up that it can become pixelated. But this option will work.
Instead of defining the height and width with the inline properties:
<canvas id="canvas" height="200" width="600" (window:resize)="onResize($event)"> </canvas>
You should use css to make the height and width 100%. This turns the canvas into an image essentially. Which is why it pixelates when you scale up. The next step is to setup functionality or styling for the element that the canvas is embedded within. This is where the solution arises. Because you can't adjust the canvas without losing the graphic. You have to adjust the element that encapsulates it!
Ex:
<div id="area-chart">
<canvas id="canvas" (window:resize)="onResize($event)"> </canvas>
</div>
You would dynamically adjust the height and width of the #area-chart. I personally suggest using viewport width to define the height as it is the most flexible in terms of scaling and the graphic pixelates far less than using other measurements (%, px, pt, etc.). Of course your needs may be different than mine, but here's some sample styling.
Sample scss:
#area-chart {
#canvas {
width: 100%;
height: 10vw;
}
}
Chart on load:
Chart scaled down:
Chart scaled up:
** note that the pixel dimensions in the screenshots are the full window size and not the size of the element

getCanvas in flot ignores original dimensions given in div and respects browser Zoom level instead

Possibly similar question: How do I resize a div automatically to the size of its contents when the contents of the div have changed?, but not the same. i.e. can't seem to work out what I need out of that question.
My situation:
I am drawing charts using flot. I then use flot.canvas module to basically convert the axis labels I have from on-screen to canvas, and later I digitize the entire canvas using plot.getCanvas() and save it to an image on disk to display later.
I have noticed that if at-the-time-of-canvas-conversion I set the Zoom Level of my browser (Mozilla Firefox) to 30%, the entire canvas is saved as a small file, ignoring the original div's dimensions.
So say my DIV is <div id="flot_chart" style="width: 1000px; height: 600px"></div>,
but image renders with sizes {width: 300px, height: 180px}, as below:
Graph still looks okay but this conversion does horrible things to the labels, when I try to display this image at original size. In other words, zooming out in browser makes the converted image unusable.
But then I have noticed that when I zoom my browser's viewport to 400%, canvas image renders HUGE and labels look great as well.
My question
How do I get a original canvas resolution, regardless of in-browser Zoom Level?
My goal is to get a good rendition of the chart, and for me it means saving the canvas in an image that has enough resolution to be reused later, in different situations, where dynamic post-factum resizing is not an option (i.e. PDF)
I use var canvas = plot.getCanvas() to get my canvas. How do I render canvas to be of the size I want in pixels (to save as an image), regardless of user's browser Zoom Level?
If I can't do above, can I dynamically resize viewport's zoom on Firefox, get my canvas, and size it back later?
Demo Example
From Flot's own example you can experience this by going to http://www.flotcharts.org/flot/examples/canvas/index.html
zoom out to 30%
clear the checkbox under the graph
check the checkbox under the graph
zoom to normal 100% and observe canvas
(result does not look so great & that's what I get when I digitize my canvas)
Dang, you have tough questions...
It seems that flot is scaling down the canvas based on the devicePixelRatio and backingStoreRatio. This is necessary for dense pixel screens (like on iPhones). When you "zoom" the browser it seems that these calculations will also scale down the canvas.
For instance if I zoom to 25%, my placeholder is still at 400px, but the canvas is down to 100:
<div id="placeholder" style="width: 400px; height: 400px; padding: 0px; position: relative;">
<canvas class="flot-base" width="100" height="100" style="direction: ltr; position: absolute; left: 0px; top: 0px; width: 400px; height: 400px;"></canvas>
With a little experimentation, it seems you can scale back up the canvas before you toDataURL it:
$( "#download" ).click(function() {
var canvas = plot.getCanvas();
$(canvas).attr('width', 400); // resize it to what you want
$(canvas).attr('height',400);
plot.setupGrid(); // redraw plot to new size
plot.draw();
var image = canvas.toDataURL("image/png");
...
});
Here's an example. Zoom down to 25%, force a reload by clicking Stop/Run button and then download the image. It should be 400x400 pixels.

Why do width/height element attributes render differently from inline/CSS styles?

Recently i've been coding a simple platformer in HTML5 and Js. My background image, which has a width of 600 pixels and a height of 400 pixels, is rendered differently depending on how i define the size of my canvas.
If i use element attributes and define its size like so: <canvas width="600" height="400"> i get the desired outcome; the image sits perfectly within the canvas.
On the other hand, if i define the canvas size by giving the canvas an ID and then style it within a CSS file like so: #canvas { width: 600px; height: 400px; }, or simply style it inline, the image appears stretched and simply doesn't fit properly within the canvas, although the values are identical.
Why don't these declaration methods render similarly?
There is a difference between the canvas dimensions and the canvas display size.
The HTML attributes sets the canvas dimensions, which determines how objects are measured that you draw on the canvas.
The CSS style sets the canvas display size, which determines how large the canvas is drawn in the browser. If the display size is different from the dimensions, the canvas will be stretched when drawn.
If you only define the dimensions, that will also be used as the display size, i.e. the canvas is drawn at scale 1:1.
If you only define the display size, the dimensions will get the default value 300 times 150.

Scaling a canvas to full screen really decreases the resolution

I'm trying to make a full screen game to help me learn JS. I made a canvas item and streched it to the size of the screen using CSS. Then I draw a circle. The issue I have is that the circle looks terrible!
_draw.arc(20, 20, 10, 0, 2 * Math.PI);
Here is a jsfiddle example. http://jsfiddle.net/H5dHD/152/
I've tried using different scale factors (so _draw.scale) but it dosent seem to matter...
What am I doing wrong?
P.S. I know the coordinates are off. I didn't include that code for the example.
The problem is that you resized the canvas using the CSS-style, and do not change the actual width and height. When you use CSS styling to change the size, the canvas will be stretched, but the internal drawing resolution stays the same. The result is that the canvas blurs.
To change the internal resolution, change the width and height attributes of the canvas HTML element itself.
document.getElementById('iDraw').height = screen.availHeight;
document.getElementById('iDraw').width = screen.availWidth;
Here is your updated fiddle:
http://jsfiddle.net/H5dHD/154/

Scrolling HTML5 Canvas viewport for printing

I am drawing a series of rectangles and text on an HTML5 Canvas. But this canvas will ultimately be printed. The rectangles are drawn according of the height of the paper(canvas)
The only canvas width that doesn't distort the text is the 300dpi or 2400x3300 canvas. This works well for print but its obviously huge on the screen.
I would like the user to have a scaled down version of the canvas on the left side that fits 100% height of the parent container with scroll bars for overflow.
I have tried div overflow:auto.. and this does work but its not scaled (still scrolling a huge version). So basically I would like to scale the image for the browser window but do all drawing/printing from the big canvas.
For this scenario you can use CSS rules with the canvas.
ONLINE DEMO HERE
Keep the pixel size but add the following rules to the canvas element itself (assuming the id of the canvas is canvas):
canvas.style.width = 'auto';
canvas.style.height = '100%';
or apply a CSS rule to the element via CSS and HTML:
.printCanvas {
width:auto;
height:100%;
}
and then in the HTML:
<canvas id="canvas" class="printCanvas" width="2400" height="3300"></canvas>
This should allow the browser to use the actual content of the canvas when printing even when the canvas is scaled down (like with an image).
In this example the canvas will fit the height of parent provided the parent has height defined. You can use as you already do overflow:auto to get scroll-bars.
If you want to show 50% of the canvas inside the parent just set height:200% for the canvas element and so on.
Note that you might loose some details on the screen if the canvas is scaled much but these should show on the print. This would be due to sub-pixeling which kicks in when a pixel is drawn as less than an actual pixel on the screen.

Categories

Resources