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.

270 lines
8.1 KiB

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