group.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview A thicker wrapper around graphics groups.
  16. * @author robbyw@google.com (Robby Walker)
  17. */
  18. goog.provide('goog.graphics.ext.Group');
  19. goog.require('goog.array');
  20. goog.require('goog.graphics.ext.Element');
  21. /**
  22. * Wrapper for a graphics group.
  23. * @param {goog.graphics.ext.Group} group Parent for this element. Can
  24. * be null if this is a Graphics instance.
  25. * @param {goog.graphics.GroupElement=} opt_wrapper The thin wrapper
  26. * to wrap. If omitted, a new group will be created. Must be included
  27. * when group is null.
  28. * @constructor
  29. * @extends {goog.graphics.ext.Element}
  30. */
  31. goog.graphics.ext.Group = function(group, opt_wrapper) {
  32. opt_wrapper = opt_wrapper ||
  33. group.getGraphicsImplementation().createGroup(group.getWrapper());
  34. goog.graphics.ext.Element.call(this, group, opt_wrapper);
  35. /**
  36. * Array of child elements this group contains.
  37. * @type {Array<goog.graphics.ext.Element>}
  38. * @private
  39. */
  40. this.children_ = [];
  41. };
  42. goog.inherits(goog.graphics.ext.Group, goog.graphics.ext.Element);
  43. /**
  44. * Add an element to the group. This should be treated as package local, as
  45. * it is called by the draw* methods.
  46. * @param {!goog.graphics.ext.Element} element The element to add.
  47. * @param {boolean=} opt_chain Whether this addition is part of a longer set
  48. * of element additions.
  49. */
  50. goog.graphics.ext.Group.prototype.addChild = function(element, opt_chain) {
  51. if (!goog.array.contains(this.children_, element)) {
  52. this.children_.push(element);
  53. }
  54. var transformed = this.growToFit_(element);
  55. if (element.isParentDependent()) {
  56. element.parentTransform();
  57. }
  58. if (!opt_chain && element.isPendingTransform()) {
  59. element.reset();
  60. }
  61. if (transformed) {
  62. this.reset();
  63. }
  64. };
  65. /**
  66. * Remove an element from the group.
  67. * @param {goog.graphics.ext.Element} element The element to remove.
  68. */
  69. goog.graphics.ext.Group.prototype.removeChild = function(element) {
  70. goog.array.remove(this.children_, element);
  71. // TODO(robbyw): shape.fireEvent('delete')
  72. this.getGraphicsImplementation().removeElement(element.getWrapper());
  73. };
  74. /**
  75. * Calls the given function on each of this component's children in order. If
  76. * {@code opt_obj} is provided, it will be used as the 'this' object in the
  77. * function when called. The function should take two arguments: the child
  78. * component and its 0-based index. The return value is ignored.
  79. * @param {Function} f The function to call for every child component; should
  80. * take 2 arguments (the child and its index).
  81. * @param {Object=} opt_obj Used as the 'this' object in f when called.
  82. */
  83. goog.graphics.ext.Group.prototype.forEachChild = function(f, opt_obj) {
  84. if (this.children_) {
  85. goog.array.forEach(this.children_, f, opt_obj);
  86. }
  87. };
  88. /**
  89. * @return {goog.graphics.GroupElement} The underlying thin wrapper.
  90. * @override
  91. */
  92. goog.graphics.ext.Group.prototype.getWrapper;
  93. /**
  94. * Reset the element.
  95. * @override
  96. */
  97. goog.graphics.ext.Group.prototype.reset = function() {
  98. goog.graphics.ext.Group.superClass_.reset.call(this);
  99. this.updateChildren();
  100. };
  101. /**
  102. * Called from the parent class, this method resets any pre-computed positions
  103. * and sizes.
  104. * @protected
  105. * @override
  106. */
  107. goog.graphics.ext.Group.prototype.redraw = function() {
  108. this.getWrapper().setSize(this.getWidth(), this.getHeight());
  109. this.transformChildren();
  110. };
  111. /**
  112. * Transform the children that need to be transformed.
  113. * @protected
  114. */
  115. goog.graphics.ext.Group.prototype.transformChildren = function() {
  116. this.forEachChild(function(child) {
  117. if (child.isParentDependent()) {
  118. child.parentTransform();
  119. }
  120. });
  121. };
  122. /**
  123. * As part of the reset process, update child elements.
  124. */
  125. goog.graphics.ext.Group.prototype.updateChildren = function() {
  126. this.forEachChild(function(child) {
  127. if (child.isParentDependent() || child.isPendingTransform()) {
  128. child.reset();
  129. } else if (child.updateChildren) {
  130. child.updateChildren();
  131. }
  132. });
  133. };
  134. /**
  135. * When adding an element, grow this group's bounds to fit it.
  136. * @param {!goog.graphics.ext.Element} element The added element.
  137. * @return {boolean} Whether the size of this group changed.
  138. * @private
  139. */
  140. goog.graphics.ext.Group.prototype.growToFit_ = function(element) {
  141. var transformed = false;
  142. var x = element.getMaxX();
  143. if (x > this.getWidth()) {
  144. this.setMinWidth(x);
  145. transformed = true;
  146. }
  147. var y = element.getMaxY();
  148. if (y > this.getHeight()) {
  149. this.setMinHeight(y);
  150. transformed = true;
  151. }
  152. return transformed;
  153. };
  154. /**
  155. * @return {number} The width of the element's coordinate space.
  156. */
  157. goog.graphics.ext.Group.prototype.getCoordinateWidth = function() {
  158. return this.getWidth();
  159. };
  160. /**
  161. * @return {number} The height of the element's coordinate space.
  162. */
  163. goog.graphics.ext.Group.prototype.getCoordinateHeight = function() {
  164. return this.getHeight();
  165. };
  166. /**
  167. * Remove all drawing elements from the group.
  168. */
  169. goog.graphics.ext.Group.prototype.clear = function() {
  170. while (this.children_.length) {
  171. this.removeChild(this.children_[0]);
  172. }
  173. };