&引用;“铲斗加注”;Javascript或coffeescript中的算法

&引用;“铲斗加注”;Javascript或coffeescript中的算法,javascript,coffeescript,Javascript,Coffeescript,我正在编写一个小coffeescript/js应用程序,允许用户设计图标(16x16像素或32X32像素)。 图标实际上是一个带有彩色单元格的二维数组。单元格可以有颜色,也可以为空 我希望用户能够用“桶油漆”工具填充空白单元格 意思是 如果用户单击空白单元格,则单击的单元格旁边的所有空白单元格都将填充choosen颜色,直到它到达彩色单元格为止 >P>如果用户点击一个彩色单元格,所有与单击的单元格相邻的共享相同颜色的单元格将被填充,但不是空白的,也不是彩色的(具有另一种颜色)。 该应用程序

我正在编写一个小coffeescript/js应用程序,允许用户设计图标(16x16像素或32X32像素)。 图标实际上是一个带有彩色单元格的二维数组。单元格可以有颜色,也可以为空

我希望用户能够用“桶油漆”工具填充空白单元格

意思是

  • 如果用户单击空白单元格,则单击的单元格旁边的所有空白单元格都将填充choosen颜色,直到它到达彩色单元格为止

  • >P>如果用户点击一个彩色单元格,所有与单击的单元格相邻的共享相同颜色的单元格将被填充,但不是空白的,也不是彩色的(具有另一种颜色)。

该应用程序已经允许用户使用选定的颜色逐个填充单元格,或使用钢笔工具删除彩色单元格

有什么建议吗


(注:我不使用html画布绘制)

因为这只是16x16或32x32,所以您可以使用递归解决方案:

假设您的起点是将像素x/y从颜色A更改为颜色B(A或B可以为空)

在伪代码中:

function floodfill(x,y,A,B) {
  if ((x<0) || (x>15) || (y<0) || (y>15)) return;
  if (get_color(x,y)!=A) return;
  set_color(x,y,B);
  floodfill(x-1,y-1,A,B);
  floodfill(x-1,y,A,B);
  floodfill(x-1,y+1,A,B);
  floodfill(x,y-1,A,B);
  floodfill(x,y+1,A,B);
  floodfill(x+1,y-1,A,B);
  floodfill(x+1,y,A,B);
  floodfill(x+1,y+1,A,B);
}
功能泛洪填充(x、y、A、B){
如果((x15)|(y15))返回;
如果(获取颜色(x,y)!=A)返回;
设置颜色(x,y,B);
漫灌(x-1、y-1、A、B);
漫灌(x-1、y、A、B);
洪水填充(x-1,y+1,A,B);
漫灌(x、y-1、A、B);
漫灌(x,y+1,A,B);
漫灌(x+1,y-1,A,B);
漫灌(x+1,y,A,B);
洪水填充(x+1,y+1,A,B);
}

我不完全确定您在寻找哪种类型的建议,但您应该看看泛洪填充算法


在维基百科上:

好吧,下面是我如何用咖啡脚本解决我的问题。 这是一个使用canvas的示例。 脚本应该在任何有canvas元素且id为canvas的页面上运行,由于stackoverflow问题,我不得不创建自己的堆栈

log = ->
  console.log arguments

class Point
  constructor:(@x,@y)->

class BucketFiller
  MAXITERATION:100000
  factor:1
  fill : (ctx,pixel, colCible, colRep)->
    P = []
    max = @MAXITERATION
    if @getColorAtPixel(ctx,pixel)!=colCible then return null
    P.push(pixel)
    while  P.length > 0 and max >=0
      --max
      currentpixel = P.pop()
      @fillRect(ctx,currentpixel.x,currentpixel.y,@factor,@factor,colRep)
      if @isInCanvas(ctx,currentpixel)
        if @getColorAtPixel(ctx,@up(currentpixel)) == colCible then P.push(@up(currentpixel))
        if @getColorAtPixel(ctx,@down(currentpixel)) == colCible then P.push(@down(currentpixel))
        if @getColorAtPixel(ctx,@right(currentpixel)) == colCible then P.push(@right(currentpixel))
        if @getColorAtPixel(ctx,@left(currentpixel)) == colCible then P.push(@left(currentpixel))
    return

  fillRect:(ctx,x,y,width,height,color)->
    ctx.fillStyle = color
    ctx.fillRect(x,y,width,height)
    return
  down :(pixel)->
    return {x:pixel.x,y:pixel.y-@factor}

  up:(pixel)->
    return {x:pixel.x,y:pixel.y+@factor}

  right :(pixel)->
    return {x:pixel.x+@factor,y:pixel.y}

  left :(pixel)->
    return {x:pixel.x-@factor,y:pixel.y}

  getColorAtPixel:(ctx,pixel)->
    try
      imageData = ctx.getImageData(pixel.x,pixel.y,1,1)
    catch e
      return null
    return @rgbArrayToCssColorString(imageData.data)

  rgbArrayToCssColorString:(array)->
    result = "rgb(#{array[0]},#{array[1]},#{array[2]})"
    return result

  isInCanvas : (ctx,pixel)->
    result = ((0 <= pixel.x <= ctx.canvas.width) and (0 <= pixel.y <= ctx.canvas.height))
    return result

main=->
    buckfiller = new BucketFiller()
    log("start")
    canvas  = document.getElementById("canvas")
    ctx = canvas.getContext("2d")
    penPosition = new Point(2,10)
    fillColor = "rgb(255,0,0)"
    colCible = buckfiller.getColorAtPixel(ctx,penPosition)
    try
      buckfiller.fill(ctx,penPosition,colCible,fillColor)
    catch e
      log e

window.onload=->
  main()
log=->
console.log参数
类点
构造函数:(@x,@y)->
木桶填料
最大迭代次数:100000
系数:1
填充:(ctx、像素、colCible、colRep)->
P=[]
max=@MAXITERATION
如果@getColorAtPixel(ctx,pixel)=colCible然后返回null
P.push(像素)
当P.length>0且max>=0时
--马克斯
currentpixel=P.pop()
@fillRect(ctx,currentpixel.x,currentpixel.y,@factor,@factor,colRep)
如果@isInCanvas(ctx,currentpixel)
如果@getColorAtPixel(ctx,@up(currentpixel))==colCible,则P.push(@up(currentpixel))
如果@getColorAtPixel(ctx,@down(currentpixel))==colCible,则P.push(@down(currentpixel))
如果@getColorAtPixel(ctx,@right(currentpixel))==colCible,则P.push(@right(currentpixel))
如果@getColorAtPixel(ctx,@left(currentpixel))==colCible,则P.push(@left(currentpixel))
返回
fillRect:(ctx、x、y、宽度、高度、颜色)->
ctx.fillStyle=颜色
ctx.fillRect(x,y,宽度,高度)
返回
向下:(像素)->
返回{x:pixel.x,y:pixel.y-@factor}
向上:(像素)->
返回{x:pixel.x,y:pixel.y+@factor}
右:(像素)->
返回{x:pixel.x+@因子,y:pixel.y}
左:(像素)->
返回{x:pixel.x-@因子,y:pixel.y}
getColorAtPixel:(ctx,pixel)->
尝试
imageData=ctx.getImageData(pixel.x,pixel.y,1,1)
抓住e
返回空
return@rgbArrayToCssColorString(imageData.data)
rgbArrayToCssColorString:(数组)->
result=“rgb(#{array[0]},#{array[1]},#{array[2]})”
返回结果
isInCanvas:(ctx,像素)->

结果=((0)为了让事情更清楚,你可以这样称呼它:
floodfill(clickX,clickY,originalColor,fillColor)
。大概你有一些识别颜色的方法(包括空的),以及一些填充单个像素的方法,这些像素将取代
设置颜色
,因此它基本上应该是一个简单的解决方案。很好,链接,谢谢,我不知道该算法有一个名称。