说我画了一个圆圈或任何有边界的形状,在其中是html canvas中的空心空间。我想用选定的颜色填充它。什么算法可以为我做的工作。我添加了一张图片一个空心的形状,我想填补黑色边界内的白色空间。这可以使用javascript.how鼠标事件lyk
e.layerX/Y ;e.ClientX/Y
可以使用
答案 0 :(得分:1)
您可以使用Flood fill填充该地区。它需要一个起点(或种子点)作为输入,并通过尝试填充其邻居来递归填充该区域。
您可以在鼠标单击事件上获取种子点,然后将其传递给洪水填充。 这是JavaScript中基于堆栈的代码:
// Takes the seed point as input
var floodfill = function(point) {
var stack = Array();
stack.push(point); // Push the seed
while(stack.length > 0) {
var currPt = stack.pop();
if(isEmpty(currPt.x, currPt.y)) { // Check if the point is not filled
setPixel(currPt.x, currPt.y); // Fill the point
stack.push(currPt.x + 1, currPt.y); // Fill the east neighbour
stack.push(currPt.x, currPt.y + 1); // Fill the south neighbour
stack.push(currPt.x - 1, currPt.y); // Fill the west neighbour
stack.push(currPt.x, currPt.y - 1); // Fill the north neighbour
}
}
};
isEmpty(x, y)
是测试点(x, y)
是否为空的函数。
setPixel(x, y)
填写了(x, y)
点。
这些功能的实现由您自己完成。
请注意,上述算法使用了4-neighborhood。但它很容易扩展到8邻域。
答案 1 :(得分:1)
这是基于William Malone教程的演示:http://jsfiddle.net/m1erickson/67xaB/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// The floodFill algorithm below is based on the good work by William Malone, Copyright 2010 William Malone (www.williammalone.com) -- Apache License: http://www.apache.org/licenses/LICENSE-2.0 -- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
var canvas=document.getElementById("canvas");
var context = canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var strokeColor = {r: 0, g: 0, b: 0};
var fillColor = {r: 101,g: 155,b: 65};
var fillData;
var strokeData;
// load image
var img=new Image();
img.onload=function(){
start();
}
img.crossOrigin="anonymous";
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/polygrid.png";
function matchstrokeColor(r, g, b, a) {
// never recolor the initial black divider strokes
// must check for near black because of anti-aliasing
return (r + g + b < 100 && a === 255);
}
function matchStartColor(pixelPos, startR, startG, startB) {
// get the color to be matched
var r = strokeData.data[pixelPos],
g = strokeData.data[pixelPos + 1],
b = strokeData.data[pixelPos + 2],
a = strokeData.data[pixelPos + 3];
// If current pixel of the outline image is black-ish
if (matchstrokeColor(r, g, b, a)) {
return false;
}
// get the potential replacement color
r = fillData.data[pixelPos];
g = fillData.data[pixelPos + 1];
b = fillData.data[pixelPos + 2];
// If the current pixel matches the clicked color
if (r === startR && g === startG && b === startB) {
return true;
}
// If current pixel matches the new color
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return false;
}
return true;
}
// Thank you William Malone!
function floodFill(startX, startY, startR, startG, startB) {
var newPos;
var x;
var y;
var pixelPos;
var neighborLeft;
var neighborRight;
var pixelStack = [[startX, startY]];
while (pixelStack.length) {
newPos = pixelStack.pop();
x = newPos[0];
y = newPos[1];
// Get current pixel position
pixelPos = (y * canvasWidth + x) * 4;
// Go up as long as the color matches and are inside the canvas
while (y >= 0 && matchStartColor(pixelPos, startR, startG, startB)) {
y -= 1;
pixelPos -= canvasWidth * 4;
}
pixelPos += canvasWidth * 4;
y += 1;
neighborLeft = false;
neighborRight = false;
// Go down as long as the color matches and in inside the canvas
while (y <= (canvasHeight-1) && matchStartColor(pixelPos, startR, startG, startB)) {
y += 1;
fillData.data[pixelPos] = fillColor.r;
fillData.data[pixelPos + 1] = fillColor.g;
fillData.data[pixelPos + 2] = fillColor.b;
fillData.data[pixelPos + 3] = 255;
if (x > 0) {
if (matchStartColor(pixelPos - 4, startR, startG, startB)) {
if (!neighborLeft) {
// Add pixel to stack
pixelStack.push([x - 1, y]);
neighborLeft = true;
}
} else if (neighborLeft) {
neighborLeft = false;
}
}
if (x < (canvasWidth-1)) {
if (matchStartColor(pixelPos + 4, startR, startG, startB)) {
if (!neighborRight) {
// Add pixel to stack
pixelStack.push([x + 1, y]);
neighborRight = true;
}
} else if (neighborRight) {
neighborRight = false;
}
}
pixelPos += canvasWidth * 4;
}
}
}
// Start a floodfill
// 1. Get the color under the mouseclick
// 2. Replace all of that color with the new color
// 3. But respect bounding areas! Replace only contiguous color.
function paintAt(startX, startY) {
// get the clicked pixel's [r,g,b,a] color data
var pixelPos = (startY * canvasWidth + startX) * 4,
r = fillData.data[pixelPos],
g = fillData.data[pixelPos + 1],
b = fillData.data[pixelPos + 2],
a = fillData.data[pixelPos + 3];
// this pixel's already filled
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return;
}
// this pixel is part of the original black image--don't fill
if (matchstrokeColor(r, g, b, a)) {
return;
}
// execute the floodfill
floodFill(startX, startY, r, g, b);
// put the colorized data back on the canvas
context.clearRect(0, 0, canvasWidth, canvasHeight);
context.putImageData(fillData, 0, 0);
context.drawImage(img,0,0);
}
// create a random color object {red,green,blue}
function randomColorRGB(){
var hex=Math.floor(Math.random()*16777215).toString(16);
var r=parseInt(hex.substring(0,2),16);
var g=parseInt(hex.substring(2,4),16);
var b=parseInt(hex.substring(4,6),16);
return({r:r,g:g,b:b});
}
// draw the image to the canvas and get its pixel array
// listen for mouse clicks and do floodfill when clicked
function start() {
context.drawImage(img,0,0);
strokeData = context.getImageData(0, 0, canvasWidth, canvasHeight);
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
fillData = context.getImageData(0, 0, canvasWidth, canvasHeight);
context.drawImage(img,0,0);
$('#canvas').mousedown(function (e) {
// Mouse down location
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
// set a new random fillColor
fillColor=randomColorRGB();
// floodfill
paintAt(mouseX, mouseY);
});
};
}); // end $(function(){});
</script>
</head>
<body>
<p>Click inside a shape below</p>
<canvas id="canvas" width=210 height=300></canvas><br/>
</body>
</html>