JSFiddle - React, Tailwind, and code Playground

by Hakan Bilgin

HTML

<script src="https://unpkg.com/magic-wand-tool@latest/dist/magic-wand.min.js"></script>
<div style="overflow: auto">
    <div class="button" onclick="uploadClick()">Upload image and click on it</div>
    <div class="button" onclick="trace()">Create polygons by current selection</div>
    <div class="button" onclick="paint('FF0000', 0.35)">Paint the selection</div>
    <input id="file-upload" type="file" accept="image/*" onchange="imgChange(this)" />
</div>
<div style="overflow: auto">
    <div style="float: left; margin-right: 10px;">Blur radius: </div>
    <input id="blurRadius" type="text" onchange="onRadiusChange.apply(this, arguments)" style="float: left; width: 20px; margin-right: 10px;"/>
    <div id="threshold"></div>
</div>
<div>(hold left mouse button and move to change the color threshold)</div>
<div>(hold the CTRL key to add selection)</div>
<div class='wrapper'>
    <div class='content'>
        <img id="test-picture" class="picture" />
        <canvas class="canvas" id="resultCanvas" onmouseup="onMouseUp.apply(this, arguments)" onmousedown="onMouseDown.apply(this, arguments)" onmousemove="onMouseMove.apply(this, arguments)"></canvas>
    </div>
</div>

CSS

.wrapper {
    top: 80px;
    width: 400px;
    height: 350px;
    overflow: auto;
}
.content {
    position: relative;
}
.canvas {
    position: absolute;
}
.canvas:hover {
    cursor: default;
}
.picture {
    position: absolute;
}
.button {
    padding: 4px;
    margin: 4px;
    border: 1px solid black;
    float: left;
}
.button:hover {
    background-color: blue;
    color: white;
    cursor: pointer;
}
#threshold {
    width: 95px;
    float: left;
}
#file-upload {
    display: none;
}
.add-mode {
    cursor: copy !important;
}

JavaScript

window.onload = function() {
    colorThreshold = 15;
    blurRadius = 5;
    simplifyTolerant = 0;
    simplifyCount = 30;
    hatchLength = 4;
    hatchOffset = 0;

    imageInfo = null;
    cacheInd = null;
    mask = null;
    oldMask = null;
    downPoint = null;
    allowDraw = false;
    addMode = false;
    currentThreshold = colorThreshold;
    
    document.onkeydown = onKeyDown;
    document.onkeyup = onKeyUp;
    
    showThreshold();
    document.getElementById("blurRadius").value = blurRadius;
    setInterval(function () { hatchTick(); }, 300);
}
function uploadClick() {
    document.getElementById("file-upload").click();
}
function onRadiusChange(e) {
    blurRadius = e.target.value;
}
function imgChange (inp) {
    if (inp.files && inp.files[0]) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var img = document.getElementById("test-picture");
            img.setAttribute('src', e.target.result);
            img.onload = function() {
                window.initCanvas(img);
            };
        }
        reader.readAsDataURL(inp.files[0]);
    }
}
function initCanvas(img) {
    var cvs = document.getElementById("resultCanvas");
    cvs.width = img.width;
    cvs.height = img.height;
    imageInfo = {
        width: img.width,
        height: img.height,
        context: cvs.getContext("2d")
    };
    mask = null;
    
    var tempCtx = document.createElement("canvas").getContext("2d");
    tempCtx.canvas.width = imageInfo.width;
    tempCtx.canvas.height = imageInfo.height;
    tempCtx.drawImage(img, 0, 0);
    imageInfo.data = tempCtx.getImageData(0, 0, imageInfo.width, imageInfo.height);
}
function getMousePosition(e) {
    var p = $(e.target).offset(),
        x = Math.round((e.clientX || e.pageX) - p.left),
        y = Math.round((e.clientY || e.pageY) - p.top);
    return { x: x, y: y };
}
function onMouseDown(e) {
    if (e.button == 0) {
        allowDraw = true;
        addMode = e.ctrlKey;
    ...