123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- /*
- * jsPlumb-defaults-1.2.3-RC1
- *
- * This script contains the default Anchors, Endpoints, Connectors and Overlays for jsPlumb. It should be used with jsPlumb 1.1.0 and above;
- * prior to version 1.1.0 of jsPlumb the defaults were included inside the main script.
- *
- * NOTE: for production usage you should use jsPlumb-all-x.x.x-min.js, which contains the main jsPlumb script and this script together,
- * in a minified file.
- *
- * Dual licensed under MIT and GPL2.
- */
- (function() {
- /**
- * Places you can anchor a connection to. These are helpers for common locations; they all just return an instance
- * of Anchor that has been configured appropriately.
- *
- * You can write your own one of these; you
- * just need to provide a 'compute' method and an 'orientation'. so you'd say something like this:
- *
- * jsPlumb.Anchors.MY_ANCHOR = {
- * compute : function(xy, wh, txy, twh) { return some mathematics on those variables; },
- * getOrientation : function() { return [ox, oy]; }
- * };
- *
- * compute takes the [x,y] position of the top left corner of the anchored element,
- * and the element's [width,height] (all in pixels), as well as the location and dimension of the element it's plumbed to,
- * and returns where the anchor should be located.
- *
- * the 'orientation' array (returned here as [ox,oy]) indicates the general direction a connection from the anchor
- * should go in, if possible. it is an [x,y] matrix where a value of 0 means no preference,
- * -1 means go in a negative direction for the given axis, and 1 means go in a positive
- * direction. so consider a TopCenter anchor: the orientation matrix for it is [0,-1],
- * meaning connections naturally want to go upwards on screen. in a Bezier implementation, for example,
- * the curve would start out going in that direction, before bending towards the target anchor.
- */
- jsPlumb.Anchors.TopCenter = jsPlumb.makeAnchor(0.5, 0, 0,-1);
- jsPlumb.Anchors.BottomCenter = jsPlumb.makeAnchor(0.5, 1, 0, 1);
- jsPlumb.Anchors.LeftMiddle = jsPlumb.makeAnchor(0, 0.5, -1, 0);
- jsPlumb.Anchors.RightMiddle = jsPlumb.makeAnchor(1, 0.5, 1, 0);
- jsPlumb.Anchors.Center = jsPlumb.makeAnchor(0.5, 0.5, 0, 0);
- jsPlumb.Anchors.TopRight = jsPlumb.makeAnchor(1, 0, 0,-1);
- jsPlumb.Anchors.BottomRight = jsPlumb.makeAnchor(1, 1, 0, 1);
- jsPlumb.Anchors.TopLeft = jsPlumb.makeAnchor(0, 0, 0, -1);
- jsPlumb.Anchors.BottomLeft = jsPlumb.makeAnchor(0, 1, 0, 1);
- jsPlumb.Anchors.AutoDefault = function() { return jsPlumb.makeDynamicAnchor([jsPlumb.Anchors.TopCenter, jsPlumb.Anchors.RightMiddle, jsPlumb.Anchors.BottomCenter, jsPlumb.Anchors.LeftMiddle]); };
-
- jsPlumb.Defaults.DynamicAnchors = [jsPlumb.Anchors.TopCenter, jsPlumb.Anchors.RightMiddle, jsPlumb.Anchors.BottomCenter, jsPlumb.Anchors.LeftMiddle];
-
- /**
- * The Straight connector draws a simple straight line between the two anchor points.
- */
- jsPlumb.Connectors.Straight = function() {
-
- var self = this;
- var currentPoints = null;
- var _m, _m2, _b, _dx, _dy, _theta, _theta2, _sx, _sy, _tx, _ty;
- /**
- * Computes the new size and position of the canvas.
- * @param sourceAnchor Absolute position on screen of the source object's anchor.
- * @param targetAnchor Absolute position on screen of the target object's anchor.
- * @param positionMatrix Indicates the relative positions of the left,top of the
- * two plumbed objects. so [0,0] indicates that the source is to the left of, and
- * above, the target. [1,0] means the source is to the right and above. [0,1] means
- * the source is to the left and below. [1,1] means the source is to the right
- * and below. this is used to figure out which direction to draw the connector in.
- * @returns an array of positioning information. the first two values are
- * the [left, top] absolute position the canvas should be placed on screen. the
- * next two values are the [width,height] the canvas should be. after that each
- * Connector can put whatever it likes into the array:it will be passed back in
- * to the paint call. This particular function stores the origin and destination of
- * the line it is going to draw. a more involved implementation, like a Bezier curve,
- * would store the control point info in this array too.
- */
- this.compute = function(sourcePos, targetPos, sourceAnchor, targetAnchor, lineWidth, minWidth) {
- var w = Math.abs(sourcePos[0] - targetPos[0]);
- var h = Math.abs(sourcePos[1] - targetPos[1]);
- var widthAdjusted = false, heightAdjusted = false;
- // these are padding to ensure the whole connector line appears
- var xo = 0.45 * w, yo = 0.45 * h;
- // these are padding to ensure the whole connector line appears
- w *= 1.9; h *=1.9;
-
- var x = Math.min(sourcePos[0], targetPos[0]) - xo;
- var y = Math.min(sourcePos[1], targetPos[1]) - yo;
-
- // minimum size is 2 * line Width if minWidth was not given.
- var calculatedMinWidth = Math.max(2 * lineWidth, minWidth);
-
- if (w < calculatedMinWidth) {
- w = calculatedMinWidth;
- x = sourcePos[0] + ((targetPos[0] - sourcePos[0]) / 2) - (calculatedMinWidth / 2);
- xo = (w - Math.abs(sourcePos[0]-targetPos[0])) / 2;
- }
- if (h < calculatedMinWidth) {
-
- h = calculatedMinWidth;
- y = sourcePos[1] + ((targetPos[1] - sourcePos[1]) / 2) - (calculatedMinWidth / 2);
- yo = (h - Math.abs(sourcePos[1]-targetPos[1])) / 2;
- }
-
- _sx = sourcePos[0] < targetPos[0] ? xo : w-xo;
- _sy = sourcePos[1] < targetPos[1] ? yo:h-yo;
- _tx = sourcePos[0] < targetPos[0] ? w-xo : xo;
- _ty = sourcePos[1] < targetPos[1] ? h-yo : yo;
- currentPoints = [ x, y, w, h, _sx, _sy, _tx, _ty ];
-
- _dx = _tx - _sx, _dy = (_ty - _sy);
- _m = _dy / _dx, _m2 = -1 / _m;
- _b = -1 * ((_m * _sx) - _sy);
- _theta = Math.atan(_m); _theta2 = Math.atan(_m2);
-
- return currentPoints;
- };
- this.paint = function(dimensions, ctx)
- {
- ctx.beginPath();
- ctx.moveTo(dimensions[4], dimensions[5]);
- ctx.lineTo(dimensions[6], dimensions[7]);
- ctx.stroke();
- };
-
- /**
- * returns the point on the connector's path that is 'location' along the length of the path, where 'location' is a decimal from
- * 0 to 1 inclusive. for the straight line connector this is simple maths. for Bezier, not so much.
- */
- this.pointOnPath = function(location) {
- var xp = _sx + (location * _dx);
- var yp = _m == Infinity ? xp + _b : (_m * xp) + _b;
- return [xp, yp];
- };
-
- /**
- * returns the gradient of the connector at the given point - which for us is constant.
- */
- this.gradientAtPoint = function(location) { return _m; };
-
- /**
- * returns the point on the connector's path that is 'distance' along the length of the path from 'location', where
- * 'location' is a decimal from 0 to 1 inclusive, and 'distance' is a number of pixels.
- */
- this.pointAlongPathFrom = function(location, distance) {
- var p = self.pointOnPath(location);
- var orientation = distance > 0 ? 1 : -1;
- var y = Math.abs(distance * Math.sin(_theta));
- if (_sy > _ty) y = y * -1;
- var x = Math.abs(distance * Math.cos(_theta));
- if (_sx > _tx) x = x * -1;
- return [p[0] + (orientation * x), p[1] + (orientation * y)];
- };
-
- /**
- * calculates a line that is perpendicular to, and centered on, the path at 'distance' pixels from the given location.
- * the line is 'length' pixels long.
- */
- this.perpendicularToPathAt = function(location, distance, length) {
- var p = self.pointAlongPathFrom(location, distance);
- var m = self.gradientAtPoint(p.location);
- var _theta2 = Math.atan(-1 / m);
- var y = length / 2 * Math.sin(_theta2);
- var x = length / 2 * Math.cos(_theta2);
- return [[p[0] + x, p[1] + y], [p[0] - x, p[1] - y]];
- };
-
- this.createGradient = function(dim, ctx) {
- return ctx.createLinearGradient(dim[4], dim[5], dim[6], dim[7]);
- };
- };
-
- /**
- * This Connector draws a Bezier curve with two control points.
- * @param curviness How 'curvy' you want the curve to be! This is a directive for the
- * placement of control points, not endpoints of the curve, so your curve does not
- * actually touch the given point, but it has the tendency to lean towards it. the larger
- * this value, the greater the curve is pulled from a straight line.
- *
- * a future implementation of this could take the control points as arguments, rather
- * than fixing the curve to one basic shape.
- */
- jsPlumb.Connectors.Bezier = function(curviness) {
- var self = this;
- this.majorAnchor = curviness || 150;
- this.minorAnchor = 10;
- var currentPoints = null;
-
- this._findControlPoint = function(point, sourceAnchorPosition, targetAnchorPosition, sourceAnchor, targetAnchor) {
- // determine if the two anchors are perpendicular to each other in their orientation. we swap the control
- // points around if so (code could be tightened up)
- var soo = sourceAnchor.getOrientation(), too = targetAnchor.getOrientation();
- var perpendicular = soo[0] != too[0] || soo[1] == too[1];
- var p = [];
- var ma = self.majorAnchor, mi = self.minorAnchor;
- if (!perpendicular) {
- if (soo[0] == 0) // X
- p.push(sourceAnchorPosition[0] < targetAnchorPosition[0] ? point[0] + mi : point[0] - mi);
- else p.push(point[0] - (ma * soo[0]));
-
- if (soo[1] == 0) // Y
- p.push(sourceAnchorPosition[1] < targetAnchorPosition[1] ? point[1] + mi : point[1] - mi);
- else p.push(point[1] + (ma * too[1]));
- }
- else {
- if (too[0] == 0) // X
- p.push(targetAnchorPosition[0] < sourceAnchorPosition[0] ? point[0] + mi : point[0] - mi);
- else p.push(point[0] + (ma * too[0]));
-
- if (too[1] == 0) // Y
- p.push(targetAnchorPosition[1] < sourceAnchorPosition[1] ? point[1] + mi : point[1] - mi);
- else p.push(point[1] + (ma * soo[1]));
- }
- return p;
- };
- var _CP, _CP2, _sx, _tx, _sx, _sy, _canvasX, _canvasY, _w, _h;
- this.compute = function(sourcePos, targetPos, sourceAnchor, targetAnchor, lineWidth, minWidth)
- {
- lineWidth = lineWidth || 0;
- _w = Math.abs(sourcePos[0] - targetPos[0]) + lineWidth;
- _h = Math.abs(sourcePos[1] - targetPos[1]) + lineWidth;
- _canvasX = Math.min(sourcePos[0], targetPos[0])-(lineWidth/2);
- _canvasY = Math.min(sourcePos[1], targetPos[1])-(lineWidth/2);
- _sx = sourcePos[0] < targetPos[0] ? _w - (lineWidth/2): (lineWidth/2);
- _sy = sourcePos[1] < targetPos[1] ? _h - (lineWidth/2) : (lineWidth/2);
- _tx = sourcePos[0] < targetPos[0] ? (lineWidth/2) : _w - (lineWidth/2);
- _ty = sourcePos[1] < targetPos[1] ? (lineWidth/2) : _h - (lineWidth/2);
- _CP = self._findControlPoint([_sx,_sy], sourcePos, targetPos, sourceAnchor, targetAnchor);
- _CP2 = self._findControlPoint([_tx,_ty], targetPos, sourcePos, targetAnchor, sourceAnchor);
- var minx1 = Math.min(_sx,_tx); var minx2 = Math.min(_CP[0], _CP2[0]); var minx = Math.min(minx1,minx2);
- var maxx1 = Math.max(_sx,_tx); var maxx2 = Math.max(_CP[0], _CP2[0]); var maxx = Math.max(maxx1,maxx2);
-
- if (maxx > _w) _w = maxx;
- if (minx < 0) {
- _canvasX += minx; var ox = Math.abs(minx);
- _w += ox; _CP[0] += ox; _sx += ox; _tx +=ox; _CP2[0] += ox;
- }
- var miny1 = Math.min(_sy,_ty); var miny2 = Math.min(_CP[1], _CP2[1]); var miny = Math.min(miny1,miny2);
- var maxy1 = Math.max(_sy,_ty); var maxy2 = Math.max(_CP[1], _CP2[1]); var maxy = Math.max(maxy1,maxy2);
- if (maxy > _h) _h = maxy;
- if (miny < 0) {
- _canvasY += miny; var oy = Math.abs(miny);
- _h += oy; _CP[1] += oy; _sy += oy; _ty +=oy; _CP2[1] += oy;
- }
-
- if (minWidth && _w < minWidth) {
- var posAdjust = (minWidth - _w) / 2;
- _w = minWidth;
- _canvasX -= posAdjust; _sx = _sx + posAdjust ; _tx = _tx + posAdjust; _CP[0] = _CP[0] + posAdjust; _CP2[0] = _CP2[0] + posAdjust;
- }
- currentPoints = [_canvasX, _canvasY, _w, _h, _sx, _sy, _tx, _ty, _CP[0], _CP[1], _CP2[0], _CP2[1] ];
- return currentPoints;
- };
- this.paint = function(d, ctx) {
- ctx.beginPath();
- ctx.moveTo(d[4],d[5]);
- ctx.bezierCurveTo(d[8],d[9],d[10],d[11],d[6],d[7]);
- ctx.stroke();
- };
-
- /**
- * returns the distance the given point is from the curve. not enabled for 1.2.3. didnt make the cut. next time.
- *
- this.distanceFrom = function(point) {
- var curve = [ {x:currentPoints[4], y:currentPoints[5]},
- {x:currentPoints[8], y:currentPoints[9]},
- {x:currentPoints[10], y:currentPoints[11]},
- {x:currentPoints[6], y:currentPoints[7]}];
- return (jsPlumb.DistanceFromCurve(point, curve));
- };*/
-
- var _quadraticPointOnPath = function(location) {
- function B1(t) { return t*t; };
- function B2(t) { return 2*t*(1-t); };
- function B3(t) { return (1-t)*(1-t); };
- var x = _sx*B1(location) + _CP[0]*B2(location) + _CP2[0]*B3(location);
- var y = _sy*B1(location) + _CP[1]*B2(location) + _CP2[1]*B3(location);
- return [x,y];
- };
-
- /**
- * returns the point on the connector's path that is 'location' along the length of the path, where 'location' is a decimal from
- * 0 to 1 inclusive. for the straight line connector this is simple maths. for Bezier, not so much.
- */
- this.pointOnPath = function(location) {
-
- // from http://13thparallel.com/archive/bezier-curves/
- function B1(t) { return t*t*t };
- function B2(t) { return 3*t*t*(1-t) };
- function B3(t) { return 3*t*(1-t)*(1-t) };
- function B4(t) { return (1-t)*(1-t)*(1-t) };
- var x = _sx*B1(location) + _CP[0]*B2(location) + _CP2[0]*B3(location) + _tx*B4(location);
- var y = _sy*B1(location) + _CP[1]*B2(location) + _CP2[1]*B3(location) + _ty*B4(location);
- return [x,y];
- };
-
- /**
- * returns the gradient of the connector at the given point.
- */
- this.gradientAtPoint = function(location) {
- var p1 = self.pointOnPath(location);
- var p2 = _quadraticPointOnPath(location);
- var dy = p2[1] - p1[1], dx = p2[0] - p1[0];
- var rtn = Math.atan(dy / dx) ;
- // http://bimixual.org/AnimationLibrary/beziertangents.html
- return rtn;
- };
-
- /**
- * finds the point that is 'distance' along the path from 'location'. this method returns both the x,y location of the point and also
- * its 'location' (proportion of travel along the path).
- */
- var _pointAlongPath = function(location, distance) {
- var _dist = function(p1,p2) { return Math.sqrt(Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2)); };
- var prev = self.pointOnPath(location), tally = 0, curLoc = location, direction = distance > 0 ? 1 : -1, cur = null;
- while (tally < Math.abs(distance)) {
- curLoc += (0.005 * direction);
- cur = self.pointOnPath(curLoc);
- tally += _dist(cur, prev);
- prev = cur;
- }
- return {point:cur, location:curLoc};
- };
-
- /**
- * for Bezier curves this method is a little tricky, cos calculating path distance algebraically is notoriously difficult.
- * this method is iterative, jumping forward .05% of the path at a time and summing the distance between this point and the previous
- * one, until the sum reaches 'distance'. the method may turn out to be computationally expensive; we'll see.
- * another drawback of this method is that if the connector gets quite long, .05% of the length of it is not necessarily smaller
- * than the desired distance, in which case the loop returns immediately and the arrow is mis-shapen. so a better strategy might be to
- * calculate the step as a function of distance/distance between endpoints.
- */
- this.pointAlongPathFrom = function(location, distance) {
- return _pointAlongPath(location, distance).point;
- };
-
- /**
- * calculates a line that is perpendicular to, and centered on, the path at 'distance' pixels from the given location.
- * the line is 'length' pixels long.
- */
- this.perpendicularToPathAt = function(location, distance, length) {
- var p = _pointAlongPath(location, distance);
- var m = self.gradientAtPoint(p.location);
- var _theta2 = Math.atan(-1 / m);
- var y = length / 2 * Math.sin(_theta2);
- var x = length / 2 * Math.cos(_theta2);
- return [[p.point[0] + x, p.point[1] + y], [p.point[0] - x, p.point[1] - y]];
- };
-
- this.createGradient = function(dim, ctx, swap) {
- return (swap) ? ctx.createLinearGradient(dim[4], dim[5], dim[6], dim[7]) : ctx.createLinearGradient(dim[6], dim[7], dim[4], dim[5]);
- };
- };
-
-
- /**
- * Types of endpoint UIs. we supply four - a circle of default radius 10px, a rectangle of
- * default size 20x20, an image (with no default), and a Triangle, of default size 15.
- * you can supply others of these if you want to - see the documentation for a howto.
- */
-
- /**
- * a round endpoint, with default radius 10 pixels.
- */
- jsPlumb.Endpoints.Dot = function(params) {
-
- params = params || { radius:10 };
- var self = this;
- this.radius = params.radius;
- var defaultOffset = 0.5 * this.radius;
- var defaultInnerRadius = this.radius / 3;
-
- var parseValue = function(value) {
- try {
- return parseInt(value);
- }
- catch(e) {
- if (value.substring(value.length - 1) == '%')
- return parseInt(value.substring(0, value - 1));
- }
- }
-
- var calculateAdjustments = function(gradient) {
- var offsetAdjustment = defaultOffset;
- var innerRadius = defaultInnerRadius;
- if (gradient.offset) offsetAdjustment = parseValue(gradient.offset);
- if(gradient.innerRadius) innerRadius = parseValue(gradient.innerRadius);
- return [offsetAdjustment, innerRadius];
- };
-
- this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
- var radius = endpointStyle.radius || self.radius;
- var x = anchorPoint[0] - radius;
- var y = anchorPoint[1] - radius;
- jsPlumb.sizeCanvas(canvas, x, y, radius * 2, radius * 2);
- var ctx = canvas.getContext('2d');
- var style = jsPlumb.extend({}, endpointStyle);
- if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
- jsPlumb.extend(ctx, style);
-
- var ie = (/MSIE/.test(navigator.userAgent) && !window.opera);
- if (endpointStyle.gradient && !ie) {
-
- var adjustments = calculateAdjustments(endpointStyle.gradient);
- var yAdjust = orientation[1] == 1 ? adjustments[0] * -1 : adjustments[0];
- var xAdjust = orientation[0] == 1 ? adjustments[0] * -1: adjustments[0];
- var g = ctx.createRadialGradient(radius, radius, radius, radius + xAdjust, radius + yAdjust, adjustments[1]);
- for (var i = 0; i < endpointStyle.gradient.stops.length; i++)
- g.addColorStop(endpointStyle.gradient.stops[i][0], endpointStyle.gradient.stops[i][1]);
- ctx.fillStyle = g;
- }
-
- ctx.beginPath();
- ctx.arc(radius, radius, radius, 0, Math.PI*2, true);
- ctx.closePath();
- ctx.fill();
- };
- };
-
- /**
- * A Rectangular endpoint, with default size 20x20.
- */
- jsPlumb.Endpoints.Rectangle = function(params) {
-
- params = params || { width:20, height:20 };
- var self = this;
- this.width = params.width;
- this.height = params.height;
-
- this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
- var width = endpointStyle.width || self.width;
- var height = endpointStyle.height || self.height;
- var x = anchorPoint[0] - (width/2);
- var y = anchorPoint[1] - (height/2);
- jsPlumb.sizeCanvas(canvas, x, y, width, height);
- var ctx = canvas.getContext('2d');
- var style = jsPlumb.extend({}, endpointStyle);
- if (style.fillStyle == null) style.fillStyle = connectorPaintStyle.strokeStyle;
- jsPlumb.extend(ctx, style);
-
- var ie = (/MSIE/.test(navigator.userAgent) && !window.opera);
- if (endpointStyle.gradient && !ie) {
- // first figure out which direction to run the gradient in (it depends on the orientation of the anchors)
- var y1 = orientation[1] == 1 ? height : orientation[1] == 0 ? height / 2 : 0;
- var y2 = orientation[1] == -1 ? height : orientation[1] == 0 ? height / 2 : 0;
- var x1 = orientation[0] == 1 ? width : orientation[0] == 0 ? width / 2 : 0;
- var x2 = orientation[0] == -1 ? width : orientation[0] == 0 ? height / 2 : 0;
- var g = ctx.createLinearGradient(x1,y1,x2,y2);
- for (var i = 0; i < endpointStyle.gradient.stops.length; i++)
- g.addColorStop(endpointStyle.gradient.stops[i][0], endpointStyle.gradient.stops[i][1]);
- ctx.fillStyle = g;
- }
-
- ctx.beginPath();
- ctx.rect(0, 0, width, height);
- ctx.closePath();
- ctx.fill();
- };
- };
-
- jsPlumb.Endpoints.Triangle = function(params) {
-
- params = params || { width:15, height:15 };
- var self = this;
- this.width = params.width;
- this.height = params.height;
-
- this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle)
- {
- var width = endpointStyle.width || self.width;
- var height = endpointStyle.height || self.height;
- var x = anchorPoint[0] - width/2;
- var y = anchorPoint[1] - height/2;
-
- jsPlumb.sizeCanvas(canvas, x, y, width, height);
-
- var ctx = canvas.getContext('2d');
- var offsetX = 0, offsetY = 0, angle = 0;
-
- if( orientation[0] == 1 )
- {
- offsetX = width;
- offsetY = height;
- angle = 180;
- }
- if( orientation[1] == -1 )
- {
- offsetX = width;
- angle = 90;
- }
- if( orientation[1] == 1 )
- {
- offsetY = height;
- angle = -90;
- }
-
- ctx.fillStyle = endpointStyle.fillStyle;
-
- ctx.translate(offsetX, offsetY);
- ctx.rotate(angle * Math.PI/180);
- ctx.beginPath();
- ctx.moveTo(0, 0);
- ctx.lineTo(width/2, height/2);
- ctx.lineTo(0, height);
- ctx.closePath();
- ctx.fill();
- };
- };
-
- /**
- * Image endpoint - draws an image as the endpoint. You must provide a 'url' property in the params object..
- */
- jsPlumb.Endpoints.Image = function(params) {
- var self = this;
- this.img = new Image();
- var ready = false;
- this.img.onload = function() {
- self.ready = true;
- };
- this.img.src = params.url;
-
- var actuallyPaint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
- var width = self.img.width || endpointStyle.width;
- var height = self.img.height || endpointStyle.height;
- var x = anchorPoint[0] - (width/2);
- var y = anchorPoint[1] - (height/2);
- jsPlumb.sizeCanvas(canvas, x, y, width, height);
- var ctx = canvas.getContext('2d');
- ctx.drawImage(self.img,0,0);
- };
-
- this.paint = function(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle) {
- if (self.ready) {
- actuallyPaint(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle)
- }
- else
- window.setTimeout(function() {
- self.paint(anchorPoint, orientation, canvas, endpointStyle, connectorPaintStyle);
- }, 200);
- };
- };
-
- /**
- * An arrow overlay. you can provide:
- *
- * length - distance in pixels from head to tail baseline. default 20.
- * width - width in pixels of the tail baseline. default 20.
- * fillStyle - style to use when filling the arrow. defaults to "black".
- * strokeStyle - style to use when stroking the arrow. defaults to null, which means the arrow is not stroked.
- * lineWidth - line width to use when stroking the arrow. defaults to 1, but only used if strokeStyle is not null.
- * foldback - distance (as a decimal from 0 to 1 inclusive) along the length of the arrow marking the point the tail points should fold back to. defaults to 0.623.
- * location - distance (as a decimal from 0 to 1 inclusive) marking where the arrow should sit on the connector. defaults to 0.5.
- */
- jsPlumb.Overlays.Arrow = function(params) {
- params = params || {};
- var self = this;
- var length = params.length || 20;
- var width = params.width || 20;
- var fillStyle = params.fillStyle || "black";
- var strokeStyle = params.strokeStyle;
- var lineWidth = params.lineWidth || 1;
- this.loc = params.location || 0.5;
- // how far along the arrow the lines folding back in come to. default is 62.3%.
- var foldback = params.foldback || 0.623;
- var _getFoldBackPoint = function(connector, loc) {
- if (foldback == 0.5) return connector.pointOnPath(loc);
- else {
- var adj = 0.5 - foldback; // we calculate relative to the center
- return connector.pointAlongPathFrom(loc, length * adj);
- }
- };
-
- this.computeMaxSize = function() { return width * 1.5; }
-
- this.draw = function(connector, ctx) {
- // this is the arrow head position
- var hxy = connector.pointAlongPathFrom(self.loc, length / 2);
- // this is the center of the tail
- var txy = connector.pointAlongPathFrom(self.loc, -length / 2), tx = txy[0], ty = txy[1];
- // this is the tail vector
- var tail = connector.perpendicularToPathAt(self.loc, -length / 2, width);
- // this is the point the tail goes in to
- var cxy = _getFoldBackPoint(connector, self.loc);
-
- ctx.lineWidth = lineWidth;
- ctx.beginPath();
- ctx.moveTo(hxy[0], hxy[1]);
- ctx.lineTo(tail[0][0], tail[0][1]);
- ctx.lineTo(cxy[0], cxy[1]);
- ctx.lineTo(tail[1][0], tail[1][1]);
- ctx.lineTo(hxy[0], hxy[1]);
- ctx.closePath();
-
- if (strokeStyle) {
- ctx.strokeStyle = strokeStyle;
- ctx.stroke();
- }
- ctx.fillStyle = fillStyle;
- ctx.fill();
- }
- };
-
- /**
- * a basic arrow. this is in fact just one instance of the more generic case in which the tail folds back on itself to some
- * point along the length of the arrow: in this case, that foldback point is the full length of the arrow. so it just does
- * a 'call' to Arrow with foldback set appropriately. See Arrow for params.
- */
- jsPlumb.Overlays.PlainArrow = function(params) {
- params = params || {};
- var p = jsPlumb.extend(params, {foldback:1});
- jsPlumb.Overlays.Arrow.call(this, p);
- };
-
- /**
- * a diamond. like PlainArrow, this is a concrete case of the more generic case of the tail points converging on some point...it just
- * happens that in this case, that point is greater than the length of the the arrow. See Arrow for params.
- *
- * this could probably do with some help with positioning...due to the way it reuses the Arrow paint code, what Arrow thinks is the
- * center is actually 1/4 of the way along for this guy. but we don't have any knowledge of pixels at this point, so we're kind of
- * stuck when it comes to helping out the Arrow class. possibly we could pass in a 'transpose' parameter or something. the value
- * would be -l/4 in this case - move along one quarter of the total length.
- */
- jsPlumb.Overlays.Diamond = function(params) {
- params = params || {};
- var l = params.length || 40;
- var p = jsPlumb.extend(params, {length:l/2, foldback:2});
- jsPlumb.Overlays.Arrow.call(this, p);
- };
-
- /**
- * A Label overlay. Params you can provide:
- *
- * labelStyle - js object containing style instructions for the label. defaults to jsPlumb.Defaults.LabelStyle.
- * label - the label to paint. may be a string or a function that returns a string. nothing will be painted if your label is null or your
- * label function returns null. empty strings _will_ be painted.
- * location - distance (as a decimal from 0 to 1 inclusive) marking where the label should sit on the connector. defaults to 0.5.
- * borderWidth - width of a border to paint. defaults to zero.
- * borderStyle - strokeStyle to use when painting the border, if necessary.
- */
- jsPlumb.Overlays.Label = function(params) {
- this.labelStyle = params.labelStyle || jsPlumb.Defaults.LabelStyle;
- this.label = params.label;
- var self = this;
- var labelWidth = null, labelHeight = null, labelText = null, labelPadding = null;
- this.location = params.location || 0.5;
- this.computeMaxSize = function(connector, ctx) {
- if (labelText) {
- ctx.save();
- if (self.labelStyle.font) ctx.font = self.labelStyle.font;
- var t = ctx.measureText(labelText).width;
- // a fake text height measurement: use the width of upper case M
- var h = ctx.measureText("M").width;
- labelPadding = self.labelStyle.padding || 0.25;
- labelWidth = t + (2 * t * labelPadding);
- labelHeight = h + (2 * h * labelPadding);
- ctx.restore();
- return Math.max(labelWidth, labelHeight) * 1.5;
- }
- return 0;
- };
- this.draw = function(connector, ctx) {
- // we allow label generation by a function here. you get given the Connection object as an argument.
- labelText = typeof self.label == 'function' ? self.label(self) : self.label;
- if (labelText) {
- if (self.labelStyle.font) ctx.font = self.labelStyle.font;
- var t = ctx.measureText(labelText).width;
- // a fake text height measurement: use the width of upper case M
- var h = ctx.measureText("M").width;
- labelPadding = self.labelStyle.padding || 0.25;
- labelWidth = t + (2 * t * labelPadding);
- labelHeight = h + (2 * h * labelPadding);
- var cxy = connector.pointOnPath(self.location);
- if (self.labelStyle.font) ctx.font = self.labelStyle.font;
- if (self.labelStyle.fillStyle)
- ctx.fillStyle = self.labelStyle.fillStyle;
- else
- ctx.fillStyle = "rgba(0,0,0,0)";
- ctx.fillRect(cxy[0] - (labelWidth / 2), cxy[1] - (labelHeight / 2) , labelWidth , labelHeight );
-
- if (self.labelStyle.color) ctx.fillStyle = self.labelStyle.color;
- ctx.textBaseline = "middle";
- ctx.textAlign = "center";
- ctx.fillText(labelText, cxy[0], cxy[1]);
-
- // border
- if (self.labelStyle.borderWidth > 0) {
- ctx.strokeStyle = self.labelStyle.borderStyle || "black";
- ctx.strokeRect(cxy[0] - (labelWidth / 2), cxy[1] - (labelHeight / 2) , labelWidth , labelHeight );
- }
- }
- };
- };
- })();
|