graphics/text.js

  1. 'use strict';
  2. var Thing = require('./thing.js');
  3. /**
  4. * @class Text
  5. * @augments Thing
  6. * @param {string|number} label - The words of the text.
  7. * @param {string} font - String of the desired font of the text.
  8. */
  9. function Text(label, font) {
  10. if (arguments.length < 1) {
  11. throw new Error('You should pass at least one argument to <span ' +
  12. 'class="code">new Text(label, font)</span>. <span class="code">' +
  13. 'label</span> is a required parameter.');
  14. }
  15. if (typeof label !== 'string' && typeof label !== 'number') {
  16. throw new TypeError('Invalid value for <span class="code">label' +
  17. '</span>. You passed a value of type ' + typeof label +
  18. ' but a string or number is required.');
  19. }
  20. font = font === undefined ? '20pt Arial' : font;
  21. if (typeof font !== 'string') {
  22. throw new TypeError('Invalid value for <span class="code">font' +
  23. '</span>. You passed a value of type ' + typeof label +
  24. ' but a string is required.');
  25. }
  26. Thing.call(this);
  27. this.label = label;
  28. this.type = 'Text';
  29. this.font = font;
  30. // Text needs a graphics context for computing height and width
  31. // we set this by default on running any graphics program, but
  32. // then it can get over-written the first time we call draw.
  33. this.context = null;
  34. this.resetDimensions();
  35. }
  36. Text.prototype = new Thing();
  37. Text.prototype.constructor = Text;
  38. Text.defaultContext = null;
  39. /**
  40. * Define a default context for the text.
  41. * Text objects need access to some 2d graphics context to compute
  42. * height and width. This might be done before a draw call.
  43. *
  44. * @param {CodeHSGraphics} __graphics__ - Instance of the graphics module.
  45. */
  46. Text.giveDefaultContext = function(__graphics__) {
  47. Text.defaultContext = __graphics__.getContext();
  48. };
  49. /**
  50. * Reset the dimensions of the text to the size in the context.
  51. */
  52. Text.prototype.resetDimensions = function() {
  53. var context = this.context || Text.defaultContext;
  54. context.font = this.font;
  55. this.width = context.measureText(this.label).width;
  56. this.height = context.measureText('m').width * 1.2; /* No height provided */
  57. };
  58. /**
  59. * Draw the text in the current context.
  60. *
  61. * @param {CodeHSGraphics} __graphics__ - Instance of the graphics module.
  62. */
  63. Text.prototype.draw = function(__graphics__) {
  64. var context = __graphics__.getContext();
  65. this.context = context;
  66. // http://stackoverflow.com/questions/17125632/html5-canvas-rotate-object-without-moving-coordinates
  67. context.save();
  68. context.fillStyle = this.color.toString();
  69. context.beginPath();
  70. context.font = this.font;
  71. this.resetDimensions();
  72. context.translate(this.x, this.y);
  73. context.rotate(this.rotation);
  74. context.fillText(this.label, 0, 0);
  75. context.closePath();
  76. context.fill();
  77. context.restore();
  78. };
  79. /**
  80. * Set the font of the text.
  81. * Re-calculates the dimensions of the font after font change.
  82. *
  83. * @param {string} font - String of the desired font for the text.
  84. */
  85. Text.prototype.setFont = function(font) {
  86. if (arguments.length !== 1) {
  87. throw new Error('You should pass exactly 1 argument to <span ' +
  88. 'class="code">setFont</span>');
  89. }
  90. if (typeof font !== 'string') {
  91. throw new TypeError('Invalid value passed to <span class=' +
  92. '"code">setFont</span>. You passed a value of type ' +
  93. typeof label + ', but a string is required.');
  94. }
  95. this.font = font;
  96. this.resetDimensions();
  97. };
  98. /**
  99. * Set the label of the text.
  100. * Re-calculates the dimensions of the font after font change.
  101. *
  102. * @param {string|number} label - The words of the text.
  103. */
  104. Text.prototype.setLabel = function(label) {
  105. if (arguments.length !== 1) {
  106. throw new Error('You should pass exactly 1 argument to <span ' +
  107. 'class="code">setLabel</span>');
  108. }
  109. if (typeof label !== 'string' && typeof label !== 'number') {
  110. throw new TypeError('Invalid value passed to <span class=' +
  111. '"code">setLabel</span>. You passed a value of type ' +
  112. typeof label + ', but a string or number is required.');
  113. }
  114. this.label = label;
  115. this.resetDimensions();
  116. };
  117. /**
  118. * Equivalent to `setLabel`. Likely created to prevent errors on
  119. * accidental calls.
  120. * Re-calculates the dimensions of the font after font change.
  121. *
  122. * @param {string|number} label - The words of the text.
  123. */
  124. Text.prototype.setText = function(label) {
  125. if (arguments.length !== 1) {
  126. throw new Error('You should pass exactly 1 argument to <span ' +
  127. 'class="code">setText</span>');
  128. }
  129. if (typeof label !== 'string' && typeof label !== 'number') {
  130. throw new TypeError('Invalid value passed to <span class=' +
  131. '"code">setText</span>. You passed a value of type ' +
  132. typeof label + ', but a string or number is required.');
  133. }
  134. this.label = label;
  135. this.resetDimensions();
  136. };
  137. /**
  138. * Returns the label of a Text object.
  139. *
  140. * @returns {string} String of the Text's current label.
  141. */
  142. Text.prototype.getLabel = function() {
  143. return this.label;
  144. };
  145. /**
  146. * Equivalent to `getLabel`. Likely created to prevent errors on accidental
  147. * calls.
  148. * Returns the label of a Text object.
  149. *
  150. * @returns {string} String of the Text's current label.
  151. */
  152. Text.prototype.getText = function() {
  153. return this.label;
  154. };
  155. /**
  156. * Returns the width of a Text object.
  157. *
  158. * @returns {number} The width of the text.
  159. */
  160. Text.prototype.getWidth = function() {
  161. return this.width;
  162. };
  163. /**
  164. * Returns the height of a Text object.
  165. *
  166. * @returns {number} The height of the text.
  167. */
  168. Text.prototype.getHeight = function() {
  169. return this.height;
  170. };
  171. /**
  172. * Checks if the passed point is contained in the text.
  173. *
  174. * @param {number} x - The x coordinate of the point being tested.
  175. * @param {number} y - The y coordinate of the point being tested.
  176. * @returns {boolean} Whether the passed point is contained in the text.
  177. */
  178. Text.prototype.containsPoint = function(x, y) {
  179. return x >= this.x && x <= this.x + this.width &&
  180. y <= this.y && y >= this.y - this.height;
  181. };
  182. module.exports = Text;