jsPlumb-defaults-1.3.6-RC1.js 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. /*
  2. * jsPlumb
  3. *
  4. * Title:jsPlumb 1.3.6
  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 default Connectors, Endpoint and Overlay definitions.
  10. *
  11. * Copyright (c) 2010 - 2012 Simon Porritt (http://jsplumb.org)
  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. * Helper class to consume unused mouse events by components that are DOM elements and
  23. * are used by all of the different rendering modes.
  24. *
  25. */
  26. jsPlumb.DOMElementComponent = function(params) {
  27. jsPlumb.jsPlumbUIComponent.apply(this, arguments);
  28. // when render mode is canvas, these functions may be called by the canvas mouse handler.
  29. // this component is safe to pipe this stuff to /dev/null.
  30. this.mousemove =
  31. this.dblclick =
  32. this.click =
  33. this.mousedown =
  34. this.mouseup = function(e) { };
  35. };
  36. /**
  37. * Class: Connectors.Straight
  38. * The Straight connector draws a simple straight line between the two anchor points. It does not have any constructor parameters.
  39. */
  40. jsPlumb.Connectors.Straight = function() {
  41. this.type = "Straight";
  42. var self = this,
  43. currentPoints = null,
  44. _m, _m2, _b, _dx, _dy, _theta, _theta2, _sx, _sy, _tx, _ty, _segment, _length;
  45. /**
  46. * Computes the new size and position of the canvas.
  47. */
  48. this.compute = function(sourcePos, targetPos, sourceEndpoint, targetEndpoint, sourceAnchor, targetAnchor, lineWidth, minWidth) {
  49. var w = Math.abs(sourcePos[0] - targetPos[0]),
  50. h = Math.abs(sourcePos[1] - targetPos[1]),
  51. // these are padding to ensure the whole connector line appears
  52. xo = 0.45 * w, yo = 0.45 * h;
  53. // these are padding to ensure the whole connector line appears
  54. w *= 1.9; h *=1.9;
  55. var x = Math.min(sourcePos[0], targetPos[0]) - xo;
  56. var y = Math.min(sourcePos[1], targetPos[1]) - yo;
  57. // minimum size is 2 * line Width if minWidth was not given.
  58. var calculatedMinWidth = Math.max(2 * lineWidth, minWidth);
  59. if (w < calculatedMinWidth) {
  60. w = calculatedMinWidth;
  61. x = sourcePos[0] + ((targetPos[0] - sourcePos[0]) / 2) - (calculatedMinWidth / 2);
  62. xo = (w - Math.abs(sourcePos[0]-targetPos[0])) / 2;
  63. }
  64. if (h < calculatedMinWidth) {
  65. h = calculatedMinWidth;
  66. y = sourcePos[1] + ((targetPos[1] - sourcePos[1]) / 2) - (calculatedMinWidth / 2);
  67. yo = (h - Math.abs(sourcePos[1]-targetPos[1])) / 2;
  68. }
  69. _sx = sourcePos[0] < targetPos[0] ? xo : w-xo;
  70. _sy = sourcePos[1] < targetPos[1] ? yo:h-yo;
  71. _tx = sourcePos[0] < targetPos[0] ? w-xo : xo;
  72. _ty = sourcePos[1] < targetPos[1] ? h-yo : yo;
  73. currentPoints = [ x, y, w, h, _sx, _sy, _tx, _ty ];
  74. _dx = _tx - _sx, _dy = _ty - _sy;
  75. //_m = _dy / _dx, _m2 = -1 / _m;
  76. _m = jsPlumb.util.gradient({x:_sx, y:_sy}, {x:_tx, y:_ty}), _m2 = -1 / _m;
  77. _b = -1 * ((_m * _sx) - _sy);
  78. _theta = Math.atan(_m); _theta2 = Math.atan(_m2);
  79. //_segment = jsPlumb.util.segment({x:_sx, y:_sy}, {x:_tx, y:_ty});
  80. _length = Math.sqrt((_dx * _dx) + (_dy * _dy));
  81. return currentPoints;
  82. };
  83. /**
  84. * returns the point on the connector's path that is 'location' along the length of the path, where 'location' is a decimal from
  85. * 0 to 1 inclusive. for the straight line connector this is simple maths. for Bezier, not so much.
  86. */
  87. this.pointOnPath = function(location) {
  88. if (location == 0)
  89. return { x:_sx, y:_sy };
  90. else if (location == 1)
  91. return { x:_tx, y:_ty };
  92. else
  93. return jsPlumb.util.pointOnLine({x:_sx, y:_sy}, {x:_tx, y:_ty}, location * _length);
  94. };
  95. /**
  96. * returns the gradient of the connector at the given point - which for us is constant.
  97. */
  98. this.gradientAtPoint = function(location) {
  99. return _m;
  100. };
  101. /**
  102. * returns the point on the connector's path that is 'distance' along the length of the path from 'location', where
  103. * 'location' is a decimal from 0 to 1 inclusive, and 'distance' is a number of pixels.
  104. * this hands off to jsPlumb.util to do the maths, supplying two points and the distance.
  105. */
  106. this.pointAlongPathFrom = function(location, distance) {
  107. var p = self.pointOnPath(location),
  108. farAwayPoint = location == 1 ? {
  109. x:_sx + ((_tx - _sx) * 10),
  110. y:_sy + ((_sy - _ty) * 10)
  111. } : {x:_tx, y:_ty };
  112. return jsPlumb.util.pointOnLine(p, farAwayPoint, distance);
  113. };
  114. };
  115. /**
  116. * Class:Connectors.Bezier
  117. * This Connector draws a Bezier curve with two control points. You can provide a 'curviness' value which gets applied to jsPlumb's
  118. * internal voodoo machine and ends up generating locations for the two control points. See the constructor documentation below.
  119. */
  120. /**
  121. * Function:Constructor
  122. *
  123. * Parameters:
  124. * curviness - How 'curvy' you want the curve to be! This is a directive for the placement of control points, not endpoints of the curve, so your curve does not
  125. * actually touch the given point, but it has the tendency to lean towards it. The larger this value, the greater the curve is pulled from a straight line.
  126. * Optional; defaults to 150.
  127. * stub - optional value for a distance to travel from the connector's endpoint before beginning the Bezier curve. defaults to 0.
  128. *
  129. */
  130. jsPlumb.Connectors.Bezier = function(params) {
  131. var self = this;
  132. params = params || {};
  133. this.majorAnchor = params.curviness || 150;
  134. this.minorAnchor = 10;
  135. var currentPoints = null;
  136. this.type = "Bezier";
  137. this._findControlPoint = function(point, sourceAnchorPosition, targetAnchorPosition, sourceEndpoint, targetEndpoint, sourceAnchor, targetAnchor) {
  138. // determine if the two anchors are perpendicular to each other in their orientation. we swap the control
  139. // points around if so (code could be tightened up)
  140. var soo = sourceAnchor.getOrientation(sourceEndpoint),
  141. too = targetAnchor.getOrientation(targetEndpoint),
  142. perpendicular = soo[0] != too[0] || soo[1] == too[1],
  143. p = [],
  144. ma = self.majorAnchor, mi = self.minorAnchor;
  145. if (!perpendicular) {
  146. if (soo[0] == 0) // X
  147. p.push(sourceAnchorPosition[0] < targetAnchorPosition[0] ? point[0] + mi : point[0] - mi);
  148. else p.push(point[0] - (ma * soo[0]));
  149. if (soo[1] == 0) // Y
  150. p.push(sourceAnchorPosition[1] < targetAnchorPosition[1] ? point[1] + mi : point[1] - mi);
  151. else p.push(point[1] + (ma * too[1]));
  152. }
  153. else {
  154. if (too[0] == 0) // X
  155. p.push(targetAnchorPosition[0] < sourceAnchorPosition[0] ? point[0] + mi : point[0] - mi);
  156. else p.push(point[0] + (ma * too[0]));
  157. if (too[1] == 0) // Y
  158. p.push(targetAnchorPosition[1] < sourceAnchorPosition[1] ? point[1] + mi : point[1] - mi);
  159. else p.push(point[1] + (ma * soo[1]));
  160. }
  161. return p;
  162. };
  163. var _CP, _CP2, _sx, _tx, _ty, _sx, _sy, _canvasX, _canvasY, _w, _h, _sStubX, _sStubY, _tStubX, _tStubY;
  164. this.compute = function(sourcePos, targetPos, sourceEndpoint, targetEndpoint, sourceAnchor, targetAnchor, lineWidth, minWidth) {
  165. lineWidth = lineWidth || 0;
  166. _w = Math.abs(sourcePos[0] - targetPos[0]) + lineWidth;
  167. _h = Math.abs(sourcePos[1] - targetPos[1]) + lineWidth;
  168. _canvasX = Math.min(sourcePos[0], targetPos[0])-(lineWidth/2);
  169. _canvasY = Math.min(sourcePos[1], targetPos[1])-(lineWidth/2);
  170. _sx = sourcePos[0] < targetPos[0] ? _w - (lineWidth/2): (lineWidth/2);
  171. _sy = sourcePos[1] < targetPos[1] ? _h - (lineWidth/2) : (lineWidth/2);
  172. _tx = sourcePos[0] < targetPos[0] ? (lineWidth/2) : _w - (lineWidth/2);
  173. _ty = sourcePos[1] < targetPos[1] ? (lineWidth/2) : _h - (lineWidth/2);
  174. _CP = self._findControlPoint([_sx,_sy], sourcePos, targetPos, sourceEndpoint, targetEndpoint, sourceAnchor, targetAnchor);
  175. _CP2 = self._findControlPoint([_tx,_ty], targetPos, sourcePos, sourceEndpoint, targetEndpoint, targetAnchor, sourceAnchor);
  176. var minx1 = Math.min(_sx,_tx), minx2 = Math.min(_CP[0], _CP2[0]), minx = Math.min(minx1,minx2),
  177. maxx1 = Math.max(_sx,_tx), maxx2 = Math.max(_CP[0], _CP2[0]), maxx = Math.max(maxx1,maxx2);
  178. if (maxx > _w) _w = maxx;
  179. if (minx < 0) {
  180. _canvasX += minx; var ox = Math.abs(minx);
  181. _w += ox; _CP[0] += ox; _sx += ox; _tx +=ox; _CP2[0] += ox;
  182. }
  183. var miny1 = Math.min(_sy,_ty), miny2 = Math.min(_CP[1], _CP2[1]), miny = Math.min(miny1,miny2),
  184. maxy1 = Math.max(_sy,_ty), maxy2 = Math.max(_CP[1], _CP2[1]), maxy = Math.max(maxy1,maxy2);
  185. if (maxy > _h) _h = maxy;
  186. if (miny < 0) {
  187. _canvasY += miny; var oy = Math.abs(miny);
  188. _h += oy; _CP[1] += oy; _sy += oy; _ty +=oy; _CP2[1] += oy;
  189. }
  190. if (minWidth && _w < minWidth) {
  191. var posAdjust = (minWidth - _w) / 2;
  192. _w = minWidth;
  193. _canvasX -= posAdjust; _sx = _sx + posAdjust ; _tx = _tx + posAdjust; _CP[0] = _CP[0] + posAdjust; _CP2[0] = _CP2[0] + posAdjust;
  194. }
  195. if (minWidth && _h < minWidth) {
  196. var posAdjust = (minWidth - _h) / 2;
  197. _h = minWidth;
  198. _canvasY -= posAdjust; _sy = _sy + posAdjust ; _ty = _ty + posAdjust; _CP[1] = _CP[1] + posAdjust; _CP2[1] = _CP2[1] + posAdjust;
  199. }
  200. currentPoints = [_canvasX, _canvasY, _w, _h,
  201. _sx, _sy, _tx, _ty,
  202. _CP[0], _CP[1], _CP2[0], _CP2[1] ];
  203. return currentPoints;
  204. };
  205. var _makeCurve = function() {
  206. return [
  207. { x:_sx, y:_sy },
  208. { x:_CP[0], y:_CP[1] },
  209. { x:_CP2[0], y:_CP2[1] },
  210. { x:_tx, y:_ty }
  211. ];
  212. };
  213. /**
  214. * returns the point on the connector's path that is 'location' along the length of the path, where 'location' is a decimal from
  215. * 0 to 1 inclusive. for the straight line connector this is simple maths. for Bezier, not so much.
  216. */
  217. this.pointOnPath = function(location) {
  218. return jsBezier.pointOnCurve(_makeCurve(), location);
  219. };
  220. /**
  221. * returns the gradient of the connector at the given point.
  222. */
  223. this.gradientAtPoint = function(location) {
  224. return jsBezier.gradientAtPoint(_makeCurve(), location);
  225. };
  226. /**
  227. * for Bezier curves this method is a little tricky, cos calculating path distance algebraically is notoriously difficult.
  228. * this method is iterative, jumping forward .05% of the path at a time and summing the distance between this point and the previous
  229. * one, until the sum reaches 'distance'. the method may turn out to be computationally expensive; we'll see.
  230. * another drawback of this method is that if the connector gets quite long, .05% of the length of it is not necessarily smaller
  231. * than the desired distance, in which case the loop returns immediately and the arrow is mis-shapen. so a better strategy might be to
  232. * calculate the step as a function of distance/distance between endpoints.
  233. */
  234. this.pointAlongPathFrom = function(location, distance) {
  235. return jsBezier.pointAlongCurveFrom(_makeCurve(), location, distance);
  236. };
  237. };
  238. /**
  239. * Class: Connectors.Flowchart
  240. * Provides 'flowchart' connectors, consisting of vertical and horizontal line segments.
  241. */
  242. /**
  243. * Function: Constructor
  244. *
  245. * Parameters:
  246. * stub - minimum length for the stub at each end of the connector. defaults to 30 pixels.
  247. */
  248. jsPlumb.Connectors.Flowchart = function(params) {
  249. this.type = "Flowchart";
  250. params = params || {};
  251. var self = this,
  252. minStubLength = params.stub || params.minStubLength /* bwds compat. */ || 30,
  253. segments = [],
  254. totalLength = 0,
  255. segmentProportions = [],
  256. segmentProportionalLengths = [],
  257. points = [],
  258. swapX, swapY,
  259. maxX = 0, maxY = 0,
  260. /**
  261. * recalculates the points at which the segments begin and end, proportional to the total length travelled
  262. * by all the segments that constitute the connector. we use this to help with pointOnPath calculations.
  263. */
  264. updateSegmentProportions = function(startX, startY, endX, endY) {
  265. var curLoc = 0;
  266. for (var i = 0; i < segments.length; i++) {
  267. segmentProportionalLengths[i] = segments[i][5] / totalLength;
  268. segmentProportions[i] = [curLoc, (curLoc += (segments[i][5] / totalLength)) ];
  269. }
  270. },
  271. appendSegmentsToPoints = function() {
  272. points.push(segments.length);
  273. for (var i = 0; i < segments.length; i++) {
  274. points.push(segments[i][0]);
  275. points.push(segments[i][1]);
  276. }
  277. },
  278. /**
  279. * helper method to add a segment.
  280. */
  281. addSegment = function(x, y, sx, sy, tx, ty) {
  282. var lx = segments.length == 0 ? sx : segments[segments.length - 1][0],
  283. ly = segments.length == 0 ? sy : segments[segments.length - 1][1],
  284. m = x == lx ? Infinity : 0,
  285. l = Math.abs(x == lx ? y - ly : x - lx);
  286. segments.push([x, y, lx, ly, m, l]);
  287. totalLength += l;
  288. maxX = Math.max(maxX, x);
  289. maxY = Math.max(maxY, y);
  290. },
  291. /**
  292. * returns [segment, proportion of travel in segment, segment index] for the segment
  293. * that contains the point which is 'location' distance along the entire path, where
  294. * 'location' is a decimal between 0 and 1 inclusive. in this connector type, paths
  295. * are made up of a list of segments, each of which contributes some fraction to
  296. * the total length.
  297. */
  298. findSegmentForLocation = function(location) {
  299. var idx = segmentProportions.length - 1, inSegmentProportion = 1;
  300. for (var i = 0; i < segmentProportions.length; i++) {
  301. if (segmentProportions[i][1] >= location) {
  302. idx = i;
  303. inSegmentProportion = (location - segmentProportions[i][0]) / segmentProportionalLengths[i];
  304. break;
  305. }
  306. }
  307. return { segment:segments[idx], proportion:inSegmentProportion, index:idx };
  308. };
  309. this.compute = function(sourcePos, targetPos, sourceEndpoint, targetEndpoint,
  310. sourceAnchor, targetAnchor, lineWidth, minWidth, sourceInfo, targetInfo) {
  311. segments = [];
  312. totalLength = 0;
  313. segmentProportionalLengths = [];
  314. maxX = maxY = 0;
  315. swapX = targetPos[0] < sourcePos[0];
  316. swapY = targetPos[1] < sourcePos[1];
  317. var lw = lineWidth || 1,
  318. offx = (lw / 2) + (minStubLength * 2),
  319. offy = (lw / 2) + (minStubLength * 2),
  320. so = sourceAnchor.orientation || sourceAnchor.getOrientation(sourceEndpoint),
  321. to = targetAnchor.orientation || targetAnchor.getOrientation(targetEndpoint),
  322. x = swapX ? targetPos[0] : sourcePos[0],
  323. y = swapY ? targetPos[1] : sourcePos[1],
  324. w = Math.abs(targetPos[0] - sourcePos[0]) + 2*offx,
  325. h = Math.abs(targetPos[1] - sourcePos[1]) + 2*offy;
  326. // if either anchor does not have an orientation set, we derive one from their relative
  327. // positions. we fix the axis to be the one in which the two elements are further apart, and
  328. // point each anchor at the other element. this is also used when dragging a new connection.
  329. if (so[0] == 0 && so[1] == 0 || to[0] == 0 && to[1] == 0) {
  330. var index = w > h ? 0 : 1, oIndex = [1,0][index];
  331. so = []; to = [];
  332. so[index] = sourcePos[index] > targetPos[index] ? -1 : 1;
  333. to[index] = sourcePos[index] > targetPos[index] ? 1 : -1;
  334. so[oIndex] = 0;
  335. to[oIndex] = 0;
  336. }
  337. if (w < minWidth) {
  338. offx += (minWidth - w) / 2;
  339. w = minWidth;
  340. }
  341. if (h < minWidth) {
  342. offy += (minWidth - h) / 2;
  343. h = minWidth;
  344. }
  345. var sx = swapX ? w-offx : offx,
  346. sy = swapY ? h-offy : offy,
  347. tx = swapX ? offx : w-offx ,
  348. ty = swapY ? offy : h-offy,
  349. startStubX = sx + (so[0] * minStubLength),
  350. startStubY = sy + (so[1] * minStubLength),
  351. endStubX = tx + (to[0] * minStubLength),
  352. endStubY = ty + (to[1] * minStubLength),
  353. isXGreaterThanStubTimes2 = Math.abs(sx - tx) > 2 * minStubLength,
  354. isYGreaterThanStubTimes2 = Math.abs(sy - ty) > 2 * minStubLength,
  355. midx = startStubX + ((endStubX - startStubX) / 2),
  356. midy = startStubY + ((endStubY - startStubY) / 2),
  357. oProduct = ((so[0] * to[0]) + (so[1] * to[1])),
  358. opposite = oProduct == -1,
  359. perpendicular = oProduct == 0,
  360. orthogonal = oProduct == 1;
  361. x -= offx; y -= offy;
  362. points = [x, y, w, h, sx, sy, tx, ty];
  363. var extraPoints = [];
  364. addSegment(startStubX, startStubY, sx, sy, tx, ty);
  365. var sourceAxis = so[0] == 0 ? "y" : "x",
  366. anchorOrientation = opposite ? "opposite" : orthogonal ? "orthogonal" : "perpendicular",
  367. segment = jsPlumb.util.segment([sx, sy], [tx, ty]),
  368. flipSourceSegments = so[sourceAxis == "x" ? 0 : 1] == -1,
  369. flipSegments = {
  370. "x":[null, 4, 3, 2, 1],
  371. "y":[null, 2, 1, 4, 3]
  372. }
  373. if (flipSourceSegments)
  374. segment = flipSegments[sourceAxis][segment];
  375. var findClearedLine = function(start, mult, anchorPos, dimension) {
  376. return start + (mult * (( 1 - anchorPos) * dimension) + minStubLength);
  377. //mx = so[0] == 0 ? startStubX + ((1 - sourceAnchor.x) * sourceInfo.width) + minStubLength : startStubX,
  378. },
  379. lineCalculators = {
  380. oppositex : function() {
  381. if (sourceEndpoint.elementId == targetEndpoint.elementId) {
  382. var _y = startStubY + ((1 - sourceAnchor.y) * sourceInfo.height) + minStubLength;
  383. return [ [ startStubX, _y ], [ endStubX, _y ]];
  384. }
  385. else if (isXGreaterThanStubTimes2 && (segment == 1 || segment == 2)) {
  386. return [[ midx, sy ], [ midx, ty ]];
  387. }
  388. else {
  389. return [[ startStubX, midy ], [endStubX, midy ]];
  390. }
  391. },
  392. orthogonalx : function() {
  393. if (segment == 1 || segment == 2) {
  394. return [ [ endStubX, startStubY ]];
  395. }
  396. else {
  397. return [ [ startStubX, endStubY ]];
  398. }
  399. },
  400. perpendicularx : function() {
  401. var my = (ty + sy) / 2;
  402. if ((segment == 1 && to[1] == 1) || (segment == 2 && to[1] == -1)) {
  403. if (Math.abs(tx - sx) > minStubLength)
  404. return [ [endStubX, startStubY ]];
  405. else
  406. return [ [startStubX, startStubY ], [ startStubX, my ], [ endStubX, my ]];
  407. }
  408. else if ((segment == 3 && to[1] == -1) || (segment == 4 && to[1] == 1)) {
  409. return [ [ startStubX, my ], [ endStubX, my ]];
  410. }
  411. else if ((segment == 3 && to[1] == 1) || (segment == 4 && to[1] == -1)) {
  412. return [ [ startStubX, endStubY ]];
  413. }
  414. else if ((segment == 1 && to[1] == -1) || (segment == 2 && to[1] == 1)) {
  415. if (Math.abs(tx - sx) > minStubLength)
  416. return [ [ midx, startStubY ], [ midx, endStubY ]];
  417. else
  418. return [ [ startStubX, endStubY ]];
  419. }
  420. },
  421. oppositey : function() {
  422. if (sourceEndpoint.elementId == targetEndpoint.elementId) {
  423. var _x = startStubX + ((1 - sourceAnchor.x) * sourceInfo.width) + minStubLength;
  424. return [ [ _x, startStubY ], [ _x, endStubY ]];
  425. }
  426. else if (isYGreaterThanStubTimes2 && (segment == 2 || segment == 3)) {
  427. return [[ sx, midy ], [ tx, midy ]];
  428. }
  429. else {
  430. return [[ midx, startStubY ], [midx, endStubY ]];
  431. }
  432. },
  433. orthogonaly : function() {
  434. if (segment == 2 || segment == 3) {
  435. return [ [ startStubX, endStubY ]];
  436. }
  437. else {
  438. return [ [ endStubX, startStubY ]];
  439. }
  440. },
  441. perpendiculary : function() {
  442. var mx = (tx + sx) / 2;
  443. if ((segment == 2 && to[0] == -1) || (segment == 3 && to[0] == 1)) {
  444. if (Math.abs(tx - sx) > minStubLength)
  445. return [ [startStubX, endStubY ]];
  446. else
  447. return [ [startStubX, midy ], [ endStubX, midy ]];
  448. }
  449. else if ((segment == 1 && to[0] == -1) || (segment == 4 && to[0] == 1)) {
  450. var mx = (tx + sx) / 2;
  451. return [ [ mx, startStubY ], [ mx, endStubY ]];
  452. }
  453. else if ((segment == 1 && to[0] == 1) || (segment == 4 && to[0] == -1)) {
  454. return [ [ endStubX, startStubY ]];
  455. }
  456. else if ((segment == 2 && to[0] == 1) || (segment == 3 && to[0] == -1)) {
  457. if (Math.abs(ty - sy) > minStubLength)
  458. return [ [ startStubX, midy ], [ endStubX, midy ]];
  459. else
  460. return [ [ endStubX, startStubY ]];
  461. }
  462. }
  463. };
  464. var p = lineCalculators[anchorOrientation + sourceAxis]();
  465. if (p) {
  466. for (var i = 0; i < p.length; i++) {
  467. addSegment(p[i][0], p[i][1], sx, sy, tx, ty);
  468. }
  469. }
  470. addSegment(endStubX, endStubY, sx, sy, tx, ty);
  471. addSegment(tx, ty, sx, sy, tx, ty);
  472. appendSegmentsToPoints();
  473. updateSegmentProportions(sx, sy, tx, ty);
  474. // adjust the max values of the canvas if we have a value that is larger than what we previously set.
  475. //
  476. if (maxY > points[3]) points[3] = maxY + (lineWidth * 2);
  477. if (maxX > points[2]) points[2] = maxX + (lineWidth * 2);
  478. return points;
  479. };
  480. /**
  481. * returns the point on the connector's path that is 'location' along the length of the path, where 'location' is a decimal from
  482. * 0 to 1 inclusive. for this connector we must first figure out which segment the given point lies in, and then compute the x,y position
  483. * from our knowledge of the segment's start and end points.
  484. */
  485. this.pointOnPath = function(location) {
  486. return self.pointAlongPathFrom(location, 0);
  487. };
  488. /**
  489. * returns the gradient of the connector at the given point; the gradient will be either 0 or Infinity, depending on the direction of the
  490. * segment the point falls in. segment gradients are calculated in the compute method.
  491. */
  492. this.gradientAtPoint = function(location) {
  493. return segments[findSegmentForLocation(location)["index"]][4];
  494. };
  495. /**
  496. * returns the point on the connector's path that is 'distance' along the length of the path from 'location', where
  497. * 'location' is a decimal from 0 to 1 inclusive, and 'distance' is a number of pixels. when you consider this concept from the point of view
  498. * of this connector, it starts to become clear that there's a problem with the overlay paint code: given that this connector makes several
  499. * 90 degree turns, it's entirely possible that an arrow overlay could be forced to paint itself around a corner, which would look stupid. this is
  500. * because jsPlumb uses this method (and pointOnPath) so determine the locations of the various points that go to make up an overlay. a better
  501. * solution would probably be to just use pointOnPath along with gradientAtPoint, and draw the overlay so that its axis ran along
  502. * a tangent to the connector. for straight line connectors this would obviously mean the overlay was painted directly on the connector, since a
  503. * tangent to a straight line is the line itself, which is what we want; for this connector, and for beziers, the results would probably be better. an additional
  504. * advantage is, of course, that there's less computation involved doing it that way.
  505. */
  506. this.pointAlongPathFrom = function(location, distance) {
  507. var s = findSegmentForLocation(location), seg = s.segment, p = s.proportion, sl = segments[s.index][5], m = segments[s.index][4];
  508. var e = {
  509. x : m == Infinity ? seg[2] : seg[2] > seg[0] ? seg[0] + ((1 - p) * sl) - distance : seg[2] + (p * sl) + distance,
  510. y : m == 0 ? seg[3] : seg[3] > seg[1] ? seg[1] + ((1 - p) * sl) - distance : seg[3] + (p * sl) + distance,
  511. segmentInfo : s
  512. };
  513. return e;
  514. };
  515. };
  516. // ********************************* END OF CONNECTOR TYPES *******************************************************************
  517. // ********************************* ENDPOINT TYPES *******************************************************************
  518. /**
  519. * Class: Endpoints.Dot
  520. * A round endpoint, with default radius 10 pixels.
  521. */
  522. /**
  523. * Function: Constructor
  524. *
  525. * Parameters:
  526. *
  527. * radius - radius of the endpoint. defaults to 10 pixels.
  528. */
  529. jsPlumb.Endpoints.Dot = function(params) {
  530. this.type = "Dot";
  531. var self = this;
  532. params = params || {};
  533. this.radius = params.radius || 10;
  534. this.defaultOffset = 0.5 * this.radius;
  535. this.defaultInnerRadius = this.radius / 3;
  536. this.compute = function(anchorPoint, orientation, endpointStyle, connectorPaintStyle) {
  537. var r = endpointStyle.radius || self.radius,
  538. x = anchorPoint[0] - r,
  539. y = anchorPoint[1] - r;
  540. return [ x, y, r * 2, r * 2, r ];
  541. };
  542. };
  543. /**
  544. * Class: Endpoints.Rectangle
  545. * A Rectangular Endpoint, with default size 20x20.
  546. */
  547. /**
  548. * Function: Constructor
  549. *
  550. * Parameters:
  551. *
  552. * width - width of the endpoint. defaults to 20 pixels.
  553. * height - height of the endpoint. defaults to 20 pixels.
  554. */
  555. jsPlumb.Endpoints.Rectangle = function(params) {
  556. this.type = "Rectangle";
  557. var self = this;
  558. params = params || {};
  559. this.width = params.width || 20;
  560. this.height = params.height || 20;
  561. this.compute = function(anchorPoint, orientation, endpointStyle, connectorPaintStyle) {
  562. var width = endpointStyle.width || self.width,
  563. height = endpointStyle.height || self.height,
  564. x = anchorPoint[0] - (width/2),
  565. y = anchorPoint[1] - (height/2);
  566. return [ x, y, width, height];
  567. };
  568. };
  569. var DOMElementEndpoint = function(params) {
  570. jsPlumb.DOMElementComponent.apply(this, arguments);
  571. var self = this;
  572. var displayElements = [ ];
  573. this.getDisplayElements = function() {
  574. return displayElements;
  575. };
  576. this.appendDisplayElement = function(el) {
  577. displayElements.push(el);
  578. };
  579. };
  580. /**
  581. * Class: Endpoints.Image
  582. * Draws an image as the Endpoint.
  583. */
  584. /**
  585. * Function: Constructor
  586. *
  587. * Parameters:
  588. *
  589. * src - location of the image to use.
  590. */
  591. jsPlumb.Endpoints.Image = function(params) {
  592. this.type = "Image";
  593. DOMElementEndpoint.apply(this, arguments);
  594. var self = this,
  595. initialized = false,
  596. widthToUse = params.width,
  597. heightToUse = params.height,
  598. _onload = null,
  599. _endpoint = params.endpoint;
  600. this.img = new Image();
  601. self.ready = false;
  602. this.img.onload = function() {
  603. self.ready = true;
  604. widthToUse = widthToUse || self.img.width;
  605. heightToUse = heightToUse || self.img.height;
  606. if (_onload) {
  607. _onload(self);
  608. }
  609. };
  610. _endpoint.setImage = function(img, onload) {
  611. var s = img.constructor == String ? img : img.src;
  612. _onload = onload;
  613. self.img.src = img;
  614. };
  615. _endpoint.setImage(params.src || params.url, params.onload);
  616. this.compute = function(anchorPoint, orientation, endpointStyle, connectorPaintStyle) {
  617. self.anchorPoint = anchorPoint;
  618. if (self.ready) return [anchorPoint[0] - widthToUse / 2, anchorPoint[1] - heightToUse / 2,
  619. widthToUse, heightToUse];
  620. else return [0,0,0,0];
  621. };
  622. self.canvas = document.createElement("img"), initialized = false;
  623. self.canvas.style["margin"] = 0;
  624. self.canvas.style["padding"] = 0;
  625. self.canvas.style["outline"] = 0;
  626. self.canvas.style["position"] = "absolute";
  627. var clazz = params.cssClass ? " " + params.cssClass : "";
  628. self.canvas.className = jsPlumb.endpointClass + clazz;
  629. if (widthToUse) self.canvas.setAttribute("width", widthToUse);
  630. if (heightToUse) self.canvas.setAttribute("height", heightToUse);
  631. jsPlumb.appendElement(self.canvas, params.parent);
  632. self.attachListeners(self.canvas, self);
  633. var actuallyPaint = function(d, style, anchor) {
  634. if (!initialized) {
  635. self.canvas.setAttribute("src", self.img.src);
  636. initialized = true;
  637. }
  638. var x = self.anchorPoint[0] - (widthToUse / 2),
  639. y = self.anchorPoint[1] - (heightToUse / 2);
  640. jsPlumb.sizeCanvas(self.canvas, x, y, widthToUse, heightToUse);
  641. };
  642. this.paint = function(d, style, anchor) {
  643. if (self.ready) {
  644. actuallyPaint(d, style, anchor);
  645. }
  646. else {
  647. window.setTimeout(function() {
  648. self.paint(d, style, anchor);
  649. }, 200);
  650. }
  651. };
  652. };
  653. /**
  654. * Class: Endpoints.Blank
  655. * An Endpoint that paints nothing (visible) on the screen. Supports cssClass and hoverClass parameters like all Endpoints.
  656. */
  657. jsPlumb.Endpoints.Blank = function(params) {
  658. var self = this;
  659. this.type = "Blank";
  660. DOMElementEndpoint.apply(this, arguments);
  661. this.compute = function(anchorPoint, orientation, endpointStyle, connectorPaintStyle) {
  662. return [anchorPoint[0], anchorPoint[1],10,0];
  663. };
  664. self.canvas = document.createElement("div");
  665. self.canvas.style.display = "block";
  666. self.canvas.style.width = "1px";
  667. self.canvas.style.height = "1px";
  668. self.canvas.style.background = "transparent";
  669. self.canvas.style.position = "absolute";
  670. self.canvas.className = self._jsPlumb.endpointClass;
  671. jsPlumb.appendElement(self.canvas, params.parent);
  672. this.paint = function(d, style, anchor) {
  673. jsPlumb.sizeCanvas(self.canvas, d[0], d[1], d[2], d[3]);
  674. };
  675. };
  676. /**
  677. * Class: Endpoints.Triangle
  678. * A triangular Endpoint.
  679. */
  680. /**
  681. * Function: Constructor
  682. *
  683. * Parameters:
  684. *
  685. * width - width of the triangle's base. defaults to 55 pixels.
  686. * height - height of the triangle from base to apex. defaults to 55 pixels.
  687. */
  688. jsPlumb.Endpoints.Triangle = function(params) {
  689. this.type = "Triangle";
  690. params = params || { };
  691. params.width = params.width || 55;
  692. params.height = params.height || 55;
  693. this.width = params.width;
  694. this.height = params.height;
  695. this.compute = function(anchorPoint, orientation, endpointStyle, connectorPaintStyle) {
  696. var width = endpointStyle.width || self.width,
  697. height = endpointStyle.height || self.height,
  698. x = anchorPoint[0] - (width/2),
  699. y = anchorPoint[1] - (height/2);
  700. return [ x, y, width, height ];
  701. };
  702. };
  703. // ********************************* END OF ENDPOINT TYPES *******************************************************************
  704. // ********************************* OVERLAY DEFINITIONS ***********************************************************************
  705. var AbstractOverlay = function(params) {
  706. var visible = true, self = this;
  707. this.isAppendedAtTopLevel = true;
  708. this.component = params.component;
  709. this.loc = params.location == null ? 0.5 : params.location;
  710. this.endpointLoc = params.endpointLocation == null ? [ 0.5, 0.5] : params.endpointLocation;
  711. this.setVisible = function(val) {
  712. visible = val;
  713. self.component.repaint();
  714. };
  715. this.isVisible = function() { return visible; };
  716. this.hide = function() { self.setVisible(false); };
  717. this.show = function() { self.setVisible(true); };
  718. this.incrementLocation = function(amount) {
  719. self.loc += amount;
  720. self.component.repaint();
  721. };
  722. this.setLocation = function(l) {
  723. self.loc = l;
  724. self.component.repaint();
  725. };
  726. this.getLocation = function() {
  727. return self.loc;
  728. };
  729. };
  730. /**
  731. * Class: Overlays.Arrow
  732. *
  733. * An arrow overlay, defined by four points: the head, the two sides of the tail, and a 'foldback' point at some distance along the length
  734. * of the arrow that lines from each tail point converge into. The foldback point is defined using a decimal that indicates some fraction
  735. * of the length of the arrow and has a default value of 0.623. A foldback point value of 1 would mean that the arrow had a straight line
  736. * across the tail.
  737. */
  738. /**
  739. * Function: Constructor
  740. *
  741. * Parameters:
  742. *
  743. * length - distance in pixels from head to tail baseline. default 20.
  744. * width - width in pixels of the tail baseline. default 20.
  745. * fillStyle - style to use when filling the arrow. defaults to "black".
  746. * strokeStyle - style to use when stroking the arrow. defaults to null, which means the arrow is not stroked.
  747. * lineWidth - line width to use when stroking the arrow. defaults to 1, but only used if strokeStyle is not null.
  748. * foldback - distance (as a decimal from 0 to 1 inclusive) along the length of the arrow marking the point the tail points should fold back to. defaults to 0.623.
  749. * location - distance (as a decimal from 0 to 1 inclusive) marking where the arrow should sit on the connector. defaults to 0.5.
  750. * direction - indicates the direction the arrow points in. valid values are -1 and 1; 1 is default.
  751. */
  752. jsPlumb.Overlays.Arrow = function(params) {
  753. this.type = "Arrow";
  754. AbstractOverlay.apply(this, arguments);
  755. this.isAppendedAtTopLevel = false;
  756. params = params || {};
  757. var self = this;
  758. this.length = params.length || 20;
  759. this.width = params.width || 20;
  760. this.id = params.id;
  761. var direction = (params.direction || 1) < 0 ? -1 : 1,
  762. paintStyle = params.paintStyle || { lineWidth:1 },
  763. // how far along the arrow the lines folding back in come to. default is 62.3%.
  764. foldback = params.foldback || 0.623;
  765. this.computeMaxSize = function() { return self.width * 1.5; };
  766. this.cleanup = function() { }; // nothing to clean up for Arrows
  767. this.draw = function(connector, currentConnectionPaintStyle, connectorDimensions) {
  768. var hxy, mid, txy, tail, cxy;
  769. if (connector.pointAlongPathFrom) {
  770. if (self.loc == 1) {
  771. hxy = connector.pointOnPath(self.loc);
  772. mid = connector.pointAlongPathFrom(self.loc, -1);
  773. txy = jsPlumb.util.pointOnLine(hxy, mid, self.length);
  774. }
  775. else if (self.loc == 0) {
  776. txy = connector.pointOnPath(self.loc);
  777. mid = connector.pointAlongPathFrom(self.loc, 1);
  778. hxy = jsPlumb.util.pointOnLine(txy, mid, self.length);
  779. }
  780. else {
  781. hxy = connector.pointAlongPathFrom(self.loc, direction * self.length / 2),
  782. mid = connector.pointOnPath(self.loc),
  783. txy = jsPlumb.util.pointOnLine(hxy, mid, self.length);
  784. }
  785. tail = jsPlumb.util.perpendicularLineTo(hxy, txy, self.width);
  786. cxy = jsPlumb.util.pointOnLine(hxy, txy, foldback * self.length);
  787. var minx = Math.min(hxy.x, tail[0].x, tail[1].x),
  788. maxx = Math.max(hxy.x, tail[0].x, tail[1].x),
  789. miny = Math.min(hxy.y, tail[0].y, tail[1].y),
  790. maxy = Math.max(hxy.y, tail[0].y, tail[1].y);
  791. var d = { hxy:hxy, tail:tail, cxy:cxy },
  792. strokeStyle = paintStyle.strokeStyle || currentConnectionPaintStyle.strokeStyle,
  793. fillStyle = paintStyle.fillStyle || currentConnectionPaintStyle.strokeStyle,
  794. lineWidth = paintStyle.lineWidth || currentConnectionPaintStyle.lineWidth;
  795. self.paint(connector, d, lineWidth, strokeStyle, fillStyle, connectorDimensions);
  796. return [ minx, maxx, miny, maxy];
  797. }
  798. else return [0,0,0,0];
  799. };
  800. };
  801. /**
  802. * Class: Overlays.PlainArrow
  803. *
  804. * A basic arrow. This is in fact just one instance of the more generic case in which the tail folds back on itself to some
  805. * point along the length of the arrow: in this case, that foldback point is the full length of the arrow. so it just does
  806. * a 'call' to Arrow with foldback set appropriately.
  807. */
  808. /**
  809. * Function: Constructor
  810. * See <Overlays.Arrow> for allowed parameters for this overlay.
  811. */
  812. jsPlumb.Overlays.PlainArrow = function(params) {
  813. params = params || {};
  814. var p = jsPlumb.extend(params, {foldback:1});
  815. jsPlumb.Overlays.Arrow.call(this, p);
  816. this.type = "PlainArrow";
  817. };
  818. /**
  819. * Class: Overlays.Diamond
  820. *
  821. * A diamond. Like PlainArrow, this is a concrete case of the more generic case of the tail points converging on some point...it just
  822. * happens that in this case, that point is greater than the length of the the arrow.
  823. *
  824. * this could probably do with some help with positioning...due to the way it reuses the Arrow paint code, what Arrow thinks is the
  825. * center is actually 1/4 of the way along for this guy. but we don't have any knowledge of pixels at this point, so we're kind of
  826. * stuck when it comes to helping out the Arrow class. possibly we could pass in a 'transpose' parameter or something. the value
  827. * would be -l/4 in this case - move along one quarter of the total length.
  828. */
  829. /**
  830. * Function: Constructor
  831. * See <Overlays.Arrow> for allowed parameters for this overlay.
  832. */
  833. jsPlumb.Overlays.Diamond = function(params) {
  834. params = params || {};
  835. var l = params.length || 40,
  836. p = jsPlumb.extend(params, {length:l/2, foldback:2});
  837. jsPlumb.Overlays.Arrow.call(this, p);
  838. this.type = "Diamond";
  839. };
  840. /**
  841. * Class: Overlays.Label
  842. * A Label overlay. For all different renderer types (SVG/Canvas/VML), jsPlumb draws a Label overlay as a styled DIV. Version 1.3.0 of jsPlumb
  843. * introduced the ability to set css classes on the label; this is now the preferred way for you to style a label. The 'labelStyle' parameter
  844. * is still supported in 1.3.0 but its usage is deprecated. Under the hood, jsPlumb just turns that object into a bunch of CSS directive that it
  845. * puts on the Label's 'style' attribute, so the end result is the same.
  846. */
  847. /**
  848. * Function: Constructor
  849. *
  850. * Parameters:
  851. * cssClass - optional css class string to append to css class. This string is appended "as-is", so you can of course have multiple classes
  852. * defined. This parameter is preferred to using labelStyle, borderWidth and borderStyle.
  853. * label - the label to paint. May be a string or a function that returns a string. Nothing will be painted if your label is null or your
  854. * label function returns null. empty strings _will_ be painted.
  855. * location - distance (as a decimal from 0 to 1 inclusive) marking where the label should sit on the connector. defaults to 0.5.
  856. *
  857. */
  858. jsPlumb.Overlays.Label = function(params) {
  859. this.type = "Label";
  860. jsPlumb.DOMElementComponent.apply(this, arguments);
  861. AbstractOverlay.apply(this, arguments);
  862. this.labelStyle = params.labelStyle || jsPlumb.Defaults.LabelStyle;
  863. this.id = params.id;
  864. this.cachedDimensions = null; // setting on 'this' rather than using closures uses a lot less memory. just don't monkey with it!
  865. var label = params.label || "",
  866. self = this,
  867. initialised = false,
  868. div = document.createElement("div"),
  869. labelText = null;
  870. div.style["position"] = "absolute";
  871. var clazz = params["_jsPlumb"].overlayClass + " " +
  872. (self.labelStyle.cssClass ? self.labelStyle.cssClass :
  873. params.cssClass ? params.cssClass : "");
  874. div.className = clazz;
  875. jsPlumb.appendElement(div, params.component.parent);
  876. jsPlumb.getId(div);
  877. self.attachListeners(div, self);
  878. self.canvas = div;
  879. //override setVisible
  880. var osv = self.setVisible;
  881. self.setVisible = function(state) {
  882. osv(state); // call superclass
  883. div.style.display = state ? "block" : "none";
  884. };
  885. this.getElement = function() {
  886. return div;
  887. };
  888. this.cleanup = function() {
  889. if (div != null) jsPlumb.CurrentLibrary.removeElement(div);
  890. };
  891. /*
  892. * Function: setLabel
  893. * sets the label's, um, label. you would think i'd call this function
  894. * 'setText', but you can pass either a Function or a String to this, so
  895. * it makes more sense as 'setLabel'.
  896. */
  897. this.setLabel = function(l) {
  898. label = l;
  899. labelText = null;
  900. self.component.repaint();
  901. };
  902. this.getLabel = function() {
  903. return label;
  904. };
  905. this.paint = function(component, d, componentDimensions) {
  906. if (!initialised) {
  907. component.appendDisplayElement(div);
  908. self.attachListeners(div, component);
  909. initialised = true;
  910. }
  911. div.style.left = (componentDimensions[0] + d.minx) + "px";
  912. div.style.top = (componentDimensions[1] + d.miny) + "px";
  913. };
  914. this.getTextDimensions = function() {
  915. if (typeof label == "function") {
  916. var lt = label(self);
  917. div.innerHTML = lt.replace(/\r\n/g, "<br/>");
  918. }
  919. else {
  920. if (labelText == null) {
  921. labelText = label;
  922. div.innerHTML = labelText.replace(/\r\n/g, "<br/>");
  923. }
  924. }
  925. var de = jsPlumb.CurrentLibrary.getElementObject(div),
  926. s = jsPlumb.CurrentLibrary.getSize(de);
  927. return {width:s[0], height:s[1]};
  928. };
  929. this.computeMaxSize = function(connector) {
  930. var td = self.getTextDimensions(connector);
  931. return td.width ? Math.max(td.width, td.height) * 1.5 : 0;
  932. };
  933. this.draw = function(component, currentConnectionPaintStyle, componentDimensions) {
  934. var td = self.getTextDimensions(component);
  935. if (td.width != null) {
  936. var cxy = {x:0,y:0};
  937. if (component.pointOnPath)
  938. cxy = component.pointOnPath(self.loc); // a connection
  939. else {
  940. var locToUse = self.loc.constructor == Array ? self.loc : self.endpointLoc;
  941. cxy = { x:locToUse[0] * componentDimensions[2],
  942. y:locToUse[1] * componentDimensions[3] };
  943. }
  944. minx = cxy.x - (td.width / 2),
  945. miny = cxy.y - (td.height / 2);
  946. self.paint(component, {
  947. minx:minx,
  948. miny:miny,
  949. td:td,
  950. cxy:cxy
  951. }, componentDimensions);
  952. return [minx, minx+td.width, miny, miny+td.height];
  953. }
  954. else return [0,0,0,0];
  955. };
  956. this.reattachListeners = function(connector) {
  957. if (div) {
  958. self.reattachListenersForElement(div, self, connector);
  959. }
  960. };
  961. };
  962. // this is really just a test overlay, so its undocumented and doesnt take any parameters. but i was loth to delete it.
  963. jsPlumb.Overlays.GuideLines = function() {
  964. var self = this;
  965. self.length = 50;
  966. self.lineWidth = 5;
  967. this.type = "GuideLines";
  968. AbstractOverlay.apply(this, arguments);
  969. jsPlumb.jsPlumbUIComponent.apply(this, arguments);
  970. this.draw = function(connector, currentConnectionPaintStyle, connectorDimensions) {
  971. var head = connector.pointAlongPathFrom(self.loc, self.length / 2),
  972. mid = connector.pointOnPath(self.loc),
  973. tail = jsPlumb.util.pointOnLine(head, mid, self.length),
  974. tailLine = jsPlumb.util.perpendicularLineTo(head, tail, 40),
  975. headLine = jsPlumb.util.perpendicularLineTo(tail, head, 20);
  976. self.paint(connector, [head, tail, tailLine, headLine], self.lineWidth, "red", null, connectorDimensions);
  977. return [Math.min(head.x, tail.x), Math.min(head.y, tail.y), Math.max(head.x, tail.x), Math.max(head.y,tail.y)];
  978. };
  979. this.computeMaxSize = function() { return 50; };
  980. this.cleanup = function() { }; // nothing to clean up for GuideLines
  981. };
  982. // ********************************* END OF OVERLAY DEFINITIONS ***********************************************************************
  983. // ********************************* OVERLAY CANVAS RENDERERS***********************************************************************
  984. // ********************************* END OF OVERLAY CANVAS RENDERERS ***********************************************************************
  985. })();