JSFiddle - React, Tailwind, and code Playground

by acbabis

HTML

<b>View 1</b><br/>
<canvas id="view1" style="border: solid 1px black" width="500" height="200"></canvas><br/>
<b>View 2</b><br/>
<span id="view2">()</span><br/>
<br/><br/>
<b>Controller</b><br/>
X: <input id="x">, Y: <input id="y"> <button id="button">Move</button>

JavaScript

/*******************
 * MODEL
 *******************/
function Model() {
    this._observers = [];
    this._x = 0;
    this._y = 0;
    this._distance = 0;
}

Model.prototype.move = function(x, y) {
    this._x = x;
    this._y = y;
    this._distance = Math.sqrt(x * x + y * y);
    // The state of the model has changed, so
    // we notify all observers.
    var obs = this._observers;
    for(var i = 0, l = obs.length; i < l; i++) {
        try {
            obs[i]('move');
        } catch(e) {
            console.error(e);
        }
    }
};

Model.prototype.addObserver = function(observer) {
    this._observers.push(observer);
}

Model.prototype.x = function() {return this._x};
Model.prototype.y = function() {return this._y};
Model.prototype.distance = function() {return this._distance};

var model = new Model();

/*******************
 * CONTROLLER
 *******************/
document.getElementById('button').addEventListener('click', function() {
    model.move(document.getElementById('x').value, document.getElementById('y').value);
});

/*******************
 * VIEW
 *******************/

// Important Note: There are 2 independent views
// that the model code knows nothing about.
model.addObserver(function(type) {
    var canvas = document.getElementById('view1');
    var ctx = canvas.getContext('2d');
    var width = canvas.width;
    var height = canvas.height;
    ctx.clearRect(0, 0, width, height);
    ctx.beginPath();
    ctx.moveTo(width / 2, 0);
    ctx.lineTo(width / 2, height);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(0, height / 2);
    ctx.lineTo(width, height / 2);
    ctx.stroke();
    ctx.beginPath();
    var x = model.x() - 2 + width / 2;
    var y = model.y() - 2 + height / 2;
    ctx.arc(x, y, 4, 0, 2 * Math.PI);
    ctx.fillStyle = '#0000FF';
    ctx.fill();
});

model.addObserver(function(type) {
    document.getElementById('view2').innerHTML = 'Dot is ' + model.distance().toFixed(1) + ' pixels from the center';
});

model.move(20, 20);