123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- ;(function() {
-
- // ********************************* CANVAS RENDERERS FOR CONNECTORS AND ENDPOINTS *******************************************************************
-
- // TODO refactor to renderer common script. put a ref to jsPlumb.sizeCanvas in there too.
- var _connectionBeingDragged = null,
- _getAttribute = function(el, attName) { return jsPlumb.CurrentLibrary.getAttribute(_getElementObject(el), attName); },
- _setAttribute = function(el, attName, attValue) { jsPlumb.CurrentLibrary.setAttribute(_getElementObject(el), attName, attValue); },
- _addClass = function(el, clazz) { jsPlumb.CurrentLibrary.addClass(_getElementObject(el), clazz); },
- _hasClass = function(el, clazz) { return jsPlumb.CurrentLibrary.hasClass(_getElementObject(el), clazz); },
- _removeClass = function(el, clazz) { jsPlumb.CurrentLibrary.removeClass(_getElementObject(el), clazz); },
- _getElementObject = function(el) { return jsPlumb.CurrentLibrary.getElementObject(el); },
- _getOffset = function(el) { return jsPlumb.CurrentLibrary.getOffset(_getElementObject(el)); },
- _getSize = function(el) { return jsPlumb.CurrentLibrary.getSize(_getElementObject(el)); },
- _pageXY = function(el) { return jsPlumb.CurrentLibrary.getPageXY(el); },
- _clientXY = function(el) { return jsPlumb.CurrentLibrary.getClientXY(el); },
- _setOffset = function(el, o) { jsPlumb.CurrentLibrary.setOffset(el, o); };
-
- /*
- * Class:CanvasMouseAdapter
- * Provides support for mouse events on canvases.
- */
- var CanvasMouseAdapter = function() {
- var self = this;
- self.overlayPlacements = [];
- jsPlumb.jsPlumbUIComponent.apply(this, arguments);
- jsPlumb.EventGenerator.apply(this, arguments);
- /**
- * returns whether or not the given event is ojver a painted area of the canvas.
- */
- this._over = function(e) {
- var o = _getOffset(_getElementObject(self.canvas)),
- pageXY = _pageXY(e),
- x = pageXY[0] - o.left, y = pageXY[1] - o.top;
- if (x > 0 && y > 0 && x < self.canvas.width && y < self.canvas.height) {
- // first check overlays
- for ( var i = 0; i < self.overlayPlacements.length; i++) {
- var p = self.overlayPlacements[i];
- if (p && (p[0] <= x && p[1] >= x && p[2] <= y && p[3] >= y))
- return true;
- }
-
- // then the canvas
- var d = self.canvas.getContext("2d").getImageData(parseInt(x), parseInt(y), 1, 1);
- return d.data[0] != 0 || d.data[1] != 0 || d.data[2] != 0 || d.data[3] != 0;
- }
- return false;
- };
-
- var _mouseover = false;
- var _mouseDown = false, _posWhenMouseDown = null, _mouseWasDown = false;
- var _nullSafeHasClass = function(el, clazz) {
- return el != null && _hasClass(el, clazz);
- };
- this.mousemove = function(e) {
- var pageXY = _pageXY(e), clientXY = _clientXY(e),
- ee = document.elementFromPoint(clientXY[0], clientXY[1]),
- eventSourceWasOverlay = _nullSafeHasClass(ee, "_jsPlumb_overlay");
- var _continue = _connectionBeingDragged == null && (_nullSafeHasClass(ee, "_jsPlumb_endpoint") || _nullSafeHasClass(ee, "_jsPlumb_connector"));
- if (!_mouseover && _continue && self._over(e)) {
- _mouseover = true;
- self.fire("mouseenter", self, e);
- return true;
- }
- // TODO here there is a remote chance that the overlay the mouse moved onto
- // is actually not an overlay for the current component. a more thorough check would
- // be to ensure the overlay belonged to the current component.
- else if (_mouseover && (!self._over(e) || !_continue) && !eventSourceWasOverlay) {
- _mouseover = false;
- self.fire("mouseexit", self, e);
- }
- self.fire("mousemove", self, e);
- };
-
- this.click = function(e) {
- if (_mouseover && self._over(e) && !_mouseWasDown)
- self.fire("click", self, e);
- _mouseWasDown = false;
- };
-
- this.dblclick = function(e) {
- if (_mouseover && self._over(e) && !_mouseWasDown)
- self.fire("dblclick", self, e);
- _mouseWasDown = false;
- };
-
- this.mousedown = function(e) {
- if(self._over(e) && !_mouseDown) {
- _mouseDown = true;
- _posWhenMouseDown = _getOffset(_getElementObject(self.canvas));
- self.fire("mousedown", self, e);
- }
- };
-
- this.mouseup = function(e) {
- //if (self == _connectionBeingDragged) _connectionBeingDragged = null;
- _mouseDown = false;
- self.fire("mouseup", self, e);
- };
- };
-
- var _newCanvas = function(params) {
- var canvas = document.createElement("canvas");
- jsPlumb.appendElement(canvas, params.parent);
- canvas.style.position = "absolute";
- if (params["class"]) canvas.className = params["class"];
- // set an id. if no id on the element and if uuid was supplied it
- // will be used, otherwise we'll create one.
- params["_jsPlumb"].getId(canvas, params.uuid);
- return canvas;
- };
-
- /**
- * Class:CanvasConnector
- * Superclass for Canvas Connector renderers.
- */
- var CanvasConnector = jsPlumb.CanvasConnector = function(params) {
-
- CanvasMouseAdapter.apply(this, arguments);
-
- var _paintOneStyle = function(dim, aStyle) {
- self.ctx.save();
- jsPlumb.extend(self.ctx, aStyle);
- if (aStyle.gradient) {
- var g = self.createGradient(dim, self.ctx);
- for ( var i = 0; i < aStyle.gradient.stops.length; i++)
- g.addColorStop(aStyle.gradient.stops[i][0], aStyle.gradient.stops[i][1]);
- self.ctx.strokeStyle = g;
- }
- self._paint(dim);
- self.ctx.restore();
- };
- var self = this,
- clazz = self._jsPlumb.connectorClass + " " + (params.cssClass || "");
- self.canvas = _newCanvas({
- "class":clazz,
- _jsPlumb:self._jsPlumb,
- parent:params.parent
- });
- self.ctx = self.canvas.getContext("2d");
-
- var displayElements = [ self.canvas ];
- this.getDisplayElements = function() {
- return displayElements;
- };
-
- this.appendDisplayElement = function(el) {
- displayElements.push(el);
- };
-
- self.paint = function(dim, style) {
- if (style != null) {
-
- jsPlumb.sizeCanvas(self.canvas, dim[0], dim[1], dim[2], dim[3]);
-
- if (style.outlineColor != null) {
- var outlineWidth = style.outlineWidth || 1,
- outlineStrokeWidth = style.lineWidth + (2 * outlineWidth);
- var outlineStyle = {
- strokeStyle:style.outlineColor,
- lineWidth:outlineStrokeWidth
- };
- _paintOneStyle(dim, outlineStyle);
- }
- _paintOneStyle(dim, style);
- }
- };
- };
-
- /**
- * Class:CanvasEndpoint
- * Superclass for Canvas Endpoint renderers.
- */
- var CanvasEndpoint = function(params) {
- var self = this;
- CanvasMouseAdapter.apply(this, arguments);
- var clazz = self._jsPlumb.endpointClass + " " + (params.cssClass || "");
- self.canvas = _newCanvas({
- "class":clazz,
- _jsPlumb:self._jsPlumb,
- parent:params.parent
- });
- self.ctx = self.canvas.getContext("2d");
-
- this.paint = function(d, style, anchor) {
- jsPlumb.sizeCanvas(self.canvas, d[0], d[1], d[2], d[3]);
-
- if (style.outlineColor != null) {
- var outlineWidth = style.outlineWidth || 1,
- outlineStrokeWidth = style.lineWidth + (2 * outlineWidth);
- var outlineStyle = {
- strokeStyle:style.outlineColor,
- lineWidth:outlineStrokeWidth
- };
- // _paintOneStyle(d, outlineStyle);
- }
-
- self._paint.apply(this, arguments);
- };
- };
-
- jsPlumb.Endpoints.canvas.Dot = function(params) {
- var self = this;
- jsPlumb.Endpoints.Dot.apply(this, arguments);
- CanvasEndpoint.apply(this, arguments);
- 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 = self.defaultOffset, innerRadius = self.defaultInnerRadius;
- gradient.offset && (offsetAdjustment = parseValue(gradient.offset));
- gradient.innerRadius && (innerRadius = parseValue(gradient.innerRadius));
- return [offsetAdjustment, innerRadius];
- };
- this._paint = function(d, style, anchor) {
- if (style != null) {
- var ctx = self.canvas.getContext('2d'), orientation = anchor.getOrientation();
- jsPlumb.extend(ctx, style);
- if (style.gradient) {
- var adjustments = calculateAdjustments(style.gradient),
- yAdjust = orientation[1] == 1 ? adjustments[0] * -1 : adjustments[0],
- xAdjust = orientation[0] == 1 ? adjustments[0] * -1: adjustments[0],
- g = ctx.createRadialGradient(d[4], d[4], d[4], d[4] + xAdjust, d[4] + yAdjust, adjustments[1]);
- for (var i = 0; i < style.gradient.stops.length; i++)
- g.addColorStop(style.gradient.stops[i][0], style.gradient.stops[i][1]);
- ctx.fillStyle = g;
- }
- ctx.beginPath();
- ctx.arc(d[4], d[4], d[4], 0, Math.PI*2, true);
- ctx.closePath();
- if (style.fillStyle || style.gradient) ctx.fill();
- if (style.strokeStyle) ctx.stroke();
- }
- };
- };
-
- jsPlumb.Endpoints.canvas.Rectangle = function(params) {
-
- var self = this;
- jsPlumb.Endpoints.Rectangle.apply(this, arguments);
- CanvasEndpoint.apply(this, arguments);
-
- this._paint = function(d, style, anchor) {
-
- var ctx = self.canvas.getContext("2d"), orientation = anchor.getOrientation();
- jsPlumb.extend(ctx, style);
-
- /* canvas gradient */
- if (style.gradient) {
- // first figure out which direction to run the gradient in (it depends on the orientation of the anchors)
- var y1 = orientation[1] == 1 ? d[3] : orientation[1] == 0 ? d[3] / 2 : 0;
- var y2 = orientation[1] == -1 ? d[3] : orientation[1] == 0 ? d[3] / 2 : 0;
- var x1 = orientation[0] == 1 ? d[2] : orientation[0] == 0 ? d[2] / 2 : 0;
- var x2 = orientation[0] == -1 ? d[2] : orientation[0] == 0 ? d[2] / 2 : 0;
- var g = ctx.createLinearGradient(x1,y1,x2,y2);
- for (var i = 0; i < style.gradient.stops.length; i++)
- g.addColorStop(style.gradient.stops[i][0], style.gradient.stops[i][1]);
- ctx.fillStyle = g;
- }
-
- ctx.beginPath();
- ctx.rect(0, 0, d[2], d[3]);
- ctx.closePath();
- if (style.fillStyle || style.gradient) ctx.fill();
- if (style.strokeStyle) ctx.stroke();
- };
- };
-
- jsPlumb.Endpoints.canvas.Triangle = function(params) {
-
- var self = this;
- jsPlumb.Endpoints.Triangle.apply(this, arguments);
- CanvasEndpoint.apply(this, arguments);
-
- this._paint = function(d, style, anchor)
- {
- var width = d[2], height = d[3], x = d[0], y = d[1];
-
- var ctx = self.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 = style.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();
- if (style.fillStyle || style.gradient) ctx.fill();
- if (style.strokeStyle) ctx.stroke();
- };
- };
-
- /*
- * Canvas Image Endpoint: uses the default version, which creates an <img> tag.
- */
- jsPlumb.Endpoints.canvas.Image = jsPlumb.Endpoints.Image;
-
- /*
- * Blank endpoint in all renderers is just the default Blank endpoint.
- */
- jsPlumb.Endpoints.canvas.Blank = jsPlumb.Endpoints.Blank;
-
- /*
- * Canvas Bezier Connector. Draws a Bezier curve onto a Canvas element.
- */
- jsPlumb.Connectors.canvas.Bezier = function() {
- var self = this;
- jsPlumb.Connectors.Bezier.apply(this, arguments);
- CanvasConnector.apply(this, arguments);
- this._paint = function(dimensions) {
- self.ctx.beginPath();
- self.ctx.moveTo(dimensions[4], dimensions[5]);
- self.ctx.bezierCurveTo(dimensions[8], dimensions[9], dimensions[10], dimensions[11], dimensions[6], dimensions[7]);
- self.ctx.stroke();
- };
-
- // TODO i doubt this handles the case that source and target are swapped.
- this.createGradient = function(dim, ctx, swap) {
- return /*(swap) ? self.ctx.createLinearGradient(dim[4], dim[5], dim[6], dim[7]) : */self.ctx.createLinearGradient(dim[6], dim[7], dim[4], dim[5]);
- };
- };
-
- /*
- * Canvas straight line Connector. Draws a straight line onto a Canvas element.
- */
- jsPlumb.Connectors.canvas.Straight = function() {
- var self = this;
- jsPlumb.Connectors.Straight.apply(this, arguments);
- CanvasConnector.apply(this, arguments);
- this._paint = function(dimensions) {
- self.ctx.beginPath();
- self.ctx.moveTo(dimensions[4], dimensions[5]);
- self.ctx.lineTo(dimensions[6], dimensions[7]);
- self.ctx.stroke();
- };
-
- // TODO this does not handle the case that src and target are swapped.
- this.createGradient = function(dim, ctx) {
- return ctx.createLinearGradient(dim[4], dim[5], dim[6], dim[7]);
- };
- };
-
- jsPlumb.Connectors.canvas.Flowchart = function() {
- var self = this;
- jsPlumb.Connectors.Flowchart.apply(this, arguments);
- CanvasConnector.apply(this, arguments);
- this._paint = function(dimensions) {
- self.ctx.beginPath();
- self.ctx.moveTo(dimensions[4], dimensions[5]);
- // loop through extra points
- for (var i = 0; i < dimensions[8]; i++) {
- self.ctx.lineTo(dimensions[9 + (i*2)], dimensions[10 + (i*2)]);
- }
- // finally draw a line to the end
- self.ctx.lineTo(dimensions[6], dimensions[7]);
- self.ctx.stroke();
- };
-
- this.createGradient = function(dim, ctx) {
- return ctx.createLinearGradient(dim[4], dim[5], dim[6], dim[7]);
- };
- };
-
- // ********************************* END OF CANVAS RENDERERS *******************************************************************
-
- jsPlumb.Overlays.canvas.Label = jsPlumb.Overlays.Label;
-
- /**
- * a placeholder right now, really just exists to mirror the fact that there are SVG and VML versions of this.
- */
- var CanvasOverlay = function() {
- jsPlumb.jsPlumbUIComponent.apply(this, arguments);
- };
-
- var AbstractCanvasArrowOverlay = function(superclass, originalArgs) {
- superclass.apply(this, originalArgs);
- CanvasOverlay.apply(this, arguments);
- this.paint = function(connector, d, lineWidth, strokeStyle, fillStyle) {
- var ctx = connector.ctx;
-
- ctx.lineWidth = lineWidth;
- ctx.beginPath();
- ctx.moveTo(d.hxy.x, d.hxy.y);
- ctx.lineTo(d.tail[0].x, d.tail[0].y);
- ctx.lineTo(d.cxy.x, d.cxy.y);
- ctx.lineTo(d.tail[1].x, d.tail[1].y);
- ctx.lineTo(d.hxy.x, d.hxy.y);
- ctx.closePath();
-
- if (strokeStyle) {
- ctx.strokeStyle = strokeStyle;
- ctx.stroke();
- }
- if (fillStyle) {
- ctx.fillStyle = fillStyle;
- ctx.fill();
- }
- };
- };
-
- jsPlumb.Overlays.canvas.Arrow = function() {
- AbstractCanvasArrowOverlay.apply(this, [jsPlumb.Overlays.Arrow, arguments]);
- };
-
- jsPlumb.Overlays.canvas.PlainArrow = function() {
- AbstractCanvasArrowOverlay.apply(this, [jsPlumb.Overlays.PlainArrow, arguments]);
- };
-
- jsPlumb.Overlays.canvas.Diamond = function() {
- AbstractCanvasArrowOverlay.apply(this, [jsPlumb.Overlays.Diamond, arguments]);
- };
- })();
|