d-simon/node-pixelscreen

View on GitHub
index.js

Summary

Maintainability
A
2 hrs
Test Coverage
var TerminalScreen = require('terminal-pixelscreen')
  , _ = require('lodash')
  , extend = require('extend');

function SubScreen (name, options, callback) {
    var opts = extend({
        x: 0,
        y: 0,
        width: 1,
        height: 1,
        channels: 3,
        dmx: false
    },options);
    this.name = name;
    this.x = opts.x;
    this.y = opts.y;
    this.width = opts.width;
    this.height = opts.height;
    this.channels = opts.channels;
    this.dmx = opts.dmx;
    this.callback = callback;
    this.image = createImageArray(this.width, this.height, this.channels);
}

function createImageArray (width, height, channels) {
    var array = [];
    for (var i = 0; i < height; i++) {
        array.push([]);
        for (var j = 0; j < width; j++) {
            array[i].push([]);
            for (var k = 0; k < channels; k++) {
                array[i][j].push(0);
            }
        }
    }
    return array;
}

function PixelScreen (options) {
    var opts = extend({
        width: 1,
        height: 1,
        channels: 3,
        displayScreen: false
    }, options);
    this.width = opts.width;
    this.height = opts.height;
    this.channels = opts.channels;
    this.image = createImageArray(this.width, this.height, this.channels);
    this.screens = [];
    this.displayScreen = opts.displayScreen;
    this.terminalScreen = new TerminalScreen(this.width,this.height,0);
}

PixelScreen.prototype.registerScreen = function (name, options, callback) {
    if (!name || this.screens[name]) throw new Error('Screen "' + name + '" already exists!');
    this.screens[name] = new SubScreen(name, options, callback);
    return this;
};

PixelScreen.prototype.unregisterScreen = function (name) {
    if (!name || !this.screens[name]) throw new Error('Screen "' + name + '" doesn\'t exist!');
    this.screen[name] = null;
    return this;
};

PixelScreen.prototype.forceUpdate = function () {
    for (var screenName in this.screens) {
        var screen = this.screens[screenName]
          , pixelImage = this.getImage(screen.name);
        if(screen.dmx === true) pixelImage = this.arrayToDMX(pixelImage);
        screen.callback(null, pixelImage);
    }
    if (this.displayScreen === true) {
        this.terminalScreen.update(this.image);
        this.terminalScreen.paint();
    }
    return this;
};

PixelScreen.prototype.update = function (input) {
    if (!input || !input.length) throw new Error('No input!');
    if (input[0][0].length !== this.channels) throw new Error('Invalid no. of channels!');
    if (input.length !== this.height ||
        input[0].length !== this.width) throw new Error('Invalid dimensions! (' + input[0].length + 'x' + input.length +
                                                        ' instead of ' + this.width + 'x' + this.height + ')');

    this.image = _.cloneDeep(input);
    this.forceUpdate();
    return this;
};

PixelScreen.prototype.getImage = function (name) {
    if (!name) return this.image;
    if (!this.screens[name]) return;

    var screen = this.screens[name]
      , image = [];

    for (var i = 0; i < screen.height; i++) {
        image.push([]);
        for (var j = 0; j < screen.width; j++) {

            if ( // out of bound ranges ranges
                i + screen.y < 0 ||
                j + screen.x < 0 ||
                i + screen.y > this.image.length ||
                j + screen.x > this.image[i+screen.y].length
            ) {
                // return flat channels ([0,...,0])
                image[i].push(this.enerateArray(3,0));
            } else {
                image[i].push(this.createBalancedChannels(this.image[i+screen.y][j+screen.x], 3));
            }
        }
    }

    return image;
};

PixelScreen.prototype.createBalancedChannels = function (inputArray, expectedChannels) {
    // return channels and flatten or cut channels
    // if we have a difference in no. of channels
    var array = [];
    for (var k = 0; k < inputArray.length; k++) {
        if (k < expectedChannels) {
            array.push(inputArray[k]);
        } else {
            array.push(0);
        }
    }
    // fill up with flat channels if we are missing channels
    if (array.length < expectedChannels) {
        for (var k = array.length; k < expectedChannels; k++) {
            array.push(0);
        }
    }
    return array;
};

PixelScreen.prototype.generateArray = function (length, value) {
    var array = [];
    for (var i = 0; i < length; i++) {
        array.push(value);
    }
    return array;
};

PixelScreen.prototype.arrayToDMX = function (input) {
    var dmx = [];
    for (var i = 0; i < input.length; i++) {
        for (var j = 0; j < input[i].length; j++) {
            for (var k = 0; k < input[i][j].length; k++) {
                dmx.push(input[i][j][k]);
            }
        }
    }
    return dmx;
};

module.exports = PixelScreen;