最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML5 Canvas translate(0.5,0.5) not fixing line blurryness - Stack Overflow

programmeradmin3浏览0评论

Reading related articles, I've tried forcing the canvas size in pixels, specifying half pixels for the paths and also context.translate(0.5) but my canvas lines are still blurry.

const boxContainer = document.querySelector('.boxes');
const canvas = document.getElementById("canvas");

canvas.width = boxContainer.offsetWidth * 2;
canvas.height = boxContainer.offsetHeight * 2;

canvas.style.width = boxContainer.offsetWidth + 'px';
canvas.style.height = boxContainer.offsetHeight + 'px';

const ctx = canvas.getContext("2d");
ctx.scale(2, 2);

/* Function to draw HTML5 canvas line */
const drawPath = (startX, startY, endX, endY) => {
  ctx.beginPath();
  ctx.lineWidth = "1";
  ctx.strokeStyle = "red";
  ctx.moveTo(startX, startY);
  ctx.lineTo(endX, endY);
  ctx.stroke();
};

/* Return coords for different points of element */
const getCoords = (elem, corner) => {
  let coords = {};
  switch (corner) {
    case 'bottomRight':
      coords.x = elem.offsetLeft + elem.offsetWidth;
      coords.y = elem.offsetTop + elem.offsetHeight;
      break;
    case 'bottomLeft':
      coords.x = elem.offsetLeft;
      coords.y = elem.offsetTop + elem.offsetHeight;
      break;
    case 'topRight':
      coords.x = elem.offsetLeft + elem.offsetWidth;
      coords.y = elem.offsetTop;
      break;
    case 'topLeft':
      coords.x = elem.offsetLeft;
      coords.y = elem.offsetTop;
      break;
  }


  return coords;
};

/* Get coords for all points */
let boxData = {};
let boxes = document.querySelectorAll('.box');

boxes.forEach((boxElem, index) => {
  boxData['box' + parseInt(index + 1)] = {
    x: getCoords(boxElem, boxElem.getAttribute('data-path-point')).x,
    y: getCoords(boxElem, boxElem.getAttribute('data-path-point')).y
  };

});

/* Start the drawing! */
drawPath(boxData.box1.x, boxData.box1.y,
  boxData.box4.x, boxData.box4.y);

drawPath(boxData.box2.x, boxData.box2.y,
  boxData.box3.x, boxData.box3.y);
.boxes {
  max-width: 500px;
  position: relative;
}

.box {
  display: inline-block;
  width: 120px;
  margin-left: 10%;
  margin-bottom: 10%;
  padding: 20px;
  border: 1px solid red;
}

#canvas {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
}
<div class="boxes">

  <canvas id="canvas"></canvas>

  <div data-path-point="bottomRight" id="box1" class="box box-pair1">a<br>b<br>x<br>y<br>z<br></div>
  <div data-path-point="bottomLeft" id="box2" class="box box-pair2">x<br>y<br>z<br></div>
  <div data-path-point="topRight" id="box3" class="box box-pair2">x<br>y<br>z<br></div>
  <div data-path-point="topLeft" id="box4" class="box box-pair1">x<br>y<br>z<br></div>

</div>

Reading related articles, I've tried forcing the canvas size in pixels, specifying half pixels for the paths and also context.translate(0.5) but my canvas lines are still blurry.

const boxContainer = document.querySelector('.boxes');
const canvas = document.getElementById("canvas");

canvas.width = boxContainer.offsetWidth * 2;
canvas.height = boxContainer.offsetHeight * 2;

canvas.style.width = boxContainer.offsetWidth + 'px';
canvas.style.height = boxContainer.offsetHeight + 'px';

const ctx = canvas.getContext("2d");
ctx.scale(2, 2);

/* Function to draw HTML5 canvas line */
const drawPath = (startX, startY, endX, endY) => {
  ctx.beginPath();
  ctx.lineWidth = "1";
  ctx.strokeStyle = "red";
  ctx.moveTo(startX, startY);
  ctx.lineTo(endX, endY);
  ctx.stroke();
};

/* Return coords for different points of element */
const getCoords = (elem, corner) => {
  let coords = {};
  switch (corner) {
    case 'bottomRight':
      coords.x = elem.offsetLeft + elem.offsetWidth;
      coords.y = elem.offsetTop + elem.offsetHeight;
      break;
    case 'bottomLeft':
      coords.x = elem.offsetLeft;
      coords.y = elem.offsetTop + elem.offsetHeight;
      break;
    case 'topRight':
      coords.x = elem.offsetLeft + elem.offsetWidth;
      coords.y = elem.offsetTop;
      break;
    case 'topLeft':
      coords.x = elem.offsetLeft;
      coords.y = elem.offsetTop;
      break;
  }


  return coords;
};

/* Get coords for all points */
let boxData = {};
let boxes = document.querySelectorAll('.box');

boxes.forEach((boxElem, index) => {
  boxData['box' + parseInt(index + 1)] = {
    x: getCoords(boxElem, boxElem.getAttribute('data-path-point')).x,
    y: getCoords(boxElem, boxElem.getAttribute('data-path-point')).y
  };

});

/* Start the drawing! */
drawPath(boxData.box1.x, boxData.box1.y,
  boxData.box4.x, boxData.box4.y);

drawPath(boxData.box2.x, boxData.box2.y,
  boxData.box3.x, boxData.box3.y);
.boxes {
  max-width: 500px;
  position: relative;
}

.box {
  display: inline-block;
  width: 120px;
  margin-left: 10%;
  margin-bottom: 10%;
  padding: 20px;
  border: 1px solid red;
}

#canvas {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
}
<div class="boxes">

  <canvas id="canvas"></canvas>

  <div data-path-point="bottomRight" id="box1" class="box box-pair1">a<br>b<br>x<br>y<br>z<br></div>
  <div data-path-point="bottomLeft" id="box2" class="box box-pair2">x<br>y<br>z<br></div>
  <div data-path-point="topRight" id="box3" class="box box-pair2">x<br>y<br>z<br></div>
  <div data-path-point="topLeft" id="box4" class="box box-pair1">x<br>y<br>z<br></div>

</div>

Where am I going wrong and how can I make my lines crisp like the border around the boxes in the demo?

How it appears for me:

Share Improve this question edited Sep 11, 2023 at 13:35 Lee Taylor 7,98416 gold badges37 silver badges53 bronze badges asked Oct 9, 2016 at 12:40 tctc91tctc91 1,3632 gold badges21 silver badges41 bronze badges 5
  • Works fine for me in Chrome imgur./a/515dZ – tctc91 Commented Oct 9, 2016 at 12:48
  • yes sorry working in chrome may be not in fx – Madhawa Priyashantha Commented Oct 9, 2016 at 12:48
  • Looking at the image you supplied. The canvas is half the resolution of the display. Zoom in and look at the pixels on the X, The DOM line is 1px yet still twice a wide as the pixels on the letter. That means the canvas is being stretched and the blur is due to the bilinear filtering. Either you are zoomed on the tab or you have a retina display. Set the canvas.width & height to twice what it is, set the canvas.style.width & height to DOM pixels. Remove the ctx.translate and add ctx.scale(2,2) and all things will be clear. – Blindman67 Commented Oct 9, 2016 at 15:14
  • Thanks, that solved it. Make that an answer and I'll accept :) – tctc91 Commented Oct 9, 2016 at 15:56
  • @Blindman67. ... and from the image only(!) -- bravo! – markE Commented Oct 9, 2016 at 22:37
Add a ment  | 

1 Answer 1

Reset to default 8

Retina & HiDPI devices

Looking at the image you supplied. The canvas is half the resolution of the display. Zoom in and look at the pixels on the "X", The DOM line is 1px yet still twice a wide as the pixels on that letter. That means the canvas is being stretched and the blur is due to the bilinear filtering. Either you are zoomed out on the tab or you have a retina or HiDPI display. Set the canvas.width & canvas.height to twice what it is, set the canvas.style.width & canvas.style.height to DOM pixels. Remove the ctx.translate and add ctx.scale(2,2) and all things will be clear.

A zoom in on the image

发布评论

评论列表(0)

  1. 暂无评论