PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/share/spice/color_picker/color_picker.js

http://github.com/duckduckgo/zeroclickinfo-spice
JavaScript | 712 lines | 533 code | 107 blank | 72 comment | 46 complexity | 79ef3290566c6f2eac9f171a24c1129a MD5 | raw file
Possible License(s): Apache-2.0
  1. (function (env) {
  2. "use strict";
  3. env.ddg_spice_color_picker = function(){
  4. //Acts as a cache of this instant answer's DOM. Because the DOM isn't necessarily ready at
  5. // this point, this all gets initialized later.
  6. var local_dom = {
  7. initialized: false
  8. };
  9. //Maintains currently selected palette type so that it doesn't have to be read from
  10. // $palette_select on every update.
  11. var palette_type = 'analogous';
  12. //Maintains the current color in all supported formats.
  13. var current_color = get_initial_color(DDG.get_query());
  14. //Holds coordinate positions for the selection markers in the hue and saturation/value
  15. // pickers.
  16. var markers = get_marker_positions(current_color.hsv);
  17. //Indicates whether the user is currently dragging the mouse in the hue and saturation/value
  18. // pickers.
  19. var saturation_value_mousedown = false,
  20. hue_mousedown = false;
  21. //Prevent duplicate touch/mouse events
  22. var mouse_and_touch_locked = false;
  23. //TODO: use the real image paths
  24. Spice.add({
  25. id: "color_picker",
  26. name: "Color Picker",
  27. data: {
  28. saturation_value_path: DDG.get_asset_path('color_picker', 'saturation_value_gradient.png'),
  29. hue_path: DDG.get_asset_path('color_picker', 'hue_gradient.png')
  30. },
  31. signal: 'high',
  32. meta: {},
  33. templates: {
  34. detail: Spice.color_picker.content,
  35. // item: Spice.color_picker.content,
  36. // item_detail: false,
  37. wrap_detail: 'base_detail'
  38. },
  39. onShow: function() {
  40. //The DOM cache was not initialized when it was created. The DOM should be ready
  41. // here, so we can initialize now.
  42. if (!local_dom.initialized)
  43. initialize_local_dom();
  44. update_all();
  45. }
  46. });
  47. /* UTILITY FUNCTIONS */
  48. //Converts a given string value to an integer, which is forced between the given bounds. If
  49. // the input string is not a valid number, it is treated as 0.
  50. function to_bounded_integer(value, lower_bound, upper_bound) {
  51. var num = Math.round(Number(value));
  52. if (isNaN(num))
  53. num = 0;
  54. if (num < lower_bound)
  55. num = Math.ceil(lower_bound);
  56. if (num > upper_bound)
  57. num = Math.floor(upper_bound);
  58. return num;
  59. }
  60. //Converts a given string value to a number, which is forced between the given bounds. If
  61. // the input string is not a valid number, it is treated as 0.
  62. function to_bounded_number(value, lower_bound, upper_bound) {
  63. var num = Number(value);
  64. if (isNaN(num))
  65. num = 0;
  66. if (num < lower_bound)
  67. num = lower_bound;
  68. if (num > upper_bound)
  69. num = upper_bound;
  70. return num;
  71. }
  72. //Finds the coordinates of a mouse or touch event relative to an element.
  73. function get_real_coordinates(event, $element) {
  74. var offset = $element.offset(),
  75. coordinates = {
  76. x: event.pageX - offset.left,
  77. y: event.pageY - offset.top
  78. };
  79. return coordinates;
  80. }
  81. //Creates a single handler that can be user for both mouse and touch events.
  82. function mouse_and_touch_handler(callback) {
  83. return function(e) {
  84. if (!mouse_and_touch_locked) {
  85. //Certain actions will result in both a mouse and touch event being fired.
  86. // In these cases, the combination of the lock and timeout below will keep
  87. // both events from being processed.
  88. mouse_and_touch_locked = true;
  89. setTimeout(function() {mouse_and_touch_locked = false;}, 0);
  90. if (e.changedTouches && e.changedTouches.length > 0) {
  91. callback(e.changedTouches[0]);
  92. } else if (e.targetTouches && e.targetTouches.length > 0) {
  93. callback(e.targetTouches[0]);
  94. } else {
  95. callback(e);
  96. }
  97. }
  98. };
  99. }
  100. /* EVENT HANDLERS */
  101. function saturation_value_clicked(event) {
  102. var coordinates = get_real_coordinates(event, local_dom.$saturation_value_picker);
  103. //Use the coordinates of the mouse/touch event to calculate the new saturation/value
  104. var saturation = Math.floor((coordinates.x / 256) * 100),
  105. value = Math.floor(((256 - coordinates.y) / 256) * 100),
  106. hue = current_color.hsv.hue;
  107. saturation = to_bounded_integer(saturation, 0, 100);
  108. value = to_bounded_integer(value, 0, 100);
  109. update_all_from_hsv(hue, saturation, value);
  110. }
  111. function hue_clicked(event) {
  112. var coordinates = get_real_coordinates(event, local_dom.$hue_picker);
  113. //Use the coordinates of the mouse/touch event to calculate the new hue
  114. var hue = Math.floor((coordinates.y / 256) * 360),
  115. saturation = current_color.hsv.saturation,
  116. value = current_color.hsv.value;
  117. hue = to_bounded_integer(hue, 0, 359);
  118. update_all_from_hsv(hue, saturation, value);
  119. }
  120. function rgb_change() {
  121. var red = local_dom.$red_input.val(),
  122. green = local_dom.$green_input.val(),
  123. blue = local_dom.$blue_input.val();
  124. red = to_bounded_integer(red, 0, 255);
  125. green = to_bounded_integer(green, 0, 255);
  126. blue = to_bounded_integer(blue, 0, 255);
  127. update_all_from_rgb(red, green, blue);
  128. }
  129. function hsv_change() {
  130. var hue = local_dom.$hue_input.val(),
  131. saturation = local_dom.$saturation_input.val(),
  132. value = local_dom.$value_input.val();
  133. hue = to_bounded_integer(hue, 0, 359);
  134. saturation = to_bounded_integer(saturation, 0, 100);
  135. value = to_bounded_integer(value, 0, 100);
  136. update_all_from_hsv(hue, saturation, value);
  137. }
  138. function cmyk_change() {
  139. var cyan = local_dom.$cyan_input.val(),
  140. magenta = local_dom.$magenta_input.val(),
  141. yellow = local_dom.$yellow_input.val(),
  142. black = local_dom.$black_input.val();
  143. cyan = to_bounded_number(cyan, 0, 100);
  144. magenta = to_bounded_number(magenta, 0, 100);
  145. yellow = to_bounded_number(yellow, 0, 100);
  146. black = to_bounded_number(black, 0, 100);
  147. update_all_from_cmyk(cyan, magenta, yellow, black);
  148. }
  149. function hex_change() {
  150. var hex = local_dom.$hex_input.val();
  151. //There are a few ways a new hex string could look and still be valid. It may more may
  152. // not start with a '#' character, and it may contain some combination of uppercase and
  153. // lowercase letters. It can also contain either three or six hex numerals. Any other
  154. // number and the string is either too long, or ambiguous (e.g. #abc -> #0a0b0c, but
  155. // #abcd -> #0a0bcd or #a0bcd and so on).
  156. if (hex.charAt(0) === '#') hex = hex.substring(1);
  157. if (/^[0-9a-f]+$/i.test(hex)) {
  158. if (hex.length === 3)
  159. hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
  160. if (hex.length === 6)
  161. update_all_from_hex(hex);
  162. else
  163. update_all_from_hex(current_color.hex.substring(1));
  164. } else
  165. update_all_from_hex(current_color.hex.substring(1));
  166. }
  167. function palette_change() {
  168. palette_type = local_dom.$palette_select.val();
  169. update_palette();
  170. }
  171. //Calculates the correct positions for the draggable markers in the hue and saturation/value
  172. // pickers, relative to the picker.
  173. function get_marker_positions(hsv) {
  174. var markers = {
  175. hue: {
  176. y: Math.round((hsv.hue / 360) * 256) - 3
  177. },
  178. saturation_value: {
  179. x: Math.round((hsv.saturation / 100) * 256) - 3,
  180. y: 256 - Math.round((hsv.value / 100) * 256) - 3
  181. }
  182. };
  183. return markers;
  184. }
  185. function update_all_from_hsv(hue, saturation, value) {
  186. current_color = get_all_colors_from_hsv(hue, saturation, value);
  187. markers = get_marker_positions(current_color.hsv);
  188. update_all();
  189. }
  190. function update_all_from_rgb(red, green, blue) {
  191. current_color = get_all_colors_from_rgb(red, green, blue);
  192. markers = get_marker_positions(current_color.hsv);
  193. update_all();
  194. }
  195. function update_all_from_cmyk(cyan, magenta, yellow, black) {
  196. current_color = get_all_colors_from_cmyk(cyan, magenta, yellow, black);
  197. markers = get_marker_positions(current_color.hsv);
  198. update_all();
  199. }
  200. function update_all_from_hex(hex) {
  201. var rgb = convert_hex_to_rgb(hex);
  202. current_color = get_all_colors_from_rgb(rgb.red, rgb.green, rgb.blue);
  203. markers = get_marker_positions(current_color.hsv);
  204. update_all();
  205. }
  206. function get_all_colors_from_hsv(hue, saturation, value) {
  207. var hsv = {
  208. hue: hue,
  209. saturation: saturation,
  210. value: value
  211. },
  212. rgb = convert_hsv_to_rgb(hue, saturation, value),
  213. cmyk = convert_rgb_to_cmyk(rgb.red, rgb.green, rgb.blue),
  214. hex = convert_rgb_to_hex(rgb.red, rgb.green, rgb.blue),
  215. hex_hue = convert_hsv_to_hex(hue, 100, 100),
  216. palette = generate_palette(hsv, palette_type),
  217. colors = {
  218. rgb: rgb,
  219. hsv: hsv,
  220. cmyk: cmyk,
  221. hex: hex,
  222. hex_hue: hex_hue,
  223. palette: palette
  224. };
  225. return colors;
  226. }
  227. function get_all_colors_from_rgb(red, green, blue) {
  228. var rgb = {
  229. red: red,
  230. green: green,
  231. blue: blue
  232. },
  233. hsv = convert_rgb_to_hsv(red, green, blue),
  234. cmyk = convert_rgb_to_cmyk(red, green, blue),
  235. hex = convert_rgb_to_hex(red, green, blue),
  236. hex_hue = convert_hsv_to_hex(hsv.hue, 100, 100),
  237. palette = generate_palette(hsv, palette_type),
  238. colors = {
  239. rgb: rgb,
  240. hsv: hsv,
  241. cmyk: cmyk,
  242. hex: hex,
  243. hex_hue: hex_hue,
  244. palette: palette
  245. };
  246. return colors;
  247. }
  248. function get_all_colors_from_cmyk(cyan, magenta, yellow, black) {
  249. var cmyk = {
  250. cyan: cyan,
  251. magenta: magenta,
  252. yellow: yellow,
  253. black: black
  254. },
  255. rgb = convert_cmyk_to_rgb(cyan, magenta, yellow, black),
  256. hsv = convert_rgb_to_hsv(rgb.red, rgb.green, rgb.blue),
  257. hex = convert_rgb_to_hex(rgb.red, rgb.green, rgb.blue),
  258. hex_hue = convert_hsv_to_hex(hsv.hue, 100, 100),
  259. palette = generate_palette(hsv, palette_type),
  260. colors = {
  261. rgb: rgb,
  262. hsv: hsv,
  263. cmyk: cmyk,
  264. hex: hex,
  265. hex_hue: hex_hue,
  266. palette: palette
  267. };
  268. return colors;
  269. }
  270. function generate_palette(hsv, type) {
  271. var hue = [],
  272. saturation = [],
  273. value = [],
  274. palette = [];
  275. switch (type) {
  276. case 'triad':
  277. hue = [hsv.hue, (hsv.hue + 120) % 360, (hsv.hue + 240) % 360];
  278. saturation = [hsv.saturation, hsv.saturation, hsv.saturation];
  279. value = [hsv.value, hsv.value, hsv.value];
  280. break;
  281. case 'tetrad':
  282. hue = [(hsv.hue + 60) % 360, (hsv.hue + 180) % 360, (hsv.hue + 240) % 360];
  283. saturation = [hsv.saturation, hsv.saturation, hsv.saturation];
  284. value = [hsv.value, hsv.value, hsv.value];
  285. break;
  286. case 'analogous': //fall through
  287. default:
  288. hue = [hsv.hue, (hsv.hue + 30) % 360, (hsv.hue + 330) % 360];
  289. saturation = [hsv.saturation, hsv.saturation, hsv.saturation];
  290. value = [hsv.value, hsv.value, hsv.value];
  291. break;
  292. }
  293. for (var i = 0; i < hue.length; i++)
  294. palette.push(convert_hsv_to_hex(hue[i], saturation[i], value[i]));
  295. return palette;
  296. }
  297. function update_palette() {
  298. current_color.palette = generate_palette(current_color.hsv, palette_type);
  299. update_all();
  300. }
  301. function update_all() {
  302. local_dom.$red_input.val(current_color.rgb.red);
  303. local_dom.$green_input.val(current_color.rgb.green);
  304. local_dom.$blue_input.val(current_color.rgb.blue);
  305. local_dom.$hue_input.val(current_color.hsv.hue);
  306. local_dom.$saturation_input.val(current_color.hsv.saturation);
  307. local_dom.$value_input.val(current_color.hsv.value);
  308. local_dom.$cyan_input.val(current_color.cmyk.cyan);
  309. local_dom.$magenta_input.val(current_color.cmyk.magenta);
  310. local_dom.$yellow_input.val(current_color.cmyk.yellow);
  311. local_dom.$black_input.val(current_color.cmyk.black);
  312. local_dom.$hex_input.val(current_color.hex.substring(1));
  313. local_dom.$saturation_value_picker.css('background-color', current_color.hex_hue);
  314. local_dom.$sample.css('background-color', current_color.hex);
  315. // local_dom.$sample.text(current_color.hex);
  316. // if (current_color.hsv.value < 70) {
  317. // local_dom.$sample.addClass('dark');
  318. // local_dom.$sample.removeClass('light');
  319. // } else {
  320. // local_dom.$sample.addClass('light');
  321. // local_dom.$sample.removeClass('dark');
  322. // }
  323. local_dom.$saturation_value_marker.css('top', markers.saturation_value.y);
  324. local_dom.$saturation_value_marker.css('left', markers.saturation_value.x);
  325. local_dom.$hue_marker.css('top', markers.hue.y);
  326. //Change the color of the text in the samples to make sure it is legible.
  327. local_dom.$palette_sample.each(function(i) {
  328. $(this).css('background-color', current_color.palette[i]);
  329. // $(this).text(current_color.palette[i]);
  330. // if (current_color.hsv.value < 70) {
  331. // $(this).addClass('dark');
  332. // $(this).removeClass('light');
  333. // } else {
  334. // $(this).addClass('light');
  335. // $(this).removeClass('dark');
  336. // }
  337. });
  338. local_dom.$palette_input.each(function(i) {
  339. $(this).text(current_color.palette[i].substring(1));
  340. });
  341. }
  342. /* CONVERSIONS */
  343. function convert_hsv_to_rgb(hue, saturation, value) {
  344. var c = (value / 100) * (saturation / 100),
  345. x = c * (1 - Math.abs(((hue / 60) % 2) - 1)),
  346. m = (value / 100) - c,
  347. red = 0,
  348. green = 0,
  349. blue = 0;
  350. switch (true) {
  351. case 0 <= hue && hue < 60:
  352. red = c; green = x; blue = 0;
  353. break;
  354. case 60 <= hue && hue < 120:
  355. red = x; green = c; blue = 0;
  356. break;
  357. case 120 <= hue && hue < 180:
  358. red = 0; green = c; blue = x;
  359. break;
  360. case 180 <= hue && hue < 240:
  361. red = 0; green = x; blue = c;
  362. break;
  363. case 240 <= hue && hue < 300:
  364. red = x; green = 0; blue = c;
  365. break;
  366. case 300 <= hue && hue < 360:
  367. red = c; green = 0; blue = x;
  368. break;
  369. }
  370. red = Math.floor(255 * (red + m));
  371. green = Math.floor(255 * (green + m));
  372. blue = Math.floor(255 * (blue + m));
  373. var rgb = {
  374. red: red,
  375. green: green,
  376. blue: blue
  377. };
  378. return rgb;
  379. }
  380. function convert_rgb_to_hsv(red, green, blue){
  381. var red_proportion = red / 255,
  382. green_proportion = green / 255,
  383. blue_proportion = blue / 255,
  384. min = Math.min(red_proportion, Math.min(green_proportion, blue_proportion)),
  385. max = Math.max(red_proportion, Math.max(green_proportion, blue_proportion)),
  386. delta = max - min,
  387. hue = 0,
  388. saturation = (max > 0) ? Math.round(((max - min) * 100) / max) : 0,
  389. value = Math.round(max * 100);
  390. if (delta > 0) {
  391. switch (max) {
  392. case red_proportion:
  393. hue = Math.round(60 * (((green_proportion - blue_proportion) / delta)));
  394. break;
  395. case green_proportion:
  396. hue = Math.round(60 * (((blue_proportion - red_proportion) / delta) + 2));
  397. break;
  398. case blue_proportion:
  399. hue = Math.round(60 * (((red_proportion - green_proportion) / delta) + 4));
  400. break;
  401. }
  402. }
  403. if (hue < 0) hue += 360;
  404. var hsv = {
  405. hue: hue,
  406. saturation: saturation,
  407. value: value
  408. };
  409. return hsv;
  410. }
  411. function convert_rgb_to_cmyk(red, green, blue){
  412. var red_proportion = red / 255,
  413. green_proportion = green / 255,
  414. blue_proportion = blue / 255,
  415. black = 1 - Math.max(red_proportion, Math.max(green_proportion, blue_proportion)),
  416. cyan = (black < 1) ? ((1 - red_proportion - black) / (1 - black)) : 0,
  417. magenta = (black < 1) ? ((1 - green_proportion - black) / (1 - black)) : 0,
  418. yellow = (black < 1) ? ((1 - blue_proportion - black) / (1 - black)) : 0,
  419. cmyk= {
  420. black: (100 * black).toFixed(0),
  421. cyan: (100 * cyan).toFixed(0),
  422. magenta: (100 * magenta).toFixed(0),
  423. yellow: (100 * yellow).toFixed(0)
  424. };
  425. return cmyk;
  426. }
  427. function convert_rgb_to_hex(red, green, blue){
  428. var red_string = red.toString(16),
  429. green_string = green.toString(16),
  430. blue_string = blue.toString(16);
  431. if (red_string.length < 2)
  432. red_string = '0' + red_string;
  433. if (green_string.length < 2)
  434. green_string = '0' + green_string;
  435. if (blue_string.length < 2)
  436. blue_string = '0' + blue_string;
  437. return '#' + red_string + green_string + blue_string;
  438. }
  439. function convert_hsv_to_hex(hue, saturation, value) {
  440. var rgb = convert_hsv_to_rgb(hue, saturation, value),
  441. hex = convert_rgb_to_hex(rgb.red, rgb.green, rgb.blue);
  442. return hex;
  443. }
  444. function convert_hex_to_rgb(hex) {
  445. var red = parseInt(hex.substring(0,2), 16),
  446. green = parseInt(hex.substring(2,4), 16),
  447. blue = parseInt(hex.substring(4,6), 16),
  448. rgb = {
  449. red: red,
  450. green: green,
  451. blue: blue
  452. };
  453. return rgb;
  454. }
  455. function convert_cmyk_to_rgb(cyan, magenta, yellow, black) {
  456. var c = cyan / 100,
  457. m = magenta / 100,
  458. y = yellow / 100,
  459. k = black / 100,
  460. red = Math.round(255 * (1 - c) * (1 - k)),
  461. green = Math.round(255 * (1 - m) * (1 - k)),
  462. blue = Math.round(255 * (1 - y) * (1 - k)),
  463. rgb = {
  464. red: red,
  465. green: green,
  466. blue: blue
  467. };
  468. return rgb;
  469. }
  470. //Generates a a color to use when the IA is first loaded. It first checks the query to find
  471. // a specified color. If no color was specified, one is randomly generated.
  472. function get_initial_color(query) {
  473. var query_color = parse_color_from_query(query);
  474. if (query_color !== null)
  475. return query_color;
  476. var hue = Math.floor(Math.random() * 360),
  477. saturation = Math.floor(Math.random() * 100),
  478. value = Math.floor(Math.random() * 100),
  479. colors = get_all_colors_from_hsv(hue, saturation, value);
  480. return colors;
  481. }
  482. //Searches the query for a color. Returns null if no color was specified in the query.
  483. function parse_color_from_query(query) {
  484. //This will take the query string, remove the first two words (e.g. 'color picker'), and
  485. // format it for later processing. The result will have all spaces, and parentheses
  486. // replaced with commas such that there will only be one comma between any text.
  487. // For example, HSV(1, 2, 3) becomes hsv,1,2,3
  488. var possible_color_query = query.split(/[\s,()]+/).slice(2)
  489. possible_color_query = $.map(possible_color_query, function(el) { if (el.length > 0) return el; }).join(',').toLowerCase();
  490. if (possible_color_query.length === 0)
  491. return null;
  492. switch (true) {
  493. case possible_color_query.lastIndexOf('rgb', 0) === 0:
  494. var rgb_nums = possible_color_query.split(',').slice(1);
  495. if (rgb_nums.length < 3)
  496. return null;
  497. var red = to_bounded_integer(rgb_nums[0], 0, 255),
  498. green = to_bounded_integer(rgb_nums[1], 0, 255),
  499. blue = to_bounded_integer(rgb_nums[2], 0, 255),
  500. colors = get_all_colors_from_rgb(red, green, blue);
  501. return colors;
  502. case possible_color_query.lastIndexOf('hsv', 0) === 0:
  503. var hsv_nums = possible_color_query.replace(/%/g, '').split(',').slice(1);
  504. if (hsv_nums.length < 3)
  505. return null;
  506. var hue = to_bounded_integer(hsv_nums[0], 0, 360),
  507. saturation = to_bounded_integer(hsv_nums[1], 0, 100),
  508. value = to_bounded_integer(hsv_nums[2], 0, 100),
  509. colors = get_all_colors_from_hsv(hue, saturation, value);
  510. return colors;
  511. case possible_color_query.lastIndexOf('cmyk', 0) === 0:
  512. var cmyk_nums = possible_color_query.split(',').slice(1);
  513. if (cmyk_nums.length < 4)
  514. return null;
  515. var cyan = to_bounded_number(cmyk_nums[0], 0, 100),
  516. magenta = to_bounded_number(cmyk_nums[1], 0, 100),
  517. yellow = to_bounded_number(cmyk_nums[2], 0, 100),
  518. black = to_bounded_number(cmyk_nums[3], 0, 100),
  519. colors = get_all_colors_from_cmyk(cyan, magenta, yellow, black);
  520. return colors;
  521. default:
  522. var hex = possible_color_query;
  523. if (hex.lastIndexOf('#', 0) === 0){
  524. hex = hex.substring(1);
  525. }
  526. if (/^[0-9a-f]+$/i.test(hex)) {
  527. if (hex.length === 3)
  528. hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
  529. if (hex.length === 6) {
  530. var rgb = convert_hex_to_rgb(hex),
  531. colors = get_all_colors_from_rgb(rgb.red, rgb.green, rgb.blue);
  532. return colors;
  533. }
  534. }
  535. }
  536. return null;
  537. }
  538. function initialize_local_dom() {
  539. //The container of this instant answer will be the root for all other elements.
  540. var $root = $('#color_picker_container');
  541. //Find all of the elements of interest within the instant answer.
  542. local_dom = {
  543. $saturation_value_picker: $root.find('#saturation_value_picker'),
  544. $hue_picker: $root.find('#hue_picker'),
  545. $red_input: $root.find('#red_input'),
  546. $green_input: $root.find('#green_input'),
  547. $blue_input: $root.find('#blue_input'),
  548. $hue_input: $root.find('#hue_input'),
  549. $saturation_input: $root.find('#saturation_input'),
  550. $value_input: $root.find('#value_input'),
  551. $cyan_input: $root.find('#cyan_input'),
  552. $magenta_input: $root.find('#magenta_input'),
  553. $yellow_input: $root.find('#yellow_input'),
  554. $black_input: $root.find('#black_input'),
  555. $hex_input: $root.find('#hex_input'),
  556. $palette_select: $root.find('#palette_select'),
  557. $sample: $root.find('#sample'),
  558. $saturation_value_marker: $root.find('#saturation_value_marker'),
  559. $hue_marker: $root.find('#hue_marker'),
  560. $palette_sample: $root.find('.palette_sample'),
  561. $palette_input: $root.find('.palette_input'),
  562. initialized: true
  563. };
  564. //Event Handling
  565. //For the hue and saturation/value pickers, there are a few things we need to do. First,
  566. // we need to listen for click events so that a user can click anywhere in the picker
  567. // to immediate jump to that color. We also need to allow the user to drag the mouse
  568. // around in the pickers, so we need to keep the browser from using the default drag
  569. // action on images. Then we respond to mousemove events if the mouse was already down
  570. // on the picker the same way we respond to a click.
  571. local_dom.$saturation_value_picker.click(mouse_and_touch_handler(saturation_value_clicked));
  572. local_dom.$saturation_value_picker.on('dragstart', function(event) {event.preventDefault();});
  573. local_dom.$saturation_value_picker.mousedown(mouse_and_touch_handler(function() { saturation_value_mousedown = true; }));
  574. local_dom.$saturation_value_picker.mousemove(mouse_and_touch_handler(function(event) { if (saturation_value_mousedown) saturation_value_clicked(event); }));
  575. local_dom.$hue_picker.click(mouse_and_touch_handler(hue_clicked));
  576. local_dom.$hue_picker.on('dragstart', function(event) {event.preventDefault();});
  577. local_dom.$hue_picker.mousedown(mouse_and_touch_handler(function() { hue_mousedown = true; }));
  578. local_dom.$hue_picker.mousemove(mouse_and_touch_handler(function(event) { if (hue_mousedown) hue_clicked(event); }));
  579. $(document).mouseup(function() { saturation_value_mousedown = false; hue_mousedown = false; });
  580. $root.focusout(function() { saturation_value_mousedown = false; hue_mousedown = false; });
  581. //Also need to listen for touch events for touch-enabled devices.
  582. local_dom.$saturation_value_picker[0].addEventListener('touchstart', mouse_and_touch_handler(saturation_value_clicked), false);
  583. local_dom.$saturation_value_picker.on('touchmove', function(event) {event.preventDefault();});
  584. local_dom.$saturation_value_picker[0].addEventListener('touchmove', mouse_and_touch_handler(saturation_value_clicked), false);
  585. local_dom.$hue_picker[0].addEventListener('touchstart', mouse_and_touch_handler(hue_clicked), false);
  586. local_dom.$hue_picker.on('touchmove', function(event) {event.preventDefault();});
  587. local_dom.$hue_picker[0].addEventListener('touchmove', mouse_and_touch_handler(hue_clicked), false);
  588. //Listen for changes to any of the text inputs
  589. local_dom.$red_input.change(rgb_change);
  590. local_dom.$green_input.change(rgb_change);
  591. local_dom.$blue_input.change(rgb_change);
  592. local_dom.$hue_input.change(hsv_change);
  593. local_dom.$saturation_input.change(hsv_change);
  594. local_dom.$value_input.change(hsv_change);
  595. local_dom.$cyan_input.change(cmyk_change);
  596. local_dom.$magenta_input.change(cmyk_change);
  597. local_dom.$yellow_input.change(cmyk_change);
  598. local_dom.$black_input.change(cmyk_change);
  599. local_dom.$hex_input.change(hex_change);
  600. //Listen to changes to the selected palette type
  601. local_dom.$palette_select.change(palette_change);
  602. }
  603. };
  604. }(this));
  605. ddg_spice_color_picker();