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