HTML5 Multiple Canvas Effect - Scalloped Edges

Our company website has a “random splicer generator” built into Flash that creates random alternating alternating color graphics of fragments under the site’s title.

http://www.clarendonmarketing.com

I am trying to replicate this effect using HTML5, and although I can easily generate random shards, mixed overlap (multiplication in Adobe terms) is a problem.

I have a solution that basically creates an array of all canvas pixel data before each shape, and then another array with canvas pixel data after every shard. Then it compares the two and where it finds an opaque pixel in the first array, the corresponding pixel in the second array corresponds to the current selected fill color, it redraws it with the new color value defined by the multiply function (topValue * bottomValue / 255).

As a rule, this works perfectly and achieves the desired effect, EXCLUDING around the edges of overlapping fragments, where the effect of the dentate is created.

I believe this is related to browser antialiasing. I tried to reproduce the original pixel alpha channel value for the calculated pixel, but this does not seem to help.

JavaScript:

// Random Shard Generator v2 (HTML5)

var theCanvas;
var ctx;

var maxShards = 6;
var minShards = 3;

var fillArray = new Array(
    [180,181,171,255], 
    [162,202,28,255], 
    [192,15,44,255], 
    [222,23,112,255], 
    [63,185,127,255], 
    [152,103,158,255], 
    [251,216,45,255], 
    [249,147,0,255], 
    [0,151,204,255]
);

var selectedFill;

window.onload = function() {

    theCanvas = document.getElementById('shards');
    ctx = theCanvas.getContext('2d');
    //ctx.translate(-0.5, -0.5)

    var totalShards = getRandom(maxShards, minShards);

    for(i=0; i<=totalShards; i++) {
        //get snapshot of current canvas
        imgData = ctx.getImageData(0,0,theCanvas.width,theCanvas.height);
        currentPix = imgData.data
        //draw a shard
        drawRandomShard();
        //get snapshot of new canvas
        imgData = ctx.getImageData(0,0,theCanvas.width,theCanvas.height);
        pix = imgData.data;
        //console.log(selectedFill[0]+','+selectedFill[1]+','+selectedFill[2]);
        //alert('break')

        //CALCULATE THE MULTIPLIED RGB VALUES FOR OVERLAPPING PIXELS

        for (var j = 0, n = currentPix.length; j < n; j += 4) {
            if (    
                //the current pixel is not blank (alpha 0)
                (currentPix[j+3]>0)
                    && //and the new pixel matches the currently selected fill colour
                (pix[j]==selectedFill[0] && pix[j+1]==selectedFill[1] && pix[j+2]==selectedFill[2])
            ) { //multiply the current pixel by the selected fill colour
                //console.log('old: '+currentPix[j]+','+currentPix[j+1]+','+currentPix[j+2]+','+currentPix[j+3]+'\n'+'new: '+pix[j]+','+pix[j+1]+','+pix[j+2]+','+pix[j+3]);
                pix[j] = multiply(selectedFill[0], currentPix[j]); // red
                pix[j+1] = multiply(selectedFill[1], currentPix[j+1]); // green
                pix[j+2] = multiply(selectedFill[2], currentPix[j+2]); // blue
            }
        }
        //update the canvas
        ctx.putImageData(imgData, 0, 0);        
    }


};

function drawRandomShard() {

    var maxShardWidth = 200;
    var minShardWidth = 30;
    var maxShardHeight = 16;
    var minShardHeight = 10;
    var minIndent = 4;
    var maxRight = theCanvas.width-maxShardWidth;
    //generate a random start point
    var randomLeftAnchor = getRandom(maxRight, 0);
    //generate a random right anchor point
    var randomRightAnchor = getRandom((randomLeftAnchor+maxShardWidth),(randomLeftAnchor+minShardWidth));
    //generate a random number between the min and max limits for the lower point
    var randomLowerAnchorX = getRandom((randomRightAnchor - minIndent),(randomLeftAnchor + minIndent));
    //generate a random height for the shard
    var randomLowerAnchorY = getRandom(maxShardHeight, minShardHeight);
    //select a fill colour from an array
    var fillSelector = getRandom(fillArray.length-1,0);
    //console.log(fillSelector);
    selectedFill = fillArray[fillSelector];

    drawShard(randomLeftAnchor, randomLowerAnchorX, randomLowerAnchorY, randomRightAnchor, selectedFill);

}

function drawShard(leftAnchor, lowerAnchorX, lowerAnchorY, rightAnchor, selectedFill) {

    ctx.beginPath();
    ctx.moveTo(leftAnchor,0);
    ctx.lineTo(lowerAnchorX,lowerAnchorY);
    ctx.lineTo(rightAnchor,0);
    ctx.closePath();
    fillColour = 'rgb('+selectedFill[0]+','+selectedFill[1]+','+selectedFill[2]+')';
    ctx.fillStyle=fillColour;
    ctx.fill();

};

function getRandom(high, low) {
    return Math.floor(Math.random() * (high-low)+1) + low;
}

function multiply(topValue, bottomValue){
    return topValue * bottomValue / 255;
};

: http://www.clarendonmarketing.com/html5shards.html

+3
1

? ?

http://jsfiddle.net/wk3eE/

ctx.globalAlpha = 0.6;
for(var i=totalShards;i--;) drawRandomShard();

. , , - :

2: http://jsfiddle.net/wk3eE/2/

<script type="text/javascript" src="context_blender.js"></script>
<script type="text/javascript">
  var ctx = document.querySelector('canvas').getContext('2d');

  // Create an off-screen canvas to draw shards to first
  var off = ctx.canvas.cloneNode(true).getContext('2d');

  var w = ctx.canvas.width, h = ctx.canvas.height;
  for(var i=totalShards;i--;){
    off.clearRect(0,0,w,h);        // clear the offscreen context first
    drawRandomShard(off);          // modify to draw to the offscreen context
    off.blendOnto(ctx,'multiply'); // multiply onto the main context
  }
</script>
+5

All Articles