hsvapalette.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright 2008 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 An HSVA (hue/saturation/value/alpha) color palette/picker
  16. * implementation.
  17. * Without the styles from the demo css file, only a hex color label and input
  18. * field show up.
  19. *
  20. * @author chrisn@google.com (Chris Nokleberg)
  21. * @see ../demos/hsvapalette.html
  22. */
  23. goog.provide('goog.ui.HsvaPalette');
  24. goog.require('goog.array');
  25. goog.require('goog.color.alpha');
  26. goog.require('goog.dom.TagName');
  27. goog.require('goog.events');
  28. goog.require('goog.events.EventType');
  29. goog.require('goog.style');
  30. goog.require('goog.ui.Component');
  31. goog.require('goog.ui.HsvPalette');
  32. /**
  33. * Creates an HSVA palette. Allows a user to select the hue, saturation,
  34. * value/brightness and alpha/opacity.
  35. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
  36. * @param {string=} opt_color Optional initial color, without alpha (default is
  37. * red).
  38. * @param {number=} opt_alpha Optional initial alpha (default is 1).
  39. * @param {string=} opt_class Optional base for creating classnames (default is
  40. * 'goog-hsva-palette').
  41. * @extends {goog.ui.HsvPalette}
  42. * @constructor
  43. * @final
  44. */
  45. goog.ui.HsvaPalette = function(opt_domHelper, opt_color, opt_alpha, opt_class) {
  46. goog.ui.HsvaPalette.base(
  47. this, 'constructor', opt_domHelper, opt_color, opt_class);
  48. /**
  49. * Alpha transparency of the currently selected color, in [0, 1]. When
  50. * undefined, the palette will behave as a non-transparent HSV palette,
  51. * assuming full opacity.
  52. * @type {number}
  53. * @private
  54. */
  55. this.alpha_ = goog.isDef(opt_alpha) ? opt_alpha : 1;
  56. /**
  57. * @override
  58. */
  59. this.className = opt_class || goog.getCssName('goog-hsva-palette');
  60. };
  61. goog.inherits(goog.ui.HsvaPalette, goog.ui.HsvPalette);
  62. /**
  63. * DOM element representing the alpha background image.
  64. * @type {HTMLElement}
  65. * @private
  66. */
  67. goog.ui.HsvaPalette.prototype.aImageEl_;
  68. /**
  69. * DOM element representing the alpha handle.
  70. * @type {HTMLElement}
  71. * @private
  72. */
  73. goog.ui.HsvaPalette.prototype.aHandleEl_;
  74. /**
  75. * DOM element representing the swatch backdrop image.
  76. * @type {Element}
  77. * @private
  78. */
  79. goog.ui.HsvaPalette.prototype.swatchBackdropEl_;
  80. /** @override */
  81. goog.ui.HsvaPalette.prototype.getAlpha = function() {
  82. return this.alpha_;
  83. };
  84. /**
  85. * Sets which color is selected and update the UI. The passed color should be
  86. * in #rrggbb format. The alpha value will be set to 1.
  87. * @param {number} alpha The selected alpha value, in [0, 1].
  88. */
  89. goog.ui.HsvaPalette.prototype.setAlpha = function(alpha) {
  90. this.setColorAlphaHelper_(this.color, alpha);
  91. };
  92. /**
  93. * Sets which color is selected and update the UI. The passed color should be
  94. * in #rrggbb format. The alpha value will be set to 1.
  95. * @param {string} color The selected color.
  96. * @override
  97. */
  98. goog.ui.HsvaPalette.prototype.setColor = function(color) {
  99. this.setColorAlphaHelper_(color, 1);
  100. };
  101. /**
  102. * Gets the color that is currently selected in this color picker, in #rrggbbaa
  103. * format.
  104. * @return {string} The string of the selected color with alpha.
  105. */
  106. goog.ui.HsvaPalette.prototype.getColorRgbaHex = function() {
  107. var alphaHex = Math.floor(this.alpha_ * 255).toString(16);
  108. return this.color + (alphaHex.length == 1 ? '0' + alphaHex : alphaHex);
  109. };
  110. /**
  111. * Sets which color is selected and update the UI. The passed color should be
  112. * in #rrggbbaa format. The alpha value will be set to 1.
  113. * @param {string} color The selected color with alpha.
  114. */
  115. goog.ui.HsvaPalette.prototype.setColorRgbaHex = function(color) {
  116. var parsed = goog.ui.HsvaPalette.parseColorRgbaHex_(color);
  117. this.setColorAlphaHelper_(parsed[0], parsed[1]);
  118. };
  119. /**
  120. * Sets which color and alpha value are selected and update the UI. The passed
  121. * color should be in #rrggbb format.
  122. * @param {string} color The selected color in #rrggbb format.
  123. * @param {number} alpha The selected alpha value, in [0, 1].
  124. * @private
  125. */
  126. goog.ui.HsvaPalette.prototype.setColorAlphaHelper_ = function(color, alpha) {
  127. var colorChange = this.color != color;
  128. var alphaChange = this.alpha_ != alpha;
  129. this.alpha_ = alpha;
  130. this.color = color;
  131. if (colorChange) {
  132. // This is to prevent multiple event dispatches.
  133. this.setColorInternal(color);
  134. }
  135. if (colorChange || alphaChange) {
  136. this.updateUi();
  137. this.dispatchEvent(goog.ui.Component.EventType.ACTION);
  138. }
  139. };
  140. /** @override */
  141. goog.ui.HsvaPalette.prototype.createDom = function() {
  142. goog.ui.HsvaPalette.base(this, 'createDom');
  143. var dom = this.getDomHelper();
  144. this.aImageEl_ = /** @type {!HTMLElement} */ (
  145. dom.createDom(
  146. goog.dom.TagName.DIV, goog.getCssName(this.className, 'a-image')));
  147. this.aHandleEl_ = /** @type {!HTMLElement} */ (
  148. dom.createDom(
  149. goog.dom.TagName.DIV, goog.getCssName(this.className, 'a-handle')));
  150. this.swatchBackdropEl_ = dom.createDom(
  151. goog.dom.TagName.DIV, goog.getCssName(this.className, 'swatch-backdrop'));
  152. var element = this.getElement();
  153. dom.appendChild(element, this.aImageEl_);
  154. dom.appendChild(element, this.aHandleEl_);
  155. dom.appendChild(element, this.swatchBackdropEl_);
  156. };
  157. /** @override */
  158. goog.ui.HsvaPalette.prototype.disposeInternal = function() {
  159. goog.ui.HsvaPalette.base(this, 'disposeInternal');
  160. delete this.aImageEl_;
  161. delete this.aHandleEl_;
  162. delete this.swatchBackdropEl_;
  163. };
  164. /** @override */
  165. goog.ui.HsvaPalette.prototype.updateUi = function() {
  166. goog.ui.HsvaPalette.base(this, 'updateUi');
  167. if (this.isInDocument()) {
  168. var a = this.alpha_ * 255;
  169. var top = this.aImageEl_.offsetTop -
  170. Math.floor(this.aHandleEl_.offsetHeight / 2) +
  171. this.aImageEl_.offsetHeight * ((255 - a) / 255);
  172. this.aHandleEl_.style.top = top + 'px';
  173. this.aImageEl_.style.backgroundColor = this.color;
  174. goog.style.setOpacity(this.swatchElement, a / 255);
  175. }
  176. };
  177. /** @override */
  178. goog.ui.HsvaPalette.prototype.updateInput = function() {
  179. if (!goog.array.equals(
  180. [this.color, this.alpha_],
  181. goog.ui.HsvaPalette.parseUserInput_(this.inputElement.value))) {
  182. this.inputElement.value = this.getColorRgbaHex();
  183. }
  184. };
  185. /** @override */
  186. goog.ui.HsvaPalette.prototype.handleMouseDown = function(e) {
  187. goog.ui.HsvaPalette.base(this, 'handleMouseDown', e);
  188. if (e.target == this.aImageEl_ || e.target == this.aHandleEl_) {
  189. // Setup value change listeners
  190. var b = goog.style.getBounds(this.valueBackgroundImageElement);
  191. this.handleMouseMoveA_(b, e);
  192. this.mouseMoveListener = goog.events.listen(
  193. this.getDomHelper().getDocument(), goog.events.EventType.MOUSEMOVE,
  194. goog.bind(this.handleMouseMoveA_, this, b));
  195. this.mouseUpListener = goog.events.listen(
  196. this.getDomHelper().getDocument(), goog.events.EventType.MOUSEUP,
  197. this.handleMouseUp, false, this);
  198. }
  199. };
  200. /**
  201. * Handles mousemove events on the document once a drag operation on the alpha
  202. * slider has started.
  203. * @param {goog.math.Rect} b Boundaries of the value slider object at the start
  204. * of the drag operation.
  205. * @param {goog.events.Event} e Event object.
  206. * @private
  207. */
  208. goog.ui.HsvaPalette.prototype.handleMouseMoveA_ = function(b, e) {
  209. e.preventDefault();
  210. var vportPos = this.getDomHelper().getDocumentScroll();
  211. var newA =
  212. (b.top + b.height -
  213. Math.min(Math.max(vportPos.y + e.clientY, b.top), b.top + b.height)) /
  214. b.height;
  215. this.setAlpha(newA);
  216. };
  217. /** @override */
  218. goog.ui.HsvaPalette.prototype.handleInput = function(e) {
  219. var parsed = goog.ui.HsvaPalette.parseUserInput_(this.inputElement.value);
  220. if (parsed) {
  221. this.setColorAlphaHelper_(parsed[0], parsed[1]);
  222. }
  223. };
  224. /**
  225. * Parses an #rrggbb or #rrggbbaa color string.
  226. * @param {string} value User-entered color value.
  227. * @return {Array<?>} A two element array [color, alpha], where color is
  228. * #rrggbb and alpha is in [0, 1]. Null if the argument was invalid.
  229. * @private
  230. */
  231. goog.ui.HsvaPalette.parseUserInput_ = function(value) {
  232. if (/^#?[0-9a-f]{8}$/i.test(value)) {
  233. return goog.ui.HsvaPalette.parseColorRgbaHex_(value);
  234. } else if (/^#?[0-9a-f]{6}$/i.test(value)) {
  235. return [value, 1];
  236. }
  237. return null;
  238. };
  239. /**
  240. * Parses a #rrggbbaa color string.
  241. * @param {string} color The color and alpha in #rrggbbaa format.
  242. * @return {!Array<?>} A two element array [color, alpha], where color is
  243. * #rrggbb and alpha is in [0, 1].
  244. * @private
  245. */
  246. goog.ui.HsvaPalette.parseColorRgbaHex_ = function(color) {
  247. var hex = goog.color.alpha.parse(color).hex;
  248. return [
  249. goog.color.alpha.extractHexColor(hex),
  250. parseInt(goog.color.alpha.extractAlpha(hex), 16) / 255
  251. ];
  252. };