graphics/rectangle.js

'use strict';

var Thing = require('./thing.js');

/**
 * @class Rectangle
 * @augments Thing
 * @param {number} width - Desired width of resulting rectangle.
 * @param {number} height - Desired height of resulting rectangle.
 */
function Rectangle(width, height) {
    if (arguments.length !== 2) {
        throw new Error(
            'You should pass exactly 2 arguments to <span ' +
                'class="code">new Rectangle(width, height)</span>'
        );
    }
    if (typeof width !== 'number' || !isFinite(width)) {
        throw new TypeError(
            'Invalid value for <span class="code">width' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">new Rectangle(width, height)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    if (typeof height !== 'number' || !isFinite(height)) {
        throw new TypeError(
            'Invalid value for <span class="code">height' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">new Rectangle(width, height)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    Thing.call(this);
    this.width = Math.max(0, width);
    this.height = Math.max(0, height);
    this.type = 'Rectangle';
}

Rectangle.prototype = new Thing();
Rectangle.prototype.constructor = Rectangle;

/**
 * Draws the rectangle in the canvas.
 *
 * @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module.
 */
Rectangle.prototype.draw = function(__graphics__) {
    var context = __graphics__.getContext();

    // http://stackoverflow.com/questions/17125632/html5-canvas-rotate-object-without-moving-coordinates
    context.save();
    context.fillStyle = this.color.toString();

    if (this.hasBorder) {
        context.lineWidth = this.lineWidth;
        context.strokeStyle = this.stroke.toString();
    }

    context.beginPath();
    context.translate(this.x + this.width / 2, this.y + this.height / 2);
    context.rotate(this.rotation);
    // Note: after transforming [0,0] is visually [x,y]
    // so the rect needs to be offset accordingly when drawn
    context.rect(-this.width / 2, -this.height / 2, this.width, this.height);
    context.closePath();

    if (this.hasBorder) {
        context.stroke();
    }

    context.fill();
    context.restore();
};

/**
 * Sets the size of the Rectangle.
 *
 * @param {number} width - The desired width of the resulting Rectangle.
 * @param {number} height - The desired height of the resulting Rectangle.
 */
Rectangle.prototype.setSize = function(width, height) {
    if (arguments.length !== 2) {
        throw new Error(
            'You should pass exactly 2 arguments to <span ' +
                'class="code">setSize(width, height)</span>'
        );
    }
    if (typeof width !== 'number' || !isFinite(width)) {
        throw new TypeError(
            'Invalid value for <span class="code">width' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">setSize(width, height)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    if (typeof height !== 'number' || !isFinite(height)) {
        throw new TypeError(
            'Invalid value for <span class="code">height' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">setSize(width, height)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    this.width = Math.max(0, width);
    this.height = Math.max(0, height);
};

/**
 * Sets the width of the Rectangle.
 *
 * @param {number} width - The desired width of the resulting Rectangle.
 */
Rectangle.prototype.setWidth = function(width) {
    if (arguments.length !== 1) {
        throw new Error(
            'You should pass exactly 1 argument to <span class="code">setWidth(width)</span>'
        );
    }
    if (typeof width !== 'number' || !isFinite(width)) {
        throw new TypeError(
            'Invalid value for <span class="code">width' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">setWidth(width)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    this.width = Math.max(0, width);
};

/**
 * Sets the height of the Rectangle.
 *
 * @param {number} height - The desired height of the resulting Rectangle.
 */
Rectangle.prototype.setHeight = function(height) {
    if (arguments.length !== 1) {
        throw new Error(
            'You should pass exactly 1 argument to <span class="code">setHeight(height)</span>'
        );
    }
    if (typeof height !== 'number' || !isFinite(height)) {
        throw new TypeError(
            'Invalid value for <span class="code">height' +
                '</span>. Make sure you are passing finite numbers to <span ' +
                'class="code">setHeight(height)</span>. Did you ' +
                'forget the parentheses in <span class="code">getWidth()</span> ' +
                'or <span class="code">getHeight()</span>? Or did you perform a ' +
                'calculation on a variable that is not a number?'
        );
    }
    this.height = Math.max(0, height);
};

/**
 * Checks if the passed point is contained in the rectangle.
 *
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {boolean} Whether the passed point is contained in the rectangle.
 */
Rectangle.prototype.containsPoint = function(x, y) {
    return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
};

/**
 * Gets the width of the rectangle.
 *
 * @returns {number} Width of the rectangle.
 */
Rectangle.prototype.getWidth = function() {
    return this.width;
};

/**
 * Gets the height of the rectangle.
 *
 * @returns {number} Height of the rectangle.
 */
Rectangle.prototype.getHeight = function() {
    return this.height;
};

module.exports = Rectangle;