reservation plugin - unbound request (unclean
[unfold.git] / portal / static / unbound_reservation_static / src / connectors-flowchart.js
1 /*
2  * jsPlumb
3  * 
4  * Title:jsPlumb 1.5.5
5  * 
6  * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
7  * elements, or VML.  
8  * 
9  * This file contains the 'flowchart' connectors, consisting of vertical and horizontal line segments.
10  *
11  * Copyright (c) 2010 - 2013 Simon Porritt (simon.porritt@gmail.com)
12  * 
13  * http://jsplumb.org
14  * http://github.com/sporritt/jsplumb
15  * http://code.google.com/p/jsplumb
16  * 
17  * Dual licensed under the MIT and GPL2 licenses.
18  */
19 ;(function() {
20    
21     /**
22      * Function: Constructor
23      * 
24      * Parameters:
25      *  stub - minimum length for the stub at each end of the connector. This can be an integer, giving a value for both ends of the connections, 
26      * or an array of two integers, giving separate values for each end. The default is an integer with value 30 (pixels). 
27      *  gap  - gap to leave between the end of the connector and the element on which the endpoint resides. if you make this larger than stub then you will see some odd looking behaviour.  
28                 Like stub, this can be an array or a single value. defaults to 0 pixels for each end.     
29      * cornerRadius - optional, defines the radius of corners between segments. defaults to 0 (hard edged corners).
30      * alwaysRespectStubs - defaults to false. whether or not the connectors should always draw the stub, or, if the two elements
31                             are in close proximity to each other (closer than the sum of the two stubs), to adjust the stubs.
32      */
33     var Flowchart = function(params) {
34         this.type = "Flowchart";
35         params = params || {};
36         params.stub = params.stub == null ? 30 : params.stub;
37         var self = this,
38             _super =  jsPlumb.Connectors.AbstractConnector.apply(this, arguments),              
39             midpoint = params.midpoint == null ? 0.5 : params.midpoint,
40             points = [], segments = [],
41             grid = params.grid,
42             alwaysRespectStubs = params.alwaysRespectStubs,
43             userSuppliedSegments = null,
44             lastx = null, lasty = null, lastOrientation,        
45             cornerRadius = params.cornerRadius != null ? params.cornerRadius : 0,       
46             sgn = function(n) { return n < 0 ? -1 : n === 0 ? 0 : 1; },            
47             /**
48              * helper method to add a segment.
49              */
50             addSegment = function(segments, x, y, paintInfo) {
51                 if (lastx == x && lasty == y) return;
52                 var lx = lastx == null ? paintInfo.sx : lastx,
53                     ly = lasty == null ? paintInfo.sy : lasty,
54                     o = lx == x ? "v" : "h",
55                     sgnx = sgn(x - lx),
56                     sgny = sgn(y - ly);
57                     
58                 lastx = x;
59                 lasty = y;                                                              
60                 segments.push([lx, ly, x, y, o, sgnx, sgny]);
61             },
62             segLength = function(s) {
63                 return Math.sqrt(Math.pow(s[0] - s[2], 2) + Math.pow(s[1] - s[3], 2));    
64             },
65             _cloneArray = function(a) { var _a = []; _a.push.apply(_a, a); return _a;},
66             updateMinMax = function(a1) {
67                 self.bounds.minX = Math.min(self.bounds.minX, a1[2]);
68                 self.bounds.maxX = Math.max(self.bounds.maxX, a1[2]);
69                 self.bounds.minY = Math.min(self.bounds.minY, a1[3]);
70                 self.bounds.maxY = Math.max(self.bounds.maxY, a1[3]);    
71             },
72             writeSegments = function(conn, segments, paintInfo) {
73                 var current, next;                
74                 for (var i = 0; i < segments.length - 1; i++) {
75                     
76                     current = current || _cloneArray(segments[i]);
77                     next = _cloneArray(segments[i + 1]);
78                     if (cornerRadius > 0 && current[4] != next[4]) {
79                         var radiusToUse = Math.min(cornerRadius, segLength(current), segLength(next));
80                         // right angle. adjust current segment's end point, and next segment's start point.
81                         current[2] -= current[5] * radiusToUse;
82                         current[3] -= current[6] * radiusToUse;
83                         next[0] += next[5] * radiusToUse;
84                         next[1] += next[6] * radiusToUse;                                                                                                                                                               
85                         var ac = (current[6] == next[5] && next[5] == 1) ||
86                                  ((current[6] == next[5] && next[5] === 0) && current[5] != next[6]) ||
87                                  (current[6] == next[5] && next[5] == -1),
88                             sgny = next[1] > current[3] ? 1 : -1,
89                             sgnx = next[0] > current[2] ? 1 : -1,
90                             sgnEqual = sgny == sgnx,
91                             cx = (sgnEqual && ac || (!sgnEqual && !ac)) ? next[0] : current[2],
92                             cy = (sgnEqual && ac || (!sgnEqual && !ac)) ? current[3] : next[1];                                                        
93                         
94                         _super.addSegment(conn, "Straight", {
95                             x1:current[0], y1:current[1], x2:current[2], y2:current[3]
96                         });
97                             
98                         _super.addSegment(conn, "Arc", {
99                             r:radiusToUse, 
100                             x1:current[2], 
101                             y1:current[3], 
102                             x2:next[0], 
103                             y2:next[1],
104                             cx:cx,
105                             cy:cy,
106                             ac:ac
107                         });                                                 
108                     }
109                     else {                 
110                         // dx + dy are used to adjust for line width.
111                         var dx = (current[2] == current[0]) ? 0 : (current[2] > current[0]) ? (paintInfo.lw / 2) : -(paintInfo.lw / 2),
112                             dy = (current[3] == current[1]) ? 0 : (current[3] > current[1]) ? (paintInfo.lw / 2) : -(paintInfo.lw / 2);
113                         _super.addSegment(conn, "Straight", {
114                             x1:current[0]- dx, y1:current[1]-dy, x2:current[2] + dx, y2:current[3] + dy
115                         });
116                     }                    
117                     current = next;
118                 }
119                 // last segment
120                 _super.addSegment(conn, "Straight", {
121                     x1:next[0], y1:next[1], x2:next[2], y2:next[3]
122                 });                             
123             };
124         
125         this.setSegments = function(s) {
126             userSuppliedSegments = s;
127         };
128         
129         this.isEditable = function() { return true; };
130         
131         /*
132             Function: getOriginalSegments
133             Gets the segments before the addition of rounded corners. This is used by the flowchart
134             connector editor, since it only wants to concern itself with the original segments.
135         */
136         this.getOriginalSegments = function() {
137             return userSuppliedSegments || segments;
138         };
139         
140         this._compute = function(paintInfo, params) {
141             
142             if (params.clearEdits)
143                 userSuppliedSegments = null;
144             
145             if (userSuppliedSegments != null) {
146                 writeSegments(this, userSuppliedSegments, paintInfo);                
147                 return;
148             }
149             
150             segments = [];
151             lastx = null; lasty = null;
152             lastOrientation = null;          
153             
154             var midx = paintInfo.startStubX + ((paintInfo.endStubX - paintInfo.startStubX) * midpoint),
155                 midy = paintInfo.startStubY + ((paintInfo.endStubY - paintInfo.startStubY) * midpoint);                                                                                                    
156     
157             var findClearedLine = function(start, mult, anchorPos, dimension) {
158                     return start + (mult * (( 1 - anchorPos) * dimension) + _super.maxStub);
159                 },
160                 orientations = { x:[ 0, 1 ], y:[ 1, 0 ] },
161                 commonStubCalculator = function(axis) {
162                     return [ paintInfo.startStubX, paintInfo.startStubY, paintInfo.endStubX, paintInfo.endStubY ];                    
163                 },
164                 stubCalculators = {
165                     perpendicular:commonStubCalculator,
166                     orthogonal:commonStubCalculator,
167                     opposite:function(axis) {  
168                         var pi = paintInfo,
169                             idx = axis == "x" ? 0 : 1, 
170                             areInProximity = {
171                                 "x":function() {                                    
172                                     return ( (pi.so[idx] == 1 && ( 
173                                         ( (pi.startStubX > pi.endStubX) && (pi.tx > pi.startStubX) ) ||
174                                         ( (pi.sx > pi.endStubX) && (pi.tx > pi.sx))))) ||
175
176                                         ( (pi.so[idx] == -1 && ( 
177                                             ( (pi.startStubX < pi.endStubX) && (pi.tx < pi.startStubX) ) ||
178                                             ( (pi.sx < pi.endStubX) && (pi.tx < pi.sx)))));
179                                 },
180                                 "y":function() {                                     
181                                     return ( (pi.so[idx] == 1 && ( 
182                                         ( (pi.startStubY > pi.endStubY) && (pi.ty > pi.startStubY) ) ||
183                                         ( (pi.sy > pi.endStubY) && (pi.ty > pi.sy))))) ||
184
185                                         ( (pi.so[idx] == -1 && ( 
186                                         ( (pi.startStubY < pi.endStubY) && (pi.ty < pi.startStubY) ) ||
187                                         ( (pi.sy < pi.endStubY) && (pi.ty < pi.sy)))));
188                                 }
189                             };
190
191                         if (!alwaysRespectStubs && areInProximity[axis]()) {                   
192                             return {
193                                 "x":[(paintInfo.sx + paintInfo.tx) / 2, paintInfo.startStubY, (paintInfo.sx + paintInfo.tx) / 2, paintInfo.endStubY],
194                                 "y":[paintInfo.startStubX, (paintInfo.sy + paintInfo.ty) / 2, paintInfo.endStubX, (paintInfo.sy + paintInfo.ty) / 2]
195                             }[axis];
196                         }
197                         else {
198                             return [ paintInfo.startStubX, paintInfo.startStubY, paintInfo.endStubX, paintInfo.endStubY ];   
199                         }
200                     }
201                 },
202                 lineCalculators = {
203                     perpendicular : function(axis, ss, oss, es, oes) {
204                         var pi = paintInfo, 
205                             sis = {
206                                 x:[ [ [ 1,2,3,4 ], null, [ 2,1,4,3 ] ], null, [ [ 4,3,2,1 ], null, [ 3,4,1,2 ] ] ],
207                                 y:[ [ [ 3,2,1,4 ], null, [ 2,3,4,1 ] ], null, [ [ 4,1,2,3 ], null, [ 1,4,3,2 ] ] ]
208                             },
209                             stubs = { 
210                                 x:[ [ pi.startStubX, pi.endStubX ] , null, [ pi.endStubX, pi.startStubX ] ],
211                                 y:[ [ pi.startStubY, pi.endStubY ] , null, [ pi.endStubY, pi.startStubY ] ]
212                             },
213                             midLines = {
214                                 x:[ [ midx, pi.startStubY ], [ midx, pi.endStubY ] ],
215                                 y:[ [ pi.startStubX, midy ], [ pi.endStubX, midy ] ]
216                             },
217                             linesToEnd = {
218                                 x:[ [ pi.endStubX, pi.startStubY ] ],
219                                 y:[ [ pi.startStubX, pi.endStubY ] ]
220                             },
221                             startToEnd = {
222                                 x:[ [ pi.startStubX, pi.endStubY ], [ pi.endStubX, pi.endStubY ] ],        
223                                 y:[ [ pi.endStubX, pi.startStubY ], [ pi.endStubX, pi.endStubY ] ]
224                             },
225                             startToMidToEnd = {
226                                 x:[ [ pi.startStubX, midy ], [ pi.endStubX, midy ], [ pi.endStubX, pi.endStubY ] ],
227                                 y:[ [ midx, pi.startStubY ], [ midx, pi.endStubY ], [ pi.endStubX, pi.endStubY ] ]
228                             },
229                             otherStubs = {
230                                 x:[ pi.startStubY, pi.endStubY ],
231                                 y:[ pi.startStubX, pi.endStubX ]                                    
232                             },
233                             soIdx = orientations[axis][0], toIdx = orientations[axis][1],
234                             _so = pi.so[soIdx] + 1,
235                             _to = pi.to[toIdx] + 1,
236                             otherFlipped = (pi.to[toIdx] == -1 && (otherStubs[axis][1] < otherStubs[axis][0])) || (pi.to[toIdx] == 1 && (otherStubs[axis][1] > otherStubs[axis][0])),
237                             stub1 = stubs[axis][_so][0],
238                             stub2 = stubs[axis][_so][1],
239                             segmentIndexes = sis[axis][_so][_to];
240
241                         if (pi.segment == segmentIndexes[3] || (pi.segment == segmentIndexes[2] && otherFlipped)) {
242                             return midLines[axis];       
243                         }
244                         else if (pi.segment == segmentIndexes[2] && stub2 < stub1) {
245                             return linesToEnd[axis];
246                         }
247                         else if ((pi.segment == segmentIndexes[2] && stub2 >= stub1) || (pi.segment == segmentIndexes[1] && !otherFlipped)) {
248                             return startToMidToEnd[axis];
249                         }
250                         else if (pi.segment == segmentIndexes[0] || (pi.segment == segmentIndexes[1] && otherFlipped)) {
251                             return startToEnd[axis];  
252                         }                                
253                     },
254                     orthogonal : function(axis, startStub, otherStartStub, endStub, otherEndStub) {                    
255                         var pi = paintInfo,                                            
256                             extent = {
257                                 "x":pi.so[0] == -1 ? Math.min(startStub, endStub) : Math.max(startStub, endStub),
258                                 "y":pi.so[1] == -1 ? Math.min(startStub, endStub) : Math.max(startStub, endStub)
259                             }[axis];
260                                                 
261                         return {
262                             "x":[ [ extent, otherStartStub ],[ extent, otherEndStub ], [ endStub, otherEndStub ] ],
263                             "y":[ [ otherStartStub, extent ], [ otherEndStub, extent ], [ otherEndStub, endStub ] ]
264                         }[axis];                    
265                     },
266                     opposite : function(axis, ss, oss, es, oes) {                                                
267                         var pi = paintInfo,
268                             otherAxis = {"x":"y","y":"x"}[axis], 
269                             dim = {"x":"height","y":"width"}[axis],
270                             comparator = pi["is" + axis.toUpperCase() + "GreaterThanStubTimes2"];
271
272                         if (params.sourceEndpoint.elementId == params.targetEndpoint.elementId) {
273                             var _val = oss + ((1 - params.sourceEndpoint.anchor[otherAxis]) * params.sourceInfo[dim]) + _super.maxStub;
274                             return {
275                                 "x":[ [ ss, _val ], [ es, _val ] ],
276                                 "y":[ [ _val, ss ], [ _val, es ] ]
277                             }[axis];
278                             
279                         }                                                        
280                         else if (!comparator || (pi.so[idx] == 1 && ss > es) || (pi.so[idx] == -1 && ss < es)) {                                            
281                             return {
282                                 "x":[[ ss, midy ], [ es, midy ]],
283                                 "y":[[ midx, ss ], [ midx, es ]]
284                             }[axis];
285                         }
286                         else if ((pi.so[idx] == 1 && ss < es) || (pi.so[idx] == -1 && ss > es)) {
287                             return {
288                                 "x":[[ midx, pi.sy ], [ midx, pi.ty ]],
289                                 "y":[[ pi.sx, midy ], [ pi.tx, midy ]]
290                             }[axis];
291                         }                        
292                     }
293                 };
294
295             var stubs = stubCalculators[paintInfo.anchorOrientation](paintInfo.sourceAxis),
296                 idx = paintInfo.sourceAxis == "x" ? 0 : 1,
297                 oidx = paintInfo.sourceAxis == "x" ? 1 : 0,                            
298                 ss = stubs[idx],
299                 oss = stubs[oidx],
300                 es = stubs[idx + 2],
301                 oes = stubs[oidx + 2];
302
303             // add the start stub segment.
304             addSegment(segments, stubs[0], stubs[1], paintInfo);           
305
306             // compute the rest of the line
307             var p = lineCalculators[paintInfo.anchorOrientation](paintInfo.sourceAxis, ss, oss, es, oes);            
308             if (p) {
309                 for (var i = 0; i < p.length; i++) {                    
310                     addSegment(segments, p[i][0], p[i][1], paintInfo);
311                 }
312             }          
313             
314             // line to end stub
315             addSegment(segments, stubs[2], stubs[3], paintInfo);
316     
317             // end stub to end
318             addSegment(segments, paintInfo.tx, paintInfo.ty, paintInfo);               
319             
320             writeSegments(this, segments, paintInfo);                            
321         };      
322
323         this.getPath = function() {
324             var _last = null, _lastAxis = null, s = [], segs = userSuppliedSegments || segments;
325             for (var i = 0; i < segs.length; i++) {
326                 var seg = segs[i], axis = seg[4], axisIndex = (axis == "v" ? 3 : 2);
327                 if (_last != null && _lastAxis === axis) {
328                     _last[axisIndex] = seg[axisIndex];                            
329                 }
330                 else {
331                     if (seg[0] != seg[2] || seg[1] != seg[3]) {
332                         s.push({
333                             start:[ seg[0], seg[1] ],
334                             end:[ seg[2], seg[3] ]
335                         });                    
336                         _last = seg;
337                         _lastAxis = seg[4];
338                     }
339                 }
340             }
341             return s;
342         };      
343
344         this.setPath = function(path) {
345             userSuppliedSegments = [];
346             for (var i = 0; i < path.length; i++) {
347                  var lx = path[i].start[0],
348                     ly = path[i].start[1],
349                     x = path[i].end[0],
350                     y = path[i].end[1],
351                     o = lx == x ? "v" : "h",
352                     sgnx = sgn(x - lx),
353                     sgny = sgn(y - ly);
354
355                 userSuppliedSegments.push([lx, ly, x, y, o, sgnx, sgny]);
356             }
357         };
358     };
359
360     jsPlumbUtil.extend(Flowchart, jsPlumb.Connectors.AbstractConnector);
361     jsPlumb.registerConnectorType(Flowchart, "Flowchart");
362 })();