如何在html画布中绘制细而锐利的线条?

时间:2015-12-29 06:56:55

标签: javascript html5-canvas

我有以下javascript代码来绘制图表。但问题是当我打印出来时,细线看起来并不敏锐。缩放html页面时会出现此问题。我希望线条更清晰。但宽度应该相同。可能吗?请帮忙。

@1x

2 个答案:

答案 0 :(得分:1)

您遇到的是屏幕PPI与您的打印机DPI之间的区别。

Canvas输出是光栅图像,如果将其大小设置为96px,则分辨率为96ppi的显示器会将其输出为1英寸大图像,但300ppi的打印机会将其输出为3.125英寸图像。
执行此操作时,打印操作将对图像进行下采样,以使其适合此新尺寸。 (每个像素将成倍增加,因此它覆盖更大的区域)。

但画布context2d有scale() method,所以如果你的所有绘图都是基于矢量的 1 ,你可以:

  • 在打印前创建更大的画布,
  • 将其上下文的比例设置为所需因子
  • 调用与小画布上相同的图纸
  • 如果您直接从浏览器的“打印页面”进行打印,请将较大的画布style.widthstyle.height属性设置为widthheight属性较小的一个,
  • 用较大的画布节点替换较小的画布节点
  • 打印,
  • 用原来的画布替换更大的画布

为此,您需要重写一下您的函数,以便它不会将传递的画布'width / height作为值,而是将您选择的值。

function drawBkg(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 drawings
var 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 ppi
function getPPI() {
  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;
}

function scaleAndPrint(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 layout
  var 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 canvas
  drawBkg(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 printer
  print();
  // set the original one back
  bigCanvas.parentNode.replaceChild(smallCanvas, bigCanvas);
}

btn_o.onclick = function() { print(); };
btn_s.onclick = function() { scaleAndPrint(300);};
<button id="btn_o">print without scaling</button>
<button id="btn_s">print with scaling</button>
<br>
<canvas id="smallCanvas" width="250" height="500"></canvas>

<子> 1。画布上的所有绘图操作都是基于矢量的,drawImage()除外,putImageData()

答案 1 :(得分:0)

实现cripser线的最简单方法是使用过采样:在画布上绘制,其分辨率大于屏幕的分辨率。

在Javascript中,如果你想以X因子过采样:

  • 将画布的宽度和高度更改为width*Xheight*X
  • 将画布的上下文缩放X系数
  • 将Css宽度和高度固定到初始宽度和高度,以保持屏幕上的大小相同。

在下面的示例中,我首先 down 对画布进行采样,以便于查看。你必须放大很多才能看到没有上采样,2 X和4X之间的区别。

function overSampleCanvas(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);
}

// -------------------- example

var $ = 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);


function drawCircle(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>

<canvas id="cv05" width="100" height="100"></canvas>
<canvas id="cv" width="100" height="100"></canvas>
<canvas id="cv2X" width="100" height="100"></canvas>
<canvas id="cv4X" width="100" height="100"></canvas>