CaveDraw源码06:油漆桶算法的实现

考虑现实中的油漆桶,填充一个方形区域,是从一点开始,填充整个区域,碰到边界就停止。很明显,要遍历整个区域,碰到边界就停止,问题是这里的边界怎么判断?从使用角度看,使用油漆桶,油漆桶有一个颜色,然后在canvas画布上点击,点击的点(目标点,startPixel)也有一个颜色,就是要使用油漆桶的颜色填充这个目标点,及其相邻的区域,考虑到canvas画布是一个网格,需要从目标点遍历整个网格,而边界就是相邻的点的颜色不是目标点的颜色。

为什么不使用递归遍历整个网格?测试会报错:Maximum call stack size exceeded

 // 这里包含了一种 newColor==oldColor 的特殊情况。
_floodFillWithQueue(imageData, queue, newColor, oldColor) {
    let color, pixel;
    while ((pixel = queue.pop())) {
        color = this._rgbFromImageDataWithPixel(imageData, pixel.x, pixel.y);
        if (this._compareColor(color, oldColor) && !this._compareColor(color, newColor)) {
            this._setColor4ImageDataWithPixel(imageData, pixel.x, pixel.y, newColor);
            if (pixel.x > 0)
                queue.push({
                    x: pixel.x - 1,
                    y: pixel.y
                });
            if (pixel.x < imageData.width - 1)
                queue.push({
                    x: pixel.x + 1,
                    y: pixel.y
                });
            if (pixel.y > 0)
                queue.push({
                    x: pixel.x,
                    y: pixel.y - 1
                });
            if (pixel.y < imageData.height - 1)
                queue.push({
                    x: pixel.x,
                    y: pixel.y + 1
                });
        }
    }
}

需要注意canvas画布上点坐标的获得,这需要的是canvas绘图表面的坐标。

// 由于 window.devicePixelRatio 的存在,所以要转化为 canvasEle 上实际的点,即对应imageData中的点
const startPixel = {
  x: parseInt(this.board.startPoint.x),
  y: parseInt(this.board.startPoint.y)
};

使用1像素的离屏canvas转换hsl格式的颜色为rgb格式的颜色。

_2rgb(color) {
  this.offscreenContext.fillStyle = color;
  this.offscreenContext.fillRect(0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height);
  const imgDataOffscreenCanvas = this.offscreenContext.getImageData(0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height);
  return this._rgbFromImageData(imgDataOffscreenCanvas, 0);
}
Copyright © 2022,枫糖, 版权所有,禁止转载、演绎、商用。
离开前,建议您浏览一下 归档 页面,或许有更多相关的、有趣的内容!
如需博主帮助,请转到 小卖铺 页面,购买手工活服务!

添加评论

code