graphics/rectangle.js

  1. 'use strict';
  2. var Thing = require('./thing.js');
  3. /**
  4. * @class Rectangle
  5. * @augments Thing
  6. * @param {number} width - Desired width of resulting rectangle.
  7. * @param {number} height - Desired height of resulting rectangle.
  8. */
  9. function Rectangle(width, height) {
  10. if (arguments.length !== 2) {
  11. throw new Error(
  12. 'You should pass exactly 2 arguments to <span ' +
  13. 'class="code">new Rectangle(width, height)</span>'
  14. );
  15. }
  16. if (typeof width !== 'number' || !isFinite(width)) {
  17. throw new TypeError(
  18. 'Invalid value for <span class="code">width' +
  19. '</span>. Make sure you are passing finite numbers to <span ' +
  20. 'class="code">new Rectangle(width, height)</span>. Did you ' +
  21. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  22. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  23. 'calculation on a variable that is not a number?'
  24. );
  25. }
  26. if (typeof height !== 'number' || !isFinite(height)) {
  27. throw new TypeError(
  28. 'Invalid value for <span class="code">height' +
  29. '</span>. Make sure you are passing finite numbers to <span ' +
  30. 'class="code">new Rectangle(width, height)</span>. Did you ' +
  31. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  32. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  33. 'calculation on a variable that is not a number?'
  34. );
  35. }
  36. Thing.call(this);
  37. this.width = Math.max(0, width);
  38. this.height = Math.max(0, height);
  39. this.type = 'Rectangle';
  40. }
  41. Rectangle.prototype = new Thing();
  42. Rectangle.prototype.constructor = Rectangle;
  43. /**
  44. * Draws the rectangle in the canvas.
  45. *
  46. * @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module.
  47. */
  48. Rectangle.prototype.draw = function(__graphics__) {
  49. var context = __graphics__.getContext();
  50. // http://stackoverflow.com/questions/17125632/html5-canvas-rotate-object-without-moving-coordinates
  51. context.save();
  52. context.fillStyle = this.color.toString();
  53. if (this.hasBorder) {
  54. context.lineWidth = this.lineWidth;
  55. context.strokeStyle = this.stroke.toString();
  56. }
  57. context.beginPath();
  58. context.translate(this.x + this.width / 2, this.y + this.height / 2);
  59. context.rotate(this.rotation);
  60. // Note: after transforming [0,0] is visually [x,y]
  61. // so the rect needs to be offset accordingly when drawn
  62. context.rect(-this.width / 2, -this.height / 2, this.width, this.height);
  63. context.closePath();
  64. if (this.hasBorder) {
  65. context.stroke();
  66. }
  67. context.fill();
  68. context.restore();
  69. };
  70. /**
  71. * Sets the size of the Rectangle.
  72. *
  73. * @param {number} width - The desired width of the resulting Rectangle.
  74. * @param {number} height - The desired height of the resulting Rectangle.
  75. */
  76. Rectangle.prototype.setSize = function(width, height) {
  77. if (arguments.length !== 2) {
  78. throw new Error(
  79. 'You should pass exactly 2 arguments to <span ' +
  80. 'class="code">setSize(width, height)</span>'
  81. );
  82. }
  83. if (typeof width !== 'number' || !isFinite(width)) {
  84. throw new TypeError(
  85. 'Invalid value for <span class="code">width' +
  86. '</span>. Make sure you are passing finite numbers to <span ' +
  87. 'class="code">setSize(width, height)</span>. Did you ' +
  88. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  89. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  90. 'calculation on a variable that is not a number?'
  91. );
  92. }
  93. if (typeof height !== 'number' || !isFinite(height)) {
  94. throw new TypeError(
  95. 'Invalid value for <span class="code">height' +
  96. '</span>. Make sure you are passing finite numbers to <span ' +
  97. 'class="code">setSize(width, height)</span>. Did you ' +
  98. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  99. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  100. 'calculation on a variable that is not a number?'
  101. );
  102. }
  103. this.width = Math.max(0, width);
  104. this.height = Math.max(0, height);
  105. };
  106. /**
  107. * Sets the width of the Rectangle.
  108. *
  109. * @param {number} width - The desired width of the resulting Rectangle.
  110. */
  111. Rectangle.prototype.setWidth = function(width) {
  112. if (arguments.length !== 1) {
  113. throw new Error(
  114. 'You should pass exactly 1 argument to <span class="code">setWidth(width)</span>'
  115. );
  116. }
  117. if (typeof width !== 'number' || !isFinite(width)) {
  118. throw new TypeError(
  119. 'Invalid value for <span class="code">width' +
  120. '</span>. Make sure you are passing finite numbers to <span ' +
  121. 'class="code">setWidth(width)</span>. Did you ' +
  122. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  123. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  124. 'calculation on a variable that is not a number?'
  125. );
  126. }
  127. this.width = Math.max(0, width);
  128. };
  129. /**
  130. * Sets the height of the Rectangle.
  131. *
  132. * @param {number} height - The desired height of the resulting Rectangle.
  133. */
  134. Rectangle.prototype.setHeight = function(height) {
  135. if (arguments.length !== 1) {
  136. throw new Error(
  137. 'You should pass exactly 1 argument to <span class="code">setHeight(height)</span>'
  138. );
  139. }
  140. if (typeof height !== 'number' || !isFinite(height)) {
  141. throw new TypeError(
  142. 'Invalid value for <span class="code">height' +
  143. '</span>. Make sure you are passing finite numbers to <span ' +
  144. 'class="code">setHeight(height)</span>. Did you ' +
  145. 'forget the parentheses in <span class="code">getWidth()</span> ' +
  146. 'or <span class="code">getHeight()</span>? Or did you perform a ' +
  147. 'calculation on a variable that is not a number?'
  148. );
  149. }
  150. this.height = Math.max(0, height);
  151. };
  152. /**
  153. * Checks if the passed point is contained in the rectangle.
  154. *
  155. * @param {number} x - The x coordinate of the point being tested.
  156. * @param {number} y - The y coordinate of the point being tested.
  157. * @returns {boolean} Whether the passed point is contained in the rectangle.
  158. */
  159. Rectangle.prototype.containsPoint = function(x, y) {
  160. return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
  161. };
  162. /**
  163. * Gets the width of the rectangle.
  164. *
  165. * @returns {number} Width of the rectangle.
  166. */
  167. Rectangle.prototype.getWidth = function() {
  168. return this.width;
  169. };
  170. /**
  171. * Gets the height of the rectangle.
  172. *
  173. * @returns {number} Height of the rectangle.
  174. */
  175. Rectangle.prototype.getHeight = function() {
  176. return this.height;
  177. };
  178. module.exports = Rectangle;