/scenes/santasearch/js/character.js

https://github.com/google/santa-tracker-web · JavaScript · 195 lines · 97 code · 33 blank · 65 comment · 10 complexity · 92a513a4fcc05a23d20930275d013251 MD5 · raw file

  1. /*
  2. * Copyright 2015 Google Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. 'use strict';
  17. goog.provide('app.Character');
  18. goog.require('app.Constants');
  19. /**
  20. * @param {String} name The name of the character.
  21. * @param {!jQuery} mapElem The element for the map.
  22. * @param {!jQuery} drawerElem The element for the drawer.
  23. * @constructor
  24. */
  25. app.Character = function(name, mapElem, drawerElem) {
  26. this.name = name;
  27. this.location = {};
  28. this.scale = {};
  29. this.isFound = false;
  30. this.mapElem = mapElem;
  31. // Find elements
  32. this.colliderElem = this.mapElem.find(`.character-collider--${this.name}`);
  33. this.drawerItemElem = drawerElem.find(`.drawer__item--${this.name}`);
  34. this.layerElem = null;
  35. // Handle found event
  36. this.colliderElem.on('click touchstart', this.onFound_.bind(this));
  37. this.drawerItemElem.on('click', this.onSelected_.bind(this));
  38. };
  39. /**
  40. * Initialize a character with location, scale and a click event
  41. * @param {{height: number, width: number}} mapDimensions The map dimensions.
  42. */
  43. app.Character.prototype.reset = function(mapDimensions) {
  44. let svgMapElem = this.mapElem.find('.map__svg');
  45. this.isFound = false;
  46. this.drawerItemElem.removeClass('drawer__item--found')
  47. .removeClass('drawer__item--focused');
  48. this.colliderElem.removeClass('character-collider--found');
  49. // Hide all spots
  50. for (let i = 1; i <= app.Constants.SPAWN_COUNT; i++) {
  51. this.getLayer_(svgMapElem, i).hide();
  52. }
  53. // Show one random spot
  54. let randomSpot = Math.ceil(Math.random() * app.Constants.SPAWN_COUNT);
  55. this.layerElem = this.getLayer_(svgMapElem, randomSpot).show();
  56. // In case character layers are missing from the SVG
  57. if (this.layerElem.length === 0) {
  58. console.error(`Layer ${randomSpot} for ${this.name} not found.`);
  59. return;
  60. }
  61. this.layerElem[0].classList.add('map__character');
  62. this.layerElem[0].classList.remove('map__character--found');
  63. let characterBoundaries = this.layerElem[0].getBoundingClientRect();
  64. let characterOffset = this.layerElem.offset();
  65. let leftOffset = (mapDimensions.width - this.mapElem.width()) / 2;
  66. let topOffset = (mapDimensions.height - this.mapElem.height()) / 2;
  67. // Start offset
  68. leftOffset -= this.mapElem.offset().left;
  69. topOffset -= this.mapElem.offset().top;
  70. this.location = {
  71. left: (characterOffset.left + leftOffset) / mapDimensions.width,
  72. top: (characterOffset.top + topOffset) / mapDimensions.height,
  73. };
  74. this.scale = {
  75. width: characterBoundaries.width / mapDimensions.width,
  76. height: characterBoundaries.height / mapDimensions.height,
  77. };
  78. };
  79. /**
  80. * Get the layer in the SVG for the character.
  81. * @param {!jQuery} svgMapElem The SVG map element.
  82. * @param {number} number The number of the layer.
  83. * @private
  84. */
  85. app.Character.prototype.getLayer_ = function(svgMapElem, number) {
  86. let name = this.name.replace('-', '').toUpperCase();
  87. return svgMapElem.find(`#${name}-${number}`);
  88. };
  89. /**
  90. * Positions a character based on map dimensions.
  91. * @param {{height: number, width: number}} mapDimensions The map dimensions.
  92. */
  93. app.Character.prototype.updatePosition = function(mapDimensions) {
  94. if (!this.colliderElem) {
  95. return;
  96. }
  97. let left = mapDimensions.width * this.location.left;
  98. let top = mapDimensions.height * this.location.top;
  99. this.colliderElem.css('transform', `translate3d(${left}px, ${top}px, 0)`);
  100. };
  101. /**
  102. * Change the scale of the character.
  103. * @param {{height: number, width: number}} mapDimensions The map dimensions.
  104. */
  105. app.Character.prototype.updateScale = function(mapDimensions) {
  106. if (!this.colliderElem) {
  107. return;
  108. }
  109. let characterWidth = mapDimensions.width * this.scale.width;
  110. let characterHeight = mapDimensions.height * this.scale.height;
  111. this.colliderElem.css('width', characterWidth);
  112. this.colliderElem.css('height', characterHeight);
  113. };
  114. /**
  115. * Called when the character has lost focus.
  116. */
  117. app.Character.prototype.onLostFocus = null;
  118. /**
  119. * Handles the event when a character is found
  120. * @private
  121. */
  122. app.Character.prototype.onFound_ = function() {
  123. if (this.isFound) {
  124. return;
  125. }
  126. window.ga('send', 'event', 'game', 'found', 'santasearch')
  127. window.santaApp.fire('sound-trigger', `ss_character_${this.name}`);
  128. let wasFocused = this.drawerItemElem.hasClass('drawer__item--focused');
  129. this.isFound = true;
  130. this.drawerItemElem.removeClass('drawer__item--focused');
  131. this.drawerItemElem.addClass('drawer__item--found');
  132. this.colliderElem.addClass('character-collider--found');
  133. this.layerElem[0].classList.add('map__character--found');
  134. if (wasFocused && this.onLostFocus) {
  135. this.onLostFocus();
  136. }
  137. };
  138. /**
  139. * Called when the character is selected.
  140. */
  141. app.Character.prototype.onSelected = null;
  142. /**
  143. * Handles the event when a character is selected.
  144. * @private
  145. */
  146. app.Character.prototype.onSelected_ = function() {
  147. if (!this.isFound && this.onSelected) {
  148. this.onSelected();
  149. }
  150. };
  151. /**
  152. * Focuses a character in the UI that the user should try to find.
  153. */
  154. app.Character.prototype.focus = function() {
  155. this.drawerItemElem.addClass('drawer__item--focused');
  156. };
  157. /**
  158. * Removes focus from the character.
  159. */
  160. app.Character.prototype.blur = function() {
  161. this.drawerItemElem.removeClass('drawer__item--focused');
  162. };