You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
8.2 KiB

  1. /*!
  2. * # Semantic UI 2.0.0 - Colorize
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2015 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.colorize = function(parameters) {
  14. var
  15. settings = ( $.isPlainObject(parameters) )
  16. ? $.extend(true, {}, $.fn.colorize.settings, parameters)
  17. : $.extend({}, $.fn.colorize.settings),
  18. // hoist arguments
  19. moduleArguments = arguments || false
  20. ;
  21. $(this)
  22. .each(function(instanceIndex) {
  23. var
  24. $module = $(this),
  25. mainCanvas = $('<canvas />')[0],
  26. imageCanvas = $('<canvas />')[0],
  27. overlayCanvas = $('<canvas />')[0],
  28. backgroundImage = new Image(),
  29. // defs
  30. mainContext,
  31. imageContext,
  32. overlayContext,
  33. image,
  34. imageName,
  35. width,
  36. height,
  37. // shortucts
  38. colors = settings.colors,
  39. paths = settings.paths,
  40. namespace = settings.namespace,
  41. error = settings.error,
  42. // boilerplate
  43. instance = $module.data('module-' + namespace),
  44. module
  45. ;
  46. module = {
  47. checkPreconditions: function() {
  48. module.debug('Checking pre-conditions');
  49. if( !$.isPlainObject(colors) || $.isEmptyObject(colors) ) {
  50. module.error(error.undefinedColors);
  51. return false;
  52. }
  53. return true;
  54. },
  55. async: function(callback) {
  56. if(settings.async) {
  57. setTimeout(callback, 0);
  58. }
  59. else {
  60. callback();
  61. }
  62. },
  63. getMetadata: function() {
  64. module.debug('Grabbing metadata');
  65. image = $module.data('image') || settings.image || undefined;
  66. imageName = $module.data('name') || settings.name || instanceIndex;
  67. width = settings.width || $module.width();
  68. height = settings.height || $module.height();
  69. if(width === 0 || height === 0) {
  70. module.error(error.undefinedSize);
  71. }
  72. },
  73. initialize: function() {
  74. module.debug('Initializing with colors', colors);
  75. if( module.checkPreconditions() ) {
  76. module.async(function() {
  77. module.getMetadata();
  78. module.canvas.create();
  79. module.draw.image(function() {
  80. module.draw.colors();
  81. module.canvas.merge();
  82. });
  83. $module
  84. .data('module-' + namespace, module)
  85. ;
  86. });
  87. }
  88. },
  89. redraw: function() {
  90. module.debug('Redrawing image');
  91. module.async(function() {
  92. module.canvas.clear();
  93. module.draw.colors();
  94. module.canvas.merge();
  95. });
  96. },
  97. change: {
  98. color: function(colorName, color) {
  99. module.debug('Changing color', colorName);
  100. if(colors[colorName] === undefined) {
  101. module.error(error.missingColor);
  102. return false;
  103. }
  104. colors[colorName] = color;
  105. module.redraw();
  106. }
  107. },
  108. canvas: {
  109. create: function() {
  110. module.debug('Creating canvases');
  111. mainCanvas.width = width;
  112. mainCanvas.height = height;
  113. imageCanvas.width = width;
  114. imageCanvas.height = height;
  115. overlayCanvas.width = width;
  116. overlayCanvas.height = height;
  117. mainContext = mainCanvas.getContext('2d');
  118. imageContext = imageCanvas.getContext('2d');
  119. overlayContext = overlayCanvas.getContext('2d');
  120. $module
  121. .append( mainCanvas )
  122. ;
  123. mainContext = $module.children('canvas')[0].getContext('2d');
  124. },
  125. clear: function(context) {
  126. module.debug('Clearing canvas');
  127. overlayContext.fillStyle = '#FFFFFF';
  128. overlayContext.fillRect(0, 0, width, height);
  129. },
  130. merge: function() {
  131. if( !$.isFunction(mainContext.blendOnto) ) {
  132. module.error(error.missingPlugin);
  133. return;
  134. }
  135. mainContext.putImageData( imageContext.getImageData(0, 0, width, height), 0, 0);
  136. overlayContext.blendOnto(mainContext, 'multiply');
  137. }
  138. },
  139. draw: {
  140. image: function(callback) {
  141. module.debug('Drawing image');
  142. callback = callback || function(){};
  143. if(image) {
  144. backgroundImage.src = image;
  145. backgroundImage.onload = function() {
  146. imageContext.drawImage(backgroundImage, 0, 0);
  147. callback();
  148. };
  149. }
  150. else {
  151. module.error(error.noImage);
  152. callback();
  153. }
  154. },
  155. colors: function() {
  156. module.debug('Drawing color overlays', colors);
  157. $.each(colors, function(colorName, color) {
  158. settings.onDraw(overlayContext, imageName, colorName, color);
  159. });
  160. }
  161. },
  162. debug: function(message, variableName) {
  163. if(settings.debug) {
  164. if(variableName !== undefined) {
  165. console.info(settings.name + ': ' + message, variableName);
  166. }
  167. else {
  168. console.info(settings.name + ': ' + message);
  169. }
  170. }
  171. },
  172. error: function(errorMessage) {
  173. console.warn(settings.name + ': ' + errorMessage);
  174. },
  175. invoke: function(methodName, context, methodArguments) {
  176. var
  177. method
  178. ;
  179. methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 );
  180. if(typeof methodName == 'string' && instance !== undefined) {
  181. methodName = methodName.split('.');
  182. $.each(methodName, function(index, name) {
  183. if( $.isPlainObject( instance[name] ) ) {
  184. instance = instance[name];
  185. return true;
  186. }
  187. else if( $.isFunction( instance[name] ) ) {
  188. method = instance[name];
  189. return true;
  190. }
  191. module.error(settings.error.method);
  192. return false;
  193. });
  194. }
  195. return ( $.isFunction( method ) )
  196. ? method.apply(context, methodArguments)
  197. : false
  198. ;
  199. }
  200. };
  201. if(instance !== undefined && moduleArguments) {
  202. // simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
  203. if(moduleArguments[0] == 'invoke') {
  204. moduleArguments = Array.prototype.slice.call( moduleArguments, 1 );
  205. }
  206. return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) );
  207. }
  208. // initializing
  209. module.initialize();
  210. })
  211. ;
  212. return this;
  213. };
  214. $.fn.colorize.settings = {
  215. name : 'Image Colorizer',
  216. debug : true,
  217. namespace : 'colorize',
  218. onDraw : function(overlayContext, imageName, colorName, color) {},
  219. // whether to block execution while updating canvas
  220. async : true,
  221. // object containing names and default values of color regions
  222. colors : {},
  223. metadata: {
  224. image : 'image',
  225. name : 'name'
  226. },
  227. error: {
  228. noImage : 'No tracing image specified',
  229. undefinedColors : 'No default colors specified.',
  230. missingColor : 'Attempted to change color that does not exist',
  231. missingPlugin : 'Blend onto plug-in must be included',
  232. undefinedHeight : 'The width or height of image canvas could not be automatically determined. Please specify a height.'
  233. }
  234. };
  235. })( jQuery, window , document );