jsPlumb-0.0.3.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. // Array.indexOf( value, begin, strict ) - Return index of the first element that matches value
  2. if (!Array.prototype.indexOf) {
  3. Array.prototype.indexOf = function( v, b, s ) {
  4. for( var i = +b || 0, l = this.length; i < l; i++ ) {
  5. if( this[i]===v || s && this[i]==v ) { return i; }
  6. }
  7. return -1;
  8. };
  9. }
  10. (function() {
  11. var jsPlumb = window.jsPlumb = {
  12. _connections : {},
  13. _offsets : [],
  14. _sizes : [],
  15. connectorClass : '_jsPlumb_connector',
  16. endpointClass : '_jsPlumb_endpoint',
  17. DEFAULT_PAINT_STYLE : {
  18. lineWidth : 10,
  19. strokeStyle : "red"
  20. },
  21. DEFAULT_ENDPOINT_STYLE : {
  22. fillStyle : null // meaning it will be derived from the stroke style of the connector.
  23. },
  24. DEFAULT_DRAG_OPTIONS : { },
  25. DEFAULT_CONNECTOR : null,
  26. DEFAULT_ENDPOINT : null,
  27. // only used for IE; a canvas needs a size before the init call to excanvas (for some reason. no idea why.)
  28. DEFAULT_NEW_CANVAS_SIZE : 1200,
  29. /**
  30. * Places you can anchor a connection to. You can write your own one of these; you
  31. * just need to provide a 'compute' method and an 'orientation'. so you'd say something like this:
  32. *
  33. * jsPlumb.Anchors.MY_ANCHOR = {
  34. * compute : function(xy, wh) { return some mathematics on those variables; },
  35. * orientation : [ox, oy]
  36. * };
  37. *
  38. * compute takes the [x,y] position of the top left corner of the anchored element,
  39. * and the element's [width,height] (all in pixels), and returns where the anchor should
  40. * be located.
  41. *
  42. * the 'orientation' array (returned here as [ox,oy]) indicates the general direction a connection from the anchor
  43. * should go in, if possible. it is an [x,y] matrix where a value of 0 means no preference,
  44. * -1 means go in a negative direction for the given axis, and 1 means go in a positive
  45. * direction. so consider a TOP_CENTER anchor: the orientation matrix for it is [0,-1],
  46. * meaning connections naturally want to go upwards on screen. in a bezier implementation, for example,
  47. * the curve would start out going in that direction, before bending towards the target anchor.
  48. */
  49. Anchors :
  50. {
  51. TOP_CENTER : {
  52. compute : function(xy,wh, txy, twh) { return [ xy[0] + (wh[0]/2), xy[1] ]; },
  53. orientation:[0,-1]
  54. },
  55. BOTTOM_CENTER : {
  56. compute : function(xy,wh, txy, twh) { return [ xy[0] + (wh[0]/2), xy[1] + wh[1] ]; },
  57. orientation:[0,1]
  58. },
  59. LEFT_MIDDLE : {
  60. compute : function(xy,wh, txy, twh) { return [ xy[0], xy[1] + (wh[1]/2) ]; },
  61. orientation:[-1,0]
  62. },
  63. RIGHT_MIDDLE : {
  64. compute : function(xy,wh, txy, twh) { return [ xy[0] + wh[0], xy[1] + (wh[1]/2) ]; },
  65. orientation:[1,0]
  66. },
  67. CENTER : {
  68. compute : function(xy, wh, txy, twh) { return [xy[0] + (wh[0] / 2), xy[1] + (wh[1]) / 2]; },
  69. orientation:[0,0]
  70. },
  71. TOP_RIGHT : {
  72. compute : function(xy,wh, txy, twh) { return [xy[0] + wh[0], xy[1]]; },
  73. orientation:[0,-1]
  74. },
  75. BOTTOM_RIGHT : {
  76. compute : function(xy,wh, txy, twh) { return [xy[0] + wh[0], xy[1] + wh[1]]; },
  77. orientation:[0,1]
  78. },
  79. TOP_LEFT : {
  80. compute : function(xy,wh, txy, twh) { return [xy[0], xy[1]]; },
  81. orientation:[0,-1]
  82. },
  83. BOTTOM_LEFT : {
  84. compute : function(xy,wh, txy, twh) { return [xy[0], xy[1] + wh[1]]; },
  85. orientation:[0,1]
  86. }
  87. },
  88. /**
  89. * Types of connectors, eg. Straight line, bezier.
  90. */
  91. Connectors :
  92. {
  93. /**
  94. * A Connector is given a Canvas context and a source xy and target xy.
  95. * those coordinates are relative to the canvas's position.
  96. * @param ctx
  97. * @param sourceXY
  98. * @param targetXY
  99. */
  100. STRAIGHT_LINE : {
  101. /**
  102. * Computes the new size and position of the canvas.
  103. * @param sourceAnchor Absolute position on screen of the source object's anchor.
  104. * @param targetAnchor Absolute position on screen of the target object's anchor.
  105. * @param positionMatrix Indicates the relative positions of the left,top of the
  106. * two plumbed objects. so [0,0] indicates that the source is to the left of, and
  107. * above, the target. [1,0] means the source is to the right and above. [0,1] means
  108. * the source is to the left and below. [1,1] means the source is to the right
  109. * and below. this is used to figure out which direction to draw the connector in.
  110. * @returns an array of positioning information. the first two values are
  111. * the [left, top] absolute position the canvas should be placed on screen. the
  112. * next two values are the [width,height] the canvas should be. after that each
  113. * Connector can put whatever it likes into the array:it will be passed back in
  114. * to the paint call. This particular function stores the origin and destination of
  115. * the line it is going to draw. a more involved implementation, like a bezier curve,
  116. * would store the control point info in this array too.
  117. */
  118. compute : function(sourcePos, targetPos, sourceAnchor, targetAnchor) {
  119. var w = Math.abs(sourcePos[0] - targetPos[0]);
  120. var h = Math.abs(sourcePos[1] - targetPos[1]);
  121. var xo = 0.25 * w;
  122. var yo=0.25*h;
  123. w *= 1.5;
  124. h *=1.5;
  125. return [Math.min(sourcePos[0], targetPos[0]) - xo,
  126. Math.min(sourcePos[1], targetPos[1]) - yo,
  127. w,h,
  128. sourcePos[0] < targetPos[0] ? w-xo : xo,
  129. sourcePos[1] < targetPos[1] ? h-yo : yo,
  130. sourcePos[0] < targetPos[0] ? xo : w-xo,
  131. sourcePos[1] < targetPos[1] ? yo : h-yo
  132. ];
  133. },
  134. paint : function(dimensions, ctx)
  135. {
  136. ctx.beginPath();
  137. ctx.moveTo(dimensions[4], dimensions[5]);
  138. ctx.lineTo(dimensions[6], dimensions[7]);
  139. ctx.stroke();
  140. }
  141. },
  142. ORG_CHART : {
  143. compute : function(sourcePos, targetPos, sourceAnchor, targetAnchor) {
  144. var w = Math.abs(sourcePos[0] - targetPos[0]);
  145. var h = Math.abs(sourcePos[1] - targetPos[1]);
  146. var xo = 0.25 * w;
  147. var yo=0.25*h;
  148. w *= 1.5;
  149. h *=1.5;
  150. return [Math.min(sourcePos[0], targetPos[0]) - xo,
  151. Math.min(sourcePos[1], targetPos[1]) - yo,
  152. w,h,
  153. sourcePos[0] < targetPos[0] ? w-xo : xo,
  154. sourcePos[1] < targetPos[1] ? h-yo : yo,
  155. sourcePos[0] < targetPos[0] ? xo : w-xo,
  156. sourcePos[1] < targetPos[1] ? yo : h-yo
  157. ];
  158. },
  159. paint : function(dimensions, ctx)
  160. {
  161. ctx.beginPath();
  162. ctx.moveTo(dimensions[4], dimensions[5]);
  163. ctx.lineTo(dimensions[6], dimensions[7]);
  164. ctx.stroke();
  165. }
  166. },
  167. BEZIER : {
  168. _findControlPoint :function(point, anchor1Position, anchor2Position, anchor1, anchor2) {
  169. var p = [];
  170. // X
  171. if (anchor1.orientation[0] == 0) {
  172. var diff = anchor1Position[0] < anchor2Position[0] ? point[0] + 10 : point[0] - 10;
  173. p.push(diff);
  174. }
  175. else {
  176. p.push(point[0] - (150 * anchor1.orientation[0]));
  177. }
  178. // Y
  179. if (anchor1.orientation[1] == 0) {
  180. var diff = anchor1Position[1] < anchor2Position[1] ? point[1] + 10 : point[1] - 10;
  181. p.push(diff);
  182. }
  183. else p.push(point[1] + (150 * anchor2.orientation[1]));
  184. return p;
  185. },
  186. compute : function(sourcePos, targetPos, sourceAnchor, targetAnchor)
  187. {
  188. var w = Math.abs(sourcePos[0] - targetPos[0]);
  189. var h = Math.abs(sourcePos[1] - targetPos[1]);
  190. var canvasX = Math.min(sourcePos[0], targetPos[0]);
  191. var canvasY = Math.min(sourcePos[1], targetPos[1]);
  192. var sx = sourcePos[0] < targetPos[0] ? w : 0;
  193. var sy = sourcePos[1] < targetPos[1] ? h : 0;
  194. var tx = sourcePos[0] < targetPos[0] ? 0 : w;
  195. var ty = sourcePos[1] < targetPos[1] ? 0 : h;
  196. var CP = jsPlumb.Connectors.BEZIER._findControlPoint([sx,sy],
  197. sourcePos, targetPos,
  198. sourceAnchor, targetAnchor);
  199. var CP2 = jsPlumb.Connectors.BEZIER._findControlPoint([tx,ty],
  200. targetPos, sourcePos,
  201. targetAnchor, sourceAnchor);
  202. var minx1 = Math.min(sx,tx); var minx2 = Math.min(CP[0], CP2[0]); var minx = Math.min(minx1,minx2);
  203. var maxx1 = Math.max(sx,tx); var maxx2 = Math.max(CP[0], CP2[0]); var maxx = Math.max(maxx1,maxx2);
  204. if (maxx > w) w = maxx;
  205. if (minx < 0) {
  206. canvasX += minx; var ox = Math.abs(minx);
  207. w += ox; CP[0] += ox; sx += ox; tx +=ox; CP2[0] += ox;
  208. }
  209. var miny1 = Math.min(sy,ty); var miny2 = Math.min(CP[1], CP2[1]); var miny = Math.min(miny1,miny2);
  210. var maxy1 = Math.max(sy,ty); var maxy2 = Math.max(CP[1], CP2[1]); var maxy = Math.max(maxy1,maxy2);
  211. if (maxy > h) h = maxy;
  212. if (miny < 0) {
  213. canvasY += miny; var oy = Math.abs(miny);
  214. h += oy; CP[1] += oy; sy += oy; ty +=oy; CP2[1] += oy;
  215. }
  216. return [canvasX,canvasY, w,h, sx,sy,tx,ty, CP[0],CP[1],CP2[0],CP2[1] ];
  217. },
  218. paint : function(d, ctx) {
  219. ctx.beginPath();
  220. ctx.moveTo(d[4],d[5]);
  221. ctx.bezierCurveTo(d[8],d[9],d[10],d[11],d[6],d[7]);
  222. // gradient experiment.
  223. /*var g = ctx.createLinearGradient(d[4],d[5],d[6], d[7]);
  224. g.addColorStop(0,'white');
  225. g.addColorStop(1,'black');
  226. ctx.strokeStyle = g;*/
  227. ctx.stroke();
  228. }
  229. }
  230. },
  231. /**
  232. * Types of endpoint UIs. we supply only one - a circle of radius 10px. you can supply others of these if you want to.
  233. */
  234. Endpoints : {
  235. DOT : {
  236. radius : 10,
  237. paint : function(anchorPoint, canvas, endpointStyle, connectorPaintStyle) {
  238. var radius = endpointStyle.radius || jsPlumb.Endpoints.DOT.radius;
  239. var x = anchorPoint[0] - radius;
  240. var y = anchorPoint[1] - radius;
  241. jsPlumb.sizeCanvas(canvas, x, y, radius * 2, radius * 2);
  242. var ctx = canvas.getContext('2d');
  243. var style = {};
  244. jsPlumb.applyPaintStyle(style, endpointStyle);
  245. if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
  246. jsPlumb.applyPaintStyle(ctx, style);
  247. ctx.beginPath();
  248. ctx.arc(radius, radius, radius, 0, Math.PI*2, true);
  249. ctx.closePath();
  250. ctx.fill();
  251. }
  252. },
  253. RECTANGLE : {
  254. width : 20,
  255. height : 20,
  256. paint : function(anchorPoint, canvas, endpointStyle, connectorPaintStyle) {
  257. var width = endpointStyle.width || jsPlumb.Endpoints.RECTANGLE.width;
  258. var height = endpointStyle.height || jsPlumb.Endpoints.RECTANGLE.height;
  259. var x = anchorPoint[0] - (width/2);
  260. var y = anchorPoint[1] - (height/2);
  261. jsPlumb.sizeCanvas(canvas, x, y, width, height);
  262. var ctx = canvas.getContext('2d');
  263. var style = {};
  264. jsPlumb.applyPaintStyle(style, endpointStyle);
  265. if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
  266. jsPlumb.applyPaintStyle(ctx, style);
  267. ctx.beginPath();
  268. ctx.rect(0, 0, width, height);
  269. ctx.closePath();
  270. ctx.fill();
  271. }
  272. }
  273. },
  274. connect : function(params) {
  275. var jpc = new jsPlumbConnection(params);
  276. var key = jpc.sourceId + "_" + jpc.targetId;
  277. jsPlumb._connections[key] = jpc;
  278. var addToList = function(elId, jpc) {
  279. var l = jsPlumb._connections[elId];
  280. if (l == null) {
  281. l = [];
  282. jsPlumb._connections[elId] = l;
  283. }
  284. l.push(jpc);
  285. };
  286. // register this connection.
  287. addToList(jpc.sourceId, jpc);
  288. addToList(jpc.targetId, jpc);
  289. },
  290. getConnections : function(elId) {
  291. return jsPlumb._connections[elId];
  292. },
  293. drag : function(element, ui) {
  294. var id = element.attr("id");
  295. var l = jsPlumb.getConnections(id);
  296. for (var i = 0; i < l.length; i++)
  297. l[i].paint(id, ui);
  298. },
  299. detach : function(sourceId, targetId) {
  300. var jpcs = jsPlumb._connections[sourceId];
  301. var idx = -1;
  302. for (var i = 0; i < jpcs.length; i++) {
  303. if ((jpcs[i].sourceId == sourceId && jpcs[i].targetId == targetId) || (jpcs[i].targetId == sourceId && jpcs[i].sourceId == targetId)) {
  304. jsPlumb.removeCanvas(jpcs[i].canvas);
  305. if (jpcs[i].drawEndpoints) {
  306. jsPlumb.removeCanvas(jpcs[i].targetEndpointCanvas);
  307. jsPlumb.removeCanvas(jpcs[i].sourceEndpointCanvas);
  308. }
  309. idx = i;
  310. break;
  311. }
  312. }
  313. if (idx != -1)
  314. jpcs.splice(idx, 1);
  315. // todo - dragging? if no more connections for an object turn off dragging by default, but
  316. // allow an override on it?
  317. },
  318. detachAll : function(elId) {
  319. var jpcs = jsPlumb._connections[elId];
  320. for (var i = 0; i < jpcs.length; i++) {
  321. jsPlumb.removeCanvas(jpcs[i].canvas);
  322. if (jpcs[i].drawEndpoints) {
  323. jsPlumb.removeCanvas(jpcs[i].targetEndpointCanvas);
  324. jsPlumb.removeCanvas(jpcs[i].sourceEndpointCanvas);
  325. }
  326. }
  327. jsPlumb._connections[elId] = [];
  328. },
  329. hide : function(elId) {
  330. jsPlumb._setVisible(elId, "none");
  331. },
  332. show : function(elId) {
  333. jsPlumb._setVisible(elId, "block");
  334. },
  335. toggle : function(elId) {
  336. var jpcs = jsPlumb._connections[elId];
  337. if (jpcs.length > 0)
  338. jsPlumb._setVisible(elId, "none" == jpcs[0].canvas.style.display ? "block" : "none");
  339. },
  340. _setVisible : function(elId, state) {
  341. var jpcs = jsPlumb._connections[elId];
  342. for (var i = 0; i < jpcs.length; i++) {
  343. jpcs[i].canvas.style.display=state;
  344. if (jpcs[i].drawEndpoints) {
  345. jpcs[i].sourceEndpointCanvas.style.display=state;
  346. jpcs[i].targetEndpointCanvas.style.display=state;
  347. }
  348. }
  349. },
  350. /**
  351. * helper to create a canvas.
  352. * @param clazz optional class name for the canvas.
  353. */
  354. newCanvas : function(clazz) {
  355. var canvas = document.createElement("canvas");
  356. document.body.appendChild(canvas);
  357. canvas.style.position="absolute";
  358. if (clazz) { canvas.className=clazz; }
  359. if (/MSIE/.test(navigator.userAgent) && !window.opera) {
  360. // for IE we have to set a big canvas size. actually you can override this, too, if 1200 pixels
  361. // is not big enough for the biggest connector/endpoint canvas you have at startup.
  362. jsPlumb.sizeCanvas(canvas, 0, 0, jsPlumb.DEFAULT_NEW_CANVAS_SIZE, jsPlumb.DEFAULT_NEW_CANVAS_SIZE);
  363. canvas = G_vmlCanvasManager.initElement(canvas);
  364. }
  365. return canvas;
  366. },
  367. /**
  368. * helper to remove a canvas from the DOM.
  369. */
  370. removeCanvas : function(canvas) {
  371. if (canvas != null) document.body.removeChild(canvas);
  372. },
  373. /**
  374. * helper to size a canvas.
  375. */
  376. sizeCanvas : function(canvas, x, y, w, h) {
  377. canvas.style.height = h + "px"; canvas.height = h;
  378. canvas.style.width = w + "px"; canvas.width = w;
  379. canvas.style.left = x + "px"; canvas.style.top = y + "px";
  380. },
  381. /**
  382. * applies all the styles to the given context.
  383. * @param canvas
  384. * @param styles
  385. */
  386. applyPaintStyle : function(context, styles) {
  387. for (var i in styles) {
  388. context[i] = styles[i];
  389. }
  390. }
  391. };
  392. // ************** connection
  393. // ****************************************
  394. /**
  395. * allowed params:
  396. * source: source element (string or a jQuery element) (required)
  397. * target: target element (string or a jQuery element) (required)
  398. * anchors: optional array of anchor placements. defaults to BOTTOM_CENTER for source
  399. * and TOP_CENTER for target.
  400. */
  401. var jsPlumbConnection = window.jsPlumbConnection = function(params) {
  402. // ************** get the source and target and register the connection. *******************
  403. var self = this;
  404. // get source and target as jQuery objects
  405. this.source = (typeof params.source == 'string') ? $("#" + params.source) : params.source;
  406. this.target = (typeof params.target == 'string') ? $("#" + params.target) : params.target;
  407. this.sourceId = $(this.source).attr("id");
  408. this.targetId = $(this.target).attr("id");
  409. this.drawEndpoints = params.drawEndpoints != null ? params.drawEndpoints : true;
  410. this.endpointsOnTop = params.endpointsOnTop != null ? params.endpointsOnTop : true;
  411. // get anchor
  412. this.anchors = params.anchors || jsPlumb.DEFAULT_ANCHORS || [jsPlumb.Anchors.BOTTOM_CENTER, jsPlumb.Anchors.TOP_CENTER];
  413. // make connector
  414. this.connector = params.connector || jsPlumb.DEFAULT_CONNECTOR || jsPlumb.Connectors.BEZIER;
  415. this.paintStyle = params.paintStyle || jsPlumb.DEFAULT_PAINT_STYLE;
  416. // init endpoints
  417. this.endpoint = params.endpoint || jsPlumb.DEFAULT_ENDPOINT || jsPlumb.Endpoints.DOT;
  418. this.endpointStyle = params.endpointStyle || jsPlumb.DEFAULT_ENDPOINT_STYLE;
  419. jsPlumb._offsets[this.sourceId] = this.source.offset();
  420. jsPlumb._sizes[this.sourceId] = [this.source.outerWidth(), this.source.outerHeight()];
  421. jsPlumb._offsets[this.targetId] = this.target.offset();
  422. jsPlumb._sizes[this.targetId] = [this.target.outerWidth(), this.target.outerHeight()];
  423. // *************** create canvases on which the connection will be drawn ************
  424. var canvas = jsPlumb.newCanvas(jsPlumb.connectorClass);
  425. this.canvas = canvas;
  426. // create endpoint canvases
  427. if (this.drawEndpoints) {
  428. this.sourceEndpointCanvas = jsPlumb.newCanvas(jsPlumb.endpointClass);
  429. this.targetEndpointCanvas = jsPlumb.newCanvas(jsPlumb.endpointClass);
  430. // sit them on top of the underlying element?
  431. if (this.endpointsOnTop) {
  432. $(this.sourceEndpointCanvas).css("zIndex", this.source.css("zIndex") + 1);
  433. $(this.targetEndpointCanvas).css("zIndex", this.target.css("zIndex") + 1);
  434. }
  435. }
  436. // ************** store the anchors
  437. this.paint = function(elId, ui) {
  438. // if the moving object is not the source we must transpose the two references.
  439. var swap = !(elId == this.sourceId);
  440. var tId = swap ? this.sourceId : this.targetId, sId = swap ? this.targetId : this.sourceId;
  441. var tIdx = swap ? 0 : 1, sIdx = swap ? 1 : 0;
  442. if (this.canvas.getContext) {
  443. var myOffset = ui.absolutePosition;
  444. jsPlumb._offsets[elId] = myOffset;
  445. var myWH = jsPlumb._sizes[elId];
  446. var ctx = canvas.getContext('2d');
  447. var otherOffset = jsPlumb._offsets[tId];
  448. var otherWH = jsPlumb._sizes[tId];
  449. var sAnchorP = this.anchors[sIdx].compute([myOffset.left, myOffset.top], myWH, [otherOffset.left, otherOffset.top], otherWH);
  450. var tAnchorP = this.anchors[tIdx].compute([otherOffset.left, otherOffset.top], otherWH, [myOffset.left, myOffset.top], myWH);
  451. var dim = this.connector.compute(sAnchorP, tAnchorP, this.anchors[sIdx], this.anchors[tIdx]);
  452. jsPlumb.sizeCanvas(canvas, dim[0], dim[1], dim[2], dim[3]);
  453. jsPlumb.applyPaintStyle(ctx, this.paintStyle);
  454. this.connector.paint(dim, ctx);
  455. if (this.drawEndpoints) {
  456. var style = this.endpointStyle || this.paintStyle;
  457. var sourceCanvas = swap ? this.targetEndpointCanvas : this.sourceEndpointCanvas;
  458. var targetCanvas = swap ? this.sourceEndpointCanvas : this.targetEndpointCanvas;
  459. this.endpoint.paint(sAnchorP, sourceCanvas, style, this.paintStyle);
  460. this.endpoint.paint(tAnchorP, targetCanvas, style, this.paintStyle);
  461. }
  462. }
  463. };
  464. var draggable = params.draggable == null ? true : params.draggable;
  465. if (draggable) {
  466. var dragOptions = params.dragOptions || jsPlumb.DEFAULT_DRAG_OPTIONS;
  467. var dragCascade = dragOptions.drag || function(e,u) {};
  468. var initDrag = function(element, dragFunc) {
  469. var opts = {};
  470. for (var i in dragOptions) {
  471. opts[i] = dragOptions[i];
  472. }
  473. opts.drag = dragFunc;
  474. element.draggable(opts);
  475. };
  476. initDrag(this.source, function(event, ui) {
  477. jsPlumb.drag(self.source, ui);
  478. dragCascade(event, ui);
  479. });
  480. initDrag(this.target, function(event, ui) {
  481. jsPlumb.drag(self.target, ui);
  482. dragCascade(event, ui);
  483. });
  484. }
  485. var o = this.source.offset();
  486. this.paint(this.sourceId, {'absolutePosition': this.source.offset()});
  487. };
  488. })();
  489. // jQuery plugin code
  490. (function($){
  491. $.fn.plumb = function(options) {
  492. var defaults = { };
  493. var options = $.extend(defaults, options);
  494. return this.each(function()
  495. {
  496. var obj = $(this);
  497. var params = {};
  498. params.source = obj;
  499. for (var i in options) {
  500. params[i] = options[i];
  501. }
  502. jsPlumb.connect(params);
  503. });
  504. };
  505. $.fn.detach = function(options) {
  506. return this.each(function()
  507. {
  508. var id = $(this).attr("id");
  509. if (typeof options == 'string') options = [options];
  510. for (var i = 0; i < options.length; i++)
  511. jsPlumb.detach(id, options[i]);
  512. });
  513. };
  514. $.fn.detachAll = function(options) {
  515. return this.each(function()
  516. {
  517. var id = $(this).attr("id");
  518. jsPlumb.detachAll(id);
  519. });
  520. };
  521. })(jQuery);