Bad quality for 100% both width and height of canvas - javascript

I have done a very tiny example with canvas, it's available on JsFiddle:
http://jsfiddle.net/yPtr5/
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
#myCanvas {
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<canvas id="myCanvas">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var canvas = document.getElementById( "myCanvas" );
var context = canvas.getContext( "2d" );
context.id = "myContext";
context.beginPath();
context.arc( 95, 50, 40, 0, 2 * Math.PI );
context.stroke();
setTimeout( function() {
var rectWidth = 150;
var rectHeight = 75;
context.fillStyle = "blue";
context.fillRect( rectWidth / -2, rectHeight / -2, rectWidth, rectHeight );
}, 2000 );
</script>
</body>
</html>
As you are able to see, the rendering result has a very low quality:
So, I'm wondering, how can I draw various figures using Canvas in a good quality, I don't want to draw in small size, I want to draw in 100% size of page.
So, maybe I didn't define some anti aliasing filter or something else?
Thanks!

Problem
In most general cases we should avoid using CSS to set the canvas size.
The default size of canvas is 300 x 150 pixels (bitmap). If you set the size using CSS we'll just end up scaling those 300 x 150 pixels meaning the browser will start interpolating and smoothing the image, which is why you end up with a blurry result.
Solution
Remove these from the CSS-rule:
#myCanvas {
/*width: 100%;
height: 100%;*/
display: block;
}
and set the size in JavaScript like this:
var canvas = document.getElementById( "myCanvas" );
canvas.width = window.innerWidth; // equals window dimension
canvas.height = window.innerHeight;
You can of course set any other size you need (in pixels). You probably want to define position (i.e. fixed or absolute) for the canvas' CSS as well if your goal is full window size.
Hope this helps.

The height and width need to be set on the height and width attributes of the canvas tag and not in CSS. Any CSS sizing of the canvas element merely stretches the canvas and does not size it properly.
<canvas id="canvas" width="500px" height="500px">
Have a look at this project that I posted on my site: Creating an HTML5 Paint App
It includes a functionto resize the canvas when the browser window size changes (which you would have to modify):
this.onScreenSizeChanged = function (forceResize) {
if (forceResize || (this.canvas.width != window.innerWidth /*||
this.canvas.height != window.innerHeight*/)) {
var image = this.context.getImageData(0, 0,
this.canvas.width, this.canvas.height);
this.canvas.width = (window.innerWidth);
this.canvas.height = (window.innerHeight);
this.context.putImageData(image, 0, 0);
}
}
this.onScreenSizeChanged(true);

In my case, it was a problem with the screen pixel ratio.
To solve it, I created a canvas with a higher pixel ratio as follows:
function createHiPPICanvas(w, h) {
let ratio = window.devicePixelRatio;
let cv = document.createElement("canvas");
cv.width = w * ratio;
cv.height = h * ratio;
cv.style.width = w + "px";
cv.style.height = h + "px";
cv.getContext("2d").scale(ratio, ratio);
return cv;
}
Then I also increased accordingly the pixel ratio of the images used inside of the canvas.

Related

What is the best way to scale an Canvas with css or js to the screen? And how do I make the width of the canvas equal to the height?

I want to make an TIC TAC TOE and im pretty new to js. I want to draw the x's and 0's to the canvas.
1. How do I make the height equal to the width of the canvas?
2. What is the best way to scale the canvas to use this for example also on phones and have the same experience?
You can make a full-screen canvas and use it to display your code.
Here is a boilerplate to get you started:
HTML
<canvas id="canvas"></canvas>
CSS
* {
margin: 0;
}
canvas {
display: block;
}
JS
window.onload = function() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
width = canvas.width = window.innerWidth,
height = canvas.height = window.innerHeight;
context.fillRect(0, 0, width, height);
};

Is there a way to modify an Image with Javascript?

So I got a project where the user can generate a pdf based on their input. Using the jspdf library to generate the PDF files. The thing is though, the user can upload a profile picture, and I would like to display that image with rounded corners or fully rounded (with a border-radius of 50%). Since there isn't a native function that allows this in jspdf or any other library as far as I know (pfdkit, pdfmake), I am looking for a way to modify the image before generating the pdf.
I already tried using html2canvas, and that worked fine actually. The problem with html2canvas occurs when a user is on their mobile. Since the width and height of the image are adjusted to the screen size (both of which are around 35px), taking a snapshot with html2canvas and then displaying that in a pdf with a width & height of 100px, the image obviously gets way to blurry.
So ideally, I need something to edit the original image or something before generating a PDF file with jspdf.
Any other ideas that bring me closer to a solution are also very much appreciated.
Just for clarification, simply adding a CSS property to the image won't help. jspdf just uses the image in the img tag, without any css properties.
I would suggest you to add a class to the image before you generate the pdf and define the rule for that class in css:
.circle {
border-radius: 50%;
}
Or, even you may need to force in case there's already css with some border-radius value to img tag:
.circle {
border-radius: 50% !important;
}
It is possible to use rounded images on jspdf, you just need to apply the rounded-ness to the image before adding it to the PDF, if your already resizing you have the context.
roundedImage taken from: Canvas drawimage with round corners
For example (wont work on SO, so no demo):
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8" />
<script src="https://unpkg.com/jspdf#latest/dist/jspdf.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: #ccc;
}
#pdf {
display: block;
position: absolute;
bottom: 0;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<embed id="pdf" src="#" type="application/pdf" width="100%" height="100%" />
<script>
function roundedImage(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(
x + width,
y + height,
x + width - radius,
y + height
);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
var img = new Image();
img.src = "https://graph.facebook.com/649650002/picture?type=square";
img.setAttribute("crossorigin", "anonymous");
img.onload = function() {
//
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
roundedImage(ctx, 0, 0, 50, 50, 5);
ctx.clip();
ctx.drawImage(img, 0, 0, img.width, img.height);
ctx.restore();
// Default export is a4 paper, portrait, using milimeters for units
var doc = new jsPDF();
doc.text("woop!..rounded corners.", 10, 15);
doc.addImage(canvas.toDataURL("image/png"), "PNG", 15, 25, 30, 30);
document.getElementById("pdf").src = doc.output(
"dataurlstring",
"its-a.pdf"
);
};
</script>
</body>
</html>
If anyone for whatever reason stumbles across this post, I managed to actually achieve my desired result. As I said the user is able to upload an image and I would like to display that image with rounded corners or with a border-radius of 50%. Anyway, before previewing (and uploading) the image to my website, the user has to crop the image using cropperjs. They can then decide for themselves if they would like to display the image with rounded corners or with a border radius of 50%. I think that gives a tremendous boost to the UX and my end result.

How do I keep an element that fills the window centered?

How do I keep the canvas in the this demo centered at all times (including when the scrollbars appear) when the window is resized? The canvas element should always fill the window.
I tried playing around with settings like left, margin-left, etc. (including negative values) but to no avail.
Is this what you wanted?
This is a refactored version of your code that resizes the canvas to the smallest dimension of the window (width or height) on window resize. It also sets the display of the canvas to block and uses margin: 0 auto to center it.
Here is the demo.
UPDATE 1 I've refactored with comments to show where to change the code to resize the canvas to the largest dimension between the window height and width.
UPDATE 2 I've refactored to fit the canvas so the crosshairs are always centered by setting the width and height to the exact window.
I've also updated the CSS to remove all padding and margins.
The canvas is redrawn on window.onresize.
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
function setSize() {
var w = window.innerWidth;
var h = window.innerHeight;
//var size = (h > w) ? h : w; //<<<< resize to largest between height and width
//var size = (h < w) ? h : w; //<<<< resize to smallest between height and width
//canvas.width = size;
//canvas.height = size;
canvas.width = w; //<<<< exact resizing to width
canvas.height = h; //<<<< exact resizing to height
}
function draw() {
var context = canvas.getContext('2d');
context.fillRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = 'red';
context.moveTo(canvas.width/2, 0);
context.lineTo(canvas.width/2, canvas.height);
context.moveTo(0, canvas.height/2);
context.lineTo(canvas.width, canvas.height/2);
context.stroke();
}
setSize();
draw();
window.onresize = function(e) {
setSize();
draw();
};
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
margin: 0 auto;
}
Did you try overflow: hidden;?
JSFiddle
body {
overflow: hidden;
}
You can do something like
canvas{
position: fixed;
top: -500px;
}
To make the canvas resize with the page, try adding a window resize listener:
window.addEventListener("resize", function () {
canvas.width = window.innerWidth;
canvas.width = window.innerHeight;
});
If you want to remove margins so the canvas fills the entire page, try adding the following CSS to your page:
body {
margin: 0 !important;
padding: 0 !important;
}
After much fiddling, I think I figured it out. Here's the working demo (fullscreen version). I ended up using the following loop:
function render() {
requestAnimationFrame(render);
window.scrollTo(
document.documentElement.scrollWidth/2 - window.innerWidth/2,
document.documentElement.scrollHeight/2 - window.innerHeight/2
);
}
requestAnimationFrame(render);
which automatically scrolls the window to the middle of the entire scrollable area (including the non-visible portions) minus half the size of the viewing area itself.
Thanks to everyone for your help!

HTML5 canvas height and width 100% distorts the game animation

I am not sure, how i can be more specific, but i am putting my best effort to explain it.I am trying to understand, what should i be looking for to be more specific, so this is all i have got at this moment.
I was exploring HTML5 JavaScript games, and I noticed, that making the canvas height and width 100% distorts the animation within.
a simple example that i got from here.
If i change the canvas size to 100% (in the example I have provided) it breaks the animation of the game(for example the asteroid).
I would like to know, which property of HTML5 is responsible for this behaviour and what should I be looking for to get the HTML5 animation fit the complete screen size?
EDIT
I tried to run cordova to build the game to native platform,but the 1st problem i am encountering is that the canvas was not fitting the screen size. (that's why i wanted it to completely fit the browser screen, but i see a complete misfit when a canvas made for the browser screen is rendered to the native using cordova).
I explored phaser, about how they are solving this problem, and found this game which is using something called a ScalingManager.
So, my questions are
1. What is scaling a Game?
2. How is the scaling-manager of phaser working
3. without using the scaling manager why will a game not fit the moile screen size even though the canvas height and width are properly mentioned?
4. is there a small experment (without using any phaser or similar javascript game framework) that i can do to understand the need for scaling with simple HTML5 javasctipt and cordova?
A canvas has two distinct sizes:
the size of the element on the page
the size in pixel of the canvas
To avoid distortion and get a pixel-perfect graphic you need to ensure they end up equal... for example:
function redraw() {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
...
}
For single-page HTML games where you just want to draw everything in a canvas a simple approach is:
<!DOCTYPE html>
<html>
<head>
<style type='text/css'>
* {
margin: 0;
padding: 0;
border: none;
}
body,html {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<script>
var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
var body = document.body;
body.insertBefore(canvas, body.firstChild);
var context = canvas.getContext('2d');
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = context.webkitBackingStorePixelRatio
|| context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio
|| context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;
var ratio = devicePixelRatio / backingStoreRatio;
redraw();
window.addEventListener('resize', redraw, false);
window.addEventListener('orientationchange', redraw, false);
function redraw() {
width = (window.innerWidth > 0 ? window.innerWidth : screen.width);
height = (window.innerHeight > 0 ? window.innerHeight : screen.height);
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
width *= ratio;
height *= ratio;
if (canvas.width === width && canvas.height === height) {
return;
}
canvas.width = width;
canvas.height = height;
}
//draw things
</script>
</body>
</html>
You will also need to check for changes in innerWidth / innerHeight if your app has parts in which you're just waiting for user interaction (not looping on calling redraw) and the user instead resizes the browser window or tilts the phone/tab.
With Phaser 3, I succeeded by adding window.innerWidthand window.innerHeightto the Scale object into my config :
config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-game',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: window.innerWidth,
height: window.innerHeight
},
scene: [MainScene],
parent: 'gameContainer',
physics: {
default: 'arcade',
arcade: {
gravity: {y: 0}
}
}
};
For the moment I don't see any problem, it makes the trick.

blurred text when a canvas is placed on top of another canvas

I want to display the mouse's x position on canvas as mouse moves. Can someone please tell why the text is so big and blurry and also is there any way to achieve the transparency between these two canvases
<body style="margin: 0; padding: 0; height: 100%; width: 100%; overflow: hidden;">
<canvas id="myCanvas" style="display: block; height: 100%; width: 100%;">
Your browser does not support the HTML5 canvas tag.</canvas> <canvas id="temp">
Your browser does not support the HTML5 canvas tag.</canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var hgap = 0;
var vgap = 0;
var rows, cols;
var annotation_x = 1;
var row = 0; var col = 0;
//ctx.font = "14px Arial";
var t = document.getElementById("temp");
tctx = t.getContext("2d");
// tctx.lineWidth = 10;
tctx.lineJoin = 'round';
tctx.lineCap = 'round';
tctx.strokStyle = 'red';
var mouse = { x: 0, y: 0 };
c.addEventListener('mousemove', function (evt) {
// tctx.clearRect(0, 0, c.width, c.height);
ctx.clearRect(0, 0, c.width, c.height);
mouse.x = evt.pageX;
mouse.y = evt.pageY;
ctx.fillText(mouse.x, 10, 10);
}, false);
</script>
</body>
The problem isn't due to having two canvas.
The problem is that you scale your canvas using CSS, but you don't modify its number of pixels (height and width attributes). Then, the result is blurry.
If you don't scale it with CSS, the result is fine: Demo
Alternatively, you can try using image-rendering CSS property (e.g. crisp-edges, demo)
You can also modify height and width attributes when the browser is resized (resize event), and redraw the canvas.
<canvas id="myCanvas" style="display: block; height: 100%; width: 100%;">
^ You shouldn't scale a canvas element with CSS unless you want it's contents to be interpolated. Consider a 300x125px image, which you've scaled to the width and height of the browser window - the image will become blurry.
If you wish to have a full-screen canvas you need to scale it with JS:
var c = document.getElementById("myCanvas");
c.width = window.innerWidth;
c.height = window.innerHeight;
..or with HTML:
<canvas width="1920" height="1080"></canvas>

Categories

Resources