我制作了一个简单的脚本来为像素和所有附近的像素着色

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <title>
            Click foto
        </title>
<style type="text/css">
/*<![CDATA[*/
html, body{
    height: 100%;
}

/*]]>*/
</style>
    </head>
    <body>
     <div id="canvasDiv">
     </div>
    </body>

  <script>
    var canvasDiv = document.getElementById('canvasDiv');
canvas = document.createElement('canvas');
canvas.setAttribute('width', 500);
canvas.setAttribute('height', 500);
canvas.setAttribute('id', 'canvas');
$(canvasDiv).prepend(canvas);
if(typeof G_vmlCanvasManager != 'undefined') {
    canvas = G_vmlCanvasManager.initElement(canvas);
}

var context = canvas.getContext('2d');
var imageObj = new Image();

imageObj.onload = function() {
    $(canvas).attr({width : this.width, height: this.height});
    context.drawImage(imageObj,0,0);
};
imageObj.src = 'cartina_italia.png';


   $('#canvas').click(function(e){
   console.time('click');
     mouseX = e.pageX - this.offsetLeft;
     mouseY = e.pageY - this.offsetTop;
      c = this.getContext('2d');
      p = c.getImageData(mouseX, mouseY, 1, 1).data;
    hex = ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
    console.timeEnd('click');
    console.time('selectArea');
    selectArea(mouseX,mouseY,c,hex);
    console.timeEnd('selectArea');
    });

    function selectArea(x,y,c,color){
    if (x>=0 && y>=0){
      p = c.getImageData(x, y, 1, 1).data;
      hex =("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);

      if (color==hex){
        c.fillStyle = "rgba(255,0,0,0.1)";
        c.fillRect( x, y, 1, 1 );
        selectArea(x+1,y,c,color);
        selectArea(x-1,y,c,color);
        selectArea(x,y+1,c,color);
        selectArea(x,y-1,c,color);
      }
      }
    }

function rgbToHex(r, g, b) {
    if (r > 255 || g > 255 || b > 255)
        throw "Invalid color component";
    return ((r << 16) | (g << 8) | b).toString(16);
}

  </script>
</html>


我正在测试该文件:http://mappa.italiachecambia.org/assets/homemap/cartina_italia.png前3次,我单击一个要着色的区域时,我的响应速度很慢(1000-5000ms),后3次该函数在50ms内结束
我无法使用jsfiddle来显示问题BC我得到跨域错误

该代码是简单的递归函数,可更改所单击像素的颜色并在附近像素上启动,直到像素颜色与第一个不同为止。
但我不明白为什么前3次反应如此缓慢,而第4次反应却有0滞后...。

最佳答案

您应该缓存孔图像的imageData并使用该数据,而不是在每个getImageData调用中调用selectArea。您也可以考虑实现迭代,以防止出现最大的调用堆栈错误。

这是一个例子:



var ExtendedCanvas = (function() {
    var context, data, canvas;
    function ExtendedCanvas(selector, imageSrc) {
        var wrapper = document.querySelector(selector);
        this.element = canvas = document.createElement('canvas');
        context = this.element.getContext('2d');
        loadImage.call(this, imageSrc, function(image) {
            canvas.setAttribute('width', image.width);
            canvas.setAttribute('height', image.height);
            context.drawImage(image,0,0);
            data = context.getImageData(0,0,canvas.width, canvas.height);
        });
        wrapper.appendChild(this.element);
    }

    function loadImage(src, cb) {
        var image = new Image();
        var canvas = this.element;
        image.onload = function() {
            cb(this);
        }
        image.crossOrigin = 'Anonymous';
        image.src = src;
    }

    ExtendedCanvas.prototype.getPixelIndex = function(x, y) {
        return (Math.floor(y) * canvas.width + Math.floor(x)) * 4;
    }

    ExtendedCanvas.prototype.getPixelColor = function(x, y) {
        var index = this.getPixelIndex(x, y);
        var d =  data.data;
        var r = d[index];
        var g = d[index + 1];
        var b = d[index + 2];
        var a = d[index + 3];
        return [r, g, b, a];
    }

    ExtendedCanvas.prototype.setPixelColor = function(x, y, color) {
        var index = this.getPixelIndex(x, y);
        var d = data.data;
        d[index] = color[0];
        d[index + 1] = color[1];
        d[index + 2] = color[2];
        d[index + 3] = color[3];
    }

    ExtendedCanvas.prototype.fill = function(x, y, fillColor) {
        if(x < 0 || y < 0 || x > canvas.width || y > canvas.height) {
            return;
        }
        fillColor = fillColor || [0,0,0,255];
        var stack = [];
        var color = this.getPixelColor(x, y).join();

        if(color === fillColor) {
            return;
        }

        stack.push([x, y]);
        context.fillStyle = fillColor;

        if(color === fillColor.join()) {
            return;
        }
        while(stack.length > 0) {
            var position = stack.pop();
            var posX = position[0];
            var posY = position[1];
            var posColor = this.getPixelColor(posX, posY).join();
            if(posColor === color) {
                this.setPixelColor(posX, posY, fillColor);
                stack.push([posX, posY + 1]);
                stack.push([posX, posY - 1]);
                stack.push([posX + 1, posY]);
                stack.push([posX - 1, posY]);
            }
        }
        context.putImageData(data, 0, 0);
    }

    return ExtendedCanvas;
})();

document.addEventListener('DOMContentLoaded', function() {
    var c = new ExtendedCanvas('#canvasWrapper', 'https://i.imgur.com/QWaKVGO.png');

    c.element.addEventListener('click', function(e) {
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        c.fill(x, y);
    });
});

<div id="canvasWrapper"></div>

10-08 16:03