JavaScript canvas fillRect可见边框

JavaScript canvas fillRect visible border

我正在尝试使用 js canvas 渲染直方图,它工作正常,但在使用 fillRect 时我在可见边框方面遇到了一些问题。我知道这是由于桶宽度是浮点数而不是整数引起的,但是将我的桶宽度设置为整数会导致它太大或太小(取决于桶的数量)。所以我的问题是,是否有任何解决方法可以摆脱这个边界?

// problem with bucket width being floating point
const bucketWidth = (Math.round(((desiredHistogramWidth / (data.buckets.length - 1))) * 100) / 100)
for (let i = 0; i < data.buckets.length - 1; ++i) {
  ctx.fillStyle = `rgb(${colors[i][0]}, ${colors[i][1]}, ${colors[i][2]})`;
  const x = histogramXOffset + i * bucketWidth;
  ctx.fillRect(x, histogramHeight, bucketWidth, -data.buckets[i] * heightPixelRatio);
  ctx.fillRect(x, histogramHeight + 20, bucketWidth, 20);
}

当桶宽度为浮点数时,可以在这个最小的可重现示例中观察到这种行为。

const data = [
  1034,
  783,
  700,
  699,
  212,
  123,
  300,
  323,
  344,
  344,
  434,
  344,
  434,
  434,
  0,
  0
];


const canvas = document.getElementById('histogram');
const ctx = canvas.getContext('2d');

const [ width, height ] = [ canvas.clientWidth, canvas.clientHeight ]

ctx.canvas.width = width;
ctx.canvas.height = height;

const max = Math.max(...data);
const heightPixelRatio = ((height) / max);
const bucketWidth = Math.round(width / (data.length) * 100) / 100

console.log(bucketWidth)

for (let i = 0; i < data.length; ++i) {
  ctx.fillStyle = '#000';
  const x = i * bucketWidth;
  ctx.fillRect(x, height, bucketWidth, -data[i] * heightPixelRatio);
}
.histogram {
  width: 600px;
  height: 800px;
  background: #ebecd2;
}
<canvas id="histogram" class="histogram"></canvas>

这样的事情怎么样:

const data = [
  1034,  783,  700,  699,
  212,  123,  300,  323,
  344,  344,  434,  344,
  434,  434,  100,  200
];

const canvas = document.getElementById('histogram');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = 180;

const heightRatio = canvas.height / Math.max(...data);
const bucketWidth = canvas.width / data.length

for (let i = 0; i < data.length; ++i) {  
  ctx.fillRect(
    i * bucketWidth, 
    canvas.height, 
    bucketWidth + 0.5, 
    -data[i] * heightRatio
  );
}
<canvas id="histogram" ></canvas>

要点:

  • 对于 bucketWidth 我们只使用 canvas.width / data.length
  • fillRect 上,我们 bucketWidth + 0.5 添加了少量

我刚刚尝试的另一个选项是只填充一次:

const data = [
  1034,  783,  700,  680,
  212,  123,  300,  323,
  354,  340,  434,  344,
  444,  430,  100,  200
];

const canvas = document.getElementById('histogram');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = 180;

const heightRatio = canvas.height / Math.max(...data);
const bucketWidth = canvas.width / data.length

for (let i = 0; i < data.length; ++i) {  
  ctx.rect(
    i * bucketWidth, 
    canvas.height, 
    bucketWidth, 
    -data[i] * heightRatio
  );
}
ctx.fill()
<canvas id="histogram" ></canvas>


对于有大量桶的情况,你不能一次显示它们,必须有一个下一步按钮或创建某种无限侧滚动,没有太多选择。
0.01 的值不能是不会显示任何内容的有效 bucketWidth