ext-shapes.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*globals svgEditor, $, DOMParser*/
  2. /*jslint es5: true, vars: true, eqeq: true*/
  3. /*
  4. * ext-shapes.js
  5. *
  6. * Licensed under the MIT License
  7. *
  8. * Copyright(c) 2010 Christian Tzurcanu
  9. * Copyright(c) 2010 Alexis Deveria
  10. *
  11. */
  12. svgEditor.addExtension('shapes', function() {'use strict';
  13. var current_d, cur_shape_id;
  14. var canv = svgEditor.canvas;
  15. var cur_shape;
  16. var start_x, start_y;
  17. var svgroot = canv.getRootElem();
  18. var lastBBox = {};
  19. // This populates the category list
  20. var categories = {
  21. basic: 'Basic',
  22. object: 'Objects',
  23. symbol: 'Symbols',
  24. arrow: 'Arrows',
  25. flowchart: 'Flowchart',
  26. animal: 'Animals',
  27. game: 'Cards & Chess',
  28. dialog_balloon: 'Dialog balloons',
  29. electronics: 'Electronics',
  30. math: 'Mathematical',
  31. music: 'Music',
  32. misc: 'Miscellaneous',
  33. raphael_1: 'raphaeljs.com set 1',
  34. raphael_2: 'raphaeljs.com set 2'
  35. };
  36. var library = {
  37. basic: {
  38. data: {
  39. 'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
  40. 'frame': 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
  41. 'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
  42. 'triangle': 'm1,280.375l149,-260.75l149,260.75z',
  43. 'right_triangle': 'm1,299l0,-298l298,298z',
  44. 'diamond': 'm1,150l149,-149l149,149l-149,149l-149,-149z',
  45. 'pentagon': 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z',
  46. 'hexagon': 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z',
  47. 'septagon1': 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z',
  48. 'heptagon': 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z',
  49. 'decagon': 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z',
  50. 'dodecagon': 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z',
  51. 'star_points_5': 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z',
  52. 'trapezoid': 'm1,299l55.875,-298l186.25001,0l55.87498,298z',
  53. 'arrow_up': 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z',
  54. 'vertical_scrool': 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875',
  55. 'smiley': 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z',
  56. 'left_braket': 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066',
  57. 'uml_actor': 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z',
  58. 'dialog_balloon_1': 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z',
  59. 'cloud': 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z',
  60. 'cylinder': 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z',
  61. 'arrow_u_turn': 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z',
  62. 'arrow_left_up': 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z',
  63. 'maximize': 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z',
  64. 'cross': 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z',
  65. 'plaque': 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z',
  66. 'page': 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234'
  67. },
  68. buttons: []
  69. }
  70. };
  71. var cur_lib = library.basic;
  72. var mode_id = 'shapelib';
  73. var startClientPos = {};
  74. function loadIcons() {
  75. $('#shape_buttons').empty().append(cur_lib.buttons);
  76. }
  77. function makeButtons(cat, shapes) {
  78. var size = cur_lib.size || 300;
  79. var fill = cur_lib.fill || false;
  80. var off = size * 0.05;
  81. var vb = [-off, -off, size + off*2, size + off*2].join(' ');
  82. var stroke = fill ? 0: (size/30);
  83. var shape_icon = new DOMParser().parseFromString(
  84. '<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="'+(fill?'#333':'none')+'" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
  85. 'text/xml');
  86. var width = 24;
  87. var height = 24;
  88. shape_icon.documentElement.setAttribute('width', width);
  89. shape_icon.documentElement.setAttribute('height', height);
  90. var svg_elem = $(document.importNode(shape_icon.documentElement,true));
  91. var data = shapes.data;
  92. cur_lib.buttons = [];
  93. var id;
  94. for (id in data) {
  95. var path_d = data[id];
  96. var icon = svg_elem.clone();
  97. icon.find('path').attr('d', path_d);
  98. var icon_btn = icon.wrap('<div class="tool_button">').parent().attr({
  99. id: mode_id + '_' + id,
  100. title: id
  101. });
  102. // Store for later use
  103. cur_lib.buttons.push(icon_btn[0]);
  104. }
  105. }
  106. function loadLibrary(cat_id) {
  107. var lib = library[cat_id];
  108. if (!lib) {
  109. $('#shape_buttons').html('Loading...');
  110. $.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + cat_id + '.json', function(result) {
  111. cur_lib = library[cat_id] = {
  112. data: result.data,
  113. size: result.size,
  114. fill: result.fill
  115. };
  116. makeButtons(cat_id, result);
  117. loadIcons();
  118. });
  119. return;
  120. }
  121. cur_lib = lib;
  122. if (!lib.buttons.length) {makeButtons(cat_id, lib);}
  123. loadIcons();
  124. }
  125. return {
  126. svgicons: svgEditor.curConfig.extPath + 'ext-shapes.xml',
  127. buttons: [{
  128. id: 'tool_shapelib',
  129. type: 'mode_flyout', // _flyout
  130. position: 6,
  131. title: 'Shape library',
  132. events: {
  133. click: function() {
  134. canv.setMode(mode_id);
  135. }
  136. }
  137. }],
  138. callback: function() {
  139. $('<style>').text('\
  140. #shape_buttons {\
  141. overflow: auto;\
  142. width: 180px;\
  143. max-height: 300px;\
  144. display: table-cell;\
  145. vertical-align: middle;\
  146. }\
  147. \
  148. #shape_cats {\
  149. min-width: 110px;\
  150. display: table-cell;\
  151. vertical-align: middle;\
  152. height: 300px;\
  153. }\
  154. #shape_cats > div {\
  155. line-height: 1em;\
  156. padding: .5em;\
  157. border:1px solid #B0B0B0;\
  158. background: #E8E8E8;\
  159. margin-bottom: -1px;\
  160. }\
  161. #shape_cats div:hover {\
  162. background: #FFFFCC;\
  163. }\
  164. #shape_cats div.current {\
  165. font-weight: bold;\
  166. }').appendTo('head');
  167. var btn_div = $('<div id="shape_buttons">');
  168. $('#tools_shapelib > *').wrapAll(btn_div);
  169. var shower = $('#tools_shapelib_show');
  170. loadLibrary('basic');
  171. // Do mouseup on parent element rather than each button
  172. $('#shape_buttons').mouseup(function(evt) {
  173. var btn = $(evt.target).closest('div.tool_button');
  174. if (!btn.length) {return;}
  175. var copy = btn.children().clone();
  176. shower.children(':not(.flyout_arrow_horiz)').remove();
  177. shower
  178. .append(copy)
  179. .attr('data-curopt', '#' + btn[0].id) // This sets the current mode
  180. .mouseup();
  181. canv.setMode(mode_id);
  182. cur_shape_id = btn[0].id.substr((mode_id+'_').length);
  183. current_d = cur_lib.data[cur_shape_id];
  184. $('.tools_flyout').fadeOut();
  185. });
  186. var shape_cats = $('<div id="shape_cats">');
  187. var cat_str = '';
  188. $.each(categories, function(id, label) {
  189. cat_str += '<div data-cat=' + id + '>' + label + '</div>';
  190. });
  191. shape_cats.html(cat_str).children().bind('mouseup', function() {
  192. var catlink = $(this);
  193. catlink.siblings().removeClass('current');
  194. catlink.addClass('current');
  195. loadLibrary(catlink.attr('data-cat'));
  196. // Get stuff
  197. return false;
  198. });
  199. shape_cats.children().eq(0).addClass('current');
  200. $('#tools_shapelib').append(shape_cats);
  201. shower.mouseup(function() {
  202. canv.setMode(current_d ? mode_id : 'select');
  203. });
  204. $('#tool_shapelib').remove();
  205. var h = $('#tools_shapelib').height();
  206. $('#tools_shapelib').css({
  207. 'margin-top': -(h/2 - 15),
  208. 'margin-left': 3
  209. });
  210. },
  211. mouseDown: function(opts) {
  212. var mode = canv.getMode();
  213. if (mode !== mode_id) {return;}
  214. start_x = opts.start_x;
  215. var x = start_x;
  216. start_y = opts.start_y;
  217. var y = start_y;
  218. var cur_style = canv.getStyle();
  219. startClientPos.x = opts.event.clientX;
  220. startClientPos.y = opts.event.clientY;
  221. cur_shape = canv.addSvgElementFromJson({
  222. 'element': 'path',
  223. 'curStyles': true,
  224. 'attr': {
  225. 'd': current_d,
  226. 'id': canv.getNextId(),
  227. 'opacity': cur_style.opacity / 2,
  228. 'style': 'pointer-events:none'
  229. }
  230. });
  231. // Make sure shape uses absolute values
  232. if (/[a-z]/.test(current_d)) {
  233. current_d = cur_lib.data[cur_shape_id] = canv.pathActions.convertPath(cur_shape);
  234. cur_shape.setAttribute('d', current_d);
  235. canv.pathActions.fixEnd(cur_shape);
  236. }
  237. cur_shape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
  238. canv.recalculateDimensions(cur_shape);
  239. var tlist = canv.getTransformList(cur_shape);
  240. lastBBox = cur_shape.getBBox();
  241. return {
  242. started: true
  243. };
  244. },
  245. mouseMove: function(opts) {
  246. var mode = canv.getMode();
  247. if (mode !== mode_id) {return;}
  248. var zoom = canv.getZoom();
  249. var evt = opts.event;
  250. var x = opts.mouse_x/zoom;
  251. var y = opts.mouse_y/zoom;
  252. var tlist = canv.getTransformList(cur_shape),
  253. box = cur_shape.getBBox(),
  254. left = box.x, top = box.y, width = box.width,
  255. height = box.height;
  256. var dx = (x-start_x), dy = (y-start_y);
  257. var newbox = {
  258. 'x': Math.min(start_x,x),
  259. 'y': Math.min(start_y,y),
  260. 'width': Math.abs(x-start_x),
  261. 'height': Math.abs(y-start_y)
  262. };
  263. var tx = 0, ty = 0,
  264. sy = height ? (height+dy)/height : 1,
  265. sx = width ? (width+dx)/width : 1;
  266. sx = (newbox.width / lastBBox.width) || 1;
  267. sy = (newbox.height / lastBBox.height) || 1;
  268. // Not perfect, but mostly works...
  269. if (x < start_x) {
  270. tx = lastBBox.width;
  271. }
  272. if (y < start_y) {ty = lastBBox.height;}
  273. // update the transform list with translate,scale,translate
  274. var translateOrigin = svgroot.createSVGTransform(),
  275. scale = svgroot.createSVGTransform(),
  276. translateBack = svgroot.createSVGTransform();
  277. translateOrigin.setTranslate(-(left+tx), -(top+ty));
  278. if (!evt.shiftKey) {
  279. var max = Math.min(Math.abs(sx), Math.abs(sy));
  280. sx = max * (sx < 0 ? -1 : 1);
  281. sy = max * (sy < 0 ? -1 : 1);
  282. }
  283. scale.setScale(sx,sy);
  284. translateBack.setTranslate(left+tx, top+ty);
  285. tlist.appendItem(translateBack);
  286. tlist.appendItem(scale);
  287. tlist.appendItem(translateOrigin);
  288. canv.recalculateDimensions(cur_shape);
  289. lastBBox = cur_shape.getBBox();
  290. },
  291. mouseUp: function(opts) {
  292. var mode = canv.getMode();
  293. if (mode !== mode_id) {return;}
  294. var keepObject = (opts.event.clientX != startClientPos.x && opts.event.clientY != startClientPos.y);
  295. return {
  296. keep: keepObject,
  297. element: cur_shape,
  298. started: false
  299. };
  300. }
  301. };
  302. });