UNPKG

codehs-graphics

Version:

Helpers used to run graphics problems in the CodeHS editor.

176 lines (153 loc) 5.93 kB
'use strict'; var Thing = require('./thing.js'); /** * Note: this is not used as a subclass for Circle since drawing ovals * is much more complex than drawing circles, and there is no point in * complicating the drawing just for some code reuse. */ /** * @class Oval * @augments Thing * @param {number} width - Desired width of the Oval * @param {number} height - Desired height of the Oval */ function Oval(width, height) { if (arguments.length !== 2) { throw new Error('You should pass exactly 2 arguments to <span ' + 'class="code">new Oval(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 Oval(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 Oval(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 = 'Oval'; } Oval.prototype = new Thing(); Oval.prototype.constructor = Oval; /** * Draws an ellipse centered at this.x and this.y. * adapted from http://stackoverflow.com/questions/2172798/ * how-to-draw-an-oval-in-html5-canvas * * @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module. */ Oval.prototype.draw = function(__graphics__) { var context = __graphics__.getContext(); // http://stackoverflow.com/questions/17125632/html5-canvas-rotate-object-without-moving-coordinates context.save(); context.translate(this.x, this.y); context.rotate(this.rotation); var w = this.width; var h = this.height; var x = -w / 2; var y = -h / 2; var kappa = 0.5522848; var ox = (w / 2) * kappa; // control point offset horizontal var oy = (h / 2) * kappa; // control point offset vertical var xe = x + w; // x-end var ye = y + h; // y-end var xm = x + w / 2; // x-middle var ym = y + h / 2; // y-middle context.beginPath(); context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.fillStyle = this.color.toString(); context.fill(); if (this.hasBorder) { context.strokeStyle = this.stroke.toString(); context.lineWidth = this.lineWidth; context.stroke(); } context.closePath(); context.restore(); }; /** * Gets the height of the oval. * * @returns {number} Height of the oval. */ Oval.prototype.getHeight = function() { return this.height; }; /** * Gets the width of the oval. * * @returns {number} Width of the oval. */ Oval.prototype.getWidth = function() { return this.width; }; /** * Sets the width of the oval. * * @param {number} width - Desired width of the resulting oval. */ Oval.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('You must pass a finite number 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 oval. * * @param {number} height - Desired height of the resulting oval. */ Oval.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('You must pass a finite number 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 oval. * Uses the equation for an oval. * * @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 circle. */ Oval.prototype.containsPoint = function(x, y) { var xRadiusSquared = Math.pow(this.width / 2, 2); var yRadiusSquared = Math.pow(this.height / 2, 2); var xDifferenceSquared = Math.pow(x - this.x, 2); var yDifferenceSquared = Math.pow(y - this.y, 2); var result = xDifferenceSquared / xRadiusSquared + yDifferenceSquared / yRadiusSquared; return result <= 1; }; module.exports = Oval;