ext-arrows.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * ext-arrows.js
  3. *
  4. * Licensed under the Apache License, Version 2
  5. *
  6. * Copyright(c) 2010 Alexis Deveria
  7. *
  8. */
  9. svgEditor.addExtension("Arrows", function(S) {
  10. var svgcontent = S.svgcontent,
  11. addElem = S.addSvgElementFromJson,
  12. nonce = S.nonce,
  13. randomize_ids = S.randomize_ids,
  14. selElems;
  15. svgCanvas.bind('setnonce', setArrowNonce);
  16. svgCanvas.bind('unsetnonce', unsetArrowNonce);
  17. var lang_list = {
  18. "en":[
  19. {"id": "arrow_none", "textContent": "No arrow" }
  20. ],
  21. "fr":[
  22. {"id": "arrow_none", "textContent": "Sans flèche" }
  23. ]
  24. };
  25. var prefix = 'se_arrow_';
  26. if (randomize_ids) {
  27. var arrowprefix = prefix + nonce + '_';
  28. } else {
  29. var arrowprefix = prefix;
  30. }
  31. var pathdata = {
  32. fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'},
  33. bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'}
  34. }
  35. function setArrowNonce(window, n) {
  36. randomize_ids = true;
  37. arrowprefix = prefix + n + '_';
  38. pathdata.fw.id = arrowprefix + 'fw';
  39. pathdata.bk.id = arrowprefix + 'bk';
  40. }
  41. function unsetArrowNonce(window) {
  42. randomize_ids = false;
  43. arrowprefix = prefix;
  44. pathdata.fw.id = arrowprefix + 'fw';
  45. pathdata.bk.id = arrowprefix + 'bk';
  46. }
  47. function getLinked(elem, attr) {
  48. var str = elem.getAttribute(attr);
  49. if(!str) return null;
  50. var m = str.match(/\(\#(.*)\)/);
  51. if(!m || m.length !== 2) {
  52. return null;
  53. }
  54. return S.getElem(m[1]);
  55. }
  56. function showPanel(on) {
  57. $('#arrow_panel').toggle(on);
  58. if(on) {
  59. var el = selElems[0];
  60. var end = el.getAttribute("marker-end");
  61. var start = el.getAttribute("marker-start");
  62. var mid = el.getAttribute("marker-mid");
  63. var val;
  64. if(end && start) {
  65. val = "both";
  66. } else if(end) {
  67. val = "end";
  68. } else if(start) {
  69. val = "start";
  70. } else if(mid) {
  71. val = "mid";
  72. if(mid.indexOf("bk") != -1) {
  73. val = "mid_bk";
  74. }
  75. }
  76. if(!start && !mid && !end) {
  77. val = "none";
  78. }
  79. $("#arrow_list").val(val);
  80. }
  81. }
  82. function resetMarker() {
  83. var el = selElems[0];
  84. el.removeAttribute("marker-start");
  85. el.removeAttribute("marker-mid");
  86. el.removeAttribute("marker-end");
  87. }
  88. function addMarker(dir, type, id) {
  89. // TODO: Make marker (or use?) per arrow type, since refX can be different
  90. id = id || arrowprefix + dir;
  91. var marker = S.getElem(id);
  92. var data = pathdata[dir];
  93. if(type == "mid") {
  94. data.refx = 5;
  95. }
  96. if(!marker) {
  97. marker = addElem({
  98. "element": "marker",
  99. "attr": {
  100. "viewBox": "0 0 10 10",
  101. "id": id,
  102. "refY": 5,
  103. "markerUnits": "strokeWidth",
  104. "markerWidth": 5,
  105. "markerHeight": 5,
  106. "orient": "auto",
  107. "style": "pointer-events:none" // Currently needed for Opera
  108. }
  109. });
  110. var arrow = addElem({
  111. "element": "path",
  112. "attr": {
  113. "d": data.d,
  114. "fill": "#000000"
  115. }
  116. });
  117. marker.appendChild(arrow);
  118. S.findDefs().appendChild(marker);
  119. }
  120. marker.setAttribute('refX', data.refx);
  121. return marker;
  122. }
  123. function setArrow() {
  124. var type = this.value;
  125. resetMarker();
  126. if(type == "none") {
  127. return;
  128. }
  129. // Set marker on element
  130. var dir = "fw";
  131. if(type == "mid_bk") {
  132. type = "mid";
  133. dir = "bk";
  134. } else if(type == "both") {
  135. addMarker("bk", type);
  136. svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")");
  137. type = "end";
  138. dir = "fw";
  139. } else if (type == "start") {
  140. dir = "bk";
  141. }
  142. addMarker(dir, type);
  143. svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")");
  144. S.call("changed", selElems);
  145. }
  146. function colorChanged(elem) {
  147. var color = elem.getAttribute('stroke');
  148. var mtypes = ['start','mid','end'];
  149. var defs = S.findDefs();
  150. $.each(mtypes, function(i, type) {
  151. var marker = getLinked(elem, 'marker-'+type);
  152. if(!marker) return;
  153. var cur_color = $(marker).children().attr('fill');
  154. var cur_d = $(marker).children().attr('d');
  155. var new_marker = null;
  156. if(cur_color === color) return;
  157. var all_markers = $(defs).find('marker');
  158. // Different color, check if already made
  159. all_markers.each(function() {
  160. var attrs = $(this).children().attr(['fill', 'd']);
  161. if(attrs.fill === color && attrs.d === cur_d) {
  162. // Found another marker with this color and this path
  163. new_marker = this;
  164. }
  165. });
  166. if(!new_marker) {
  167. // Create a new marker with this color
  168. var last_id = marker.id;
  169. var dir = last_id.indexOf('_fw') !== -1?'fw':'bk';
  170. new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length);
  171. $(new_marker).children().attr('fill', color);
  172. }
  173. $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")");
  174. // Check if last marker can be removed
  175. var remove = true;
  176. $(S.svgcontent).find('line, polyline, path, polygon').each(function() {
  177. var elem = this;
  178. $.each(mtypes, function(j, mtype) {
  179. if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") {
  180. return remove = false;
  181. }
  182. });
  183. if(!remove) return false;
  184. });
  185. // Not found, so can safely remove
  186. if(remove) {
  187. $(marker).remove();
  188. }
  189. });
  190. }
  191. return {
  192. name: "Arrows",
  193. context_tools: [{
  194. type: "select",
  195. panel: "arrow_panel",
  196. title: "Select arrow type",
  197. id: "arrow_list",
  198. options: {
  199. none: "No arrow",
  200. end: "---->",
  201. start: "<----",
  202. both: "<--->",
  203. mid: "-->--",
  204. mid_bk: "--<--"
  205. },
  206. defval: "none",
  207. events: {
  208. change: setArrow
  209. }
  210. }],
  211. callback: function() {
  212. $('#arrow_panel').hide();
  213. // Set ID so it can be translated in locale file
  214. $('#arrow_list option')[0].id = 'connector_no_arrow';
  215. },
  216. addLangData: function(lang) {
  217. return {
  218. data: lang_list[lang]
  219. };
  220. },
  221. selectedChanged: function(opts) {
  222. // Use this to update the current selected elements
  223. selElems = opts.elems;
  224. var i = selElems.length;
  225. var marker_elems = ['line','path','polyline','polygon'];
  226. while(i--) {
  227. var elem = selElems[i];
  228. if(elem && $.inArray(elem.tagName, marker_elems) != -1) {
  229. if(opts.selectedElement && !opts.multiselected) {
  230. showPanel(true);
  231. } else {
  232. showPanel(false);
  233. }
  234. } else {
  235. showPanel(false);
  236. }
  237. }
  238. },
  239. elementChanged: function(opts) {
  240. var elem = opts.elems[0];
  241. if(elem && (
  242. elem.getAttribute("marker-start") ||
  243. elem.getAttribute("marker-mid") ||
  244. elem.getAttribute("marker-end")
  245. )) {
  246. // var start = elem.getAttribute("marker-start");
  247. // var mid = elem.getAttribute("marker-mid");
  248. // var end = elem.getAttribute("marker-end");
  249. // Has marker, so see if it should match color
  250. colorChanged(elem);
  251. }
  252. }
  253. };
  254. });