Canvas drawings, like lines, are blurry
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
HTML5 canvas stroke() thick and fuzzy
For some reason, your canvas is stretched. Because you have its css property width
set to 100%
, it is stretching it from some sort of native size. It's the difference between using the css width
property and the width
attribute on the <canvas>
tag. You might want to try using a bit of javascript to make it fill the viewport (see jQuery .width()):
jQuery(document).ready(function(){
var canvas = document.getElementById('drawing');
canvas.width(($(window).width()).height($(window).height());
var context = canvas.getContext('2d');
//...
How do I fix blurry shape edges in HTML5 canvas?
I figured out what was wrong. It was the device-pixel-ratio
property of the device. Anything other than a value of 1
would result in pixelated canvas content. Adjusting the zoom in a browser alters device-pixel-ratio
, and some devices come with a high device-pixel-ratio such as retina display iPhones.
You have to account for this using Javascript. There is no other way. I wrote about this in more detail on my blog, and provide some other sources as well.
You can see the final result below.
Responsive canvas using vanilla JavaScript:
var aWrapper = document.getElementById("aWrapper");var canvas = document.getElementById("myCanvas");
//Accesses the 2D rendering context for our canvasdfdfvar ctx = canvas.getContext("2d");
function setCanvasScalingFactor() { return window.devicePixelRatio || 1;}
function resizeCanvas() { //Gets the devicePixelRatio var pixelRatio = setCanvasScalingFactor();
//The viewport is in portrait mode, so var width should be based off viewport WIDTH if (window.innerHeight > window.innerWidth) { //Makes the canvas 100% of the viewport width var width = Math.round(1.0 * window.innerWidth); } //The viewport is in landscape mode, so var width should be based off viewport HEIGHT else { //Makes the canvas 100% of the viewport height var width = Math.round(1.0 * window.innerHeight); }
//This is done in order to maintain the 1:1 aspect ratio, adjust as needed var height = width;
//This will be used to downscale the canvas element when devicePixelRatio > 1 aWrapper.style.width = width + "px"; aWrapper.style.height = height + "px";
canvas.width = width * pixelRatio; canvas.height = height * pixelRatio;}
var cascadeFactor = 255;var cascadeCoefficient = 1;
function draw() { //The number of color block columns and rows var columns = 5; var rows = 5; //The length of each square var length = Math.round(canvas.width/columns) - 2; //Increments or decrements cascadeFactor by 1, based on cascadeCoefficient cascadeFactor += cascadeCoefficient;
//Makes sure the canvas is clean at the beginning of a frame ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = columns; i >= 1; i--) { for (var j = rows; j >= 1; j--) { //Where the color magic happens ctx.fillStyle = "rgba(" + (j*i*(cascadeFactor-110)) + "," + (i*cascadeFactor) + "," + (j*cascadeFactor) + "," + 0.6 + ")"; ctx.fillRect((length*(i-1)) + ((i-1)*2), (length*(j-1)) + ((j-1)*2), length, length); } } if (cascadeFactor > 255 || cascadeFactor < 0) { //Resets the color cascade cascadeCoefficient = -cascadeCoefficient; } //Continuously calls draw() again until cancelled var aRequest = window.requestAnimationFrame(draw);}
window.addEventListener("resize", resizeCanvas, false);
resizeCanvas();draw();
#aWrapper { /*Horizontally centers the canvas*/ margin: 0 auto;}
#myCanvas { /*This eliminates inconsistent rendering across browsers, canvas is supposed to be a block-level element across all browsers anyway*/ display: block;
/*myCanvas will inherit its CSS width and style property values from aWrapper*/ width: 100%; height: 100%;}asdfasdf
<div id="aWrapper"> <!--Include some fallback content on the 0.00001% chance your user's browser doesn't support canvas --> <canvas id="myCanvas">Fallback content</canvas></div>
Canvas element with blurred lines
You can oversample the canvas (fake double resolution):
Here's an illustration with standard resolution on top and "double" resolution on bottom:
A Demo: http://jsfiddle.net/m1erickson/M5NHN/
Html:
<canvas id="canvas1" width=300 height=150></canvas>
<canvas id="canvas2" width=600 height=300></canvas>
CSS:
#canvas1 {
border:1px solid red;
width:300px;
height:150px;
}
#canvas2 {
border:1px solid green;
width:300px;
height:150px;
}
JS:
var canvas = document.getElementById("canvas1");
var context1 = canvas.getContext("2d");
var canvas = document.getElementById("canvas2");
var context2 = canvas.getContext("2d");
draw(context1);
context2.scale(2, 2);
draw(context2);
function draw(c2){
c2.fillStyle = '#f00';
c2.beginPath();
c2.moveTo(0, 0);
c2.lineTo(100, 0);
c2.lineTo(80, 50);
c2.lineTo(0, 50);
c2.closePath();
c2.fill();
c2.fillStyle = "#000";
c2.beginPath();
c2.moveTo(0, 50);
c2.lineTo(80, 50);
c2.lineTo(60, 100);
c2.lineTo(0, 100);
c2.closePath();
c2.fill();
}
How come the canvas drawing is blurry, and how do I sharpen it?
Use image-rendering: pixelated;
css property to turn off antialiasing
document.querySelectorAll('canvas').forEach(canvas => {
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'magenta'
for (let i = 0; i < canvas.width; i += 1) {
ctx.fillRect(i, i, 1, 1)
}
})
canvas {
width: 100px;
height: 100px;
border: 1px solid black;
}
.pixelated {
image-rendering: pixelated;
}
<canvas width="10" height="10"></canvas>
<canvas class="pixelated" width="10" height="10"></canvas>
html5 canvas. blurry lines
The lines shown in the code are as crisp as they can get. Lines cannot be thinner than one pixel (this is what I get from your code in Firefox and Opera):
You can from this point only give the illusion of them being thinner by reducing the blackness. For example, if you stroke with mid-gray (#777) color they will appear like this:
But they are the exact same size.
This illusion is the same that you would get if you used a line width of 0.5 or used a double sized canvas and reduced it to half using CSS (in those cases due to resampling / interpolation).
Addendum: If the lines in the images above still look uneven there is the possibility that your monitor settings aren't optimal, ie. the resolution in use does not match the physical pixels of the screen. Check that the system settings are using the recommended resolution as any other will force interpolation/resampling at system/hardware level and no matter what you do in canvas won't help.
function doStuff() { var cnv = document.getElementById("cnvs"); var ctx = cnv.getContext("2d"); var lw = 1; ctx.lineWidth = lw; var xMax = cnv.width; var ygMax = cnv.height;
var iTranslate = 0.5; // (lw % 2) / 2; ctx.translate(iTranslate, iTranslate);
deltaX = 12;
ctx.strokeStyle = "#777"; for (var x = deltaX; x < xMax; x += deltaX) { drawLine(ctx, x, ygMax, x, 0); }}
function drawLine(ctx, x0, y0, xf, yf) { ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(xf, yf); ctx.stroke();}
doStuff();
<canvas id="cnvs" width="200" height="100"></canvas>
Blurry effect using canvas
The solution requires (as noted by @Kaiido), the use of Window.devicePixelRatio
:
The devicePixelRatio of Window interface returns the ratio of the resolution in physical pixels to the resolution in CSS pixels for the current display device. This value could also be interpreted as the ratio of pixel sizes: the size of one CSS pixel to the size of one physical pixel. In simpler terms, this tells the browser how many of the screen's actual pixels should be used to draw a single CSS pixel.
The code that solves the problem is:
if (devicePixelRatio != 1.0) {
context.canvas.style.width = (context.canvas.width / devicePixelRatio) + "px";
context.canvas.style.height = (context.canvas.height / devicePixelRatio) + "px";
}
This also works in browsers other than Chrome, They (in my own case) return the value 1 for Window.devicePixelRatio
, leaving the previous functionality intact.
Related Topics
Why Display Grid with 100% in Grid-Template-Columns Goes Out of Body
Changing <Select> Highlight Color
Flex Items Not Respecting Margins and Box-Sizing: Border-Box
Pure CSS Multi-Level Drop-Down Menu
Colspan/Rowspan For Elements Whose Display Is Set to Table-Cell
I Have Position But Z Index Is Not Working
Highlight Words in HTML Using Regex & JavaScript - Almost There
Hiding Elements in Responsive Layout
Css Background Color With Floating Elements
How to Make ≪Div≫ Fill ≪Td≫ Height
Regex Replace Text Outside HTML Tags
Turn Off Iphone/Safari Input Element Rounding
Text-Align Class for Inside a Table
Extend Bootstrap Row Outside the Container
Ellipsis For Overflow Text in Dropdown Boxes
How to Correctly Select the First or the Last Child With Css