How Do I Draw Thin But Sharper Lines In Html Canvas?
Solution 1:
What you are experiencing is the difference between your screen's PPI and your printer's DPI.
Canvas output is a raster image, if you set its size to be like 96px, a monitor with a resolution of 96ppi will output it as a one inch large image, but a printer with 300ppi will output it as a 3.125 inch image. When doing so, the printing operation will downsample your image so it can fit into this new size. (each pixel will be multiplied so it covers a bigger area).
But the canvas context2d has a scale() method, so if all your drawings are vector based, you can :
- create a bigger canvas before printing,
 - set its context's scale to the wanted factor,
 - call the same drawing as on the smaller canvas
 - if you are printing directly from the browser's "print the page", set the bigger canvas 
style.widthandstyle.heightproperties to thewidthandheightproperties of the smaller one, - replace the smaller canvas node with the bigger one,
 - print,
 - replace the bigger canvas with the original one
 
For this, you will need to rewrite a little bit your function so it doesn't take the passed canvas' width/height as values, but rather values that you have chosen.
functiondrawBkg(ctx, width, height, squareSize, minorLineWidthStr, lineColStr) {
  var nLinesDone = 0;
  var i, curX, curY;
  ctx.clearRect(0, 0, width, height);
  // draw the vertical lines
  curX = 0;
  ctx.strokeStyle = lineColStr;
  while (curX < width) {
    if (nLinesDone % 5 == 0)
      ctx.lineWidth = 0.7;
    else
      ctx.lineWidth = minorLineWidthStr;
    ctx.beginPath();
    ctx.moveTo(curX, 0);
    ctx.lineTo(curX, height);
    ctx.stroke();
    curX += squareSize;
    nLinesDone++;
  }
  // draw the horizontal lines
  curY = 0;
  nLinesDone = 0;
  while (curY < height) {
    if (nLinesDone % 5 == 0)
      ctx.lineWidth = 0.7;
    else
      ctx.lineWidth = minorLineWidthStr;
    ctx.beginPath();
    ctx.moveTo(0, curY);
    ctx.lineTo(width, curY);
    ctx.stroke();
    curY += squareSize;
    nLinesDone++;
  }
}
// your drawingsvar smallCanvas = document.getElementById('smallCanvas');
var smallCtx = smallCanvas.getContext('2d');
drawBkg(smallCtx, smallCanvas.width, smallCanvas.height, 3.78, "0.35", "green");
// a function to get the screen's ppifunctiongetPPI() {
  var test = document.createElement('div');
  test.style.width = "1in";
  test.style.height = 0;
  document.body.appendChild(test);
  var dpi = devicePixelRatio || 1;
  var ppi = parseInt(getComputedStyle(test).width) * dpi;
  document.body.removeChild(test);
  return ppi;
}
functionscaleAndPrint(outputDPI) {
  var factor = outputDPI / getPPI();
  var bigCanvas = smallCanvas.cloneNode();
  // set the required size of our "printer version" canvas
  bigCanvas.width = smallCanvas.width * factor;
  bigCanvas.height = smallCanvas.height * factor;
  // set the display size the same as the original one to don't brake the page's layoutvar rect = smallCanvas.getBoundingClientRect();
  bigCanvas.style.width = rect.width + 'px';
  bigCanvas.style.height = rect.height + 'px';
  var bigCtx = bigCanvas.getContext('2d');
  // change the scale of our big context
  bigCtx.scale(factor, factor);
  // tell the function we want the height and width of the small canvasdrawBkg(bigCtx, smallCanvas.width, smallCanvas.height, 3.78, "0.35", "green");
  // replace our original canvas with the bigger one
  smallCanvas.parentNode.replaceChild(bigCanvas, smallCanvas);
  // call the printerprint();
  // set the original one back
  bigCanvas.parentNode.replaceChild(smallCanvas, bigCanvas);
}
btn_o.onclick = function() { print(); };
btn_s.onclick = function() { scaleAndPrint(300);};<buttonid="btn_o">print without scaling</button><buttonid="btn_s">print with scaling</button><br><canvasid="smallCanvas"width="250"height="500"></canvas>1. all drawing operations on canvas are vector based, except for drawImage(), and putImageData()
Solution 2:
Most simple way to achieve cripser lines is to use oversampling : you draw in a canvas which has a resolution bigger than the screen's resolution.
In Javascript if you want to oversample by a factor of X :
- Change canvas's width and height to 
width*Xandheight*X - Scale the canvas's context by a factor of X
 - Fix Css width and height to inital width and height to keep same size on screen.
 
In the below sample i first downsampled the canvas to make it easier to see. You have to zoom quite a lot to see the difference between no upsampling, 2 X and 4X.
functionoverSampleCanvas(tgtCanvas, ctx, factor) {
  var width = tgtCanvas.width;
  var height = tgtCanvas.height;
  tgtCanvas.width = 0 | (width * factor);
  tgtCanvas.height = 0 | (height * factor);
  tgtCanvas.style.width = width + 'px';
  tgtCanvas.style.height = height + 'px';
  ctx.scale(factor, factor);
}
// -------------------- examplevar $ = document.getElementById.bind(document);
var cv05 = $('cv05'),
  ctx05 = cv05.getContext('2d');
var cv = $('cv'),
  ctx = cv.getContext('2d');
var cv2X = $('cv2X'),
  ctx2X = cv2X.getContext('2d');
var cv4X = $('cv4X'),
  ctx4X = cv4X.getContext('2d');
overSampleCanvas(cv05, ctx05, 0.5);
overSampleCanvas(cv2X, ctx2X, 2);
overSampleCanvas(cv4X, ctx4X, 4);
functiondrawCircle(ctx) {
  ctx.beginPath();
  ctx.arc(100, 100, 50, 0, 6.28);
  ctx.fillStyle = '#AB6';
  ctx.fill();
}
drawCircle(ctx05);
drawCircle(ctx);
drawCircle(ctx2X);
drawCircle(ctx4X); canvas downsampled by 2X, normal, then upsampled by 2X, then 4X. <br><canvasid="cv05"width="100"height="100"></canvas><canvasid="cv"width="100"height="100"></canvas><canvasid="cv2X"width="100"height="100"></canvas><canvasid="cv4X"width="100"height="100"></canvas>

Post a Comment for "How Do I Draw Thin But Sharper Lines In Html Canvas?"