jquery.jsPlumb-defaults-1.1.1-RC1.js 17 KB

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