jsPlumb-defaults-1.2.2-RC1.js 17 KB

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