jquery.jsPlumb-defaults-1.1.0-RC1.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. (function() {
  2. /**
  3. * Places you can anchor a connection to. These are helpers for common locations; they all just return an instance
  4. * of Anchor that has been configured appropriately.
  5. *
  6. * You can write your own one of these; you
  7. * just need to provide a 'compute' method and an 'orientation'. so you'd say something like this:
  8. *
  9. * jsPlumb.Anchors.MY_ANCHOR = {
  10. * compute : function(xy, wh, txy, twh) { return some mathematics on those variables; },
  11. * getOrientation : function() { return [ox, oy]; }
  12. * };
  13. *
  14. * compute takes the [x,y] position of the top left corner of the anchored element,
  15. * and the element's [width,height] (all in pixels), as well as the location and dimension of the element it's plumbed to,
  16. * and returns where the anchor should be located.
  17. *
  18. * the 'orientation' array (returned here as [ox,oy]) indicates the general direction a connection from the anchor
  19. * should go in, if possible. it is an [x,y] matrix where a value of 0 means no preference,
  20. * -1 means go in a negative direction for the given axis, and 1 means go in a positive
  21. * direction. so consider a TopCenter anchor: the orientation matrix for it is [0,-1],
  22. * meaning connections naturally want to go upwards on screen. in a Bezier implementation, for example,
  23. * the curve would start out going in that direction, before bending towards the target anchor.
  24. */
  25. jsPlumb.Anchors.TopCenter = jsPlumb.makeAnchor(0.5, 0, 0,-1);
  26. jsPlumb.Anchors.BottomCenter = jsPlumb.makeAnchor(0.5, 1, 0, 1);
  27. jsPlumb.Anchors.LeftMiddle = jsPlumb.makeAnchor(0, 0.5, -1, 0);
  28. jsPlumb.Anchors.RightMiddle = jsPlumb.makeAnchor(1, 0.5, 1, 0);
  29. jsPlumb.Anchors.Center = jsPlumb.makeAnchor(0.5, 0.5, 0, 0);
  30. jsPlumb.Anchors.TopRight = jsPlumb.makeAnchor(1, 0, 0,-1);
  31. jsPlumb.Anchors.BottomRight = jsPlumb.makeAnchor(1, 1, 0, 1);
  32. jsPlumb.Anchors.TopLeft = jsPlumb.makeAnchor(0, 0, 0, -1);
  33. jsPlumb.Anchors.BottomLeft = jsPlumb.makeAnchor(0, 1, 0, 1);
  34. /**
  35. * The Straight connector draws a simple straight line between the two anchor points.
  36. */
  37. jsPlumb.Connectors.Straight = function() {
  38. var self = this;
  39. /**
  40. * Computes the new size and position of the canvas.
  41. * @param sourceAnchor Absolute position on screen of the source object's anchor.
  42. * @param targetAnchor Absolute position on screen of the target object's anchor.
  43. * @param positionMatrix Indicates the relative positions of the left,top of the
  44. * two plumbed objects. so [0,0] indicates that the source is to the left of, and
  45. * above, the target. [1,0] means the source is to the right and above. [0,1] means
  46. * the source is to the left and below. [1,1] means the source is to the right
  47. * and below. this is used to figure out which direction to draw the connector in.
  48. * @returns an array of positioning information. the first two values are
  49. * the [left, top] absolute position the canvas should be placed on screen. the
  50. * next two values are the [width,height] the canvas should be. after that each
  51. * Connector can put whatever it likes into the array:it will be passed back in
  52. * to the paint call. This particular function stores the origin and destination of
  53. * the line it is going to draw. a more involved implementation, like a Bezier curve,
  54. * would store the control point info in this array too.
  55. */
  56. this.compute = function(sourcePos, targetPos, sourceAnchor, targetAnchor, lineWidth) {
  57. var w = Math.abs(sourcePos[0] - targetPos[0]);
  58. var h = Math.abs(sourcePos[1] - targetPos[1]);
  59. var widthAdjusted = false, heightAdjusted = false;
  60. // these are padding to ensure the whole connector line appears
  61. var xo = 0.45 * w, yo = 0.45 * h;
  62. // these are padding to ensure the whole connector line appears
  63. w *= 1.9; h *=1.9;
  64. var x = Math.min(sourcePos[0], targetPos[0]) - xo;
  65. var y = Math.min(sourcePos[1], targetPos[1]) - yo;
  66. if (w < 2 * lineWidth) {
  67. w = 2 * lineWidth;
  68. x = sourcePos[0] + ((targetPos[0] - sourcePos[0]) / 2) - lineWidth;
  69. xo = (w - Math.abs(sourcePos[0]-targetPos[0])) / 2;
  70. }
  71. if (h < 2 * lineWidth) {
  72. // minimum size is 2 * line Width
  73. h = 2 * lineWidth;
  74. y = sourcePos[1] + ((targetPos[1] - sourcePos[1]) / 2) - lineWidth;
  75. yo = (h - Math.abs(sourcePos[1]-targetPos[1])) / 2;
  76. }
  77. var sx = sourcePos[0] < targetPos[0] ? w-xo : xo;
  78. var sy = sourcePos[1] < targetPos[1] ? h-yo : yo;
  79. var tx = sourcePos[0] < targetPos[0] ? xo : w-xo;
  80. var ty = sourcePos[1] < targetPos[1] ? yo : h-yo;
  81. var retVal = [ x, y, w, h, sx, sy, tx, ty ];
  82. return retVal;
  83. };
  84. this.paint = function(dimensions, ctx)
  85. {
  86. ctx.beginPath();
  87. ctx.moveTo(dimensions[4], dimensions[5]);
  88. ctx.lineTo(dimensions[6], dimensions[7]);
  89. ctx.stroke();
  90. };
  91. };
  92. /**
  93. * This Connector draws a Bezier curve with two control points.
  94. * @param curviness How 'curvy' you want the curve to be! This is a directive for the
  95. * placement of control points, not endpoints of the curve, so your curve does not
  96. * actually touch the given point, but it has the tendency to lean towards it. the larger
  97. * this value, the greater the curve is pulled from a straight line.
  98. *
  99. * a future implementation of this could take the control points as arguments, rather
  100. * than fixing the curve to one basic shape.
  101. */
  102. jsPlumb.Connectors.Bezier = function(curviness) {
  103. var self = this;
  104. this.majorAnchor = curviness || 150;
  105. this.minorAnchor = 10;
  106. this._findControlPoint = function(point, sourceAnchorPosition, targetAnchorPosition, sourceAnchor, targetAnchor) {
  107. // determine if the two anchors are perpendicular to each other in their orientation. we swap the control
  108. // points around if so (code could be tightened up)
  109. var soo = sourceAnchor.getOrientation(), too = targetAnchor.getOrientation();
  110. var perpendicular = soo[0] != too[0] || soo[1] == too[1];
  111. var p = [];
  112. var ma = self.majorAnchor, mi = self.minorAnchor;
  113. if (!perpendicular) {
  114. if (soo[0] == 0) // X
  115. p.push(sourceAnchorPosition[0] < targetAnchorPosition[0] ? point[0] + mi : point[0] - mi);
  116. else p.push(point[0] - (ma * soo[0]));
  117. if (soo[1] == 0) // Y
  118. p.push(sourceAnchorPosition[1] < targetAnchorPosition[1] ? point[1] + mi : point[1] - mi);
  119. else p.push(point[1] + (ma * too[1]));
  120. }
  121. else {
  122. if (too[0] == 0) // X
  123. p.push(targetAnchorPosition[0] < sourceAnchorPosition[0] ? point[0] + mi : point[0] - mi);
  124. else p.push(point[0] + (ma * too[0]));
  125. if (too[1] == 0) // Y
  126. p.push(targetAnchorPosition[1] < sourceAnchorPosition[1] ? point[1] + mi : point[1] - mi);
  127. else p.push(point[1] + (ma * soo[1]));
  128. }
  129. return p;
  130. };
  131. this.compute = function(sourcePos, targetPos, sourceAnchor, targetAnchor, lineWidth)
  132. {
  133. lineWidth = lineWidth || 0;
  134. var w = Math.abs(sourcePos[0] - targetPos[0]) + lineWidth, h = Math.abs(sourcePos[1] - targetPos[1]) + lineWidth;
  135. var canvasX = Math.min(sourcePos[0], targetPos[0])-(lineWidth/2), canvasY = Math.min(sourcePos[1], targetPos[1])-(lineWidth/2);
  136. var sx = sourcePos[0] < targetPos[0] ? w - (lineWidth/2): (lineWidth/2), sy = sourcePos[1] < targetPos[1] ? h-(lineWidth/2) : (lineWidth/2);
  137. var tx = sourcePos[0] < targetPos[0] ? (lineWidth/2) : w-(lineWidth/2), ty = sourcePos[1] < targetPos[1] ? (lineWidth/2) : h-(lineWidth/2);
  138. var CP = self._findControlPoint([sx,sy], sourcePos, targetPos, sourceAnchor, targetAnchor);
  139. var CP2 = self._findControlPoint([tx,ty], targetPos, sourcePos, targetAnchor, sourceAnchor);
  140. var minx1 = Math.min(sx,tx); var minx2 = Math.min(CP[0], CP2[0]); var minx = Math.min(minx1,minx2);
  141. var maxx1 = Math.max(sx,tx); var maxx2 = Math.max(CP[0], CP2[0]); var maxx = Math.max(maxx1,maxx2);
  142. if (maxx > w) w = maxx;
  143. if (minx < 0) {
  144. canvasX += minx; var ox = Math.abs(minx);
  145. w += ox; CP[0] += ox; sx += ox; tx +=ox; CP2[0] += ox;
  146. }
  147. var miny1 = Math.min(sy,ty); var miny2 = Math.min(CP[1], CP2[1]); var miny = Math.min(miny1,miny2);
  148. var maxy1 = Math.max(sy,ty); var maxy2 = Math.max(CP[1], CP2[1]); var maxy = Math.max(maxy1,maxy2);
  149. if (maxy > h) h = maxy;
  150. if (miny < 0) {
  151. canvasY += miny; var oy = Math.abs(miny);
  152. h += oy; CP[1] += oy; sy += oy; ty +=oy; CP2[1] += oy;
  153. }
  154. // return [ canvasx, canvasy, canvasWidth, canvasHeight,
  155. // sourceX, sourceY, targetX, targetY,
  156. // controlPoint1_X, controlPoint1_Y, controlPoint2_X, controlPoint2_Y
  157. return [canvasX, canvasY, w, h, sx, sy, tx, ty, CP[0], CP[1], CP2[0], CP2[1] ];
  158. };
  159. this.paint = function(d, ctx) {
  160. /*var img = new Image();
  161. img.src = "../img/pattern.jpg";
  162. ctx.fillStyle = ctx.createPattern(img, 'repeat-y');*/
  163. ctx.beginPath();
  164. ctx.moveTo(d[4],d[5]);
  165. ctx.bezierCurveTo(d[8],d[9],d[10],d[11],d[6],d[7]);
  166. ctx.stroke();
  167. //ctx.fill();
  168. }
  169. };
  170. /**
  171. * Types of endpoint UIs. we supply three - a circle of default radius 10px, a rectangle of
  172. * default size 20x20, and an image (with no default). you can supply others of these if you want to - see the documentation
  173. * for a howto.
  174. */
  175. /**
  176. * a round endpoint, with default radius 10 pixels.
  177. */
  178. jsPlumb.Endpoints.Dot = function(params) {
  179. params = params || { radius:10 };
  180. var self = this;
  181. this.radius = params.radius;
  182. var defaultOffset = 0.5 * this.radius;
  183. var defaultInnerRadius = this.radius / 3;
  184. var parseValue = function(value) {
  185. try {
  186. return parseInt(value);
  187. }
  188. catch(e) {
  189. if (value.substring(value.length - 1) == '%')
  190. return parseInt(value.substring(0, value - 1));
  191. }
  192. }
  193. var calculateAdjustments = function(gradient) {
  194. var offsetAdjustment = defaultOffset;
  195. var innerRadius = defaultInnerRadius;
  196. if (gradient.offset) offsetAdjustment = parseValue(gradient.offset);
  197. if(gradient.innerRadius) innerRadius = parseValue(gradient.innerRadius);
  198. return [offsetAdjustment, innerRadius];
  199. };
  200. this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
  201. var radius = endpointStyle.radius || self.radius;
  202. var x = anchorPoint[0] - radius;
  203. var y = anchorPoint[1] - radius;
  204. jsPlumb.sizeCanvas(canvas, x, y, radius * 2, radius * 2);
  205. var ctx = canvas.getContext('2d');
  206. var style = $.extend({}, endpointStyle);
  207. if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
  208. $.extend(ctx, style);
  209. var ie = (/MSIE/.test(navigator.userAgent) && !window.opera);
  210. if (endpointStyle.gradient && !ie) {
  211. var adjustments = calculateAdjustments(endpointStyle.gradient);
  212. var yAdjust = orientation[1] == 1 ? adjustments[0] * -1 : adjustments[0];
  213. var xAdjust = orientation[0] == 1 ? adjustments[0] * -1: adjustments[0];
  214. var g = ctx.createRadialGradient(radius, radius, radius, radius + xAdjust, radius + yAdjust, adjustments[1]);
  215. for (var i = 0; i < endpointStyle.gradient.stops.length; i++)
  216. g.addColorStop(endpointStyle.gradient.stops[i][0], endpointStyle.gradient.stops[i][1]);
  217. ctx.fillStyle = g;
  218. }
  219. ctx.beginPath();
  220. ctx.arc(radius, radius, radius, 0, Math.PI*2, true);
  221. ctx.closePath();
  222. ctx.fill();
  223. };
  224. };
  225. /**
  226. * A Rectangular endpoint, with default size 20x20.
  227. */
  228. jsPlumb.Endpoints.Rectangle = function(params) {
  229. params = params || { width:20, height:20 };
  230. var self = this;
  231. this.width = params.width;
  232. this.height = params.height;
  233. this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
  234. var width = endpointStyle.width || self.width;
  235. var height = endpointStyle.height || self.height;
  236. var x = anchorPoint[0] - (width/2);
  237. var y = anchorPoint[1] - (height/2);
  238. jsPlumb.sizeCanvas(canvas, x, y, width, height);
  239. var ctx = canvas.getContext('2d');
  240. //todo: the fillStyle needs some thought. we want to support a few options:
  241. // 1. nothing supplied; use the stroke color or the default if no stroke color.
  242. // 2. a fill color supplied - use it
  243. // 3. a gradient supplied - use it
  244. // 4. setting the endpoint to the same color as the bg of the element it is attached to.
  245. var style = $.extend({}, endpointStyle);
  246. if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
  247. $.extend(ctx, style);
  248. var ie = (/MSIE/.test(navigator.userAgent) && !window.opera);
  249. if (endpointStyle.gradient && !ie) {
  250. // first figure out which direction to run the gradient in (it depends on the orientation of the anchors)
  251. var y1 = orientation[1] == 1 ? height : orientation[1] == 0 ? height / 2 : 0;
  252. var y2 = orientation[1] == -1 ? height : orientation[1] == 0 ? height / 2 : 0;
  253. var x1 = orientation[0] == 1 ? width : orientation[0] == 0 ? width / 2 : 0;
  254. var x2 = orientation[0] == -1 ? width : orientation[0] == 0 ? height / 2 : 0;
  255. var g = ctx.createLinearGradient(x1,y1,x2,y2);
  256. for (var i = 0; i < endpointStyle.gradient.stops.length; i++)
  257. g.addColorStop(endpointStyle.gradient.stops[i][0], endpointStyle.gradient.stops[i][1]);
  258. ctx.fillStyle = g;
  259. }
  260. ctx.beginPath();
  261. ctx.rect(0, 0, width, height);
  262. ctx.closePath();
  263. ctx.fill();
  264. };
  265. };
  266. /**
  267. * Image endpoint - draws an image as the endpoint. You must provide a 'url' property in the params object..
  268. */
  269. jsPlumb.Endpoints.Image = function(params) {
  270. var self = this;
  271. this.img = new Image();
  272. var ready = false;
  273. this.img.onload = function() {
  274. self.ready = true;
  275. };
  276. this.img.src = params.url;
  277. var actuallyPaint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
  278. var width = self.img.width || endpointStyle.width;
  279. var height = self.img.height || endpointStyle.height;
  280. var x = anchorPoint[0] - (width/2);
  281. var y = anchorPoint[1] - (height/2);
  282. jsPlumb.sizeCanvas(canvas, x, y, width, height);
  283. var ctx = canvas.getContext('2d');
  284. ctx.drawImage(self.img,0,0);
  285. };
  286. this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
  287. if (self.ready) {
  288. actuallyPaint(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle)
  289. }
  290. else
  291. window.setTimeout(function() {
  292. self.paint(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle);
  293. }, 200);
  294. };
  295. };
  296. })();