Canvas image: center wide image and hide overflow - html

I have a very wide image that exceeds mostly viewing widths and must be rendered using a <canvas> tag. How would I hide the overflow and also center the image?
In other words, I'm looking for the canvas equivalent to background-position: center.
Ideally, this would be done in a way which is responsive - so if the viewing window is resized, the image stays centered.
Here's an example:
window.onload = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
ctx.drawImage(img, 0, 0);
};
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
canvas {
overflow: hidden;
}
.canvasContainer {
width: 100%;
overflow-x: hidden;
}
img {
display: none;
}
<div class="container">
<div class="canvasContainer">
<img id="image" src="http://via.placeholder.com/2400x800?text=center" />
<canvas id="canvas" width="2400" height="800" />
</div>
</div>
Note: There is a text Center present in the placeholder, but is currently not visible

This code should do what you need.
The image width should be set to the canvas.width to avoid the image overflowing the canvas.
The image height is now relative to the image width so the ratio stays the same.
I have included an event listener which will resize your canvas/image to the size of the window.
function init() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
var canHeight = window.innerWidth / 4;
canvas.width = window.innerWidth;
canvas.height = canHeight;
var width = canvas.width;
ctx.drawImage(img, 0, 0, width, canHeight);
}
init();
window.addEventListener('resize', function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
init();
});

For the canvas you just draw the image where you want it. It will not add scroll bars. The example loads the image and centers it on the canvas. You can click to see the image scaled to fit (see all the image), fill (see full height, or full width whichever fits best to fill the canvas) and click again to see at full resolution centered.
const image = new Image();
image.src = "http://via.placeholder.com/2400x800";
image.onload = showImage;
addEventListener("resize",showImageFit)
function drawText(text){
const ctx = canvas.getContext("2d");
ctx.font = "28px arial";
ctx.textAlign = "center";
ctx.fillText(text,canvas.width / 2, 28);
}
function showImage(){
canvas.width = innerWidth - 8;
canvas.height = innerHeight - 8;
const x = (canvas.width / 2 - image.naturalWidth / 2) | 0;
const y = (canvas.height / 2 - image.naturalHeight / 2) | 0;
canvas.getContext("2d").drawImage(image,x,y);
drawText("Click to scale image to fit");
canvas.onclick = showImageFit;
}
function showImageFit(){
canvas.width = innerWidth - 8;
canvas.height = innerHeight - 8;
const scale = Math.min( canvas.width /image.naturalWidth , canvas.height / image.naturalHeight );
const x = (canvas.width / 2 - (image.naturalWidth / 2) * scale) | 0;
const y = (canvas.height / 2 - (image.naturalHeight / 2) * scale) | 0;
canvas.getContext("2d").drawImage(image,x,y,image.naturalWidth * scale, image.naturalHeight * scale);
drawText("Click to scale image to fill");
canvas.onclick = showImageFill;
}
function showImageFill(){
canvas.width = innerWidth - 8;
canvas.height = innerHeight - 8;
const scale = Math.max( canvas.width /image.naturalWidth , canvas.height / image.naturalHeight );
const x = (canvas.width / 2 - (image.naturalWidth / 2) * scale) | 0;
const y = (canvas.height / 2 - (image.naturalHeight / 2) * scale) | 0;
canvas.getContext("2d").drawImage(image,x,y,image.naturalWidth * scale, image.naturalHeight * scale);
drawText("Click to see image at full resolution and centered");
canvas.onclick = showImage;
}
canvas {
border : 2px solid black;
}
body {
margin : 0px;
}
<canvas id="canvas"></canvas>

Thanks for the feedback - the suggested solutions work with solving the canvas problem.
I found another solution, which was to treat the canvas as I would any other oversized element and use CSS.
+-------------------------------------------+
| page container |
+---------------------------------------------------------+
| |
| canvas |
+---------------------------------------------------------+
| |
+-------------------------------------------+
Solution (and illustration) taken from here:
center oversized image in div
margin-left: 50%;
transform: translateX(-50%);

Related

How to resize and rotate image simulataneously using canvas

I have to resize and rotate a image before upload, resize is to make the picture smaller, and rotate is to correct the image captured by iPhone.
Here is the code i am using, for resize, i am using a smaller canvas to redraw the image, for rotation, i am using canvas to do it.
the problem is that, my image only show a portion of the source image. how to show the full image?
This is the source image
This is what i got with the code: you can see the rotation was correct, but the resize is not, it clips the source image and left only part of it.
this is what i want.
const img = new Image();
img.src = 'https://i.stack.imgur.com/rzJQD.jpg';
img.onload = e => resize_and_rotate(img, 6);
function resize_and_rotate(img, orientation) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
// limit the image to at most 600px width or 900px height.
let ratio = img.height / img.width;
if (img.width > 600) {
canvas.width = 600;
canvas.height = canvas.width * ratio;
} else if (img.height > 900) {
canvas.height = 900;
canvas.width = canvas.height / ratio;
}
let width = canvas.width;
let height = canvas.height;
/*
For iPhone, landscape mode(with home key point to right) is the correct mode, it orientation is 1
for portrait mode(home key point to bottom), the image will rotate right by 90 degree.
*/
if (orientation === 6) { // rotate 90 degree.
// swap canvas width and height.
canvas.width = height;
canvas.height = width;
// move to the center of the canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
// rotate the canvas to the specified degrees
ctx.rotate(0.5 * Math.PI);
// since the context is rotated, the image will be rotated also
ctx.drawImage(img, -img.width / 2, -img.height / 2);
} else if (orientation === 3) { // rotate 180 degree.
// 180° rotate left
ctx.translate(canvas.width, canvas.height);
ctx.rotate(Math.PI);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
} else if (orientation === 8) { // rotate 90 degree, counter-clockwise.
canvas.width = height;
canvas.height = width;
// move to the center of the canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
// rotate the canvas to the specified degrees
ctx.rotate(-0.5 * Math.PI);
// since the context is rotated, the image will be rotated also
ctx.drawImage(img, -img.width / 2, -img.height / 2);
} else {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
}
// return base64 data.
// let base64 = canvas.toDataURL("image/jpeg");
// return base64;
// for SO
document.body.append(canvas);
}
canvas{max-height: 100vh; max-width: 100vw}
If i remove the following piece of code, the result was right, but it does not resize my image. seems like something wrong with the canvas size? please help.
// limit the image to at most 600px width or 900px height.
let ratio = img.height / img.width;
if (img.width > 600) {
canvas.width = 600;
canvas.height = canvas.width * ratio;
} else if (img.height > 900) {
canvas.height = 900;
canvas.width = canvas.height / ratio;
}
Your problem lies in drawImage.
You are not using enough arguments and your are not using the correct values there.
After you have done your transformations (translate(center); rotate()), you correctly try to inverse the translation so that the image be painted from the top-left corner as it should. However, you are using the original size of your image as x,y parameters instead of the destination ones.
Also, by using the 3 params version, you let destinationWidth and destinationHeight be the original size of your image, while you need the width and height of your canvas:
ctx.drawImage(img, -width / 2, -height / 2, width, height);
const img = new Image();
img.src = 'https://i.stack.imgur.com/rzJQD.jpg';
img.onload = e => resize_and_rotate(img, 6);
function resize_and_rotate(img, orientation) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
// limit the image to at most 600px width or 900px height.
let ratio = img.height / img.width;
if (img.width > 600) {
canvas.width = 600;
canvas.height = canvas.width * ratio;
} else if (img.height > 900) {
canvas.height = 900;
canvas.width = canvas.height / ratio;
}
let width = canvas.width;
let height = canvas.height;
/*
For iPhone, landscape mode(with home key point to right) is the correct mode, it orientation is 1
for portrait mode(home key point to bottom), the image will rotate right by 90 degree.
*/
if (orientation === 6) { // rotate 90 degree.
// swap canvas width and height.
canvas.width = height;
canvas.height = width;
// move to the center of the canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
// rotate the canvas to the specified degrees
ctx.rotate(0.5 * Math.PI);
// since the context is rotated, the image will be rotated also
ctx.drawImage(img, -width / 2, -height / 2, width, height);
} else if (orientation === 3) { // rotate 180 degree.
// 180° rotate left
ctx.translate(canvas.width, canvas.height);
ctx.rotate(Math.PI);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
} else if (orientation === 8) { // rotate 90 degree, counter-clockwise.
canvas.width = height;
canvas.height = width;
// move to the center of the canvas
ctx.translate(height / 2, width / 2);
// rotate the canvas to the specified degrees
ctx.rotate(-0.5 * Math.PI);
// since the context is rotated, the image will be rotated also
ctx.drawImage(img, -width / 2, -height / 2, width, height);
} else {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, width, height);
}
// return base64 data.
// let base64 = canvas.toDataURL("image/jpeg");
// return base64;
// for SO
document.body.append(canvas);
}
canvas{max-height: 100vh; max-width: 100vw}

canvas drawImage upscale and then crop

Using drawImage, I am trying to do the following with an image that is 1280x720...
Upscale it to 1920x1080
Crop it so that only 600x1080 remains from the centre
I have this so far...
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
img=new Image();
img.onload=function(){
canvas.width=1920;
canvas.height=1080;
ctx.drawImage(img,0,0,img.width,img.height,0,0,1920,1080);
}
img.src="https://dummyimage.com/1280x720/000/fff";
//img.src="https://dummyimage.com/1920x1080/000/fff";
body{ background-color: ivory; }
canvas{border:1px solid red;}
<canvas id="canvas" width=100 height=100></canvas>
The upscaling part I have got working but now I am looking at the crop, anyone have an example I can see?
Is there any benefit from cropping first before rescaling?
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 1920, 1080);
Something like that:
x = (img.width - 600) / 2;
y = (img.height - 1080) / 2;
ctx.drawImage(img, x, y, 600, 1080, 0, 0, 1920, 1080);
but check for the destination area parameters depending on what exactly you want to get.
Clip image to fit canvas
The canvas will clip the image for you.
By default all rendering has a clip region set to the canvas size. Because the clip is performed regardless of the size of the content (all content must be checked against the clip region and is done in hardware (GPU)) rendering the full image is slightly quicker than rendering a portion of the image.
ctx.drawImage(image,x,y); // is the quicker function
ctx.drawImage(image,ix,iy,iw,ih,x,y,w,h); // the slower function
Note; This is not true when the rendered visible destination content is significantly smaller than the image source
Thus to render the image cropped to a smaller canvas you only need to find the center and then render the image at half its size away from that center.
ctx.drawImage(
image, // image to render
(ctx.canvas.width - image.width) / 2, // center sub half image width
(ctx.canvas.height - image.height) / 2 // center sub half image height
);
If you need to up scale first the following will render any size image to fit 1080 height.
const imgW = 1920;
const imgH = 1080;
ctx.drawImage(
image, // image to render
(ctx.canvas.width - imgW) / 2, // center sub half image display width
(ctx.canvas.height - imgH) / 2, // center sub half image display height
imgW, imgH
);
Crop image
If you wish to save memory and crop the image you use a canvas to hold the cropped image.
function cropImageCenter(image,w,h){
const c = document.createElement("canvas");
c.width = w;
c.height = h;
const ctx = c.getContext("2d");
ctx.drawImage(image,(w - image.width) / 2, (h - image.height) / 2);
return c;
}
var img = new Image;
img.src = "imageURL1280by720.jpg";
img.onload = () => {
img = cropImageCenter(img, 600, 1080);
ctx.drawImage(img,0,0); /// render cropped image on to canvas
};
Or to upscale and crop
function scaleCropToHeight(image,w,h){
const c = document.createElement("canvas");
c.width = w;
c.height = h;
const scale = h / image.height;
const ctx = c.getContext("2d");
ctx.drawImage(
image,
(w - image.width * scale) / 2,
(h - image.height * scale) / 2,
image.width * scale,
image.height * scale
);
return c;
}
var img = new Image;
img.src = "imageURL1920by1080.jpg";
img.onload = () => {
img = scaleCropToHeight(img, 600, 1080);
ctx.drawImage(img,0,0); /// render cropped image on to canvas
};

HTML 5 canvas lines appear distorted

I am trying to make a grid on my 500px x 500px canvas:
<canvas id="area" style="width: 500px; height: 500px;"></canvas>
var canvas = document.getElementById('area');
var context = canvas.getContext('2d');
for (var x = 0.5; x < 500; x += 10) {
context.moveTo(x, 0);
context.lineTo(x, 500);
}
for (var y = 0.5; y < 500; y += 10) {
context.moveTo(0, y);
context.lineTo(500, y);
}
context.strokeStyle = "#eee";
context.stroke();
The code looks correct to me but for some reason its coming out elongated and pixelated:
http://jsfiddle.net/DK4m7/1/
Would anyone know why this occurring?
Avoid using CSS to set the canvas size, do instead:
<canvas id="area" width=500 height=500></canvas>
Using CSS will just stretch the current size of the canvas' bitmap which defaults to 350 x 150 pixels. You need to specifically define the bitmap size using the width and height attributes.
Modified fiddle

Canvas items not rendering properly

I have defined the two functions to render a circle and a triangle. Very straight forward stuff.
function circle(offset, size){
var color = $("#color option:selected").val();
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
radius = size * 1;
context.beginPath();
context.arc(offset, 2, radius, 0, 2 * Math.PI, false);
context.fillStyle = color;
context.fill();
}
function triangle(offset, size){
var color = $("#color option:selected").val();
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = size * 6;
var height = size * 5;
var padding = 0;
// Draw a path
context.beginPath();
context.moveTo(offset + width/2, padding);
context.lineTo(offset + width, height + padding);
context.lineTo(offset, height + padding);
context.closePath();
// Fill the path
context.fillStyle = color;
context.fill();
}
I am have added the canvas to my page with:
<canvas id="canvas"></canvas>
For some reason I can see the circle and square a not rendering correctly. See attached screen shots.
I can almost guarantee that it is because you are setting the width and height of the Canvas using CSS width and height and not the <canvas> html attributes.
You need to define the width/height either in the canvas tag:<canvas width="500" height="500">
or in code:
var canvas = document.getElementById("canvas");
canvas.width = 500;
canvas.height = 500;
And not by CSS. If you did this:
<canvas style="width: 500px; height: 500px;">
Then you would have a 300x150 canvas (the default size) that was scaled/warped to be 500x500, which is almost certainly what you're getting.
(I wrote the above freehand so there might be a typo, but you get the idea)

Canvas drawings, like lines, are blurry

I have a <div style="border:1px solid border;" /> and canvas, which is drawn using:
context.lineWidth = 1;
context.strokeStyle = "gray";
The drawing looks quite blurry (lineWidth less than one creates even worse picture), and nothing near to the div's border. Is it possible to get the same quality of drawing as HTML using canvas?
var ctx = document.getElementById("canvas").getContext("2d");
ctx.lineWidth = 1;
ctx.moveTo(2, 2);
ctx.lineTo(98, 2);
ctx.lineTo(98, 98);
ctx.lineTo(2, 98);
ctx.lineTo(2, 2);
ctx.stroke();
div {
border: 1px solid black;
width: 100px;
height: 100px;
}
canvas, div {background-color: #F5F5F5;}
canvas {border: 1px solid white;display: block;}
<table>
<tr><td>Line on canvas:</td><td>1px border:</td></tr>
<tr><td><canvas id="canvas" width="100" height="100"/></td><td><div> </div></td></tr>
</table>
I found that setting the canvas size in CSS caused my images to be displayed in a blurry manner.
Try this:
<canvas id="preview" width="640" height="260"></canvas>
as per my post: HTML Blurry Canvas Images
When drawing lines in canvas, you actually need to straddle the pixels. It was a bizarre choice in the API in my opinion, but easy to work with:
Instead of this:
context.moveTo(10, 0);
context.lineTo(10, 30);
Do this:
context.moveTo(10.5, 0);
context.lineTo(10.5, 30);
Dive into HTML5's canvas chapter talks about this nicely
Even easier fix is to just use this:
context = canvas.context2d;
context.translate(0.5, 0.5);
From here on out your coordinates should be adjusted by that 0.5 pixel.
I use a retina display and I found a solution that worked for me here.
Small recap :
First you need to set the size of your canvas twice as large as you want it, for example :
canvas = document.getElementById('myCanvas');
canvas.width = 200;
canvas.height = 200;
Then using CSS you set it to the desired size :
canvas.style.width = "100px";
canvas.style.height = "100px";
And finally you scale the drawing context by 2 :
const dpi = window.devicePixelRatio;
canvas.getContext('2d').scale(dpi, dpi);
The Mozilla website has example code for how to apply the correct resolution in a canvas:
https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Set display size (css pixels).
var size = 200;
canvas.style.width = size + "px";
canvas.style.height = size + "px";
// Set actual size in memory (scaled to account for extra pixel density).
var scale = window.devicePixelRatio; // Change to 1 on retina screens to see blurry canvas.
canvas.width = size * scale;
canvas.height = size * scale;
// Normalize coordinate system to use css pixels.
ctx.scale(scale, scale);
ctx.fillStyle = "#bada55";
ctx.fillRect(10, 10, 300, 300);
ctx.fillStyle = "#ffffff";
ctx.font = '18px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var x = size / 2;
var y = size / 2;
var textString = "I love MDN";
ctx.fillText(textString, x, y);
<canvas id="canvas"></canvas>
Lines are blurred because the canvas virtual size is zoomed to its HTML element actual size. To overcome this issue you need to adjust canvas virtual size before drawing:
function Draw () {
var e, surface;
e = document.getElementById ("surface");
/* Begin size adjusting. */
e.width = e.offsetWidth;
e.height = e.offsetHeight;
/* End size adjusting. */
surface = e.getContext ("2d");
surface.strokeRect (10, 10, 20, 20);
}
window.onload = Draw ()
<!DOCTYPE html>
<html>
<head>
<title>Canvas size adjusting demo</title>
</head>
<body>
<canvas id="surface"></canvas>
</body>
</html>
HTML:
Ok, I've figured this out once and for all. You need to do two things:
place any lines on 0.5 px. Refer to this, which provides a great explanation:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors#A_lineWidth_example
There are essentially two heights and two widths associated with the canvas. There is the canvas height and width and then there is the css style height and width of the element. These need to be in sync.
To do this, you need to calculate the css height and width as:
var myCanvasEl = document.getElementById('myCanvas');
var ctx = myCanvasEl.getContext('2d');
myCanvasEl.style.height = myCanvasEl.height / window.devicePixelRatio + "px";
myCanvasEl.style.width = myCanvasEl.width / window.devicePixelRatio + "px";
where myCanvasEl.style.height and myCanvasEl.style.widthis the css styling height and width of the element, while myCanvasEl.height and myCanvasEl.width is the height and width of the canvas.
OLD ANSWER (superseded by above):
This is the best solution I've found in 2020. Notice I've multiplied the devicePixelRatio by 2:
var size = 100;
var scale = window.devicePixelRatio*2;
context.width = size * scale;
cartesian_001El.style.height = cartesian_001El.height / window.devicePixelRatio + "px";
cartesian_001El.style.height = cartesian_001El.height / window.devicePixelRatio + "px";
context.height = size * scale;
context.scale(scale, scale);
Something else that nobody talked about here when images are scaled (which was my issue) is imageSmoothingEnabled.
The imageSmoothingEnabled property of the CanvasRenderingContext2D interface, part of the Canvas API, determines whether scaled images are smoothed (true, default) or not (false). On getting the imageSmoothingEnabled property, the last value it was set to is returned.
This property is useful for games and other apps that use pixel art. When enlarging images, the default resizing algorithm will blur the pixels. Set this property to false to retain the pixels' sharpness.
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled
To disable it, simply set the properity to false:
ctx.imageSmoothingEnabled = false;
canvas.width=canvas.clientWidth
canvas.height=canvas.clientHeight
To avoid this issue in animation I would like to share a small demo.
Basically I am checking increment values each time & jumping in a set of 1px by removing float values.
HTML:
<canvas id="canvas" width="600" height="600"></canvas>
CSS:
html, body{
height: 100%;
}
body{
font-family: monaco, Consolas,"Lucida Console", monospace;
background: #000;
}
canvas{
position: fixed;
top: 0;
left: 0;
transform: translateZ(0);
}
JS:
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
ctx.translate(0.5, 0.5);
var i = 0;
var iInc = 0.005;
var range = 0.5;
raf = window.requestAnimationFrame(draw);
function draw() {
var animInc = EasingFunctions.easeInQuad(i) * 250;
ctx.clearRect(0, 0, 600, 600);
ctx.save();
ctx.beginPath();
ctx.strokeStyle = '#fff';
var rectInc = 10 + animInc;
// Avoid Half Pixel
rectIncFloat = rectInc % 1; // Getting decimal value.
rectInc = rectInc - rectIncFloat; // Removing decimal.
// console.log(rectInc);
ctx.rect(rectInc, rectInc, 130, 60);
ctx.stroke();
ctx.closePath();
ctx.font = "14px arial";
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.fillText("MAIN BUTTON", 65.5 + rectInc, 35.5 + rectInc);
i += iInc;
if (i >= 1) {
iInc = -iInc;
}
if (i <= 0) {
iInc = Math.abs(iInc);
}
raf = window.requestAnimationFrame(draw);
}
// Easing
EasingFunctions = {
// no easing, no acceleration
linear: function(t) {
return t
},
// accelerating from zero velocity
easeInQuad: function(t) {
return t * t
},
// decelerating to zero velocity
easeOutQuad: function(t) {
return t * (2 - t)
},
// acceleration until halfway, then deceleration
easeInOutQuad: function(t) {
return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t
},
// accelerating from zero velocity
easeInCubic: function(t) {
return t * t * t
},
// decelerating to zero velocity
easeOutCubic: function(t) {
return (--t) * t * t + 1
},
// acceleration until halfway, then deceleration
easeInOutCubic: function(t) {
return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
},
// accelerating from zero velocity
easeInQuart: function(t) {
return t * t * t * t
},
// decelerating to zero velocity
easeOutQuart: function(t) {
return 1 - (--t) * t * t * t
},
// acceleration until halfway, then deceleration
easeInOutQuart: function(t) {
return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t
},
// accelerating from zero velocity
easeInQuint: function(t) {
return t * t * t * t * t
},
// decelerating to zero velocity
easeOutQuint: function(t) {
return 1 + (--t) * t * t * t * t
},
// acceleration until halfway, then deceleration
easeInOutQuint: function(t) {
return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t
}
}
A related issue could be that you're setting the <canvas>'s height and width from CSS or other sources. I'm guessing it scales the canvas and associated drawings. Setting the <canvas> size using the height and width property (either from the HTML tag or a JS script) resolved the error for me.
Here is my solution: set width and height for canvas
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Also set in css, so it will not overflow from its parent
canvas {
width: 100%
height: 100%
}
Although LittleJoe's solution worked perfect on desktop it didn't work on mobile because on iphone 11 pro for example the dpi is 3 so I had to set width/height based on dpi. At the end it worked:
let width = 100, height = 100;
const dpi = window.devicePixelRatio;
canvas = document.getElementById('myCanvas');
canvas.width = width * dpi;
canvas.height = height * dpi;
canvas.style.width = width + "px";
canvas.style.height = width + "px";
canvas.getContext('2d').scale(dpi, dpi);
in order to get rid of the blurryness you need to set the size of the canvas in two manners:
first withcanvas.width = yourwidthhere;
and canvas.height = yourheighthere;
second by setting the css attribute either by js or a stylesheet
HTML:
<canvas class="canvas_hangman"></canvas>
JS:
function setUpCanvas() {
canvas = document.getElementsByClassName("canvas_hangman")[0];
ctx = canvas.getContext('2d');
ctx.translate(0.5, 0.5);
// Set display size (vw/vh).
var sizeWidth = 80 * window.innerWidth / 100,
sizeHeight = 100 * window.innerHeight / 100 || 766;
// console.log(sizeWidth, sizeHeight);
// Setting the canvas height and width to be responsive
canvas.width = sizeWidth;
canvas.height = sizeHeight;
canvas.style.width = sizeWidth;
canvas.style.height = sizeHeight;
}
window.onload = setUpCanvas();
This perfectly sets up your HTML canvas to draw on, and in a responsive manner too :)