JS Pinch Effect (Pixels)

by Noreh AD

HTML

<img id="grid" style="display: none"...

CSS

* {
    margin: 0;
    padding: 0;
    box-sizing: inherit;
    line-height: inherit;
    font-size: inherit;
    font-family: inherit;
}

body {
    font-family: sans-serif;
    box-sizing: border-box;
    background-color: hsl(0, 0%, 90%);
}

canvas {
    display: block;
    background: white;
    box-shadow: 0 0 2px rgba(0, 0, 0, .2), 0 1px 1px rgba(0, 0, 0, .1);
    margin: auto;
}

#container {
    display: table;
    margin: 20px auto;
}

#controls {
    margin-top: 10px;
    font-size: 15px;
}

#controls input {
    width: 100px;
}

#controls td {
    padding: 5px 2px;
}

#controls td:last-child {
    width: 35px;
}

#controls #texture {
    width: 100%;
}

JavaScript

Number.prototype.clamp = function(min, max) {
    return Math.min(Math.max(min, this), max);
};

/* ========================= SETUP ========================= */

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

var texture, originalPixels;

loadTexture("grid");

function loadTexture(id) {
    texture = document.getElementById(id);

    canvas.width  = texture.width;
    canvas.height = texture.height;

    context.drawImage(texture, 0, 0);

    originalPixels = context.getImageData(0, 0, canvas.width, canvas.height);
}

var effectRadius = 90;
var effectStrength = 0;

var origin = {
    x : canvas.width / 2,
    y : canvas.height / 2,
};

/* ========================= UI ========================= */

var strengthTimeoutHandler = null;

document.getElementById("strength").addEventListener("input", function () {
    var value = parseFloat(this.value, 10);
    if (value != effectStrength) {
        clearTimeout(strengthTimeoutHandler);
        strengthTimeoutHandler = setTimeout(function () {
            effectStrength = value;
            draw();
        }.bind(this), 200);
        document.getElementById("strength-value").innerText = value.toFixed(2);
    }
});

var radiusTimeoutHandler = null;

document.getElementById("radius").addEventListener("input", function () {
    var value = parseInt(this.value, 10);
    if (value != effectRadius) {
        clearTimeout(radiusTimeoutHandler);
        radiusTimeoutHandler = setTimeout(function () {
            effectRadius = value;
            draw();
        }.bind(this), 200);
        document.getElementById("radius-value").innerText = value;
    }
});

document.getElementById("texture").addEventListener("change", function () {
    loadTexture(this.value);
    draw();
});

document.getElementById("method").addEventListener("change", function () {
    draw();
});

/* ========================= FILTER ========================= */

function draw() {

    var affectedPixels =...