Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用颜色填充空心形状_Javascript_Html_Canvas - Fatal编程技术网

Javascript 用颜色填充空心形状

Javascript 用颜色填充空心形状,javascript,html,canvas,Javascript,Html,Canvas,假设我在html画布上画了一个圆圈或任何有边界的形状,其中有一个空白。我想用选定的颜色填充它。什么算法可以帮我完成这项工作。我添加了一个空心形状的图片,我想填充黑色边界内的空白。如何使用javascript实现这一点。如何使用鼠标事件lyk e.layerX/Y ;e.ClientX/Y 可以使用 您可以使用填充区域。它以一个起始点(或种子点)作为输入,并通过尝试填充其相邻区域来递归填充该区域 您可以在鼠标单击事件上获取种子点,然后将其传递给flood fill。 以下是JavaScript

假设我在html画布上画了一个圆圈或任何有边界的形状,其中有一个空白。我想用选定的颜色填充它。什么算法可以帮我完成这项工作。我添加了一个空心形状的图片,我想填充黑色边界内的空白。如何使用javascript实现这一点。如何使用鼠标事件lyk

e.layerX/Y ;e.ClientX/Y 
可以使用

您可以使用填充区域。它以一个起始点(或种子点)作为输入,并通过尝试填充其相邻区域来递归填充该区域

您可以在鼠标单击事件上获取种子点,然后将其传递给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-邻域。但它可以很容易地扩展到8个街区。

以下是基于威廉·马龙教程的演示:


画布{边框:1px纯红;}
$(函数(){
//下面的洪水填充算法基于William Malone的优秀作品,版权2010 William Malone(www.williammone.com)——Apache许可证:http://www.apache.org/licenses/LICENSE-2.0 --除非适用法律要求或书面同意,否则根据许可证分发的软件按“原样”分发基础,无任何明示或暗示的保证或条件。有关许可证项下管辖权限和限制的特定语言,请参阅许可证。
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数据;
var-strokeData;
//加载图像
var img=新图像();
img.onload=函数(){
start();
}
img.crossOrigin=“匿名”;
img.src=”https://dl.dropboxusercontent.com/u/139992952/stackoverflow/polygrid.png";
函数匹配StrokeColor(r、g、b、a){
//切勿回忆最初的黑色分隔符笔划
//由于抗锯齿,必须检查是否接近黑色
返回(r+g+b<100&&a==255);
}
功能匹配StartColor(像素位置、startR、startG、startB){
//获取要匹配的颜色
var r=strokeData.data[pixelPos],
g=strokeData.data[pixelPos+1],
b=strokeData.data[pixelPos+2],
a=strokeData.data[pixelPos+3];
//如果轮廓图像的当前像素为黑色
if(匹配strokeColor(r、g、b、a)){
返回false;
}
//获得潜在的替换颜色
r=fillData.data[pixelPos];
g=填充数据。数据[pixelPos+1];
b=fillData.data[pixelPos+2];
//如果当前像素与单击的颜色匹配
如果(r==startR&&g==startG&&b==startB){
返回true;
}
//如果当前像素与新颜色匹配
如果(r==fillColor.r&&g==fillColor.g&&b==fillColor.b){
返回false;
}
返回true;
}
//谢谢威廉·马龙!
功能注水(startX、startY、startR、startG、startB){
var newPos;
var x;
变量y;
var-pixelPos;
var neighborLeft;
邻里关系;
var pixelStack=[[startX,startY]];
while(pixelStack.length){
newPos=pixelStack.pop();
x=newPos[0];
y=新位置[1];
//获取当前像素位置
pixelPos=(y*画布宽度+x)*4;
//只要颜色匹配并且在画布内,就可以向上移动
而(y>=0&&matchStartColor(像素点、startR、startG、startB)){
y-=1;
pixelPos-=画布宽度*4;
}
pixelPos+=画布宽度*4;
y+=1;
邻里关系=假;
邻里关系=错误;
//只要颜色匹配,就在画布内向下移动
while(y0){
if(匹配StartColor(像素位置-4、startR、startG、startB)){
如果(!Neightarleft){
//将像素添加到堆栈
pixelStack.push([x-1,y]);
邻里关系=正确;
}
}else if(邻里金融){
邻里关系=假;
}
}
如果(x<(画布宽度-1)){
if(匹配StartColor(像素位置+4、startR、startG、startB)){
如果(!邻居){
//将像素添加到堆栈
pixelStack.push([x+1,y]);
邻里关系=正确;
}
}else if(邻里关系){
邻里关系=错误;
}
}
pixelPos+=画布宽度*4;
}
}
}
//开始注水
//1.获取鼠标单击下的颜色
//2.用新颜色替换所有颜色
//3.但要尊重边界区域!仅替换相邻颜色。
功能油漆(startX、startY){
//获取点击像素的[r,g,b,a]颜色数据
变量pixelPos=(星形*画布宽度+星形)*4,
r=fillData.data[pixelPos],
g=fillData.data[pixelPos+1],
b=填充数据。数据[pixelPos+2],
a=fillData.data[pixelPos+3];
//这个像素已经满了
如果(r==fillColor.r&&g==fillColor.g&&b==fillColor.b){
回来
}
//此像素是原始黑色图像的一部分--不要填充
if(匹配strokeColor(r、g、b、a)){
回来
}
//执行洪水填充
漫灌(startX、startY、r、g、b);
//把彩色的纸放在d上
<!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>