Статья по теме:
Демо JavaScript:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imageData;
var xMouse = 0;
var yMouse = 0;
var stack = [];
// Данная строчка необходима для правильной работы алгоритма
// Смысл залючается в переносе начала координат на пол пикселя
// Это необходимо для достижения четких границ линий
// Без этого метода линии в канвасе не идеально черные, тк имеют сглаживание
ctx.translate(0.5, 0.5);
// Ставим пиксель, по умолчанию цвет черный
function putPixel(x, y, c = {R: 0, G: 0, B: 0, A: 255}) {
var index = (y * imageData.width + x) * 4;
imageData.data[index + 0] = c.R;
imageData.data[index + 1] = c.G;
imageData.data[index + 2] = c.B;
imageData.data[index + 3] = c.A;
}
// Узнать цвет пикселя
function getPixel(x, y) {
var index = (y * imageData.width + x) * 4;
return {
R: imageData.data[index + 0],
G: imageData.data[index + 1],
B: imageData.data[index + 2],
A: imageData.data[index + 3]
};
}
// Получить (x,y) кордианты курсора, в момент нажатия
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect();
xMouse = (event.clientX - rect.left) | 0;
yMouse = (event.clientY - rect.top) | 0;
}
// Функция поиска в ширину
function clicked(stack, used) {
// Блок try catch для избежания кликов вне замкнутых фигур
while (stack.length != 0) {
// Из стека достаем в обратном порядке
var y = stack.pop();
var x = stack.pop();
if (used[x][y] != 1) {
used[x][y] = 1;
} else {
continue;
}
// Красим пиксель
putPixel(x, y);
// Проверяем соседей текущего пикселя на цвет
if (isBorderColor(x,y-1) || used[x][y - 1] == 1) {
} else {
stack.push(x);
stack.push(y - 1);
}
if (isBorderColor(x,y+1) || used[x][y + 1] == 1) {
} else {
stack.push(x);
stack.push(y + 1);
}
if (isBorderColor(x+1,y) || used[x + 1][y] == 1) {
} else {
stack.push(x + 1);
stack.push(y);
}
if (isBorderColor(x-1,y) || used[x - 1][y] == 1) {
} else {
stack.push(x - 1);
stack.push(y);
}
}
// Обновляем данные
ctx.putImageData(imageData, 0, 0);
}
// Проверка на наличие замкнутой границы фигуры
function checkBorder(x, y) {
for (let i = x; i <= canvas.width; i++) {
if (isBorderColor(i,y)) {
break;
}
if (i == canvas.width) {
return false;
}
}
for (let i = x; i >= 0; i--) {
if (isBorderColor(i,y)) {
break;
}
if (i == 0) {
return false;
}
}
for (let i = y; i >= 0; i--) {
if (isBorderColor(x,i)) {
break;
}
if (i == 0) {
return false;
}
}
for (let i = y; i <= canvas.height; i++) {
if (isBorderColor(x,i)) {
break;
}
if (i == canvas.height) {
return false;
}
}
return true;
}
// Проверка пикселя на совпадения цвета с цветом границы
function isBorderColor(x,y){
if (getPixel(x, y).R == 0 && getPixel(x, y).G == 0 && getPixel(x, y).B == 0) {
return true;
}
return false;
}
function start() {
// Массив, необходимый для Поиска в ширину
let used = new Array(canvas.width);
for (let i = 0; i < canvas.width; i++) {
used[i] = new Array(canvas.height).fill(0);
}
// Красим канвас
ctx.fillStyle = "#ccc";
ctx.fillRect(0, 0, 600, 600);
// Рисуем фигуры
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(100, 50);
ctx.lineTo(100, 100);
ctx.lineTo(50, 50);
ctx.strokeRect(350, 250, 50, 50);
ctx.stroke();
imageData = ctx.getImageData(0, 0, 600, 600);
// Клик мыши
canvas.addEventListener('mousedown', function (e) {
getCursorPosition(canvas, e)
// Если замкнута, то закрашиваем
if (checkBorder(xMouse, yMouse)) {
stack.push(xMouse, yMouse);
clicked(stack, used);
} else {
alert("Нет границ")
}
})
}
start();
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var imageData; var xMouse = 0; var yMouse = 0; var stack = []; // Данная строчка необходима для правильной работы алгоритма // Смысл залючается в переносе начала координат на пол пикселя // Это необходимо для достижения четких границ линий // Без этого метода линии в канвасе не идеально черные, тк имеют сглаживание ctx.translate(0.5, 0.5); // Ставим пиксель, по умолчанию цвет черный function putPixel(x, y, c = {R: 0, G: 0, B: 0, A: 255}) { var index = (y * imageData.width + x) * 4; imageData.data[index + 0] = c.R; imageData.data[index + 1] = c.G; imageData.data[index + 2] = c.B; imageData.data[index + 3] = c.A; } // Узнать цвет пикселя function getPixel(x, y) { var index = (y * imageData.width + x) * 4; return { R: imageData.data[index + 0], G: imageData.data[index + 1], B: imageData.data[index + 2], A: imageData.data[index + 3] }; } // Получить (x,y) кордианты курсора, в момент нажатия function getCursorPosition(canvas, event) { const rect = canvas.getBoundingClientRect(); xMouse = (event.clientX - rect.left) | 0; yMouse = (event.clientY - rect.top) | 0; } // Функция поиска в ширину function clicked(stack, used) { // Блок try catch для избежания кликов вне замкнутых фигур while (stack.length != 0) { // Из стека достаем в обратном порядке var y = stack.pop(); var x = stack.pop(); if (used[x][y] != 1) { used[x][y] = 1; } else { continue; } // Красим пиксель putPixel(x, y); // Проверяем соседей текущего пикселя на цвет if (isBorderColor(x,y-1) || used[x][y - 1] == 1) { } else { stack.push(x); stack.push(y - 1); } if (isBorderColor(x,y+1) || used[x][y + 1] == 1) { } else { stack.push(x); stack.push(y + 1); } if (isBorderColor(x+1,y) || used[x + 1][y] == 1) { } else { stack.push(x + 1); stack.push(y); } if (isBorderColor(x-1,y) || used[x - 1][y] == 1) { } else { stack.push(x - 1); stack.push(y); } } // Обновляем данные ctx.putImageData(imageData, 0, 0); } // Проверка на наличие замкнутой границы фигуры function checkBorder(x, y) { for (let i = x; i <= canvas.width; i++) { if (isBorderColor(i,y)) { break; } if (i == canvas.width) { return false; } } for (let i = x; i >= 0; i--) { if (isBorderColor(i,y)) { break; } if (i == 0) { return false; } } for (let i = y; i >= 0; i--) { if (isBorderColor(x,i)) { break; } if (i == 0) { return false; } } for (let i = y; i <= canvas.height; i++) { if (isBorderColor(x,i)) { break; } if (i == canvas.height) { return false; } } return true; } // Проверка пикселя на совпадения цвета с цветом границы function isBorderColor(x,y){ if (getPixel(x, y).R == 0 && getPixel(x, y).G == 0 && getPixel(x, y).B == 0) { return true; } return false; } function start() { // Массив, необходимый для Поиска в ширину let used = new Array(canvas.width); for (let i = 0; i < canvas.width; i++) { used[i] = new Array(canvas.height).fill(0); } // Красим канвас ctx.fillStyle = "#ccc"; ctx.fillRect(0, 0, 600, 600); // Рисуем фигуры ctx.beginPath(); ctx.moveTo(50, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 100); ctx.lineTo(50, 50); ctx.strokeRect(350, 250, 50, 50); ctx.stroke(); imageData = ctx.getImageData(0, 0, 600, 600); // Клик мыши canvas.addEventListener('mousedown', function (e) { getCursorPosition(canvas, e) // Если замкнута, то закрашиваем if (checkBorder(xMouse, yMouse)) { stack.push(xMouse, yMouse); clicked(stack, used); } else { alert("Нет границ") } }) }
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var imageData; var xMouse = 0; var yMouse = 0; var stack = []; // Данная строчка необходима для правильной работы алгоритма // Смысл залючается в переносе начала координат на пол пикселя // Это необходимо для достижения четких границ линий // Без этого метода линии в канвасе не идеально черные, тк имеют сглаживание ctx.translate(0.5, 0.5); // Ставим пиксель, по умолчанию цвет черный function putPixel(x, y, c = {R: 0, G: 0, B: 0, A: 255}) { var index = (y * imageData.width + x) * 4; imageData.data[index + 0] = c.R; imageData.data[index + 1] = c.G; imageData.data[index + 2] = c.B; imageData.data[index + 3] = c.A; } // Узнать цвет пикселя function getPixel(x, y) { var index = (y * imageData.width + x) * 4; return { R: imageData.data[index + 0], G: imageData.data[index + 1], B: imageData.data[index + 2], A: imageData.data[index + 3] }; } // Получить (x,y) кордианты курсора, в момент нажатия function getCursorPosition(canvas, event) { const rect = canvas.getBoundingClientRect(); xMouse = (event.clientX - rect.left) | 0; yMouse = (event.clientY - rect.top) | 0; } // Функция поиска в ширину function clicked(stack, used) { // Блок try catch для избежания кликов вне замкнутых фигур while (stack.length != 0) { // Из стека достаем в обратном порядке var y = stack.pop(); var x = stack.pop(); if (used[x][y] != 1) { used[x][y] = 1; } else { continue; } // Красим пиксель putPixel(x, y); // Проверяем соседей текущего пикселя на цвет if (isBorderColor(x,y-1) || used[x][y - 1] == 1) { } else { stack.push(x); stack.push(y - 1); } if (isBorderColor(x,y+1) || used[x][y + 1] == 1) { } else { stack.push(x); stack.push(y + 1); } if (isBorderColor(x+1,y) || used[x + 1][y] == 1) { } else { stack.push(x + 1); stack.push(y); } if (isBorderColor(x-1,y) || used[x - 1][y] == 1) { } else { stack.push(x - 1); stack.push(y); } } // Обновляем данные ctx.putImageData(imageData, 0, 0); } // Проверка на наличие замкнутой границы фигуры function checkBorder(x, y) { for (let i = x; i <= canvas.width; i++) { if (isBorderColor(i,y)) { break; } if (i == canvas.width) { return false; } } for (let i = x; i >= 0; i--) { if (isBorderColor(i,y)) { break; } if (i == 0) { return false; } } for (let i = y; i >= 0; i--) { if (isBorderColor(x,i)) { break; } if (i == 0) { return false; } } for (let i = y; i <= canvas.height; i++) { if (isBorderColor(x,i)) { break; } if (i == canvas.height) { return false; } } return true; } // Проверка пикселя на совпадения цвета с цветом границы function isBorderColor(x,y){ if (getPixel(x, y).R == 0 && getPixel(x, y).G == 0 && getPixel(x, y).B == 0) { return true; } return false; } function start() { // Массив, необходимый для Поиска в ширину let used = new Array(canvas.width); for (let i = 0; i < canvas.width; i++) { used[i] = new Array(canvas.height).fill(0); } // Красим канвас ctx.fillStyle = "#ccc"; ctx.fillRect(0, 0, 600, 600); // Рисуем фигуры ctx.beginPath(); ctx.moveTo(50, 50); ctx.lineTo(100, 50); ctx.lineTo(100, 100); ctx.lineTo(50, 50); ctx.strokeRect(350, 250, 50, 50); ctx.stroke(); imageData = ctx.getImageData(0, 0, 600, 600); // Клик мыши canvas.addEventListener('mousedown', function (e) { getCursorPosition(canvas, e) // Если замкнута, то закрашиваем if (checkBorder(xMouse, yMouse)) { stack.push(xMouse, yMouse); clicked(stack, used); } else { alert("Нет границ") } }) }