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.

272 lines
8.1 KiB

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