jquery.jsPlumb-defaults-1.1.0.js 16 KB

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