sigma.renderers.customShapes.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. ;(function(undefined) {
  2. 'use strict';
  3. if (typeof sigma === 'undefined')
  4. throw 'sigma is not declared';
  5. if (typeof ShapeLibrary === 'undefined')
  6. throw 'ShapeLibrary is not declared';
  7. // Initialize package:
  8. sigma.utils.pkg('sigma.canvas.nodes');
  9. sigma.utils.pkg('sigma.svg.nodes');
  10. var sigInst = undefined;
  11. var imgCache = {};
  12. var initPlugin = function(inst) {
  13. sigInst = inst;
  14. }
  15. var drawImage = function (node,x,y,size,context) {
  16. if(sigInst && node.image && node.image.url) {
  17. var url = node.image.url;
  18. var ih = node.image.h || 1; // 1 is arbitrary, anyway only the ratio counts
  19. var iw = node.image.w || 1;
  20. var scale = node.image.scale || 1;
  21. var clip = node.image.clip || 1;
  22. // create new IMG or get from imgCache
  23. var image = imgCache[url];
  24. if(!image) {
  25. image = document.createElement('IMG');
  26. image.src = url;
  27. image.status = 'loading';
  28. image.onerror = function() {
  29. console.log("error loading", url);
  30. image.status = 'error';
  31. };
  32. image.onload = function(){
  33. // TODO see how we redraw on load
  34. // need to provide the siginst as a parameter to the library
  35. console.log("redraw on image load", url);
  36. image.status = 'ok';
  37. sigInst.refresh();
  38. };
  39. imgCache[url] = image;
  40. }
  41. // calculate position and draw
  42. var xratio = (iw<ih) ? (iw/ih) : 1;
  43. var yratio = (ih<iw) ? (ih/iw) : 1;
  44. var r = size*scale;
  45. // Draw the clipping disc:
  46. context.save(); // enter clipping mode
  47. context.beginPath();
  48. context.arc(x,y,size*clip,0,Math.PI*2,true);
  49. context.closePath();
  50. context.clip();
  51. if(image.status === 'ok') {
  52. // Draw the actual image
  53. context.drawImage(image,
  54. x+Math.sin(-3.142/4)*r*xratio,
  55. y-Math.cos(-3.142/4)*r*yratio,
  56. r*xratio*2*Math.sin(-3.142/4)*(-1),
  57. r*yratio*2*Math.cos(-3.142/4));
  58. }
  59. context.restore(); // exit clipping mode
  60. }
  61. }
  62. var drawSVGImage = function (node, group, settings) {
  63. if(sigInst && node.image && node.image.url) {
  64. var clipCircle = document.createElementNS(settings('xmlns'), 'circle'),
  65. clipPath = document.createElementNS(settings('xmlns'), 'clipPath'),
  66. clipPathId = settings('classPrefix') + '-clip-path-' + node.id,
  67. def = document.createElementNS(settings('xmlns'), 'defs'),
  68. image = document.createElementNS(settings('xmlns'), 'image'),
  69. url = node.image.url;
  70. clipPath.setAttributeNS(null, 'id', clipPathId);
  71. clipPath.appendChild(clipCircle);
  72. def.appendChild(clipPath);
  73. // angular's base tag will change the relative fragment id, so
  74. // #<clipPathId> doesn't work
  75. // HACKHACK: IE <=9 does not respect the HTML base element in SVG.
  76. // They don't need the current URL in the clip path reference.
  77. var absolutePath = /MSIE [5-9]/.test(navigator.userAgent) ?
  78. "" : document.location.href;
  79. // To fix cases where an anchor tag was used
  80. absolutePath = absolutePath.split("#")[0];
  81. image.setAttributeNS(null, 'class',
  82. settings('classPrefix') + '-node-image');
  83. image.setAttributeNS(null, 'clip-path',
  84. 'url(' + absolutePath + '#' + clipPathId + ')');
  85. image.setAttributeNS(null, 'pointer-events', 'none');
  86. image.setAttributeNS('http://www.w3.org/1999/xlink', 'href',
  87. node.image.url);
  88. group.appendChild(def);
  89. group.appendChild(image);
  90. }
  91. }
  92. var register = function(name,drawShape,drawBorder) {
  93. sigma.canvas.nodes[name] = function(node, context, settings) {
  94. var args = arguments,
  95. prefix = settings('prefix') || '',
  96. size = node[prefix + 'size'],
  97. color = node.color || settings('defaultNodeColor'),
  98. borderColor = node.borderColor || color,
  99. x = node[prefix + 'x'],
  100. y = node[prefix + 'y'];
  101. context.save();
  102. if(drawShape) {
  103. drawShape(node,x,y,size,color,context);
  104. }
  105. if(drawBorder) {
  106. drawBorder(node,x,y,size,borderColor,context);
  107. }
  108. drawImage(node,x,y,size,context);
  109. context.restore();
  110. };
  111. sigma.svg.nodes[name] = {
  112. create: function(node, settings) {
  113. var group = document.createElementNS(settings('xmlns'), 'g'),
  114. circle = document.createElementNS(settings('xmlns'), 'circle');
  115. group.setAttributeNS(null, 'class',
  116. settings('classPrefix') + '-node-group');
  117. group.setAttributeNS(null, 'data-node-id', node.id);
  118. // Defining the node's circle
  119. circle.setAttributeNS(null, 'data-node-id', node.id);
  120. circle.setAttributeNS(null, 'class',
  121. settings('classPrefix') + '-node');
  122. circle.setAttributeNS(null, 'fill',
  123. node.color || settings('defaultNodeColor'));
  124. group.appendChild(circle);
  125. drawSVGImage(node, group, settings);
  126. return group;
  127. },
  128. update: function(node, group, settings) {
  129. var classPrefix = settings('classPrefix'),
  130. clip = node.image.clip || 1,
  131. // 1 is arbitrary, anyway only the ratio counts
  132. ih = node.image.h || 1,
  133. iw = node.image.w || 1,
  134. prefix = settings('prefix') || '',
  135. scale = node.image.scale || 1,
  136. size = node[prefix + 'size'],
  137. x = node[prefix + 'x'],
  138. y = node[prefix + 'y'];
  139. var r = scale * size,
  140. xratio = (iw<ih) ? (iw/ih) : 1,
  141. yratio = (ih<iw) ? (ih/iw) : 1;
  142. for(var i = 0, childNodes = group.childNodes; i < childNodes.length; i ++) {
  143. var className = childNodes[i].getAttribute('class');
  144. switch (className) {
  145. case classPrefix + '-node':
  146. childNodes[i].setAttributeNS(null, 'cx', x);
  147. childNodes[i].setAttributeNS(null, 'cy', y);
  148. childNodes[i].setAttributeNS(null, 'r', size);
  149. // // Updating only if not freestyle
  150. if (!settings('freeStyle')) {
  151. childNodes[i].setAttributeNS(
  152. null,
  153. 'fill',
  154. node.color || settings('defaultNodeColor'));
  155. }
  156. break;
  157. case classPrefix + '-node-image':
  158. childNodes[i].setAttributeNS(null, 'x',
  159. x+Math.sin(-3.142/4)*r*xratio);
  160. childNodes[i].setAttributeNS(null, 'y',
  161. y-Math.cos(-3.142/4)*r*yratio);
  162. childNodes[i].setAttributeNS(null, 'width',
  163. r*xratio*2*Math.sin(-3.142/4)*(-1));
  164. childNodes[i].setAttributeNS(null, 'height',
  165. r*yratio*2*Math.cos(-3.142/4));
  166. break;
  167. default:
  168. // no class name, must be the clip-path
  169. var clipPath = childNodes[i].firstChild;
  170. if (clipPath != null) {
  171. var clipPathId = classPrefix + '-clip-path-' + node.id;
  172. if (clipPath.getAttribute('id') === clipPathId) {
  173. clipPath.firstChild.setAttributeNS(null, 'cx', x);
  174. clipPath.firstChild.setAttributeNS(null, 'cy', y);
  175. clipPath.firstChild.setAttributeNS(null, 'r',
  176. clip * size);
  177. }
  178. }
  179. break;
  180. }
  181. }
  182. // showing
  183. group.style.display = '';
  184. }
  185. }
  186. }
  187. ShapeLibrary.enumerate().forEach(function(shape) {
  188. register(shape.name,shape.drawShape,shape.drawBorder);
  189. });
  190. /**
  191. * Exporting
  192. * ----------
  193. */
  194. this.CustomShapes = {
  195. // Functions
  196. init: initPlugin,
  197. // add pre-cache images
  198. // Version
  199. version: '0.1'
  200. };
  201. }).call(this);