Skip to content

Mithril

Audun Wigum Arbo edited this page May 22, 2018 · 1 revision

The application uses Mithril as its 'main' framework. Mithril is used to render the actual page (e.g. generating HTML/DOM and updating it when data changes). The reason for using Mithril (or an similar framework like React), is that it makes developing and maintaining of code much easier, in addition to increase readability and reduce duplicate code. This might sound a little abstract, so here is an example using a simple speed-o-meter module:

The example

VanillaJS (plain JavaScript)

The following code shows how you would program the module in plain JavaScript. You can see that you need to manually select the elements and update their inner HTML when you want to update anything.

import {Module} from "../Module.js";

const MIN_SPEED = 0;
const MAX_SPEED = 120;

export class Speedometer extends Module {
    constructor(id, area) {
        // id and area becomes fields of the class
        super(id, area);
        this.pinElement = null;
        this.speed = 0;
        this.currentRotation = 0;
        this.goalRotation = 0;
    }

    render(node) {
        let html = `
<div class="cell" style="grid-area: ${this.area}"><div id="${this.id}" class="speedometer">
    <!--Speed: <p class="speed">0</p>-->
    <div class="pin"></div>
</div></div>`;

        node.insertAdjacentHTML("beforeend", html);
        this.element = document.getElementById(this.id);
        this.pinElement = this.element.getElementsByClassName("pin")[0];
    }

    calculateRotation(speed) {
        let speedRange = MAX_SPEED - MIN_SPEED;
        let percentage = speed / speedRange;
        return percentage * 180 - 90;
    }


    onData(value) {
        this.goalRotation = this.calculateRotation(value);
        this.speed = value;
    }

    update() {
        let nextRotation = Math.lerp(this.currentRotation, this.goalRotation, 0.2);
        this.currentRotation = nextRotation;
        this.pinElement.style.transform = `rotate(${nextRotation}deg)`;
    }
}

To display this module, you have to call

let module = new Speedometer(...);
module.render(document.body);

To update the DOM/HTML with new data, you have to call this for each module:

module.update();

Mithril

When you use Mithril, you can do this much easier. Mithril handles the rendering, and you don't need to worry about the elements.

import {Module} from "../Module.js";

const MIN_SPEED = 0;
const MAX_SPEED = 120;

export class Speedometer extends Module {
    constructor(area) {
        super( area);
        this.rotation = 0;
    }

    view() {
        return m("div.cell", { style: { "grid-area": this.area } },
            m("div.speedometer",
                m("div.pin", {style: {transform: `rotate(${this.rotation}deg)`}})
            )
        );
    }

    calculateRotation(speed) {
        let speedRange = MAX_SPEED - MIN_SPEED;
        let percentage = speed / speedRange;
        return percentage * 180 - 90;
    }


    onData(value) {
        this.rotation = this.calculateRotation(value);
    }
}

To display this module, you have to call

m.mount(document.body, new Speedometer(...));

To update the DOM/HTML with new data from all modules, you just have to call

m.redraw();