Responsive PaperJS canvas (stretch canvas) - javascript

PaperJS has documentation how to setup the canvas in to resize the canvas when the window changes dimensions. The same solution can be found in this SO answer.
The problem with this approach is that it will change the coordinates while drawing, and also it will be resizing the canvas, which can be less performant.
I would like to scale the canvas without changing the width of the element. The problem I found is that PaperJS adds a width and height to the canvas element in runtime, and I could not find a way to stop this behaviour, this will result the calculated value when the setup is done, and could be for instance:
width="817" height="817"
Here is an example of a HTML Canvas that behaves the way I intend, and also the PaperJS version which does not scale. Resize the browser window to see how the example in the bottom will stretch the canvas content, but keeping the circle in the center of the canvas.
I would like to find a way to configure PaperJS that would work in the same way, without having to change the draw coordinates inside a onResize handler.
Is this possible?
const SIZE = 150;
window.onload = () => {
// --- Paperjs ---
const canvas = document.getElementById('paper');
paper.setup(canvas);
// draw circle in the center of the view
const c = new paper.Path.Circle(new paper.Point(SIZE, SIZE), SIZE);
c.strokeColor = 'white';
c.strokeWidth = 3;
// --- END Paperjs ---
// --- Canvas ---
const ctx = document.querySelector("#canvas").getContext("2d");
ctx.strokeStyle = "#FFFFFF";
ctx.fillStyle = "white";
ctx.lineWidth = 3;
ctx.beginPath();
// x, y, width
ctx.arc(SIZE, SIZE, SIZE, 0, 2 * Math.PI);
ctx.stroke();
// --- END Canvas ---
}
.wrapper {
margin-left: 10vw;
width: 80vw;
border: 1px solid cyan;
}
.responsive-canvas {
background-color: silver;
max-width: inherit;
max-height: inherit;
height: inherit !important;
width: inherit !important;
object-fit: contain;
}
* {
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.17/paper-full.min.js"></script>
<h2>PaperJS</h2>
<div class="wrapper">
<canvas id="paper" class="responsive-canvas" width="300px" height="300px"></canvas>
</div>
<h2>Canvas</h2>
<div class="wrapper">
<canvas class="responsive-canvas" id="canvas" width="300px" height="300px"></canvas>
</div>

Related

Does using percentages instead of pixels change an html 5 canvas change its properties?

I am practicing javascript and I am trying to make a game. I want the canvas element to be fullscreen, so I used percentages for the height and width attribute, but when I do, it doesn't behave like it normally does. When I run my debug code, it is supposed to make a box that is 50px by 50px, but the graphics look bigger than normal.
I've tried getting the canvas height and width in pixels, but that did not work. It does not report any error messages, but it is still too big.
<!DOCTYPE html>
<html>
<head></head>
<body>
<canvas id="canvas" style="height: 100%; width:100%;"></canvas>
</body>
<style>
html, body {width: 100%;
margin: 0;
height: 100%;
overflow: hidden;
position:fixed;}
</style>
<script>
var canvas = document.getElementById("canvas")
var c = canvas.getContext("2d")
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
</script>
There are no error messages none appearing, but it is not sized correctly, and I can't figure out why it's not working.
It makes a difference if canvas size is set in CSS or using element attributes.
The canvas element size is set by its width and height attributes (as numbers). This sets the number of addressable pixels used to store the canvas drawing in memory. In the absence of width and height attributes, canvas element dimensions are set to 300 by 150 (pixels) by default.
CSS applied to the canvas can scale its dimensions using software interpolation of the canvas treated as an image. Just as a small image looks bigger when scaled to full screen, both the 300 by 150 pixel canvas and objects drawn within it (using canvas pixel coordinates) appear larger when blown up.
To make canvas coordinates match the screen size in pixels, set its width and height attributes to pixel number values. E.G.
var canvas = document.getElementById("canvas")
var c = canvas.getContext("2d")
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
console.log( canvas.width, canvas.height);
alert( "fix?" )
canvas.style=""; // remove CSS scaling
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
body {
width: 100%;
margin: 0;
height: 100%;
background-color: honeydew;
overflow: hidden;
position:fixed;
}
canvas {
background-color: silver;
}
<canvas id="canvas" style="height: 100%; width:100%;"></canvas>

Drawing text in canvas element

could you tell me what is the problem with the text on my canvas? I tried to change the text size if I make it bigger it looks fine but if I make it smaller it looks weird. I'm not sure what exactly affect the text; I tried to play with font property but with no result, whenever I make the font smaller I got the result like in the snippet below
here is my code
(function(){
function init(){
var canvas = document.getElementsByTagName('canvas')[0];
var c = canvas.getContext('2d');
var animationStartTime =0;
c.fillStyle = 'white';
c.font = 'normal 10pt';
var textarray = 'you can live a beatiful life with a postive mind';
var j=1;
//time - next repaint time - HRT
function draw(time){
c.fillText(textarray.substr(0,j),10,70);
if(time - animationStartTime > 100){
animationStartTime = time;
j++;
}
if( j <= textarray.length){
requestAnimationFrame(draw); // 17ms
}
}
function start(){
animationStartTime = window.performance.now();
requestAnimationFrame(draw);
}
start();
}
//invoke function init once document is fully loaded
window.addEventListener('load',init,false);
}()); //self invoking function
#canvas{
overflow:hidden;
background-image: url('http://linux2.gps.stthomas.edu/~algh3635/practice/proj/img/img4.jpeg');
background-repeat: no-repeat;
background-size: cover;
}
canvas {
width:100%;
height:80vh;
left: 0;
margin: 0;
padding: 0;
position: relative;
top: 0;
}
<div id="canvas">
<div class="row">
<div class="col-lg-12 text-center" >
<canvas >
</canvas>
</div>
</div>
</div>
When you fillText on the canvas, it stops being letters and starts being a letter-shaped collection of pixels. When you zoom in on it, the pixels become bigger. That's how a canvas works.
When you want the text to scale as a vector-based font and not as pixels, don't draw them on the canvas. You could create HTML elements instead and place them on top of the canvas using CSS positioning. That way the rendering engine will render the fonts in a higher resolution when you zoom in and they will stay sharp. But anything you draw on the canvas will zoom accordingly.
But what I would recommend for this simple example is just doing it in html, css, and javascript like so:
var showText = function (target, message, index, interval) {
if (index < message.length) {
$(target).append(message[index++]);
setTimeout(function () { showText(target, message, index, interval); }, interval);
}
}
$(function () {
showText("#text", "you can live a beatiful life with a postive mind", 0, 100);
});
#canvas{
position: relative;
width: 100%;
height: 80vh;
overflow:hidden;
background-image: url('http://linux2.gps.stthomas.edu/~algh3635/practice/proj/img/img4.jpeg');
background-repeat: no-repeat;
background-size: cover;
}
#text {
position: absolute;
top: 50%;
left: 20px;
color: #fff;
font-size: 20px;
}
<div id="canvas">
<p id="text"> </p>
</div>
I'll leave it up to you to position the text and whatnot but you can see in this example that you can make the text as small, or as big, as you want.
However
...if you still absolutely need it to be a canvas then the following example works. It works because the canvas is not being stretched by css, the width and height are predefined.
The canvas element runs independent from the device or monitor's pixel ratio.
On the iPad 3+, this ratio is 2. This essentially means that your 1000px width canvas would now need to fill 2000px to match it's stated width on the iPad display. Fortunately for us, this is done automatically by the browser. On the other hand, this is also the reason why you see less definition on images and canvas elements that were made to directly fit their visible area. Because your canvas only knows how to fill 1000px but is asked to draw to 2000px, the browser must now intelligently fill in the blanks between pixels to display the element at its proper size.
I would highly recommend you read this article from HTML5Rocks which explains in more detail how to create high definition elements.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "12px Arial";
ctx.fillText("Hello World",10,50);
#canvas{
position: relative;
overflow:hidden;
background-image: url('http://linux2.gps.stthomas.edu/~algh3635/practice/proj/img/img4.jpeg');
background-repeat: no-repeat;
background-size: cover;
}
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="800" height="500"
style="border:1px solid #d3d3d3;">
Your browser does not support the canvas element.
</canvas>
</body>
</html>

html 5 canvas not resizing after javascript resize

I have the following html and css for a Tetris game I am making:
html
<div id = "TetrisHolder">
<canvas id = "TetrisCanvas" style = "width:400px; height:500px"></canvas>
</div>
css
div#TetrisHolder {
display: table;
margin:auto;
background: black;
border: solid black 3px;
}
canvas#TetrisCanvas {
background: url(Resources/bg.png) no-repeat center;
background-size: cover ;
}
When I attempt to resize it with the following javascript, nothing happens. I have seen most other StackOverflow questions about resizing DOM elements answered this way, however it does not work for me. what am I missing?
note: I am aware that I will need to redraw what is on the canvas but all I want right now is to resize it.
js
function resize() {
canvas = document.getElementById("TetrisCanvas");
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth*0.6;
canvas.height = window.innerHeight*0.6;
}

How to rerender (rather than resample) a canvas?

Chrome and Firefox handle the following code fine when rendered at 100%.
<!DOCTYPE html>
<html>
<head>
<script type="application/x-javascript">
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(50,50,25,0,2*Math.PI);
ctx.stroke();
}
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas" width="100" height="100">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
</body>
</html>
But if someone magnifies my page a little, the canvas is sampled, not repainted. It's only a little ugly at 150%, but by the time the viewer reaches 300%, it will look very ugly:
How do I rewrite the code above so that the circle is repainted at the new magnification, not resampled?
This answer leads me to believe that it can be easily done. My attempt
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
<script type="application/x-javascript">
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
</body>
</html>
is no good. The circle is still resampled when the user magnifies. Can you do better?
(Chrome and Firefox behave differently when one magnifies. The effect I'm aiming for is for the circle to stay put with its center in the middle of the canvas and its radius a quarter of the window's height.)
Try doing the onload combined with the window resize event to redraw the canvas (zooming triggers the resize event):
window.addEventListener('resize', draw);
CANVAS REDRAWING
Example: http://jsfiddle.net/ksvyndwp/
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
}
draw();
window.addEventListener('resize', draw);
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
<canvas id="canvas">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
If you're still worried about pixelization at higher zoom levels, I'm afraid there's nothing you can do about it directly on the canvas, because canvas' pixels scale with the window, and although you enter the sub-pixel rendering stage, there's nothing you can do to make it look better.
CSS SCALING
However, if you don't want to do it purely inside the canvas, you can do a simple CSS transformation that will make your circle look correctly on all zoom levels. Setting the width and the height to 100% will keep the canvas (as in canvas, the DOM element; not the actual canvas.width and canvas.height) the size of the window, so it's basically "immune" to zooming.
See it here (actually works much better when zooming the jsfiddle: http://jsfiddle.net/406h7xm0/ than the Stack Overflow iframe):
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
console.log(window.innerWidth);
}
draw();
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
canvas {
width: 100%;
height: 100%;
}
<canvas id="canvas"></canvas>
The final solution of what you're trying to do probably lies somewhere between the two approaches I've shown you.

Centering fullscreen in javascript/html

I'm trying to make the fullscreen option work in html/javascript.
I have placed my canvas and buttons in a div, fullscreen works, But now I want to center my game in the middle of the screen, and I want my canvas height to be equal to the monitor height of the display. And I want my width to be equal to my height. So my canvas has the shape of a square.
I think I need css for this, but I never used it so I don't know where to start.
My html code looks now like this:
<div id="theGame">
<canvas id="canvas" width="500" height="500" style=" position:absolute; top:40px; left:0px; border:6px ridge #FFAB00;"></canvas>
<button buttonSpecs... </button>
<button buttonSpecs... </button>
</div>
Currently when I'm in fullscreen it looks like this:
https://www.dropbox.com/s/ee4bv0cn2tm2nns/fullscreen.jpg
But thats not how I want it, I want it like this:
https://www.dropbox.com/s/cu54fqz0gzap1ul/howIwant.jpg
See the following question: HTML5 Canvas 100% Width Height of Viewport?
(function() {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
// resize the canvas to fill browser window dynamically
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvas goes will be cleared.
*/
drawStuff();
}
resizeCanvas();
function drawStuff() {
// do your drawing stuff here
}
})();
Okay, I can now stretch the canvas, using
CSS:
#canvas {
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
z-index: 0;
}

Categories

Resources