Javascript 洪水填充算法
我正在使用泛洪填充算法,但速度非常慢。例如,我有画布(512px 512px),要填满整个画布需要6秒钟。你能帮我改进我的实施吗?我使用的是来自 这里是我试图改进算法的链接:Javascript 洪水填充算法,javascript,canvas,ecmascript-6,html5-canvas,Javascript,Canvas,Ecmascript 6,Html5 Canvas,我正在使用泛洪填充算法,但速度非常慢。例如,我有画布(512px 512px),要填满整个画布需要6秒钟。你能帮我改进我的实施吗?我使用的是来自 这里是我试图改进算法的链接: 函数泛洪(上下文、画布、颜色、目标){ 功能泛光填充(startX、startY、彩色){ 函数isStartColor(位置、起始颜色、图像数据){ 如果((图像数据[position+0])!=((startColor>>24)和0xFF) ||(图像数据[位置+1])!=((起始颜色>>16)和0xFF) ||(图
函数泛洪(上下文、画布、颜色、目标){
功能泛光填充(startX、startY、彩色){
函数isStartColor(位置、起始颜色、图像数据){
如果((图像数据[position+0])!=((startColor>>24)和0xFF)
||(图像数据[位置+1])!=((起始颜色>>16)和0xFF)
||(图像数据[position+2])!=((startColor>>8)和0xFF)){
返回false;
}
返回true;
}
函数drawPixel(位置、图像数据){
imageData[位置]=color.r;
imageData[位置+1]=颜色.g;
imageData[位置+2]=颜色b;
图像数据[位置+3]=255;
}
让堆栈=[[startX,startY]];
while(堆栈长度){
const image=context.getImageData(0,0,canvas.width,canvas.height);
常量imageData=image.data;
const newPosition=stack.pop();
常数x=数学圆(newPosition[0]);
常数y=数学圆(newPosition[1]);
常量像素位置=(y*canvas.width+x)*4;
常数startColor={
r:imageData[像素位置+0]{
如果(!target.classList.contains('active-tool')){
返回
}
泛光填充(event.offsetX/xCoordinateScale、event.offsetY/yCoordinateScale、泛光颜色);
});
}
在您的代码中移动const image=context.getImageData(0,0,canvas.width,canvas.height);
在上一行,而和context.putImageData(image,0,0);
在关闭后向下一行
当然,你会看到一个巨大的改进谢谢,它提高了我的算法的性能,解决了我的问题。
function flood(context, canvas, color, target) {
function floodFill(startX, startY, color) {
function isStartColor(position, startColor, imageData) {
if ((imageData[position + 0]) != ((startColor >> 24) & 0xFF)
|| (imageData[position + 1]) != ((startColor >> 16) & 0xFF)
|| (imageData[position + 2]) != ((startColor >> 8) & 0xFF)) {
return false;
}
return true;
}
function drawPixel(position, imageData) {
imageData[position] = color.r;
imageData[position + 1] = color.g;
imageData[position + 2] = color.b;
imageData[position + 3] = 255;
}
let stack = [[startX, startY]];
while (stack.length) {
const image = context.getImageData(0, 0, canvas.width, canvas.height);
const imageData = image.data;
const newPosition = stack.pop();
const x = Math.round(newPosition[0]);
const y = Math.round(newPosition[1]);
const pixelPosition = (y * canvas.width + x) * 4;
const startColor = {
r: imageData[pixelPosition + 0] << 24,
g: imageData[pixelPosition + 1] << 16,
b: imageData[pixelPosition + 2] << 8
}
while (y-- >= 0 && isStartColor(pixelPosition, startColor, imageData)) {
pixelPosition = pixelPosition - canvas.width * 4;
}
y++;
pixelPosition = pixelPosition + canvas.width * 4;
let reachLeft = false;
let reachRight = false;
while (y++ < canvas.height - 1 && isStartColor(pixelPosition, startColor, imageData)) {
drawPixel(pixelPosition, imageData);
if (x > 0) {
if (isStartColor(pixelPosition - 4, startColor, imageData)) {
if (!reachLeft) {
stack.push([x - 1, y]);
reachLeft = true;
}
} else {
if (reachLeft) {
reachLeft = false;
}
}
}
if (x < canvas.width - 1) {
if (isStartColor(pixelPosition + 4, startColor, imageData)) {
if (!reachRight) {
stack.push([x + 1, y]);
reachRight = true;
}
} else {
if (reachRight) {
reachRight = false;
}
}
}
pixelPosition = pixelPosition + canvas.width * 4;
}
context.putImageData(image, 0, 0);
}
}
const canvasHTMLWidth = document.querySelector('.main-canvas').offsetWidth;
const canvasHTMLHeight = document.querySelector('.main-canvas').offsetHeight;
let xCoordinateScale;
let yCoordinateScale;
function getCoodinateScale() {
xCoordinateScale = (canvasHTMLWidth / canvas.width);
yCoordinateScale = (canvasHTMLHeight / canvas.height);
}
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
a: 255
} : null;
}
getCoodinateScale();
const floodColor = hexToRgb(color.value);
canvas.addEventListener('mousedown', (event) => {
if (!target.classList.contains('active-tool')) {
return
}
floodFill(event.offsetX / xCoordinateScale, event.offsetY / yCoordinateScale, floodColor);
});
}