JSFiddle - React, Tailwind, and code Playground

by evankennedy

HTML

<canvas width="200" height="200"></canvas>
<br>
<button id='undo'>Undo</button>
<button id='redo'>Redo</button>

JavaScript

ctx = document.getElementsByTagName('canvas')[0].getContext('2d');
$('#undo').click(function(){
    ctx.history.undo();
});

$('#redo').click(function(){
    ctx.history.redo();
});

var context = Object.getPrototypeOf(document.createElement('canvas').getContext('2d'));
var canvas = Object.getPrototypeOf(document.createElement('canvas'));

function bind(context, p) {
    var original = context[p];
    context[p] = function() {
        var h = context.history;
        if(h.write){
            h.data.splice(h.index, h.data.length - h.index, [original, arguments, this]);
            h.index++;
        }
        return original.apply(this, arguments);
    };
}

for (var p in context) {
    if (context.hasOwnProperty(p)) {
        bind(context, p);
    }
}
context.redraw = function(){
    this.history.write = false;
    var context = this.history.data[0][2];
    context.clearRect(0,0,context.canvas.width,context.canvas.height);
    
    for (var i = 0; i < this.history.index; i++) {
        this.history.data[i][0].apply(context,this.history.data[i][1]);
    }
}
context.history = {
    index: 0,
    data: [],
    undo: function() {
        if(this.index != 0) this.index--;
        context.redraw();
    },
    redo: function() {
        if(this.index != this.data.length) this.index++;
        context.redraw();
    },
    write: true
};

// Filled triangle
ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(105, 25);
ctx.lineTo(25, 105);
ctx.fill();

// Stroked triangle
ctx.beginPath();
ctx.moveTo(125, 125);
ctx.lineTo(125, 45);
ctx.lineTo(45, 125);
ctx.closePath();
ctx.stroke();