From 200b354127a062d3fb2456fad5ecf93fe9fae8fe Mon Sep 17 00:00:00 2001 From: "PERCALLNET\\rpallares" Date: Thu, 29 Dec 2016 16:37:12 +0100 Subject: [PATCH 01/14] Added an optional ability to define an array of restrictions for links --- README.md | 2 + jquery.flowchart.js | 863 ++++++++++++++++++++-------------------- jquery.flowchart.min.js | 2 +- 3 files changed, 439 insertions(+), 428 deletions(-) diff --git a/README.md b/README.md index f554d56..83dbd81 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ http://sebastien.drouyer.com/jquery.flowchart-demo/ * __toConnector:__ ID of the connector the link goes to. * __toSubConnector:__ (optional) If it is a multiple connector, which subconnector is it. * __color:__ Color of the link. If undefined, default value is the same as `defaultLinkColor`. + + * __linkRestrictions:__ (optional, default: `[]`) If not empty, define which links are allowed. Same structure as `links`. * __operatorTypes:__ (optional) Hash allowing you to define common operator types in order to not repeat the properties key. Key define the operator's type ID and the value define the properties (same structure as `data.operators.properties`). diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 7ceb862..e9ed6a6 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -1,7 +1,7 @@ -$(function () { +$(function() { // the widget definition, where "custom" is the namespace, // "colorize" the widget name - $.widget("flowchart.flowchart", { + $.widget( "flowchart.flowchart", { // default options options: { canUserEditLinks: true, @@ -16,41 +16,35 @@ $(function () { multipleLinksOnOutput: false, multipleLinksOnInput: false, linkVerticalDecal: 0, - onOperatorSelect: function (operatorId) { + onOperatorSelect: function(operatorId) { return true; }, - onOperatorUnselect: function () { + onOperatorUnselect: function() { return true; }, - onOperatorMouseOver: function (operatorId) { + onLinkSelect: function(linkId) { return true; }, - onOperatorMouseOut: function (operatorId) { + onLinkUnselect: function() { return true; }, - onLinkSelect: function (linkId) { + onOperatorCreate: function(operatorId, operatorData, fullElement) { return true; }, - onLinkUnselect: function () { + onLinkCreate: function(linkId, linkData) { return true; }, - onOperatorCreate: function (operatorId, operatorData, fullElement) { + onOperatorDelete: function(operatorId) { return true; }, - onLinkCreate: function (linkId, linkData) { + onLinkDelete: function(linkId, forced) { return true; }, - onOperatorDelete: function (operatorId) { - return true; - }, - onLinkDelete: function (linkId, forced) { - return true; - }, - onOperatorMoved: function (operatorId, position) { - + onOperatorMoved: function(operatorId, position) { + }, - onAfterChange: function (changeType) { - + onAfterChange: function(changeType) { + } }, data: null, @@ -63,28 +57,29 @@ $(function () { selectedLinkId: null, positionRatio: 1, globalId: null, + // the constructor - _create: function () { + _create: function() { if (typeof document.__flowchartNumber == 'undefined') { - document.__flowchartNumber = 0; + document.__flowchartNumber = 0; } else { - document.__flowchartNumber++; + document.__flowchartNumber++; } this.globalId = document.__flowchartNumber; - this._unitVariables(); - + this._unitVariables(); + this.element.addClass('flowchart-container'); - + this.objs.layers.links = $(''); this.objs.layers.links.appendTo(this.element); - + this.objs.layers.operators = $('
'); this.objs.layers.operators.appendTo(this.element); - + this.objs.layers.temporaryLink = $(''); this.objs.layers.temporaryLink.appendTo(this.element); - + var shape = document.createElementNS("http://www.w3.org/2000/svg", "line"); shape.setAttribute("x1", "0"); shape.setAttribute("y1", "0"); @@ -96,18 +91,18 @@ $(function () { shape.setAttribute("fill", "none"); this.objs.layers.temporaryLink[0].appendChild(shape); this.objs.temporaryLink = shape; - + this._initEvents(); - + if (typeof this.options.data != 'undefined') { this.setData(this.options.data); } }, - - _unitVariables: function () { + + _unitVariables: function() { this.data = { operators: {}, - links: {} + links: {}, }; this.objs = { layers: { @@ -119,142 +114,171 @@ $(function () { temporaryLink: null }; }, - - _initEvents: function () { - + + _initEvents: function() { + var self = this; - - this.element.mousemove(function (e) { + + this.element.mousemove(function(e) { var $this = $(this); var offset = $this.offset(); self._mousemove((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - this.element.click(function (e) { + + this.element.click(function(e) { var $this = $(this); var offset = $this.offset(); self._click((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - - this.objs.layers.operators.on('pointerdown mousedown touchstart', '.flowchart-operator', function (e) { + + + + this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function(e) { e.stopImmediatePropagation(); }); - - this.objs.layers.operators.on('click', '.flowchart-operator', function (e) { + + this.objs.layers.operators.on('click', '.flowchart-operator', function(e) { if ($(e.target).closest('.flowchart-operator-connector').length == 0) { self.selectOperator($(this).data('operator_id')); } }); - - this.objs.layers.operators.on('click', '.flowchart-operator-connector', function () { + + this.objs.layers.operators.on('click', '.flowchart-operator-connector', function() { var $this = $(this); if (self.options.canUserEditLinks) { self._connectorClicked($this.closest('.flowchart-operator').data('operator_id'), $this.data('connector'), $this.data('sub_connector'), $this.closest('.flowchart-operator-connector-set').data('connector_type')); } }); - - this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function (e) { + + this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function(e) { e.stopImmediatePropagation(); }); - - this.objs.layers.links.on('mouseover', '.flowchart-link', function () { + + this.objs.layers.links.on('mouseover', '.flowchart-link', function() { self._connecterMouseOver($(this).data('link_id')); }); - - this.objs.layers.links.on('mouseout', '.flowchart-link', function () { + + this.objs.layers.links.on('mouseout', '.flowchart-link', function() { self._connecterMouseOut($(this).data('link_id')); }); - - this.objs.layers.links.on('click', '.flowchart-link', function () { + + this.objs.layers.links.on('click', '.flowchart-link', function() { self.selectLink($(this).data('link_id')); }); - - this.objs.layers.operators.on('mouseover', '.flowchart-operator', function (e) { - self._operatorMouseOver($(this).data('operator_id')); - }); - - this.objs.layers.operators.on('mouseout', '.flowchart-operator', function (e) { - self._operatorMouseOut($(this).data('operator_id')); - }); - + + }, - - setData: function (data) { + + setData: function(data) { this._clearOperatorsLayer(); this.data.operatorTypes = {}; if (typeof data.operatorTypes != 'undefined') { - this.data.operatorTypes = data.operatorTypes; + this.data.operatorTypes = data.operatorTypes; } - + + this.data.linkRestrictions = []; + if(typeof data.linkRestrictions != 'undefined' && data.linkRestrictions.length>0) { + this.data.linkRestrictions = data.linkRestrictions; + } + this.data.operators = {}; for (var operatorId in data.operators) { - if (data.operators.hasOwnProperty(operatorId)) { - this.createOperator(operatorId, data.operators[operatorId]); - } + this.createOperator(operatorId, data.operators[operatorId]); } - this.data.links = {}; for (var linkId in data.links) { - if (data.links.hasOwnProperty(linkId)) { - this.createLink(linkId, data.links[linkId]); - } + this.createLink(linkId, data.links[linkId]); } this.redrawLinksLayer(); }, - - addLink: function (linkData) { - while (typeof this.data.links[this.linkNum] != 'undefined') { + + addLink: function(linkData) { + while(typeof this.data.links[this.linkNum] != 'undefined') { this.linkNum++; } - + this.createLink(this.linkNum, linkData); return this.linkNum; }, - - createLink: function (linkId, linkDataOriginal) { + + createLink: function(linkId, linkDataOriginal) { var linkData = $.extend(true, {}, linkDataOriginal); if (!this.options.onLinkCreate(linkId, linkData)) { return; } - + + var restrictionLinkIndex = this._indexOfLinkGranted(linkData); + if(restrictionLinkIndex == -1) { + return; + } + var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - + var multipleLinksOnOutput = this.options.multipleLinksOnOutput; var multipleLinksOnInput = this.options.multipleLinksOnInput; if (!multipleLinksOnOutput || !multipleLinksOnInput) { for (var linkId2 in this.data.links) { - if (this.data.links.hasOwnProperty(linkId2)) { - var currentLink = this.data.links[linkId2]; - - var currentSubConnectors = this._getSubConnectors(currentLink); - var currentFromSubConnector = currentSubConnectors[0]; - var currentToSubConnector = currentSubConnectors[1]; - - if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { - this.deleteLink(linkId2); - continue; - } - if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { - this.deleteLink(linkId2); - } + var currentLink = this.data.links[linkId2]; + + var currentSubConnectors = this._getSubConnectors(currentLink); + var currentFromSubConnector = currentSubConnectors[0]; + var currentToSubConnector = currentSubConnectors[1]; + + if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { + this.deleteLink(linkId2); + continue; + } + if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { + this.deleteLink(linkId2); + continue; } } } - + this._autoCreateSubConnector(linkData.fromOperator, linkData.fromConnector, 'outputs', fromSubConnector); this._autoCreateSubConnector(linkData.toOperator, linkData.toConnector, 'inputs', toSubConnector); - + + //try to colorize link with restriction link data + if(restrictionLinkIndex!=null) { + var restriction = this.data.linkRestrictions[restrictionLinkIndex]; + if(typeof restriction.color != 'undefined') { + linkData.color = restriction.color; + } + } + this.data.links[linkId] = linkData; this._drawLink(linkId); - this.options.onAfterChange('link_create'); }, - - _autoCreateSubConnector: function (operator, connector, connectorType, subConnector) { + + /** Search into this.data.linkRestrictions if the given link is granted + * Return null if linkRestrictions is disabled (empty array) + * Return -1 if the link is forbidden, and the index into the link restriction array otherwise + */ + _indexOfLinkGranted: function(linkData) { + if(this.data.linkRestrictions.length == 0) { + return null; + } + + var linkRestrictions = this.data.linkRestrictions; + + for(var i=0; i'); $operator.addClass(infos.class); - + var $operator_title = $('
'); - $operator_title.html(infos.title); + $operator_title.text(infos.title); $operator_title.appendTo($operator); - + var $operator_inputs_outputs = $('
'); - + + $operator_inputs_outputs.appendTo($operator); - + var $operator_inputs = $('
'); $operator_inputs.appendTo($operator_inputs_outputs); - + var $operator_outputs = $('
'); $operator_outputs.appendTo($operator_inputs_outputs); - + var self = this; - + var connectorArrows = {}; var connectorSmallArrows = {}; var connectorSets = {}; var connectors = {}; - - var fullElement = { - operator: $operator, - title: $operator_title, - connectorSets: connectorSets, - connectors: connectors, - connectorArrows: connectorArrows, - connectorSmallArrows: connectorSmallArrows - }; - + + var fullElement = {operator: $operator, title: $operator_title, connectorSets: connectorSets, connectors: connectors, connectorArrows: connectorArrows, connectorSmallArrows: connectorSmallArrows}; + function addConnector(connectorKey, connectorInfos, $operator_container, connectorType) { var $operator_connector_set = $('
'); $operator_connector_set.data('connector_type', connectorType); $operator_connector_set.appendTo($operator_container); - + connectorArrows[connectorKey] = []; connectorSmallArrows[connectorKey] = []; connectors[connectorKey] = []; connectorSets[connectorKey] = $operator_connector_set; - + self._createSubConnector(connectorKey, connectorInfos, fullElement); } - - for (var key_i in infos.inputs) { - if (infos.inputs.hasOwnProperty(key_i)) { - addConnector(key_i, infos.inputs[key_i], $operator_inputs, 'inputs'); - } + + for (var key in infos.inputs) { + addConnector(key, infos.inputs[key], $operator_inputs, 'inputs'); } - - for (var key_o in infos.outputs) { - if (infos.outputs.hasOwnProperty(key_o)) { - addConnector(key_o, infos.outputs[key_o], $operator_outputs, 'outputs'); - } + + for (var key in infos.outputs) { + addConnector(key, infos.outputs[key], $operator_outputs, 'outputs'); } - + return fullElement; }, - - _createSubConnector: function (connectorKey, connectorInfos, fullElement) { + + _createSubConnector: function(connectorKey, connectorInfos, fullElement) { var $operator_connector_set = fullElement.connectorSets[connectorKey]; - + var subConnector = fullElement.connectors[connectorKey].length; - + var $operator_connector = $('
'); $operator_connector.appendTo($operator_connector_set); $operator_connector.data('connector', connectorKey); @@ -554,73 +565,70 @@ $(function () { fullElement.connectorArrows[connectorKey].push($operator_connector_arrow); fullElement.connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); }, - - getOperatorElement: function (operatorData) { + + getOperatorElement: function(operatorData) { var fullElement = this._getOperatorFullElement(operatorData); return fullElement.operator; }, - - addOperator: function (operatorData) { - while (typeof this.data.operators[this.operatorNum] != 'undefined') { + + addOperator: function(operatorData) { + while(typeof this.data.operators[this.operatorNum] != 'undefined') { this.operatorNum++; } - + this.createOperator(this.operatorNum, operatorData); return this.operatorNum; }, - - createOperator: function (operatorId, operatorData) { + + createOperator: function(operatorId, operatorData) { operatorData.internal = {}; this._refreshInternalProperties(operatorData); - + var fullElement = this._getOperatorFullElement(operatorData); if (!this.options.onOperatorCreate(operatorId, operatorData, fullElement)) { return false; } - + var grid = this.options.grid; - - if (grid) { - operatorData.top = Math.round(operatorData.top / grid) * grid; - operatorData.left = Math.round(operatorData.left / grid) * grid; - } - + + operatorData.top = Math.round(operatorData.top / grid) * grid; + operatorData.left = Math.round(operatorData.left / grid) * grid; + fullElement.operator.appendTo(this.objs.layers.operators); fullElement.operator.css({top: operatorData.top, left: operatorData.left}); fullElement.operator.data('operator_id', operatorId); - + this.data.operators[operatorId] = operatorData; this.data.operators[operatorId].internal.els = fullElement; - + if (operatorId == this.selectedOperatorId) { this._addSelectedClass(operatorId); } - + + var operatorData = this.data.operators[operatorId] ; + var self = this; - + function operatorChangedPosition(operator_id, pos) { operatorData.top = pos.top; operatorData.left = pos.left; for (var linkId in self.data.links) { - if (self.data.links.hasOwnProperty(linkId)) { - var linkData = self.data.links[linkId]; - if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { - self._refreshLinkPositions(linkId); - } + var linkData = self.data.links[linkId]; + if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { + self._refreshLinkPositions(linkId); } } } - + // Small fix has been added in order to manage eventual zoom // http://stackoverflow.com/questions/2930092/jquery-draggable-with-zoom-problem if (this.options.canUserMoveOperators) { var pointerX; var pointerY; fullElement.operator.draggable({ - containment: operatorData.internal.properties.uncontained ? false : this.element, handle: '.flowchart-operator-title', - start: function (e, ui) { + start: function(e, ui) { if (self.lastOutputConnectorClicked != null) { e.preventDefault(); return; @@ -629,58 +637,51 @@ $(function () { pointerX = (e.pageX - elementOffset.left) / self.positionRatio - parseInt($(e.target).css('left')); pointerY = (e.pageY - elementOffset.top) / self.positionRatio - parseInt($(e.target).css('top')); }, - drag: function (e, ui) { - if (self.options.grid) { - var grid = self.options.grid; - var elementOffset = self.element.offset(); - ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; - ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; - - if (!operatorData.internal.properties.uncontained) { - var $this = $(this); - ui.position.left = Math.min(Math.max(ui.position.left, 0), self.element.width() - $this.outerWidth()); - ui.position.top = Math.min(Math.max(ui.position.top, 0), self.element.height() - $this.outerHeight()); - } - - ui.offset.left = Math.round(ui.position.left + elementOffset.left); - ui.offset.top = Math.round(ui.position.top + elementOffset.top); - fullElement.operator.css({left: ui.position.left, top: ui.position.top}); - } + drag: function(e, ui){ + var grid = self.options.grid; + var elementOffset = self.element.offset(); + ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; + ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; + ui.offset.left = Math.round(ui.position.left + elementOffset.left); + ui.offset.top = Math.round(ui.position.top + elementOffset.top); + fullElement.operator.css({left: ui.position.left, top: ui.position.top}); operatorChangedPosition($(this).data('operator_id'), ui.position); }, - stop: function (e, ui) { + stop: function(e, ui){ self._unsetTemporaryLink(); var operatorId = $(this).data('operator_id'); operatorChangedPosition(operatorId, ui.position); fullElement.operator.css({ - height: 'auto' + height: 'auto' }); - + self.options.onOperatorMoved(operatorId, ui.position); self.options.onAfterChange('operator_moved'); - } + }, }); } - + this.options.onAfterChange('operator_create'); }, - - _connectorClicked: function (operator, connector, subConnector, connectorCategory) { + + _connectorClicked: function(operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { var d = new Date(); - // var currentTime = d.getTime(); + var currentTime = d.getTime(); this.lastOutputConnectorClicked = { - operator: operator, - connector: connector, - subConnector: subConnector + operator: operator, + connector: connector, + subConnector: subConnector, + grantedLinks: this._getGrantedLinks(operator, connector) }; this.objs.layers.temporaryLink.show(); var position = this.getConnectorPosition(operator, connector, subConnector); var x = position.x + position.width; var y = position.y; - this.objs.temporaryLink.setAttribute('x1', x.toString()); - this.objs.temporaryLink.setAttribute('y1', y.toString()); + this.objs.temporaryLink.setAttribute('x1', x); + this.objs.temporaryLink.setAttribute('y1', y); this._mousemove(x, y); + this._colorizeGrantedLinks(); } if (connectorCategory == 'inputs' && this.lastOutputConnectorClicked != null) { var linkData = { @@ -692,43 +693,95 @@ $(function () { toSubConnector: subConnector }; - this.addLink(linkData); this._unsetTemporaryLink(); + this.addLink(linkData); } }, + _getGrantedLinks: function(operator, connector) { + if(this.data.linkRestrictions.length == 0) { + return []; + } + + var grantedLinks = this.data.linkRestrictions.filter(function(r) { + return operator==r.fromOperator && connector==r.fromConnector; + }); + + var that = this; + + return grantedLinks.map(function(l) { + if(typeof l.color == 'undefined') { + l.color = defaultLinkColor; + } + + var toOperator = that.data.operators[l.toOperator]; + var smallArrows = toOperator.internal.els.connectorSmallArrows[l.toConnector]; + + l.smallArrows = smallArrows.map(function(sa) { + return {els: sa, oldColor: sa.css('border-left-color')}; + }); + + return l; + }); + }, + + _colorizeGrantedLinks: function() { + if(this.lastOutputConnectorClicked != null) { + var grantedLinks = this.lastOutputConnectorClicked.grantedLinks; + + grantedLinks.forEach(function(l) { + l.smallArrows.forEach(function(sa) { + sa.els.css('border-left-color', l.color); + }); + }); + } + }, + + _restoreGrantedLinksColor: function() { + if(this.lastOutputConnectorClicked != null) { + var grantedLinks = this.lastOutputConnectorClicked.grantedLinks; + + grantedLinks.forEach(function(l) { + l.smallArrows.forEach(function(sa) { + sa.els.css('border-left-color', sa.oldColor); + }); + }); + } + }, + _unsetTemporaryLink: function () { - this.lastOutputConnectorClicked = null; + this._restoreGrantedLinksColor(); + this.lastOutputConnectorClicked = null; this.objs.layers.temporaryLink.hide(); }, - - _mousemove: function (x, y, e) { + + _mousemove: function(x, y, e) { if (this.lastOutputConnectorClicked != null) { this.objs.temporaryLink.setAttribute('x2', x); this.objs.temporaryLink.setAttribute('y2', y); } }, - - _click: function (x, y, e) { + + _click: function(x, y, e) { var $target = $(e.target); if ($target.closest('.flowchart-operator-connector').length == 0) { this._unsetTemporaryLink(); } - + if ($target.closest('.flowchart-operator').length == 0) { this.unselectOperator(); } - + if ($target.closest('.flowchart-link').length == 0) { this.unselectLink(); } }, - - _removeSelectedClassOperators: function () { + + _removeSelectedClassOperators: function() { this.objs.layers.operators.find('.flowchart-operator').removeClass('selected'); }, - - unselectOperator: function () { + + unselectOperator: function() { if (this.selectedOperatorId != null) { if (!this.options.onOperatorUnselect()) { return; @@ -737,12 +790,12 @@ $(function () { this.selectedOperatorId = null; } }, - - _addSelectedClass: function (operatorId) { + + _addSelectedClass: function(operatorId) { this.data.operators[operatorId].internal.els.operator.addClass('selected'); }, - - selectOperator: function (operatorId) { + + selectOperator: function(operatorId) { if (!this.options.onOperatorSelect(operatorId)) { return; } @@ -751,80 +804,46 @@ $(function () { this._addSelectedClass(operatorId); this.selectedOperatorId = operatorId; }, - - addClassOperator: function (operatorId, className) { - this.data.operators[operatorId].internal.els.operator.addClass(className); - }, - - removeClassOperator: function (operatorId, className) { - this.data.operators[operatorId].internal.els.operator.removeClass(className); - }, - - removeClassOperators: function (className) { - this.objs.layers.operators.find('.flowchart-operator').removeClass(className); - }, - - _addHoverClassOperator: function (operatorId) { - this.data.operators[operatorId].internal.els.operator.addClass('hover'); - }, - - _removeHoverClassOperators: function () { - this.objs.layers.operators.find('.flowchart-operator').removeClass('hover'); - }, - - _operatorMouseOver: function (operatorId) { - if (!this.options.onOperatorMouseOver(operatorId)) { - return; - } - this._addHoverClassOperator(operatorId); - }, - - _operatorMouseOut: function (operatorId) { - if (!this.options.onOperatorMouseOut(operatorId)) { - return; - } - this._removeHoverClassOperators(); - }, - - getSelectedOperatorId: function () { + + getSelectedOperatorId: function() { return this.selectedOperatorId; }, - - getSelectedLinkId: function () { + + getSelectedLinkId: function() { return this.selectedLinkId; }, - + // Found here : http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - _shadeColor: function (color, percent) { - var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF; - return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); + _shadeColor: function(color, percent) { + var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; + return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1); }, - - colorizeLink: function (linkId, color) { + + colorizeLink: function(linkId, color) { var linkData = this.data.links[linkId]; linkData.internal.els.path.setAttribute('stroke', color); linkData.internal.els.rect.setAttribute('fill', color); linkData.internal.els.fromSmallConnector.css('border-left-color', color); linkData.internal.els.toSmallConnector.css('border-left-color', color); }, - - uncolorizeLink: function (linkId) { + + uncolorizeLink: function(linkId) { this.colorizeLink(linkId, this.getLinkMainColor(linkId)); }, - - _connecterMouseOver: function (linkId) { + + _connecterMouseOver: function(linkId) { if (this.selectedLinkId != linkId) { this.colorizeLink(linkId, this._shadeColor(this.getLinkMainColor(linkId), -0.4)); } }, - - _connecterMouseOut: function (linkId) { + + _connecterMouseOut: function(linkId) { if (this.selectedLinkId != linkId) { this.uncolorizeLink(linkId); } }, - - unselectLink: function () { + + unselectLink: function() { if (this.selectedLinkId != null) { if (!this.options.onLinkUnselect()) { return; @@ -833,8 +852,8 @@ $(function () { this.selectedLinkId = null; } }, - - selectLink: function (linkId) { + + selectLink: function(linkId) { this.unselectLink(); if (!this.options.onLinkSelect(linkId)) { return; @@ -843,22 +862,20 @@ $(function () { this.selectedLinkId = linkId; this.colorizeLink(linkId, this.options.defaultSelectedLinkColor); }, - - deleteOperator: function (operatorId) { + + deleteOperator: function(operatorId) { this._deleteOperator(operatorId, false); }, - - _deleteOperator: function (operatorId, replace) { + + _deleteOperator: function(operatorId, replace) { if (!this.options.onOperatorDelete(operatorId, replace)) { return false; } if (!replace) { for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var currentLink = this.data.links[linkId]; - if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { - this._deleteLink(linkId, true); - } + var currentLink = this.data.links[linkId]; + if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { + this._deleteLink(linkId, true); } } } @@ -867,19 +884,19 @@ $(function () { } this.data.operators[operatorId].internal.els.operator.remove(); delete this.data.operators[operatorId]; - + this.options.onAfterChange('operator_delete'); }, - - deleteLink: function (linkId) { + + deleteLink: function(linkId) { this._deleteLink(linkId, false); }, - - _deleteLink: function (linkId, forced) { + + _deleteLink: function(linkId, forced) { if (this.selectedLinkId == linkId) { this.unselectLink(); } - if (!this.options.onLinkDelete(linkId, forced)) { + if (!this.options.onLinkDelete(linkId, forced)) { if (!forced) { return; } @@ -892,18 +909,18 @@ $(function () { var toConnector = linkData.toConnector; linkData.internal.els.overallGroup.remove(); delete this.data.links[linkId]; - + this._cleanMultipleConnectors(fromOperator, fromConnector, 'from'); this._cleanMultipleConnectors(toOperator, toConnector, 'to'); - + this.options.onAfterChange('link_delete'); }, - - _cleanMultipleConnectors: function (operator, connector, linkFromTo) { - if (!this.data.operators[operator].properties[linkFromTo == 'from' ? 'outputs' : 'inputs'][connector].multiple) { + + _cleanMultipleConnectors: function(operator, connector, linkFromTo) { + if (!this.data.operators[operator].properties[linkFromTo == 'from' ? 'outputs': 'inputs'][connector].multiple) { return; } - + var maxI = -1; var fromToOperator = linkFromTo + 'Operator'; var fromToConnector = linkFromTo + 'Connector'; @@ -911,18 +928,16 @@ $(function () { var els = this.data.operators[operator].internal.els; var subConnectors = els.connectors[connector]; var nbSubConnectors = subConnectors.length; - + for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var linkData = this.data.links[linkId]; - if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { - if (maxI < linkData[fromToSubConnector]) { - maxI = linkData[fromToSubConnector]; - } + var linkData = this.data.links[linkId]; + if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { + if (maxI < linkData[fromToSubConnector]) { + maxI = linkData[fromToSubConnector]; } } } - + var nbToDelete = Math.min(nbSubConnectors - maxI - 2, nbSubConnectors - 1); for (var i = 0; i < nbToDelete; i++) { subConnectors[subConnectors.length - 1].remove(); @@ -931,8 +946,8 @@ $(function () { els.connectorSmallArrows[connector].pop(); } }, - - deleteSelected: function () { + + deleteSelected: function() { if (this.selectedLinkId != null) { this.deleteLink(this.selectedLinkId); } @@ -940,36 +955,32 @@ $(function () { this.deleteOperator(this.selectedOperatorId); } }, - - setPositionRatio: function (positionRatio) { + + setPositionRatio: function(positionRatio) { this.positionRatio = positionRatio; }, - - getPositionRatio: function () { + + getPositionRatio: function() { return this.positionRatio; }, - - getData: function () { + + getData: function() { var keys = ['operators', 'links']; var data = {}; data.operators = $.extend(true, {}, this.data.operators); data.links = $.extend(true, {}, this.data.links); for (var keyI in keys) { - if (keys.hasOwnProperty(keyI)) { - var key = keys[keyI]; - for (var objId in data[key]) { - if (data[key].hasOwnProperty(objId)) { - delete data[key][objId].internal; - } - } + var key = keys[keyI]; + for (var objId in data[key]) { + delete data[key][objId].internal; } } data.operatorTypes = this.data.operatorTypes; return data; }, - - setOperatorTitle: function (operatorId, title) { - this.data.operators[operatorId].internal.els.title.html(title); + + setOperatorTitle: function(operatorId, title) { + this.data.operators[operatorId].internal.els.title.text(title); if (typeof this.data.operators[operatorId].properties == 'undefined') { this.data.operators[operatorId].properties = {}; } @@ -977,20 +988,21 @@ $(function () { this._refreshInternalProperties(this.data.operators[operatorId]); this.options.onAfterChange('operator_title_change'); }, - - getOperatorTitle: function (operatorId) { + + getOperatorTitle: function(operatorId) { return this.data.operators[operatorId].internal.properties.title; }, - - setOperatorData: function (operatorId, operatorData) { + + setOperatorData: function(operatorId, operatorData) { var infos = this.getOperatorCompleteData(operatorData); for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var linkData = this.data.links[linkId]; - if ((linkData.fromOperator == operatorId && typeof infos.outputs[linkData.fromConnector] == 'undefined') || - (linkData.toOperator == operatorId && typeof infos.inputs[linkData.toConnector] == 'undefined')) { + var linkData = this.data.links[linkId]; + if ((linkData.fromOperator == operatorId && + typeof infos.outputs[linkData.fromConnector] == 'undefined') || + (linkData.toOperator == operatorId && + typeof infos.inputs[linkData.toConnector] == 'undefined')) { this._deleteLink(linkId, true); - } + continue; } } this._deleteOperator(operatorId, true); @@ -999,17 +1011,13 @@ $(function () { this.options.onAfterChange('operator_data_change'); }, - doesOperatorExists: function (operatorId) { - return typeof this.data.operators[operatorId] != 'undefined'; - }, - - getOperatorData: function (operatorId) { + getOperatorData: function(operatorId) { var data = $.extend(true, {}, this.data.operators[operatorId]); delete data.internal; return data; }, - - getOperatorFullProperties: function (operatorData) { + + getOperatorFullProperties: function(operatorData) { if (typeof operatorData.type != 'undefined') { var typeProperties = this.data.operatorTypes[operatorData.type]; var operatorProperties = {}; @@ -1017,13 +1025,14 @@ $(function () { operatorProperties = operatorData.properties; } return $.extend({}, typeProperties, operatorProperties); - } else { + } + else { return operatorData.properties; } }, - - _refreshInternalProperties: function (operatorData) { + + _refreshInternalProperties: function(operatorData) { operatorData.internal.properties = this.getOperatorFullProperties(operatorData); } }); -}); +}); \ No newline at end of file diff --git a/jquery.flowchart.min.js b/jquery.flowchart.min.js index 8b64b38..f0847ad 100644 --- a/jquery.flowchart.min.js +++ b/jquery.flowchart.min.js @@ -1 +1 @@ -$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(t){return!0},onOperatorUnselect:function(){return!0},onOperatorMouseOver:function(t){return!0},onOperatorMouseOut:function(t){return!0},onLinkSelect:function(t){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(t,e,r){return!0},onLinkCreate:function(t,e){return!0},onOperatorDelete:function(t){return!0},onLinkDelete:function(t,e){return!0},onOperatorMoved:function(t,e){},onAfterChange:function(t){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var r=$(this),o=r.offset();t._mousemove((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.element.click(function(e){var r=$(this),o=r.offset();t._click((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(e){t._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(e){t._operatorMouseOut($(this).data("operator_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var r in t.links)t.links.hasOwnProperty(r)&&this.createLink(r,t.links[r]);this.redrawLinksLayer()},addLink:function(t){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var r=$.extend(!0,{},e);if(this.options.onLinkCreate(t,r)){var o=this._getSubConnectors(r),n=o[0],i=o[1],a=this.options.multipleLinksOnOutput,s=this.options.multipleLinksOnInput;if(!a||!s)for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var p=this.data.links[l],c=this._getSubConnectors(p),u=c[0],h=c[1];if(!a&&p.fromOperator==r.fromOperator&&p.fromConnector==r.fromConnector&&u==n){this.deleteLink(l);continue}s||p.toOperator!=r.toOperator||p.toConnector!=r.toConnector||h!=i||this.deleteLink(l)}this._autoCreateSubConnector(r.fromOperator,r.fromConnector,"outputs",n),this._autoCreateSubConnector(r.toOperator,r.toConnector,"inputs",i),this.data.links[t]=r,this._drawLink(t),this.options.onAfterChange("link_create")}},_autoCreateSubConnector:function(t,e,r,o){var n=this.data.operators[t].properties[r][e];if(n.multiple)for(var i=this.data.operators[t].internal.els,a=this.data.operators[t].internal.els.connectors[e].length,s=a;o+2>s;s++)this._createSubConnector(e,n,i)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,r){var o=this.data.operators[t],n=o.internal.els.connectorArrows[e][r],i=n.offset(),a=this.element.offset(),s=(i.left-a.left)/this.positionRatio,l=parseInt(n.css("border-top-width")),p=(i.top-a.top-1)/this.positionRatio+parseInt(n.css("border-left-width"));return{x:s,width:l,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,r=this.data.links[t];return"undefined"!=typeof r.color&&(e=r.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];"undefined"==typeof e.internal&&(e.internal={}),e.internal.els={};var r=e.fromOperator,o=e.fromConnector,n=e.toOperator,i=e.toConnector,a=this._getSubConnectors(e),s=a[0],l=a[1],c=(this.getLinkMainColor(t),this.data.operators[r]),u=this.data.operators[n],h=c.internal.els.connectorSmallArrows[o][s],d=u.internal.els.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=d;var f=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(f),e.internal.els.overallGroup=f;var v=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,v.setAttribute("id",k),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.setAttribute("x","0"),m.setAttribute("y","0"),m.setAttribute("width","100%"),m.setAttribute("height","100%"),m.setAttribute("stroke","none"),m.setAttribute("fill","white"),v.appendChild(m);var C=document.createElementNS("http://www.w3.org/2000/svg","polygon");C.setAttribute("stroke","none"),C.setAttribute("fill","black"),v.appendChild(C),e.internal.els.mask=C;var O=document.createElementNS("http://www.w3.org/2000/svg","g");O.setAttribute("class","flowchart-link"),O.setAttribute("data-link_id",t),f.appendChild(O);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",this.options.linkWidth.toString()),w.setAttribute("fill","none"),O.appendChild(w),e.internal.els.path=w;var b=document.createElementNS("http://www.w3.org/2000/svg","rect");b.setAttribute("stroke","none"),b.setAttribute("mask","url(#"+k+")"),O.appendChild(b),e.internal.els.rect=b,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;"undefined"!=typeof t.fromSubConnector&&(e=t.fromSubConnector);var r=0;return"undefined"!=typeof t.toSubConnector&&(r=t.toSubConnector),[e,r]},_refreshLinkPositions:function(t){var e=this.data.links[t],r=this._getSubConnectors(e),o=r[0],n=r[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,o),a=this.getConnectorPosition(e.toOperator,e.toConnector,n),s=i.x,l=i.width,p=i.y,c=a.x,u=a.y;p+=this.options.linkVerticalDecal,u+=this.options.linkVerticalDecal;var h=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",s+","+(p-l-h)+" "+(s+l+h)+","+p+" "+s+","+(p+l+h));var d=s+l+h,f=c+1,v=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(p-u)));e.internal.els.path.setAttribute("d","M"+d+","+p+" C"+(s+l+h+v)+","+p+" "+(c-v)+","+u+" "+f+","+u),e.internal.els.rect.setAttribute("x",s),e.internal.els.rect.setAttribute("y",p-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+h+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){"undefined"==typeof t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var r in e.inputs)e.inputs.hasOwnProperty(r)&&null==e.inputs[r]&&delete e.inputs[r];for(var o in e.outputs)e.outputs.hasOwnProperty(o)&&null==e.outputs[o]&&delete e.outputs[o];return"undefined"==typeof e["class"]&&(e["class"]=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function d(t,e,r,o){var n=$('
');n.data("connector_type",o),n.appendTo(r),l[t]=[],p[t]=[],u[t]=[],c[t]=n,s._createSubConnector(t,e,h)}var e=this.getOperatorCompleteData(t),r=$('
');r.addClass(e["class"]);var o=$('
');o.html(e.title),o.appendTo(r);var n=$('
');n.appendTo(r);var i=$('
');i.appendTo(n);var a=$('
');a.appendTo(n);var s=this,l={},p={},c={},u={},h={operator:r,title:o,connectorSets:c,connectors:u,connectorArrows:l,connectorSmallArrows:p};for(var f in e.inputs)e.inputs.hasOwnProperty(f)&&d(f,e.inputs[f],i,"inputs");for(var v in e.outputs)e.outputs.hasOwnProperty(v)&&d(v,e.outputs[v],a,"outputs");return h},_createSubConnector:function(t,e,r){var o=r.connectorSets[t],n=r.connectors[t].length,i=$('
');i.appendTo(o),i.data("connector",t),i.data("sub_connector",n);var a=$('
');a.text(e.label.replace("(:i)",n+1)),a.appendTo(i);var s=$('
');s.appendTo(i);var l=$('
');l.appendTo(i),r.connectors[t].push(i),r.connectorArrows[t].push(s),r.connectorSmallArrows[t].push(l)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function i(t,r){e.top=r.top,e.left=r.left;for(var o in n.data.links)if(n.data.links.hasOwnProperty(o)){var i=n.data.links[o];(i.fromOperator==t||i.toOperator==t)&&n._refreshLinkPositions(o)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var o=this.options.grid;o&&(e.top=Math.round(e.top/o)*o,e.left=Math.round(e.left/o)*o),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var n=this;if(this.options.canUserMoveOperators){var a,s;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t,e){if(null!=n.lastOutputConnectorClicked)return void t.preventDefault();var r=n.element.offset();a=(t.pageX-r.left)/n.positionRatio-parseInt($(t.target).css("left")),s=(t.pageY-r.top)/n.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,o){if(n.options.grid){var l=n.options.grid,p=n.element.offset();if(o.position.left=Math.round(((t.pageX-p.left)/n.positionRatio-a)/l)*l,o.position.top=Math.round(((t.pageY-p.top)/n.positionRatio-s)/l)*l,!e.internal.properties.uncontained){var c=$(this);o.position.left=Math.min(Math.max(o.position.left,0),n.element.width()-c.outerWidth()),o.position.top=Math.min(Math.max(o.position.top,0),n.element.height()-c.outerHeight())}o.offset.left=Math.round(o.position.left+p.left),o.offset.top=Math.round(o.position.top+p.top),r.operator.css({left:o.position.left,top:o.position.top})}i($(this).data("operator_id"),o.position)},stop:function(t,e){n._unsetTemporaryLink();var o=$(this).data("operator_id");i(o,e.position),r.operator.css({height:"auto"}),n.options.onOperatorMoved(o,e.position),n.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,r,o){if("outputs"==o){new Date;this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:r},this.objs.layers.temporaryLink.show();var i=this.getConnectorPosition(t,e,r),a=i.x+i.width,s=i.y;this.objs.temporaryLink.setAttribute("x1",a.toString()),this.objs.temporaryLink.setAttribute("y1",s.toString()),this._mousemove(a,s)}if("inputs"==o&&null!=this.lastOutputConnectorClicked){var l={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:r};this.addLink(l),this._unsetTemporaryLink()}},_unsetTemporaryLink:function(){this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e,r){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,r){var o=$(r.target);0==o.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==o.closest(".flowchart-operator").length&&this.unselectOperator(),0==o.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},addClassOperator:function(t,e){this.data.operators[t].internal.els.operator.addClass(e)},removeClassOperator:function(t,e){this.data.operators[t].internal.els.operator.removeClass(e)},removeClassOperators:function(t){this.objs.layers.operators.find(".flowchart-operator").removeClass(t)},_addHoverClassOperator:function(t){this.data.operators[t].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(t){this.options.onOperatorMouseOver(t)&&this._addHoverClassOperator(t)},_operatorMouseOut:function(t){this.options.onOperatorMouseOut(t)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var r=parseInt(t.slice(1),16),o=0>e?0:255,n=0>e?-1*e:e,i=r>>16,a=r>>8&255,s=255&r;return"#"+(16777216+65536*(Math.round((o-i)*n)+i)+256*(Math.round((o-a)*n)+a)+(Math.round((o-s)*n)+s)).toString(16).slice(1)},colorizeLink:function(t,e){var r=this.data.links[t];r.internal.els.path.setAttribute("stroke",e),r.internal.els.rect.setAttribute("fill",e),r.internal.els.fromSmallConnector.css("border-left-color",e),r.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var o=this.data.links[r];(o.fromOperator==t||o.toOperator==t)&&this._deleteLink(r,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var r=this.data.links[t],o=r.fromOperator,n=r.fromConnector,i=r.toOperator,a=r.toConnector;r.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(o,n,"from"),this._cleanMultipleConnectors(i,a,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,r){if(this.data.operators[t].properties["from"==r?"outputs":"inputs"][e].multiple){var o=-1,n=r+"Operator",i=r+"Connector",a=r+"SubConnector",s=this.data.operators[t].internal.els,l=s.connectors[e],p=l.length;for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var u=this.data.links[c];u[n]==t&&u[i]==e&&od;d++)l[l.length-1].remove(),l.pop(),s.connectorArrows[e].pop(),s.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links);for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];for(var n in e[o])e[o].hasOwnProperty(n)&&delete e[o][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),"undefined"==typeof this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var r=this.getOperatorCompleteData(e);for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var n=this.data.links[o];(n.fromOperator==t&&"undefined"==typeof r.outputs[n.fromConnector]||n.toOperator==t&&"undefined"==typeof r.inputs[n.toConnector])&&this._deleteLink(o,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},doesOperatorExists:function(t){return"undefined"!=typeof this.data.operators[t]},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if("undefined"!=typeof t.type){var e=this.data.operatorTypes[t.type],r={};return"undefined"!=typeof t.properties&&(r=t.properties),$.extend({},e,r)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file +$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(a){return!0},onOperatorUnselect:function(){return!0},onLinkSelect:function(a){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(a,b,c){return!0},onLinkCreate:function(a,b){return!0},onOperatorDelete:function(a){return!0},onLinkDelete:function(a,b){return!0},onOperatorMoved:function(a,b){},onAfterChange:function(a){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var a=document.createElementNS("http://www.w3.org/2000/svg","line");a.setAttribute("x1","0"),a.setAttribute("y1","0"),a.setAttribute("x2","0"),a.setAttribute("y2","0"),a.setAttribute("stroke-dasharray","6,6"),a.setAttribute("stroke-width","4"),a.setAttribute("stroke","black"),a.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(a),this.objs.temporaryLink=a,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var a=this;this.element.mousemove(function(b){var c=$(this),d=c.offset();a._mousemove((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.element.click(function(b){var c=$(this),d=c.offset();a._click((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.objs.layers.operators.on("mousedown touchstart",".flowchart-operator",function(a){a.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(b){0==$(b.target).closest(".flowchart-operator-connector").length&&a.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var b=$(this);a.options.canUserEditLinks&&a._connectorClicked(b.closest(".flowchart-operator").data("operator_id"),b.data("connector"),b.data("sub_connector"),b.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(a){a.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){a._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){a._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){a.selectLink($(this).data("link_id"))})},setData:function(a){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof a.operatorTypes&&(this.data.operatorTypes=a.operatorTypes),this.data.linkRestrictions=[],"undefined"!=typeof a.linkRestrictions&&a.linkRestrictions.length>0&&(this.data.linkRestrictions=a.linkRestrictions),this.data.operators={};for(var b in a.operators)this.createOperator(b,a.operators[b]);for(var c in a.links)this.createLink(c,a.links[c]);this.redrawLinksLayer()},addLink:function(a){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,a),this.linkNum},createLink:function(a,b){var c=$.extend(!0,{},b);if(this.options.onLinkCreate(a,c)){var d=this._indexOfLinkGranted(c);if(d!=-1){var e=this._getSubConnectors(c),f=e[0],g=e[1],h=this.options.multipleLinksOnOutput,i=this.options.multipleLinksOnInput;if(!h||!i)for(var j in this.data.links){var k=this.data.links[j],l=this._getSubConnectors(k),m=l[0],n=l[1];h||k.fromOperator!=c.fromOperator||k.fromConnector!=c.fromConnector||m!=f?i||k.toOperator!=c.toOperator||k.toConnector!=c.toConnector||n!=g||this.deleteLink(j):this.deleteLink(j)}if(this._autoCreateSubConnector(c.fromOperator,c.fromConnector,"outputs",f),this._autoCreateSubConnector(c.toOperator,c.toConnector,"inputs",g),null!=d){var o=this.data.linkRestrictions[d];"undefined"!=typeof o.color&&(c.color=o.color)}this.data.links[a]=c,this._drawLink(a),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(a){if(0==this.data.linkRestrictions.length)return null;for(var b=this.data.linkRestrictions,c=0;c');e.data("connector_type",d),e.appendTo(c),i[a]=[],j[a]=[],l[a]=[],k[a]=e,h._createSubConnector(a,b,m)}var b=this.getOperatorCompleteData(a),c=$('
');c.addClass(b.class);var d=$('
');d.text(b.title),d.appendTo(c);var e=$('
');e.appendTo(c);var f=$('
');f.appendTo(e);var g=$('
');g.appendTo(e);var h=this,i={},j={},k={},l={},m={operator:c,title:d,connectorSets:k,connectors:l,connectorArrows:i,connectorSmallArrows:j};for(var o in b.inputs)n(o,b.inputs[o],f,"inputs");for(var o in b.outputs)n(o,b.outputs[o],g,"outputs");return m},_createSubConnector:function(a,b,c){var d=c.connectorSets[a],e=c.connectors[a].length,f=$('
');f.appendTo(d),f.data("connector",a),f.data("sub_connector",e);var g=$('
');g.text(b.label.replace("(:i)",e+1)),g.appendTo(f);var h=$('
');h.appendTo(f);var i=$('
');i.appendTo(f),c.connectors[a].push(f),c.connectorArrows[a].push(h),c.connectorSmallArrows[a].push(i)},getOperatorElement:function(a){var b=this._getOperatorFullElement(a);return b.operator},addOperator:function(a){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,a),this.operatorNum},createOperator:function(a,b){function f(a,c){b.top=c.top,b.left=c.left;for(var d in e.data.links){var f=e.data.links[d];f.fromOperator!=a&&f.toOperator!=a||e._refreshLinkPositions(d)}}b.internal={},this._refreshInternalProperties(b);var c=this._getOperatorFullElement(b);if(!this.options.onOperatorCreate(a,b,c))return!1;var d=this.options.grid;b.top=Math.round(b.top/d)*d,b.left=Math.round(b.left/d)*d,c.operator.appendTo(this.objs.layers.operators),c.operator.css({top:b.top,left:b.left}),c.operator.data("operator_id",a),this.data.operators[a]=b,this.data.operators[a].internal.els=c,a==this.selectedOperatorId&&this._addSelectedClass(a);var b=this.data.operators[a],e=this;if(this.options.canUserMoveOperators){var g,h;c.operator.draggable({handle:".flowchart-operator-title",start:function(a,b){if(null!=e.lastOutputConnectorClicked)return void a.preventDefault();var c=e.element.offset();g=(a.pageX-c.left)/e.positionRatio-parseInt($(a.target).css("left")),h=(a.pageY-c.top)/e.positionRatio-parseInt($(a.target).css("top"))},drag:function(a,b){var d=e.options.grid,i=e.element.offset();b.position.left=Math.round(((a.pageX-i.left)/e.positionRatio-g)/d)*d,b.position.top=Math.round(((a.pageY-i.top)/e.positionRatio-h)/d)*d,b.offset.left=Math.round(b.position.left+i.left),b.offset.top=Math.round(b.position.top+i.top),c.operator.css({left:b.position.left,top:b.position.top}),f($(this).data("operator_id"),b.position)},stop:function(a,b){e._unsetTemporaryLink();var d=$(this).data("operator_id");f(d,b.position),c.operator.css({height:"auto"}),e.options.onOperatorMoved(d,b.position),e.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(a,b,c,d){if("outputs"==d){var e=new Date;e.getTime();this.lastOutputConnectorClicked={operator:a,connector:b,subConnector:c,grantedLinks:this._getGrantedLinks(a,b)},this.objs.layers.temporaryLink.show();var g=this.getConnectorPosition(a,b,c),h=g.x+g.width,i=g.y;this.objs.temporaryLink.setAttribute("x1",h),this.objs.temporaryLink.setAttribute("y1",i),this._mousemove(h,i),this._colorizeGrantedLinks()}if("inputs"==d&&null!=this.lastOutputConnectorClicked){var j={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:a,toConnector:b,toSubConnector:c};this._unsetTemporaryLink(),this.addLink(j)}},_getGrantedLinks:function(a,b){if(0==this.data.linkRestrictions.length)return[];var c=this.data.linkRestrictions.filter(function(c){return a==c.fromOperator&&b==c.fromConnector}),d=this;return c.map(function(a){"undefined"==typeof a.color&&(a.color=defaultLinkColor);var b=d.data.operators[a.toOperator],c=b.internal.els.connectorSmallArrows[a.toConnector];return a.smallArrows=c.map(function(a){return{els:a,oldColor:a.css("border-left-color")}}),a})},_colorizeGrantedLinks:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(b){b.els.css("border-left-color",a.color)})})}},_restoreGrantedLinksColor:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(a){a.els.css("border-left-color",a.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedLinksColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(a,b,c){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",a),this.objs.temporaryLink.setAttribute("y2",b))},_click:function(a,b,c){var d=$(c.target);0==d.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==d.closest(".flowchart-operator").length&&this.unselectOperator(),0==d.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(a){this.data.operators[a].internal.els.operator.addClass("selected")},selectOperator:function(a){this.options.onOperatorSelect(a)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(a),this.selectedOperatorId=a)},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(a,b){var c=parseInt(a.slice(1),16),d=b<0?0:255,e=b<0?b*-1:b,f=c>>16,g=c>>8&255,h=255&c;return"#"+(16777216+65536*(Math.round((d-f)*e)+f)+256*(Math.round((d-g)*e)+g)+(Math.round((d-h)*e)+h)).toString(16).slice(1)},colorizeLink:function(a,b){var c=this.data.links[a];c.internal.els.path.setAttribute("stroke",b),c.internal.els.rect.setAttribute("fill",b),c.internal.els.fromSmallConnector.css("border-left-color",b),c.internal.els.toSmallConnector.css("border-left-color",b)},uncolorizeLink:function(a){this.colorizeLink(a,this.getLinkMainColor(a))},_connecterMouseOver:function(a){this.selectedLinkId!=a&&this.colorizeLink(a,this._shadeColor(this.getLinkMainColor(a),-.4))},_connecterMouseOut:function(a){this.selectedLinkId!=a&&this.uncolorizeLink(a)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(a){this.unselectLink(),this.options.onLinkSelect(a)&&(this.unselectOperator(),this.selectedLinkId=a,this.colorizeLink(a,this.options.defaultSelectedLinkColor))},deleteOperator:function(a){this._deleteOperator(a,!1)},_deleteOperator:function(a,b){if(!this.options.onOperatorDelete(a,b))return!1;if(!b)for(var c in this.data.links){var d=this.data.links[c];d.fromOperator!=a&&d.toOperator!=a||this._deleteLink(c,!0)}b||a!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[a].internal.els.operator.remove(),delete this.data.operators[a],this.options.onAfterChange("operator_delete")},deleteLink:function(a){this._deleteLink(a,!1)},_deleteLink:function(a,b){if(this.selectedLinkId==a&&this.unselectLink(),this.options.onLinkDelete(a,b)||b){this.colorizeLink(a,"transparent");var c=this.data.links[a],d=c.fromOperator,e=c.fromConnector,f=c.toOperator,g=c.toConnector;c.internal.els.overallGroup.remove(),delete this.data.links[a],this._cleanMultipleConnectors(d,e,"from"),this._cleanMultipleConnectors(f,g,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(a,b,c){if(this.data.operators[a].properties["from"==c?"outputs":"inputs"][b].multiple){var d=-1,e=c+"Operator",f=c+"Connector",g=c+"SubConnector",h=this.data.operators[a].internal.els,i=h.connectors[b],j=i.length;for(var k in this.data.links){var l=this.data.links[k];l[e]==a&&l[f]==b&&d Date: Thu, 29 Dec 2016 16:58:04 +0100 Subject: [PATCH 02/14] Revert "Added an optional ability to define an array of restrictions for links" This reverts commit 200b354127a062d3fb2456fad5ecf93fe9fae8fe. --- README.md | 2 - jquery.flowchart.js | 863 ++++++++++++++++++++-------------------- jquery.flowchart.min.js | 2 +- 3 files changed, 428 insertions(+), 439 deletions(-) diff --git a/README.md b/README.md index 83dbd81..f554d56 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,6 @@ http://sebastien.drouyer.com/jquery.flowchart-demo/ * __toConnector:__ ID of the connector the link goes to. * __toSubConnector:__ (optional) If it is a multiple connector, which subconnector is it. * __color:__ Color of the link. If undefined, default value is the same as `defaultLinkColor`. - - * __linkRestrictions:__ (optional, default: `[]`) If not empty, define which links are allowed. Same structure as `links`. * __operatorTypes:__ (optional) Hash allowing you to define common operator types in order to not repeat the properties key. Key define the operator's type ID and the value define the properties (same structure as `data.operators.properties`). diff --git a/jquery.flowchart.js b/jquery.flowchart.js index e9ed6a6..7ceb862 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -1,7 +1,7 @@ -$(function() { +$(function () { // the widget definition, where "custom" is the namespace, // "colorize" the widget name - $.widget( "flowchart.flowchart", { + $.widget("flowchart.flowchart", { // default options options: { canUserEditLinks: true, @@ -16,35 +16,41 @@ $(function() { multipleLinksOnOutput: false, multipleLinksOnInput: false, linkVerticalDecal: 0, - onOperatorSelect: function(operatorId) { + onOperatorSelect: function (operatorId) { return true; }, - onOperatorUnselect: function() { + onOperatorUnselect: function () { return true; }, - onLinkSelect: function(linkId) { + onOperatorMouseOver: function (operatorId) { return true; }, - onLinkUnselect: function() { + onOperatorMouseOut: function (operatorId) { return true; }, - onOperatorCreate: function(operatorId, operatorData, fullElement) { + onLinkSelect: function (linkId) { return true; }, - onLinkCreate: function(linkId, linkData) { + onLinkUnselect: function () { return true; }, - onOperatorDelete: function(operatorId) { + onOperatorCreate: function (operatorId, operatorData, fullElement) { return true; }, - onLinkDelete: function(linkId, forced) { + onLinkCreate: function (linkId, linkData) { return true; }, - onOperatorMoved: function(operatorId, position) { - + onOperatorDelete: function (operatorId) { + return true; + }, + onLinkDelete: function (linkId, forced) { + return true; + }, + onOperatorMoved: function (operatorId, position) { + }, - onAfterChange: function(changeType) { - + onAfterChange: function (changeType) { + } }, data: null, @@ -57,29 +63,28 @@ $(function() { selectedLinkId: null, positionRatio: 1, globalId: null, - // the constructor - _create: function() { + _create: function () { if (typeof document.__flowchartNumber == 'undefined') { - document.__flowchartNumber = 0; + document.__flowchartNumber = 0; } else { - document.__flowchartNumber++; + document.__flowchartNumber++; } this.globalId = document.__flowchartNumber; - this._unitVariables(); - + this._unitVariables(); + this.element.addClass('flowchart-container'); - + this.objs.layers.links = $(''); this.objs.layers.links.appendTo(this.element); - + this.objs.layers.operators = $('
'); this.objs.layers.operators.appendTo(this.element); - + this.objs.layers.temporaryLink = $(''); this.objs.layers.temporaryLink.appendTo(this.element); - + var shape = document.createElementNS("http://www.w3.org/2000/svg", "line"); shape.setAttribute("x1", "0"); shape.setAttribute("y1", "0"); @@ -91,18 +96,18 @@ $(function() { shape.setAttribute("fill", "none"); this.objs.layers.temporaryLink[0].appendChild(shape); this.objs.temporaryLink = shape; - + this._initEvents(); - + if (typeof this.options.data != 'undefined') { this.setData(this.options.data); } }, - - _unitVariables: function() { + + _unitVariables: function () { this.data = { operators: {}, - links: {}, + links: {} }; this.objs = { layers: { @@ -114,171 +119,142 @@ $(function() { temporaryLink: null }; }, - - _initEvents: function() { - + + _initEvents: function () { + var self = this; - - this.element.mousemove(function(e) { + + this.element.mousemove(function (e) { var $this = $(this); var offset = $this.offset(); self._mousemove((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - this.element.click(function(e) { + + this.element.click(function (e) { var $this = $(this); var offset = $this.offset(); self._click((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - - - this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function(e) { + + + this.objs.layers.operators.on('pointerdown mousedown touchstart', '.flowchart-operator', function (e) { e.stopImmediatePropagation(); }); - - this.objs.layers.operators.on('click', '.flowchart-operator', function(e) { + + this.objs.layers.operators.on('click', '.flowchart-operator', function (e) { if ($(e.target).closest('.flowchart-operator-connector').length == 0) { self.selectOperator($(this).data('operator_id')); } }); - - this.objs.layers.operators.on('click', '.flowchart-operator-connector', function() { + + this.objs.layers.operators.on('click', '.flowchart-operator-connector', function () { var $this = $(this); if (self.options.canUserEditLinks) { self._connectorClicked($this.closest('.flowchart-operator').data('operator_id'), $this.data('connector'), $this.data('sub_connector'), $this.closest('.flowchart-operator-connector-set').data('connector_type')); } }); - - this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function(e) { + + this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function (e) { e.stopImmediatePropagation(); }); - - this.objs.layers.links.on('mouseover', '.flowchart-link', function() { + + this.objs.layers.links.on('mouseover', '.flowchart-link', function () { self._connecterMouseOver($(this).data('link_id')); }); - - this.objs.layers.links.on('mouseout', '.flowchart-link', function() { + + this.objs.layers.links.on('mouseout', '.flowchart-link', function () { self._connecterMouseOut($(this).data('link_id')); }); - - this.objs.layers.links.on('click', '.flowchart-link', function() { + + this.objs.layers.links.on('click', '.flowchart-link', function () { self.selectLink($(this).data('link_id')); }); - - + + this.objs.layers.operators.on('mouseover', '.flowchart-operator', function (e) { + self._operatorMouseOver($(this).data('operator_id')); + }); + + this.objs.layers.operators.on('mouseout', '.flowchart-operator', function (e) { + self._operatorMouseOut($(this).data('operator_id')); + }); + }, - - setData: function(data) { + + setData: function (data) { this._clearOperatorsLayer(); this.data.operatorTypes = {}; if (typeof data.operatorTypes != 'undefined') { - this.data.operatorTypes = data.operatorTypes; - } - - this.data.linkRestrictions = []; - if(typeof data.linkRestrictions != 'undefined' && data.linkRestrictions.length>0) { - this.data.linkRestrictions = data.linkRestrictions; + this.data.operatorTypes = data.operatorTypes; } - + this.data.operators = {}; for (var operatorId in data.operators) { - this.createOperator(operatorId, data.operators[operatorId]); + if (data.operators.hasOwnProperty(operatorId)) { + this.createOperator(operatorId, data.operators[operatorId]); + } } + this.data.links = {}; for (var linkId in data.links) { - this.createLink(linkId, data.links[linkId]); + if (data.links.hasOwnProperty(linkId)) { + this.createLink(linkId, data.links[linkId]); + } } this.redrawLinksLayer(); }, - - addLink: function(linkData) { - while(typeof this.data.links[this.linkNum] != 'undefined') { + + addLink: function (linkData) { + while (typeof this.data.links[this.linkNum] != 'undefined') { this.linkNum++; } - + this.createLink(this.linkNum, linkData); return this.linkNum; }, - - createLink: function(linkId, linkDataOriginal) { + + createLink: function (linkId, linkDataOriginal) { var linkData = $.extend(true, {}, linkDataOriginal); if (!this.options.onLinkCreate(linkId, linkData)) { return; } - - var restrictionLinkIndex = this._indexOfLinkGranted(linkData); - if(restrictionLinkIndex == -1) { - return; - } - + var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - + var multipleLinksOnOutput = this.options.multipleLinksOnOutput; var multipleLinksOnInput = this.options.multipleLinksOnInput; if (!multipleLinksOnOutput || !multipleLinksOnInput) { for (var linkId2 in this.data.links) { - var currentLink = this.data.links[linkId2]; - - var currentSubConnectors = this._getSubConnectors(currentLink); - var currentFromSubConnector = currentSubConnectors[0]; - var currentToSubConnector = currentSubConnectors[1]; - - if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { - this.deleteLink(linkId2); - continue; - } - if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { - this.deleteLink(linkId2); - continue; + if (this.data.links.hasOwnProperty(linkId2)) { + var currentLink = this.data.links[linkId2]; + + var currentSubConnectors = this._getSubConnectors(currentLink); + var currentFromSubConnector = currentSubConnectors[0]; + var currentToSubConnector = currentSubConnectors[1]; + + if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { + this.deleteLink(linkId2); + continue; + } + if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { + this.deleteLink(linkId2); + } } } } - + this._autoCreateSubConnector(linkData.fromOperator, linkData.fromConnector, 'outputs', fromSubConnector); this._autoCreateSubConnector(linkData.toOperator, linkData.toConnector, 'inputs', toSubConnector); - - //try to colorize link with restriction link data - if(restrictionLinkIndex!=null) { - var restriction = this.data.linkRestrictions[restrictionLinkIndex]; - if(typeof restriction.color != 'undefined') { - linkData.color = restriction.color; - } - } - + this.data.links[linkId] = linkData; this._drawLink(linkId); + this.options.onAfterChange('link_create'); }, - - /** Search into this.data.linkRestrictions if the given link is granted - * Return null if linkRestrictions is disabled (empty array) - * Return -1 if the link is forbidden, and the index into the link restriction array otherwise - */ - _indexOfLinkGranted: function(linkData) { - if(this.data.linkRestrictions.length == 0) { - return null; - } - - var linkRestrictions = this.data.linkRestrictions; - - for(var i=0; i'); $operator.addClass(infos.class); - + var $operator_title = $('
'); - $operator_title.text(infos.title); + $operator_title.html(infos.title); $operator_title.appendTo($operator); - + var $operator_inputs_outputs = $('
'); - - + $operator_inputs_outputs.appendTo($operator); - + var $operator_inputs = $('
'); $operator_inputs.appendTo($operator_inputs_outputs); - + var $operator_outputs = $('
'); $operator_outputs.appendTo($operator_inputs_outputs); - + var self = this; - + var connectorArrows = {}; var connectorSmallArrows = {}; var connectorSets = {}; var connectors = {}; - - var fullElement = {operator: $operator, title: $operator_title, connectorSets: connectorSets, connectors: connectors, connectorArrows: connectorArrows, connectorSmallArrows: connectorSmallArrows}; - + + var fullElement = { + operator: $operator, + title: $operator_title, + connectorSets: connectorSets, + connectors: connectors, + connectorArrows: connectorArrows, + connectorSmallArrows: connectorSmallArrows + }; + function addConnector(connectorKey, connectorInfos, $operator_container, connectorType) { var $operator_connector_set = $('
'); $operator_connector_set.data('connector_type', connectorType); $operator_connector_set.appendTo($operator_container); - + connectorArrows[connectorKey] = []; connectorSmallArrows[connectorKey] = []; connectors[connectorKey] = []; connectorSets[connectorKey] = $operator_connector_set; - + self._createSubConnector(connectorKey, connectorInfos, fullElement); } - - for (var key in infos.inputs) { - addConnector(key, infos.inputs[key], $operator_inputs, 'inputs'); + + for (var key_i in infos.inputs) { + if (infos.inputs.hasOwnProperty(key_i)) { + addConnector(key_i, infos.inputs[key_i], $operator_inputs, 'inputs'); + } } - - for (var key in infos.outputs) { - addConnector(key, infos.outputs[key], $operator_outputs, 'outputs'); + + for (var key_o in infos.outputs) { + if (infos.outputs.hasOwnProperty(key_o)) { + addConnector(key_o, infos.outputs[key_o], $operator_outputs, 'outputs'); + } } - + return fullElement; }, - - _createSubConnector: function(connectorKey, connectorInfos, fullElement) { + + _createSubConnector: function (connectorKey, connectorInfos, fullElement) { var $operator_connector_set = fullElement.connectorSets[connectorKey]; - + var subConnector = fullElement.connectors[connectorKey].length; - + var $operator_connector = $('
'); $operator_connector.appendTo($operator_connector_set); $operator_connector.data('connector', connectorKey); @@ -565,70 +554,73 @@ $(function() { fullElement.connectorArrows[connectorKey].push($operator_connector_arrow); fullElement.connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); }, - - getOperatorElement: function(operatorData) { + + getOperatorElement: function (operatorData) { var fullElement = this._getOperatorFullElement(operatorData); return fullElement.operator; }, - - addOperator: function(operatorData) { - while(typeof this.data.operators[this.operatorNum] != 'undefined') { + + addOperator: function (operatorData) { + while (typeof this.data.operators[this.operatorNum] != 'undefined') { this.operatorNum++; } - + this.createOperator(this.operatorNum, operatorData); return this.operatorNum; }, - - createOperator: function(operatorId, operatorData) { + + createOperator: function (operatorId, operatorData) { operatorData.internal = {}; this._refreshInternalProperties(operatorData); - + var fullElement = this._getOperatorFullElement(operatorData); if (!this.options.onOperatorCreate(operatorId, operatorData, fullElement)) { return false; } - + var grid = this.options.grid; - - operatorData.top = Math.round(operatorData.top / grid) * grid; - operatorData.left = Math.round(operatorData.left / grid) * grid; - + + if (grid) { + operatorData.top = Math.round(operatorData.top / grid) * grid; + operatorData.left = Math.round(operatorData.left / grid) * grid; + } + fullElement.operator.appendTo(this.objs.layers.operators); fullElement.operator.css({top: operatorData.top, left: operatorData.left}); fullElement.operator.data('operator_id', operatorId); - + this.data.operators[operatorId] = operatorData; this.data.operators[operatorId].internal.els = fullElement; - + if (operatorId == this.selectedOperatorId) { this._addSelectedClass(operatorId); } - - var operatorData = this.data.operators[operatorId] ; - + var self = this; - + function operatorChangedPosition(operator_id, pos) { operatorData.top = pos.top; operatorData.left = pos.left; for (var linkId in self.data.links) { - var linkData = self.data.links[linkId]; - if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { - self._refreshLinkPositions(linkId); + if (self.data.links.hasOwnProperty(linkId)) { + var linkData = self.data.links[linkId]; + if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { + self._refreshLinkPositions(linkId); + } } } } - + // Small fix has been added in order to manage eventual zoom // http://stackoverflow.com/questions/2930092/jquery-draggable-with-zoom-problem if (this.options.canUserMoveOperators) { var pointerX; var pointerY; fullElement.operator.draggable({ + containment: operatorData.internal.properties.uncontained ? false : this.element, handle: '.flowchart-operator-title', - start: function(e, ui) { + start: function (e, ui) { if (self.lastOutputConnectorClicked != null) { e.preventDefault(); return; @@ -637,51 +629,58 @@ $(function() { pointerX = (e.pageX - elementOffset.left) / self.positionRatio - parseInt($(e.target).css('left')); pointerY = (e.pageY - elementOffset.top) / self.positionRatio - parseInt($(e.target).css('top')); }, - drag: function(e, ui){ - var grid = self.options.grid; - var elementOffset = self.element.offset(); - ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; - ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; - ui.offset.left = Math.round(ui.position.left + elementOffset.left); - ui.offset.top = Math.round(ui.position.top + elementOffset.top); - fullElement.operator.css({left: ui.position.left, top: ui.position.top}); + drag: function (e, ui) { + if (self.options.grid) { + var grid = self.options.grid; + var elementOffset = self.element.offset(); + ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; + ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; + + if (!operatorData.internal.properties.uncontained) { + var $this = $(this); + ui.position.left = Math.min(Math.max(ui.position.left, 0), self.element.width() - $this.outerWidth()); + ui.position.top = Math.min(Math.max(ui.position.top, 0), self.element.height() - $this.outerHeight()); + } + + ui.offset.left = Math.round(ui.position.left + elementOffset.left); + ui.offset.top = Math.round(ui.position.top + elementOffset.top); + fullElement.operator.css({left: ui.position.left, top: ui.position.top}); + } operatorChangedPosition($(this).data('operator_id'), ui.position); }, - stop: function(e, ui){ + stop: function (e, ui) { self._unsetTemporaryLink(); var operatorId = $(this).data('operator_id'); operatorChangedPosition(operatorId, ui.position); fullElement.operator.css({ - height: 'auto' + height: 'auto' }); - + self.options.onOperatorMoved(operatorId, ui.position); self.options.onAfterChange('operator_moved'); - }, + } }); } - + this.options.onAfterChange('operator_create'); }, - - _connectorClicked: function(operator, connector, subConnector, connectorCategory) { + + _connectorClicked: function (operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { var d = new Date(); - var currentTime = d.getTime(); + // var currentTime = d.getTime(); this.lastOutputConnectorClicked = { - operator: operator, - connector: connector, - subConnector: subConnector, - grantedLinks: this._getGrantedLinks(operator, connector) + operator: operator, + connector: connector, + subConnector: subConnector }; this.objs.layers.temporaryLink.show(); var position = this.getConnectorPosition(operator, connector, subConnector); var x = position.x + position.width; var y = position.y; - this.objs.temporaryLink.setAttribute('x1', x); - this.objs.temporaryLink.setAttribute('y1', y); + this.objs.temporaryLink.setAttribute('x1', x.toString()); + this.objs.temporaryLink.setAttribute('y1', y.toString()); this._mousemove(x, y); - this._colorizeGrantedLinks(); } if (connectorCategory == 'inputs' && this.lastOutputConnectorClicked != null) { var linkData = { @@ -693,95 +692,43 @@ $(function() { toSubConnector: subConnector }; - this._unsetTemporaryLink(); this.addLink(linkData); + this._unsetTemporaryLink(); } }, - _getGrantedLinks: function(operator, connector) { - if(this.data.linkRestrictions.length == 0) { - return []; - } - - var grantedLinks = this.data.linkRestrictions.filter(function(r) { - return operator==r.fromOperator && connector==r.fromConnector; - }); - - var that = this; - - return grantedLinks.map(function(l) { - if(typeof l.color == 'undefined') { - l.color = defaultLinkColor; - } - - var toOperator = that.data.operators[l.toOperator]; - var smallArrows = toOperator.internal.els.connectorSmallArrows[l.toConnector]; - - l.smallArrows = smallArrows.map(function(sa) { - return {els: sa, oldColor: sa.css('border-left-color')}; - }); - - return l; - }); - }, - - _colorizeGrantedLinks: function() { - if(this.lastOutputConnectorClicked != null) { - var grantedLinks = this.lastOutputConnectorClicked.grantedLinks; - - grantedLinks.forEach(function(l) { - l.smallArrows.forEach(function(sa) { - sa.els.css('border-left-color', l.color); - }); - }); - } - }, - - _restoreGrantedLinksColor: function() { - if(this.lastOutputConnectorClicked != null) { - var grantedLinks = this.lastOutputConnectorClicked.grantedLinks; - - grantedLinks.forEach(function(l) { - l.smallArrows.forEach(function(sa) { - sa.els.css('border-left-color', sa.oldColor); - }); - }); - } - }, - _unsetTemporaryLink: function () { - this._restoreGrantedLinksColor(); - this.lastOutputConnectorClicked = null; + this.lastOutputConnectorClicked = null; this.objs.layers.temporaryLink.hide(); }, - - _mousemove: function(x, y, e) { + + _mousemove: function (x, y, e) { if (this.lastOutputConnectorClicked != null) { this.objs.temporaryLink.setAttribute('x2', x); this.objs.temporaryLink.setAttribute('y2', y); } }, - - _click: function(x, y, e) { + + _click: function (x, y, e) { var $target = $(e.target); if ($target.closest('.flowchart-operator-connector').length == 0) { this._unsetTemporaryLink(); } - + if ($target.closest('.flowchart-operator').length == 0) { this.unselectOperator(); } - + if ($target.closest('.flowchart-link').length == 0) { this.unselectLink(); } }, - - _removeSelectedClassOperators: function() { + + _removeSelectedClassOperators: function () { this.objs.layers.operators.find('.flowchart-operator').removeClass('selected'); }, - - unselectOperator: function() { + + unselectOperator: function () { if (this.selectedOperatorId != null) { if (!this.options.onOperatorUnselect()) { return; @@ -790,12 +737,12 @@ $(function() { this.selectedOperatorId = null; } }, - - _addSelectedClass: function(operatorId) { + + _addSelectedClass: function (operatorId) { this.data.operators[operatorId].internal.els.operator.addClass('selected'); }, - - selectOperator: function(operatorId) { + + selectOperator: function (operatorId) { if (!this.options.onOperatorSelect(operatorId)) { return; } @@ -804,46 +751,80 @@ $(function() { this._addSelectedClass(operatorId); this.selectedOperatorId = operatorId; }, - - getSelectedOperatorId: function() { + + addClassOperator: function (operatorId, className) { + this.data.operators[operatorId].internal.els.operator.addClass(className); + }, + + removeClassOperator: function (operatorId, className) { + this.data.operators[operatorId].internal.els.operator.removeClass(className); + }, + + removeClassOperators: function (className) { + this.objs.layers.operators.find('.flowchart-operator').removeClass(className); + }, + + _addHoverClassOperator: function (operatorId) { + this.data.operators[operatorId].internal.els.operator.addClass('hover'); + }, + + _removeHoverClassOperators: function () { + this.objs.layers.operators.find('.flowchart-operator').removeClass('hover'); + }, + + _operatorMouseOver: function (operatorId) { + if (!this.options.onOperatorMouseOver(operatorId)) { + return; + } + this._addHoverClassOperator(operatorId); + }, + + _operatorMouseOut: function (operatorId) { + if (!this.options.onOperatorMouseOut(operatorId)) { + return; + } + this._removeHoverClassOperators(); + }, + + getSelectedOperatorId: function () { return this.selectedOperatorId; }, - - getSelectedLinkId: function() { + + getSelectedLinkId: function () { return this.selectedLinkId; }, - + // Found here : http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - _shadeColor: function(color, percent) { - var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; - return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1); + _shadeColor: function (color, percent) { + var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF; + return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); }, - - colorizeLink: function(linkId, color) { + + colorizeLink: function (linkId, color) { var linkData = this.data.links[linkId]; linkData.internal.els.path.setAttribute('stroke', color); linkData.internal.els.rect.setAttribute('fill', color); linkData.internal.els.fromSmallConnector.css('border-left-color', color); linkData.internal.els.toSmallConnector.css('border-left-color', color); }, - - uncolorizeLink: function(linkId) { + + uncolorizeLink: function (linkId) { this.colorizeLink(linkId, this.getLinkMainColor(linkId)); }, - - _connecterMouseOver: function(linkId) { + + _connecterMouseOver: function (linkId) { if (this.selectedLinkId != linkId) { this.colorizeLink(linkId, this._shadeColor(this.getLinkMainColor(linkId), -0.4)); } }, - - _connecterMouseOut: function(linkId) { + + _connecterMouseOut: function (linkId) { if (this.selectedLinkId != linkId) { this.uncolorizeLink(linkId); } }, - - unselectLink: function() { + + unselectLink: function () { if (this.selectedLinkId != null) { if (!this.options.onLinkUnselect()) { return; @@ -852,8 +833,8 @@ $(function() { this.selectedLinkId = null; } }, - - selectLink: function(linkId) { + + selectLink: function (linkId) { this.unselectLink(); if (!this.options.onLinkSelect(linkId)) { return; @@ -862,20 +843,22 @@ $(function() { this.selectedLinkId = linkId; this.colorizeLink(linkId, this.options.defaultSelectedLinkColor); }, - - deleteOperator: function(operatorId) { + + deleteOperator: function (operatorId) { this._deleteOperator(operatorId, false); }, - - _deleteOperator: function(operatorId, replace) { + + _deleteOperator: function (operatorId, replace) { if (!this.options.onOperatorDelete(operatorId, replace)) { return false; } if (!replace) { for (var linkId in this.data.links) { - var currentLink = this.data.links[linkId]; - if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { - this._deleteLink(linkId, true); + if (this.data.links.hasOwnProperty(linkId)) { + var currentLink = this.data.links[linkId]; + if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { + this._deleteLink(linkId, true); + } } } } @@ -884,19 +867,19 @@ $(function() { } this.data.operators[operatorId].internal.els.operator.remove(); delete this.data.operators[operatorId]; - + this.options.onAfterChange('operator_delete'); }, - - deleteLink: function(linkId) { + + deleteLink: function (linkId) { this._deleteLink(linkId, false); }, - - _deleteLink: function(linkId, forced) { + + _deleteLink: function (linkId, forced) { if (this.selectedLinkId == linkId) { this.unselectLink(); } - if (!this.options.onLinkDelete(linkId, forced)) { + if (!this.options.onLinkDelete(linkId, forced)) { if (!forced) { return; } @@ -909,18 +892,18 @@ $(function() { var toConnector = linkData.toConnector; linkData.internal.els.overallGroup.remove(); delete this.data.links[linkId]; - + this._cleanMultipleConnectors(fromOperator, fromConnector, 'from'); this._cleanMultipleConnectors(toOperator, toConnector, 'to'); - + this.options.onAfterChange('link_delete'); }, - - _cleanMultipleConnectors: function(operator, connector, linkFromTo) { - if (!this.data.operators[operator].properties[linkFromTo == 'from' ? 'outputs': 'inputs'][connector].multiple) { + + _cleanMultipleConnectors: function (operator, connector, linkFromTo) { + if (!this.data.operators[operator].properties[linkFromTo == 'from' ? 'outputs' : 'inputs'][connector].multiple) { return; } - + var maxI = -1; var fromToOperator = linkFromTo + 'Operator'; var fromToConnector = linkFromTo + 'Connector'; @@ -928,16 +911,18 @@ $(function() { var els = this.data.operators[operator].internal.els; var subConnectors = els.connectors[connector]; var nbSubConnectors = subConnectors.length; - + for (var linkId in this.data.links) { - var linkData = this.data.links[linkId]; - if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { - if (maxI < linkData[fromToSubConnector]) { - maxI = linkData[fromToSubConnector]; + if (this.data.links.hasOwnProperty(linkId)) { + var linkData = this.data.links[linkId]; + if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { + if (maxI < linkData[fromToSubConnector]) { + maxI = linkData[fromToSubConnector]; + } } } } - + var nbToDelete = Math.min(nbSubConnectors - maxI - 2, nbSubConnectors - 1); for (var i = 0; i < nbToDelete; i++) { subConnectors[subConnectors.length - 1].remove(); @@ -946,8 +931,8 @@ $(function() { els.connectorSmallArrows[connector].pop(); } }, - - deleteSelected: function() { + + deleteSelected: function () { if (this.selectedLinkId != null) { this.deleteLink(this.selectedLinkId); } @@ -955,32 +940,36 @@ $(function() { this.deleteOperator(this.selectedOperatorId); } }, - - setPositionRatio: function(positionRatio) { + + setPositionRatio: function (positionRatio) { this.positionRatio = positionRatio; }, - - getPositionRatio: function() { + + getPositionRatio: function () { return this.positionRatio; }, - - getData: function() { + + getData: function () { var keys = ['operators', 'links']; var data = {}; data.operators = $.extend(true, {}, this.data.operators); data.links = $.extend(true, {}, this.data.links); for (var keyI in keys) { - var key = keys[keyI]; - for (var objId in data[key]) { - delete data[key][objId].internal; + if (keys.hasOwnProperty(keyI)) { + var key = keys[keyI]; + for (var objId in data[key]) { + if (data[key].hasOwnProperty(objId)) { + delete data[key][objId].internal; + } + } } } data.operatorTypes = this.data.operatorTypes; return data; }, - - setOperatorTitle: function(operatorId, title) { - this.data.operators[operatorId].internal.els.title.text(title); + + setOperatorTitle: function (operatorId, title) { + this.data.operators[operatorId].internal.els.title.html(title); if (typeof this.data.operators[operatorId].properties == 'undefined') { this.data.operators[operatorId].properties = {}; } @@ -988,21 +977,20 @@ $(function() { this._refreshInternalProperties(this.data.operators[operatorId]); this.options.onAfterChange('operator_title_change'); }, - - getOperatorTitle: function(operatorId) { + + getOperatorTitle: function (operatorId) { return this.data.operators[operatorId].internal.properties.title; }, - - setOperatorData: function(operatorId, operatorData) { + + setOperatorData: function (operatorId, operatorData) { var infos = this.getOperatorCompleteData(operatorData); for (var linkId in this.data.links) { - var linkData = this.data.links[linkId]; - if ((linkData.fromOperator == operatorId && - typeof infos.outputs[linkData.fromConnector] == 'undefined') || - (linkData.toOperator == operatorId && - typeof infos.inputs[linkData.toConnector] == 'undefined')) { + if (this.data.links.hasOwnProperty(linkId)) { + var linkData = this.data.links[linkId]; + if ((linkData.fromOperator == operatorId && typeof infos.outputs[linkData.fromConnector] == 'undefined') || + (linkData.toOperator == operatorId && typeof infos.inputs[linkData.toConnector] == 'undefined')) { this._deleteLink(linkId, true); - continue; + } } } this._deleteOperator(operatorId, true); @@ -1011,13 +999,17 @@ $(function() { this.options.onAfterChange('operator_data_change'); }, - getOperatorData: function(operatorId) { + doesOperatorExists: function (operatorId) { + return typeof this.data.operators[operatorId] != 'undefined'; + }, + + getOperatorData: function (operatorId) { var data = $.extend(true, {}, this.data.operators[operatorId]); delete data.internal; return data; }, - - getOperatorFullProperties: function(operatorData) { + + getOperatorFullProperties: function (operatorData) { if (typeof operatorData.type != 'undefined') { var typeProperties = this.data.operatorTypes[operatorData.type]; var operatorProperties = {}; @@ -1025,14 +1017,13 @@ $(function() { operatorProperties = operatorData.properties; } return $.extend({}, typeProperties, operatorProperties); - } - else { + } else { return operatorData.properties; } }, - - _refreshInternalProperties: function(operatorData) { + + _refreshInternalProperties: function (operatorData) { operatorData.internal.properties = this.getOperatorFullProperties(operatorData); } }); -}); \ No newline at end of file +}); diff --git a/jquery.flowchart.min.js b/jquery.flowchart.min.js index f0847ad..8b64b38 100644 --- a/jquery.flowchart.min.js +++ b/jquery.flowchart.min.js @@ -1 +1 @@ -$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(a){return!0},onOperatorUnselect:function(){return!0},onLinkSelect:function(a){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(a,b,c){return!0},onLinkCreate:function(a,b){return!0},onOperatorDelete:function(a){return!0},onLinkDelete:function(a,b){return!0},onOperatorMoved:function(a,b){},onAfterChange:function(a){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var a=document.createElementNS("http://www.w3.org/2000/svg","line");a.setAttribute("x1","0"),a.setAttribute("y1","0"),a.setAttribute("x2","0"),a.setAttribute("y2","0"),a.setAttribute("stroke-dasharray","6,6"),a.setAttribute("stroke-width","4"),a.setAttribute("stroke","black"),a.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(a),this.objs.temporaryLink=a,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var a=this;this.element.mousemove(function(b){var c=$(this),d=c.offset();a._mousemove((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.element.click(function(b){var c=$(this),d=c.offset();a._click((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.objs.layers.operators.on("mousedown touchstart",".flowchart-operator",function(a){a.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(b){0==$(b.target).closest(".flowchart-operator-connector").length&&a.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var b=$(this);a.options.canUserEditLinks&&a._connectorClicked(b.closest(".flowchart-operator").data("operator_id"),b.data("connector"),b.data("sub_connector"),b.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(a){a.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){a._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){a._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){a.selectLink($(this).data("link_id"))})},setData:function(a){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof a.operatorTypes&&(this.data.operatorTypes=a.operatorTypes),this.data.linkRestrictions=[],"undefined"!=typeof a.linkRestrictions&&a.linkRestrictions.length>0&&(this.data.linkRestrictions=a.linkRestrictions),this.data.operators={};for(var b in a.operators)this.createOperator(b,a.operators[b]);for(var c in a.links)this.createLink(c,a.links[c]);this.redrawLinksLayer()},addLink:function(a){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,a),this.linkNum},createLink:function(a,b){var c=$.extend(!0,{},b);if(this.options.onLinkCreate(a,c)){var d=this._indexOfLinkGranted(c);if(d!=-1){var e=this._getSubConnectors(c),f=e[0],g=e[1],h=this.options.multipleLinksOnOutput,i=this.options.multipleLinksOnInput;if(!h||!i)for(var j in this.data.links){var k=this.data.links[j],l=this._getSubConnectors(k),m=l[0],n=l[1];h||k.fromOperator!=c.fromOperator||k.fromConnector!=c.fromConnector||m!=f?i||k.toOperator!=c.toOperator||k.toConnector!=c.toConnector||n!=g||this.deleteLink(j):this.deleteLink(j)}if(this._autoCreateSubConnector(c.fromOperator,c.fromConnector,"outputs",f),this._autoCreateSubConnector(c.toOperator,c.toConnector,"inputs",g),null!=d){var o=this.data.linkRestrictions[d];"undefined"!=typeof o.color&&(c.color=o.color)}this.data.links[a]=c,this._drawLink(a),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(a){if(0==this.data.linkRestrictions.length)return null;for(var b=this.data.linkRestrictions,c=0;c');e.data("connector_type",d),e.appendTo(c),i[a]=[],j[a]=[],l[a]=[],k[a]=e,h._createSubConnector(a,b,m)}var b=this.getOperatorCompleteData(a),c=$('
');c.addClass(b.class);var d=$('
');d.text(b.title),d.appendTo(c);var e=$('
');e.appendTo(c);var f=$('
');f.appendTo(e);var g=$('
');g.appendTo(e);var h=this,i={},j={},k={},l={},m={operator:c,title:d,connectorSets:k,connectors:l,connectorArrows:i,connectorSmallArrows:j};for(var o in b.inputs)n(o,b.inputs[o],f,"inputs");for(var o in b.outputs)n(o,b.outputs[o],g,"outputs");return m},_createSubConnector:function(a,b,c){var d=c.connectorSets[a],e=c.connectors[a].length,f=$('
');f.appendTo(d),f.data("connector",a),f.data("sub_connector",e);var g=$('
');g.text(b.label.replace("(:i)",e+1)),g.appendTo(f);var h=$('
');h.appendTo(f);var i=$('
');i.appendTo(f),c.connectors[a].push(f),c.connectorArrows[a].push(h),c.connectorSmallArrows[a].push(i)},getOperatorElement:function(a){var b=this._getOperatorFullElement(a);return b.operator},addOperator:function(a){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,a),this.operatorNum},createOperator:function(a,b){function f(a,c){b.top=c.top,b.left=c.left;for(var d in e.data.links){var f=e.data.links[d];f.fromOperator!=a&&f.toOperator!=a||e._refreshLinkPositions(d)}}b.internal={},this._refreshInternalProperties(b);var c=this._getOperatorFullElement(b);if(!this.options.onOperatorCreate(a,b,c))return!1;var d=this.options.grid;b.top=Math.round(b.top/d)*d,b.left=Math.round(b.left/d)*d,c.operator.appendTo(this.objs.layers.operators),c.operator.css({top:b.top,left:b.left}),c.operator.data("operator_id",a),this.data.operators[a]=b,this.data.operators[a].internal.els=c,a==this.selectedOperatorId&&this._addSelectedClass(a);var b=this.data.operators[a],e=this;if(this.options.canUserMoveOperators){var g,h;c.operator.draggable({handle:".flowchart-operator-title",start:function(a,b){if(null!=e.lastOutputConnectorClicked)return void a.preventDefault();var c=e.element.offset();g=(a.pageX-c.left)/e.positionRatio-parseInt($(a.target).css("left")),h=(a.pageY-c.top)/e.positionRatio-parseInt($(a.target).css("top"))},drag:function(a,b){var d=e.options.grid,i=e.element.offset();b.position.left=Math.round(((a.pageX-i.left)/e.positionRatio-g)/d)*d,b.position.top=Math.round(((a.pageY-i.top)/e.positionRatio-h)/d)*d,b.offset.left=Math.round(b.position.left+i.left),b.offset.top=Math.round(b.position.top+i.top),c.operator.css({left:b.position.left,top:b.position.top}),f($(this).data("operator_id"),b.position)},stop:function(a,b){e._unsetTemporaryLink();var d=$(this).data("operator_id");f(d,b.position),c.operator.css({height:"auto"}),e.options.onOperatorMoved(d,b.position),e.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(a,b,c,d){if("outputs"==d){var e=new Date;e.getTime();this.lastOutputConnectorClicked={operator:a,connector:b,subConnector:c,grantedLinks:this._getGrantedLinks(a,b)},this.objs.layers.temporaryLink.show();var g=this.getConnectorPosition(a,b,c),h=g.x+g.width,i=g.y;this.objs.temporaryLink.setAttribute("x1",h),this.objs.temporaryLink.setAttribute("y1",i),this._mousemove(h,i),this._colorizeGrantedLinks()}if("inputs"==d&&null!=this.lastOutputConnectorClicked){var j={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:a,toConnector:b,toSubConnector:c};this._unsetTemporaryLink(),this.addLink(j)}},_getGrantedLinks:function(a,b){if(0==this.data.linkRestrictions.length)return[];var c=this.data.linkRestrictions.filter(function(c){return a==c.fromOperator&&b==c.fromConnector}),d=this;return c.map(function(a){"undefined"==typeof a.color&&(a.color=defaultLinkColor);var b=d.data.operators[a.toOperator],c=b.internal.els.connectorSmallArrows[a.toConnector];return a.smallArrows=c.map(function(a){return{els:a,oldColor:a.css("border-left-color")}}),a})},_colorizeGrantedLinks:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(b){b.els.css("border-left-color",a.color)})})}},_restoreGrantedLinksColor:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(a){a.els.css("border-left-color",a.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedLinksColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(a,b,c){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",a),this.objs.temporaryLink.setAttribute("y2",b))},_click:function(a,b,c){var d=$(c.target);0==d.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==d.closest(".flowchart-operator").length&&this.unselectOperator(),0==d.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(a){this.data.operators[a].internal.els.operator.addClass("selected")},selectOperator:function(a){this.options.onOperatorSelect(a)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(a),this.selectedOperatorId=a)},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(a,b){var c=parseInt(a.slice(1),16),d=b<0?0:255,e=b<0?b*-1:b,f=c>>16,g=c>>8&255,h=255&c;return"#"+(16777216+65536*(Math.round((d-f)*e)+f)+256*(Math.round((d-g)*e)+g)+(Math.round((d-h)*e)+h)).toString(16).slice(1)},colorizeLink:function(a,b){var c=this.data.links[a];c.internal.els.path.setAttribute("stroke",b),c.internal.els.rect.setAttribute("fill",b),c.internal.els.fromSmallConnector.css("border-left-color",b),c.internal.els.toSmallConnector.css("border-left-color",b)},uncolorizeLink:function(a){this.colorizeLink(a,this.getLinkMainColor(a))},_connecterMouseOver:function(a){this.selectedLinkId!=a&&this.colorizeLink(a,this._shadeColor(this.getLinkMainColor(a),-.4))},_connecterMouseOut:function(a){this.selectedLinkId!=a&&this.uncolorizeLink(a)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(a){this.unselectLink(),this.options.onLinkSelect(a)&&(this.unselectOperator(),this.selectedLinkId=a,this.colorizeLink(a,this.options.defaultSelectedLinkColor))},deleteOperator:function(a){this._deleteOperator(a,!1)},_deleteOperator:function(a,b){if(!this.options.onOperatorDelete(a,b))return!1;if(!b)for(var c in this.data.links){var d=this.data.links[c];d.fromOperator!=a&&d.toOperator!=a||this._deleteLink(c,!0)}b||a!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[a].internal.els.operator.remove(),delete this.data.operators[a],this.options.onAfterChange("operator_delete")},deleteLink:function(a){this._deleteLink(a,!1)},_deleteLink:function(a,b){if(this.selectedLinkId==a&&this.unselectLink(),this.options.onLinkDelete(a,b)||b){this.colorizeLink(a,"transparent");var c=this.data.links[a],d=c.fromOperator,e=c.fromConnector,f=c.toOperator,g=c.toConnector;c.internal.els.overallGroup.remove(),delete this.data.links[a],this._cleanMultipleConnectors(d,e,"from"),this._cleanMultipleConnectors(f,g,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(a,b,c){if(this.data.operators[a].properties["from"==c?"outputs":"inputs"][b].multiple){var d=-1,e=c+"Operator",f=c+"Connector",g=c+"SubConnector",h=this.data.operators[a].internal.els,i=h.connectors[b],j=i.length;for(var k in this.data.links){var l=this.data.links[k];l[e]==a&&l[f]==b&&d'),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var r=$(this),o=r.offset();t._mousemove((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.element.click(function(e){var r=$(this),o=r.offset();t._click((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(e){t._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(e){t._operatorMouseOut($(this).data("operator_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var r in t.links)t.links.hasOwnProperty(r)&&this.createLink(r,t.links[r]);this.redrawLinksLayer()},addLink:function(t){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var r=$.extend(!0,{},e);if(this.options.onLinkCreate(t,r)){var o=this._getSubConnectors(r),n=o[0],i=o[1],a=this.options.multipleLinksOnOutput,s=this.options.multipleLinksOnInput;if(!a||!s)for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var p=this.data.links[l],c=this._getSubConnectors(p),u=c[0],h=c[1];if(!a&&p.fromOperator==r.fromOperator&&p.fromConnector==r.fromConnector&&u==n){this.deleteLink(l);continue}s||p.toOperator!=r.toOperator||p.toConnector!=r.toConnector||h!=i||this.deleteLink(l)}this._autoCreateSubConnector(r.fromOperator,r.fromConnector,"outputs",n),this._autoCreateSubConnector(r.toOperator,r.toConnector,"inputs",i),this.data.links[t]=r,this._drawLink(t),this.options.onAfterChange("link_create")}},_autoCreateSubConnector:function(t,e,r,o){var n=this.data.operators[t].properties[r][e];if(n.multiple)for(var i=this.data.operators[t].internal.els,a=this.data.operators[t].internal.els.connectors[e].length,s=a;o+2>s;s++)this._createSubConnector(e,n,i)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,r){var o=this.data.operators[t],n=o.internal.els.connectorArrows[e][r],i=n.offset(),a=this.element.offset(),s=(i.left-a.left)/this.positionRatio,l=parseInt(n.css("border-top-width")),p=(i.top-a.top-1)/this.positionRatio+parseInt(n.css("border-left-width"));return{x:s,width:l,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,r=this.data.links[t];return"undefined"!=typeof r.color&&(e=r.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];"undefined"==typeof e.internal&&(e.internal={}),e.internal.els={};var r=e.fromOperator,o=e.fromConnector,n=e.toOperator,i=e.toConnector,a=this._getSubConnectors(e),s=a[0],l=a[1],c=(this.getLinkMainColor(t),this.data.operators[r]),u=this.data.operators[n],h=c.internal.els.connectorSmallArrows[o][s],d=u.internal.els.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=d;var f=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(f),e.internal.els.overallGroup=f;var v=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,v.setAttribute("id",k),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.setAttribute("x","0"),m.setAttribute("y","0"),m.setAttribute("width","100%"),m.setAttribute("height","100%"),m.setAttribute("stroke","none"),m.setAttribute("fill","white"),v.appendChild(m);var C=document.createElementNS("http://www.w3.org/2000/svg","polygon");C.setAttribute("stroke","none"),C.setAttribute("fill","black"),v.appendChild(C),e.internal.els.mask=C;var O=document.createElementNS("http://www.w3.org/2000/svg","g");O.setAttribute("class","flowchart-link"),O.setAttribute("data-link_id",t),f.appendChild(O);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",this.options.linkWidth.toString()),w.setAttribute("fill","none"),O.appendChild(w),e.internal.els.path=w;var b=document.createElementNS("http://www.w3.org/2000/svg","rect");b.setAttribute("stroke","none"),b.setAttribute("mask","url(#"+k+")"),O.appendChild(b),e.internal.els.rect=b,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;"undefined"!=typeof t.fromSubConnector&&(e=t.fromSubConnector);var r=0;return"undefined"!=typeof t.toSubConnector&&(r=t.toSubConnector),[e,r]},_refreshLinkPositions:function(t){var e=this.data.links[t],r=this._getSubConnectors(e),o=r[0],n=r[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,o),a=this.getConnectorPosition(e.toOperator,e.toConnector,n),s=i.x,l=i.width,p=i.y,c=a.x,u=a.y;p+=this.options.linkVerticalDecal,u+=this.options.linkVerticalDecal;var h=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",s+","+(p-l-h)+" "+(s+l+h)+","+p+" "+s+","+(p+l+h));var d=s+l+h,f=c+1,v=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(p-u)));e.internal.els.path.setAttribute("d","M"+d+","+p+" C"+(s+l+h+v)+","+p+" "+(c-v)+","+u+" "+f+","+u),e.internal.els.rect.setAttribute("x",s),e.internal.els.rect.setAttribute("y",p-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+h+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){"undefined"==typeof t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var r in e.inputs)e.inputs.hasOwnProperty(r)&&null==e.inputs[r]&&delete e.inputs[r];for(var o in e.outputs)e.outputs.hasOwnProperty(o)&&null==e.outputs[o]&&delete e.outputs[o];return"undefined"==typeof e["class"]&&(e["class"]=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function d(t,e,r,o){var n=$('
');n.data("connector_type",o),n.appendTo(r),l[t]=[],p[t]=[],u[t]=[],c[t]=n,s._createSubConnector(t,e,h)}var e=this.getOperatorCompleteData(t),r=$('
');r.addClass(e["class"]);var o=$('
');o.html(e.title),o.appendTo(r);var n=$('
');n.appendTo(r);var i=$('
');i.appendTo(n);var a=$('
');a.appendTo(n);var s=this,l={},p={},c={},u={},h={operator:r,title:o,connectorSets:c,connectors:u,connectorArrows:l,connectorSmallArrows:p};for(var f in e.inputs)e.inputs.hasOwnProperty(f)&&d(f,e.inputs[f],i,"inputs");for(var v in e.outputs)e.outputs.hasOwnProperty(v)&&d(v,e.outputs[v],a,"outputs");return h},_createSubConnector:function(t,e,r){var o=r.connectorSets[t],n=r.connectors[t].length,i=$('
');i.appendTo(o),i.data("connector",t),i.data("sub_connector",n);var a=$('
');a.text(e.label.replace("(:i)",n+1)),a.appendTo(i);var s=$('
');s.appendTo(i);var l=$('
');l.appendTo(i),r.connectors[t].push(i),r.connectorArrows[t].push(s),r.connectorSmallArrows[t].push(l)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function i(t,r){e.top=r.top,e.left=r.left;for(var o in n.data.links)if(n.data.links.hasOwnProperty(o)){var i=n.data.links[o];(i.fromOperator==t||i.toOperator==t)&&n._refreshLinkPositions(o)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var o=this.options.grid;o&&(e.top=Math.round(e.top/o)*o,e.left=Math.round(e.left/o)*o),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var n=this;if(this.options.canUserMoveOperators){var a,s;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t,e){if(null!=n.lastOutputConnectorClicked)return void t.preventDefault();var r=n.element.offset();a=(t.pageX-r.left)/n.positionRatio-parseInt($(t.target).css("left")),s=(t.pageY-r.top)/n.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,o){if(n.options.grid){var l=n.options.grid,p=n.element.offset();if(o.position.left=Math.round(((t.pageX-p.left)/n.positionRatio-a)/l)*l,o.position.top=Math.round(((t.pageY-p.top)/n.positionRatio-s)/l)*l,!e.internal.properties.uncontained){var c=$(this);o.position.left=Math.min(Math.max(o.position.left,0),n.element.width()-c.outerWidth()),o.position.top=Math.min(Math.max(o.position.top,0),n.element.height()-c.outerHeight())}o.offset.left=Math.round(o.position.left+p.left),o.offset.top=Math.round(o.position.top+p.top),r.operator.css({left:o.position.left,top:o.position.top})}i($(this).data("operator_id"),o.position)},stop:function(t,e){n._unsetTemporaryLink();var o=$(this).data("operator_id");i(o,e.position),r.operator.css({height:"auto"}),n.options.onOperatorMoved(o,e.position),n.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,r,o){if("outputs"==o){new Date;this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:r},this.objs.layers.temporaryLink.show();var i=this.getConnectorPosition(t,e,r),a=i.x+i.width,s=i.y;this.objs.temporaryLink.setAttribute("x1",a.toString()),this.objs.temporaryLink.setAttribute("y1",s.toString()),this._mousemove(a,s)}if("inputs"==o&&null!=this.lastOutputConnectorClicked){var l={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:r};this.addLink(l),this._unsetTemporaryLink()}},_unsetTemporaryLink:function(){this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e,r){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,r){var o=$(r.target);0==o.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==o.closest(".flowchart-operator").length&&this.unselectOperator(),0==o.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},addClassOperator:function(t,e){this.data.operators[t].internal.els.operator.addClass(e)},removeClassOperator:function(t,e){this.data.operators[t].internal.els.operator.removeClass(e)},removeClassOperators:function(t){this.objs.layers.operators.find(".flowchart-operator").removeClass(t)},_addHoverClassOperator:function(t){this.data.operators[t].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(t){this.options.onOperatorMouseOver(t)&&this._addHoverClassOperator(t)},_operatorMouseOut:function(t){this.options.onOperatorMouseOut(t)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var r=parseInt(t.slice(1),16),o=0>e?0:255,n=0>e?-1*e:e,i=r>>16,a=r>>8&255,s=255&r;return"#"+(16777216+65536*(Math.round((o-i)*n)+i)+256*(Math.round((o-a)*n)+a)+(Math.round((o-s)*n)+s)).toString(16).slice(1)},colorizeLink:function(t,e){var r=this.data.links[t];r.internal.els.path.setAttribute("stroke",e),r.internal.els.rect.setAttribute("fill",e),r.internal.els.fromSmallConnector.css("border-left-color",e),r.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var o=this.data.links[r];(o.fromOperator==t||o.toOperator==t)&&this._deleteLink(r,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var r=this.data.links[t],o=r.fromOperator,n=r.fromConnector,i=r.toOperator,a=r.toConnector;r.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(o,n,"from"),this._cleanMultipleConnectors(i,a,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,r){if(this.data.operators[t].properties["from"==r?"outputs":"inputs"][e].multiple){var o=-1,n=r+"Operator",i=r+"Connector",a=r+"SubConnector",s=this.data.operators[t].internal.els,l=s.connectors[e],p=l.length;for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var u=this.data.links[c];u[n]==t&&u[i]==e&&od;d++)l[l.length-1].remove(),l.pop(),s.connectorArrows[e].pop(),s.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links);for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];for(var n in e[o])e[o].hasOwnProperty(n)&&delete e[o][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),"undefined"==typeof this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var r=this.getOperatorCompleteData(e);for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var n=this.data.links[o];(n.fromOperator==t&&"undefined"==typeof r.outputs[n.fromConnector]||n.toOperator==t&&"undefined"==typeof r.inputs[n.toConnector])&&this._deleteLink(o,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},doesOperatorExists:function(t){return"undefined"!=typeof this.data.operators[t]},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if("undefined"!=typeof t.type){var e=this.data.operatorTypes[t.type],r={};return"undefined"!=typeof t.properties&&(r=t.properties),$.extend({},e,r)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file From aa7eee2357627df89755084cfc84cf5972e80a61 Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Thu, 29 Dec 2016 17:16:49 +0100 Subject: [PATCH 03/14] Added ability to restrict links by passing array of link restrictions. Older commit cancelled due to internal merge before pull request --- README.md | 4 +- jquery.flowchart.js | 102 ++++++++++++++++++++++++++++++++++++++-- jquery.flowchart.min.js | 2 +- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f554d56..34594d5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Contributors ------------ * Simone Gasparini - alias [@simmyg89](https://github.com/simmyg89) - for bug fixes and code formatting. * Guijin Ding - alias [@dingguijin](https://github.com/dingguijin) - for bug fixes. -* Fatih Marabaoğlu - alias [@MonoLightTech](https://github.com/MFatihMAR) - for adding the uncontained parameter and improving the grid system. +* Fatih Marabaoglu - alias [@MonoLightTech](https://github.com/MFatihMAR) - for adding the uncontained parameter and improving the grid system. * Peter Vavro - alias [@petervavro](https://github.com/petervavro) - for adding mouse events. * Mike Branham - alias [@Mike-Branham](https://github.com/Mike-Branham) - for bug fixes in the demo page. @@ -79,6 +79,8 @@ http://sebastien.drouyer.com/jquery.flowchart-demo/ * __toConnector:__ ID of the connector the link goes to. * __toSubConnector:__ (optional) If it is a multiple connector, which subconnector is it. * __color:__ Color of the link. If undefined, default value is the same as `defaultLinkColor`. + + * __linkRestrictions:__ (optional, default: `[]`) If not empty, define which links are allowed. Same structure as `links`. * __operatorTypes:__ (optional) Hash allowing you to define common operator types in order to not repeat the properties key. Key define the operator's type ID and the value define the properties (same structure as `data.operators.properties`). diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 7ceb862..7cd394d 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -186,6 +186,11 @@ $(function () { if (typeof data.operatorTypes != 'undefined') { this.data.operatorTypes = data.operatorTypes; } + + this.data.linkRestrictions = []; + if(typeof data.linkRestrictions != 'undefined' && data.linkRestrictions.length>0) { + this.data.linkRestrictions = data.linkRestrictions; + } this.data.operators = {}; for (var operatorId in data.operators) { @@ -216,6 +221,11 @@ $(function () { if (!this.options.onLinkCreate(linkId, linkData)) { return; } + + var restrictionLinkIndex = this._indexOfLinkGranted(linkData); + if(restrictionLinkIndex == -1) { + return; + } var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; @@ -245,12 +255,44 @@ $(function () { this._autoCreateSubConnector(linkData.fromOperator, linkData.fromConnector, 'outputs', fromSubConnector); this._autoCreateSubConnector(linkData.toOperator, linkData.toConnector, 'inputs', toSubConnector); + + //try to colorize link with restriction link data + if(restrictionLinkIndex!=null) { + var restriction = this.data.linkRestrictions[restrictionLinkIndex]; + if(typeof restriction.color != 'undefined') { + linkData.color = restriction.color; + } + } this.data.links[linkId] = linkData; this._drawLink(linkId); this.options.onAfterChange('link_create'); }, + + /** Search into this.data.linkRestrictions if the given link is granted + * Return null if linkRestrictions is disabled (empty array) + * Return -1 if the link is forbidden, and the index into the link restriction array otherwise + */ + _indexOfLinkGranted: function(linkData) { + if(this.data.linkRestrictions.length == 0) { + return null; + } + + var linkRestrictions = this.data.linkRestrictions; + + for(var i=0; i'),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var r=$(this),o=r.offset();t._mousemove((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.element.click(function(e){var r=$(this),o=r.offset();t._click((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(e){t._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(e){t._operatorMouseOut($(this).data("operator_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var r in t.links)t.links.hasOwnProperty(r)&&this.createLink(r,t.links[r]);this.redrawLinksLayer()},addLink:function(t){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var r=$.extend(!0,{},e);if(this.options.onLinkCreate(t,r)){var o=this._getSubConnectors(r),n=o[0],i=o[1],a=this.options.multipleLinksOnOutput,s=this.options.multipleLinksOnInput;if(!a||!s)for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var p=this.data.links[l],c=this._getSubConnectors(p),u=c[0],h=c[1];if(!a&&p.fromOperator==r.fromOperator&&p.fromConnector==r.fromConnector&&u==n){this.deleteLink(l);continue}s||p.toOperator!=r.toOperator||p.toConnector!=r.toConnector||h!=i||this.deleteLink(l)}this._autoCreateSubConnector(r.fromOperator,r.fromConnector,"outputs",n),this._autoCreateSubConnector(r.toOperator,r.toConnector,"inputs",i),this.data.links[t]=r,this._drawLink(t),this.options.onAfterChange("link_create")}},_autoCreateSubConnector:function(t,e,r,o){var n=this.data.operators[t].properties[r][e];if(n.multiple)for(var i=this.data.operators[t].internal.els,a=this.data.operators[t].internal.els.connectors[e].length,s=a;o+2>s;s++)this._createSubConnector(e,n,i)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,r){var o=this.data.operators[t],n=o.internal.els.connectorArrows[e][r],i=n.offset(),a=this.element.offset(),s=(i.left-a.left)/this.positionRatio,l=parseInt(n.css("border-top-width")),p=(i.top-a.top-1)/this.positionRatio+parseInt(n.css("border-left-width"));return{x:s,width:l,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,r=this.data.links[t];return"undefined"!=typeof r.color&&(e=r.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];"undefined"==typeof e.internal&&(e.internal={}),e.internal.els={};var r=e.fromOperator,o=e.fromConnector,n=e.toOperator,i=e.toConnector,a=this._getSubConnectors(e),s=a[0],l=a[1],c=(this.getLinkMainColor(t),this.data.operators[r]),u=this.data.operators[n],h=c.internal.els.connectorSmallArrows[o][s],d=u.internal.els.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=d;var f=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(f),e.internal.els.overallGroup=f;var v=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,v.setAttribute("id",k),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.setAttribute("x","0"),m.setAttribute("y","0"),m.setAttribute("width","100%"),m.setAttribute("height","100%"),m.setAttribute("stroke","none"),m.setAttribute("fill","white"),v.appendChild(m);var C=document.createElementNS("http://www.w3.org/2000/svg","polygon");C.setAttribute("stroke","none"),C.setAttribute("fill","black"),v.appendChild(C),e.internal.els.mask=C;var O=document.createElementNS("http://www.w3.org/2000/svg","g");O.setAttribute("class","flowchart-link"),O.setAttribute("data-link_id",t),f.appendChild(O);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",this.options.linkWidth.toString()),w.setAttribute("fill","none"),O.appendChild(w),e.internal.els.path=w;var b=document.createElementNS("http://www.w3.org/2000/svg","rect");b.setAttribute("stroke","none"),b.setAttribute("mask","url(#"+k+")"),O.appendChild(b),e.internal.els.rect=b,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;"undefined"!=typeof t.fromSubConnector&&(e=t.fromSubConnector);var r=0;return"undefined"!=typeof t.toSubConnector&&(r=t.toSubConnector),[e,r]},_refreshLinkPositions:function(t){var e=this.data.links[t],r=this._getSubConnectors(e),o=r[0],n=r[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,o),a=this.getConnectorPosition(e.toOperator,e.toConnector,n),s=i.x,l=i.width,p=i.y,c=a.x,u=a.y;p+=this.options.linkVerticalDecal,u+=this.options.linkVerticalDecal;var h=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",s+","+(p-l-h)+" "+(s+l+h)+","+p+" "+s+","+(p+l+h));var d=s+l+h,f=c+1,v=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(p-u)));e.internal.els.path.setAttribute("d","M"+d+","+p+" C"+(s+l+h+v)+","+p+" "+(c-v)+","+u+" "+f+","+u),e.internal.els.rect.setAttribute("x",s),e.internal.els.rect.setAttribute("y",p-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+h+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){"undefined"==typeof t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var r in e.inputs)e.inputs.hasOwnProperty(r)&&null==e.inputs[r]&&delete e.inputs[r];for(var o in e.outputs)e.outputs.hasOwnProperty(o)&&null==e.outputs[o]&&delete e.outputs[o];return"undefined"==typeof e["class"]&&(e["class"]=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function d(t,e,r,o){var n=$('
');n.data("connector_type",o),n.appendTo(r),l[t]=[],p[t]=[],u[t]=[],c[t]=n,s._createSubConnector(t,e,h)}var e=this.getOperatorCompleteData(t),r=$('
');r.addClass(e["class"]);var o=$('
');o.html(e.title),o.appendTo(r);var n=$('
');n.appendTo(r);var i=$('
');i.appendTo(n);var a=$('
');a.appendTo(n);var s=this,l={},p={},c={},u={},h={operator:r,title:o,connectorSets:c,connectors:u,connectorArrows:l,connectorSmallArrows:p};for(var f in e.inputs)e.inputs.hasOwnProperty(f)&&d(f,e.inputs[f],i,"inputs");for(var v in e.outputs)e.outputs.hasOwnProperty(v)&&d(v,e.outputs[v],a,"outputs");return h},_createSubConnector:function(t,e,r){var o=r.connectorSets[t],n=r.connectors[t].length,i=$('
');i.appendTo(o),i.data("connector",t),i.data("sub_connector",n);var a=$('
');a.text(e.label.replace("(:i)",n+1)),a.appendTo(i);var s=$('
');s.appendTo(i);var l=$('
');l.appendTo(i),r.connectors[t].push(i),r.connectorArrows[t].push(s),r.connectorSmallArrows[t].push(l)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function i(t,r){e.top=r.top,e.left=r.left;for(var o in n.data.links)if(n.data.links.hasOwnProperty(o)){var i=n.data.links[o];(i.fromOperator==t||i.toOperator==t)&&n._refreshLinkPositions(o)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var o=this.options.grid;o&&(e.top=Math.round(e.top/o)*o,e.left=Math.round(e.left/o)*o),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var n=this;if(this.options.canUserMoveOperators){var a,s;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t,e){if(null!=n.lastOutputConnectorClicked)return void t.preventDefault();var r=n.element.offset();a=(t.pageX-r.left)/n.positionRatio-parseInt($(t.target).css("left")),s=(t.pageY-r.top)/n.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,o){if(n.options.grid){var l=n.options.grid,p=n.element.offset();if(o.position.left=Math.round(((t.pageX-p.left)/n.positionRatio-a)/l)*l,o.position.top=Math.round(((t.pageY-p.top)/n.positionRatio-s)/l)*l,!e.internal.properties.uncontained){var c=$(this);o.position.left=Math.min(Math.max(o.position.left,0),n.element.width()-c.outerWidth()),o.position.top=Math.min(Math.max(o.position.top,0),n.element.height()-c.outerHeight())}o.offset.left=Math.round(o.position.left+p.left),o.offset.top=Math.round(o.position.top+p.top),r.operator.css({left:o.position.left,top:o.position.top})}i($(this).data("operator_id"),o.position)},stop:function(t,e){n._unsetTemporaryLink();var o=$(this).data("operator_id");i(o,e.position),r.operator.css({height:"auto"}),n.options.onOperatorMoved(o,e.position),n.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,r,o){if("outputs"==o){new Date;this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:r},this.objs.layers.temporaryLink.show();var i=this.getConnectorPosition(t,e,r),a=i.x+i.width,s=i.y;this.objs.temporaryLink.setAttribute("x1",a.toString()),this.objs.temporaryLink.setAttribute("y1",s.toString()),this._mousemove(a,s)}if("inputs"==o&&null!=this.lastOutputConnectorClicked){var l={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:r};this.addLink(l),this._unsetTemporaryLink()}},_unsetTemporaryLink:function(){this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e,r){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,r){var o=$(r.target);0==o.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==o.closest(".flowchart-operator").length&&this.unselectOperator(),0==o.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},addClassOperator:function(t,e){this.data.operators[t].internal.els.operator.addClass(e)},removeClassOperator:function(t,e){this.data.operators[t].internal.els.operator.removeClass(e)},removeClassOperators:function(t){this.objs.layers.operators.find(".flowchart-operator").removeClass(t)},_addHoverClassOperator:function(t){this.data.operators[t].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(t){this.options.onOperatorMouseOver(t)&&this._addHoverClassOperator(t)},_operatorMouseOut:function(t){this.options.onOperatorMouseOut(t)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var r=parseInt(t.slice(1),16),o=0>e?0:255,n=0>e?-1*e:e,i=r>>16,a=r>>8&255,s=255&r;return"#"+(16777216+65536*(Math.round((o-i)*n)+i)+256*(Math.round((o-a)*n)+a)+(Math.round((o-s)*n)+s)).toString(16).slice(1)},colorizeLink:function(t,e){var r=this.data.links[t];r.internal.els.path.setAttribute("stroke",e),r.internal.els.rect.setAttribute("fill",e),r.internal.els.fromSmallConnector.css("border-left-color",e),r.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var o=this.data.links[r];(o.fromOperator==t||o.toOperator==t)&&this._deleteLink(r,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var r=this.data.links[t],o=r.fromOperator,n=r.fromConnector,i=r.toOperator,a=r.toConnector;r.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(o,n,"from"),this._cleanMultipleConnectors(i,a,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,r){if(this.data.operators[t].properties["from"==r?"outputs":"inputs"][e].multiple){var o=-1,n=r+"Operator",i=r+"Connector",a=r+"SubConnector",s=this.data.operators[t].internal.els,l=s.connectors[e],p=l.length;for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var u=this.data.links[c];u[n]==t&&u[i]==e&&od;d++)l[l.length-1].remove(),l.pop(),s.connectorArrows[e].pop(),s.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links);for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];for(var n in e[o])e[o].hasOwnProperty(n)&&delete e[o][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),"undefined"==typeof this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var r=this.getOperatorCompleteData(e);for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var n=this.data.links[o];(n.fromOperator==t&&"undefined"==typeof r.outputs[n.fromConnector]||n.toOperator==t&&"undefined"==typeof r.inputs[n.toConnector])&&this._deleteLink(o,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},doesOperatorExists:function(t){return"undefined"!=typeof this.data.operators[t]},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if("undefined"!=typeof t.type){var e=this.data.operatorTypes[t.type],r={};return"undefined"!=typeof t.properties&&(r=t.properties),$.extend({},e,r)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file +$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(a){return!0},onOperatorUnselect:function(){return!0},onOperatorMouseOver:function(a){return!0},onOperatorMouseOut:function(a){return!0},onLinkSelect:function(a){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(a,b,c){return!0},onLinkCreate:function(a,b){return!0},onOperatorDelete:function(a){return!0},onLinkDelete:function(a,b){return!0},onOperatorMoved:function(a,b){},onAfterChange:function(a){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var a=document.createElementNS("http://www.w3.org/2000/svg","line");a.setAttribute("x1","0"),a.setAttribute("y1","0"),a.setAttribute("x2","0"),a.setAttribute("y2","0"),a.setAttribute("stroke-dasharray","6,6"),a.setAttribute("stroke-width","4"),a.setAttribute("stroke","black"),a.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(a),this.objs.temporaryLink=a,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var a=this;this.element.mousemove(function(b){var c=$(this),d=c.offset();a._mousemove((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.element.click(function(b){var c=$(this),d=c.offset();a._click((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(a){a.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(b){0==$(b.target).closest(".flowchart-operator-connector").length&&a.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var b=$(this);a.options.canUserEditLinks&&a._connectorClicked(b.closest(".flowchart-operator").data("operator_id"),b.data("connector"),b.data("sub_connector"),b.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(a){a.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){a._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){a._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){a.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(b){a._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(b){a._operatorMouseOut($(this).data("operator_id"))})},setData:function(a){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof a.operatorTypes&&(this.data.operatorTypes=a.operatorTypes),this.data.linkRestrictions=[],"undefined"!=typeof a.linkRestrictions&&a.linkRestrictions.length>0&&(this.data.linkRestrictions=a.linkRestrictions),this.data.operators={};for(var b in a.operators)a.operators.hasOwnProperty(b)&&this.createOperator(b,a.operators[b]);this.data.links={};for(var c in a.links)a.links.hasOwnProperty(c)&&this.createLink(c,a.links[c]);this.redrawLinksLayer()},addLink:function(a){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,a),this.linkNum},createLink:function(a,b){var c=$.extend(!0,{},b);if(this.options.onLinkCreate(a,c)){var d=this._indexOfLinkGranted(c);if(d!=-1){var e=this._getSubConnectors(c),f=e[0],g=e[1],h=this.options.multipleLinksOnOutput,i=this.options.multipleLinksOnInput;if(!h||!i)for(var j in this.data.links)if(this.data.links.hasOwnProperty(j)){var k=this.data.links[j],l=this._getSubConnectors(k),m=l[0],n=l[1];if(!h&&k.fromOperator==c.fromOperator&&k.fromConnector==c.fromConnector&&m==f){this.deleteLink(j);continue}i||k.toOperator!=c.toOperator||k.toConnector!=c.toConnector||n!=g||this.deleteLink(j)}if(this._autoCreateSubConnector(c.fromOperator,c.fromConnector,"outputs",f),this._autoCreateSubConnector(c.toOperator,c.toConnector,"inputs",g),null!=d){var o=this.data.linkRestrictions[d];"undefined"!=typeof o.color&&(c.color=o.color)}this.data.links[a]=c,this._drawLink(a),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(a){if(0==this.data.linkRestrictions.length)return null;for(var b=this.data.linkRestrictions,c=0;c');e.data("connector_type",d),e.appendTo(c),i[a]=[],j[a]=[],l[a]=[],k[a]=e,h._createSubConnector(a,b,m)}var b=this.getOperatorCompleteData(a),c=$('
');c.addClass(b.class);var d=$('
');d.html(b.title),d.appendTo(c);var e=$('
');e.appendTo(c);var f=$('
');f.appendTo(e);var g=$('
');g.appendTo(e);var h=this,i={},j={},k={},l={},m={operator:c,title:d,connectorSets:k,connectors:l,connectorArrows:i,connectorSmallArrows:j};for(var o in b.inputs)b.inputs.hasOwnProperty(o)&&n(o,b.inputs[o],f,"inputs");for(var p in b.outputs)b.outputs.hasOwnProperty(p)&&n(p,b.outputs[p],g,"outputs");return m},_createSubConnector:function(a,b,c){var d=c.connectorSets[a],e=c.connectors[a].length,f=$('
');f.appendTo(d),f.data("connector",a),f.data("sub_connector",e);var g=$('
');g.text(b.label.replace("(:i)",e+1)),g.appendTo(f);var h=$('
');h.appendTo(f);var i=$('
');i.appendTo(f),c.connectors[a].push(f),c.connectorArrows[a].push(h),c.connectorSmallArrows[a].push(i)},getOperatorElement:function(a){var b=this._getOperatorFullElement(a);return b.operator},addOperator:function(a){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,a),this.operatorNum},createOperator:function(a,b){function f(a,c){b.top=c.top,b.left=c.left;for(var d in e.data.links)if(e.data.links.hasOwnProperty(d)){var f=e.data.links[d];f.fromOperator!=a&&f.toOperator!=a||e._refreshLinkPositions(d)}}b.internal={},this._refreshInternalProperties(b);var c=this._getOperatorFullElement(b);if(!this.options.onOperatorCreate(a,b,c))return!1;var d=this.options.grid;d&&(b.top=Math.round(b.top/d)*d,b.left=Math.round(b.left/d)*d),c.operator.appendTo(this.objs.layers.operators),c.operator.css({top:b.top,left:b.left}),c.operator.data("operator_id",a),this.data.operators[a]=b,this.data.operators[a].internal.els=c,a==this.selectedOperatorId&&this._addSelectedClass(a);var e=this;if(this.options.canUserMoveOperators){var g,h;c.operator.draggable({containment:!b.internal.properties.uncontained&&this.element,handle:".flowchart-operator-title",start:function(a,b){if(null!=e.lastOutputConnectorClicked)return void a.preventDefault();var c=e.element.offset();g=(a.pageX-c.left)/e.positionRatio-parseInt($(a.target).css("left")),h=(a.pageY-c.top)/e.positionRatio-parseInt($(a.target).css("top"))},drag:function(a,d){if(e.options.grid){var i=e.options.grid,j=e.element.offset();if(d.position.left=Math.round(((a.pageX-j.left)/e.positionRatio-g)/i)*i,d.position.top=Math.round(((a.pageY-j.top)/e.positionRatio-h)/i)*i,!b.internal.properties.uncontained){var k=$(this);d.position.left=Math.min(Math.max(d.position.left,0),e.element.width()-k.outerWidth()),d.position.top=Math.min(Math.max(d.position.top,0),e.element.height()-k.outerHeight())}d.offset.left=Math.round(d.position.left+j.left),d.offset.top=Math.round(d.position.top+j.top),c.operator.css({left:d.position.left,top:d.position.top})}f($(this).data("operator_id"),d.position)},stop:function(a,b){e._unsetTemporaryLink();var d=$(this).data("operator_id");f(d,b.position),c.operator.css({height:"auto"}),e.options.onOperatorMoved(d,b.position),e.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(a,b,c,d){if("outputs"==d){new Date;this.lastOutputConnectorClicked={operator:a,connector:b,subConnector:c,grantedLinks:this._getGrantedLinks(a,b)},this.objs.layers.temporaryLink.show();var f=this.getConnectorPosition(a,b,c),g=f.x+f.width,h=f.y;this.objs.temporaryLink.setAttribute("x1",g.toString()),this.objs.temporaryLink.setAttribute("y1",h.toString()),this._mousemove(g,h),this._colorizeGrantedLinks()}if("inputs"==d&&null!=this.lastOutputConnectorClicked){var i={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:a,toConnector:b,toSubConnector:c};this._unsetTemporaryLink(),this.addLink(i)}},_getGrantedLinks:function(a,b){if(0==this.data.linkRestrictions.length)return[];var c=this.data.linkRestrictions.filter(function(c){return a==c.fromOperator&&b==c.fromConnector}),d=this;return c.map(function(a){"undefined"==typeof a.color&&(a.color=defaultLinkColor);var b=d.data.operators[a.toOperator],c=b.internal.els.connectorSmallArrows[a.toConnector];return a.smallArrows=c.map(function(a){return{els:a,oldColor:a.css("border-left-color")}}),a})},_colorizeGrantedLinks:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(b){b.els.css("border-left-color",a.color)})})}},_restoreGrantedLinksColor:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(a){a.els.css("border-left-color",a.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedLinksColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(a,b,c){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",a),this.objs.temporaryLink.setAttribute("y2",b))},_click:function(a,b,c){var d=$(c.target);0==d.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==d.closest(".flowchart-operator").length&&this.unselectOperator(),0==d.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(a){this.data.operators[a].internal.els.operator.addClass("selected")},selectOperator:function(a){this.options.onOperatorSelect(a)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(a),this.selectedOperatorId=a)},addClassOperator:function(a,b){this.data.operators[a].internal.els.operator.addClass(b)},removeClassOperator:function(a,b){this.data.operators[a].internal.els.operator.removeClass(b)},removeClassOperators:function(a){this.objs.layers.operators.find(".flowchart-operator").removeClass(a)},_addHoverClassOperator:function(a){this.data.operators[a].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(a){this.options.onOperatorMouseOver(a)&&this._addHoverClassOperator(a)},_operatorMouseOut:function(a){this.options.onOperatorMouseOut(a)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(a,b){var c=parseInt(a.slice(1),16),d=b<0?0:255,e=b<0?b*-1:b,f=c>>16,g=c>>8&255,h=255&c;return"#"+(16777216+65536*(Math.round((d-f)*e)+f)+256*(Math.round((d-g)*e)+g)+(Math.round((d-h)*e)+h)).toString(16).slice(1)},colorizeLink:function(a,b){var c=this.data.links[a];c.internal.els.path.setAttribute("stroke",b),c.internal.els.rect.setAttribute("fill",b),c.internal.els.fromSmallConnector.css("border-left-color",b),c.internal.els.toSmallConnector.css("border-left-color",b)},uncolorizeLink:function(a){this.colorizeLink(a,this.getLinkMainColor(a))},_connecterMouseOver:function(a){this.selectedLinkId!=a&&this.colorizeLink(a,this._shadeColor(this.getLinkMainColor(a),-.4))},_connecterMouseOut:function(a){this.selectedLinkId!=a&&this.uncolorizeLink(a)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(a){this.unselectLink(),this.options.onLinkSelect(a)&&(this.unselectOperator(),this.selectedLinkId=a,this.colorizeLink(a,this.options.defaultSelectedLinkColor))},deleteOperator:function(a){this._deleteOperator(a,!1)},_deleteOperator:function(a,b){if(!this.options.onOperatorDelete(a,b))return!1;if(!b)for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var d=this.data.links[c];d.fromOperator!=a&&d.toOperator!=a||this._deleteLink(c,!0)}b||a!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[a].internal.els.operator.remove(),delete this.data.operators[a],this.options.onAfterChange("operator_delete")},deleteLink:function(a){this._deleteLink(a,!1)},_deleteLink:function(a,b){if(this.selectedLinkId==a&&this.unselectLink(),this.options.onLinkDelete(a,b)||b){this.colorizeLink(a,"transparent");var c=this.data.links[a],d=c.fromOperator,e=c.fromConnector,f=c.toOperator,g=c.toConnector;c.internal.els.overallGroup.remove(),delete this.data.links[a],this._cleanMultipleConnectors(d,e,"from"),this._cleanMultipleConnectors(f,g,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(a,b,c){if(this.data.operators[a].properties["from"==c?"outputs":"inputs"][b].multiple){var d=-1,e=c+"Operator",f=c+"Connector",g=c+"SubConnector",h=this.data.operators[a].internal.els,i=h.connectors[b],j=i.length;for(var k in this.data.links)if(this.data.links.hasOwnProperty(k)){var l=this.data.links[k];l[e]==a&&l[f]==b&&d Date: Mon, 2 Jan 2017 11:18:19 +0100 Subject: [PATCH 04/14] Bugfix Bad small arrow selection and strokes display when an operator have the same connector id for an input and an output --- jquery.flowchart.js | 848 ++++++++++++++++++++------------------------ 1 file changed, 386 insertions(+), 462 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 7cd394d..532f9e0 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -1,7 +1,7 @@ -$(function () { +$(function() { // the widget definition, where "custom" is the namespace, // "colorize" the widget name - $.widget("flowchart.flowchart", { + $.widget( "flowchart.flowchart", { // default options options: { canUserEditLinks: true, @@ -16,41 +16,35 @@ $(function () { multipleLinksOnOutput: false, multipleLinksOnInput: false, linkVerticalDecal: 0, - onOperatorSelect: function (operatorId) { + onOperatorSelect: function(operatorId) { return true; }, - onOperatorUnselect: function () { + onOperatorUnselect: function() { return true; }, - onOperatorMouseOver: function (operatorId) { + onLinkSelect: function(linkId) { return true; }, - onOperatorMouseOut: function (operatorId) { + onLinkUnselect: function() { return true; }, - onLinkSelect: function (linkId) { + onOperatorCreate: function(operatorId, operatorData, fullElement) { return true; }, - onLinkUnselect: function () { + onLinkCreate: function(linkId, linkData) { return true; }, - onOperatorCreate: function (operatorId, operatorData, fullElement) { + onOperatorDelete: function(operatorId) { return true; }, - onLinkCreate: function (linkId, linkData) { + onLinkDelete: function(linkId, forced) { return true; }, - onOperatorDelete: function (operatorId) { - return true; - }, - onLinkDelete: function (linkId, forced) { - return true; - }, - onOperatorMoved: function (operatorId, position) { - + onOperatorMoved: function(operatorId, position) { + }, - onAfterChange: function (changeType) { - + onAfterChange: function(changeType) { + } }, data: null, @@ -63,28 +57,29 @@ $(function () { selectedLinkId: null, positionRatio: 1, globalId: null, + // the constructor - _create: function () { + _create: function() { if (typeof document.__flowchartNumber == 'undefined') { - document.__flowchartNumber = 0; + document.__flowchartNumber = 0; } else { - document.__flowchartNumber++; + document.__flowchartNumber++; } this.globalId = document.__flowchartNumber; - this._unitVariables(); - + this._unitVariables(); + this.element.addClass('flowchart-container'); - + this.objs.layers.links = $(''); this.objs.layers.links.appendTo(this.element); - + this.objs.layers.operators = $('
'); this.objs.layers.operators.appendTo(this.element); - + this.objs.layers.temporaryLink = $(''); this.objs.layers.temporaryLink.appendTo(this.element); - + var shape = document.createElementNS("http://www.w3.org/2000/svg", "line"); shape.setAttribute("x1", "0"); shape.setAttribute("y1", "0"); @@ -96,18 +91,18 @@ $(function () { shape.setAttribute("fill", "none"); this.objs.layers.temporaryLink[0].appendChild(shape); this.objs.temporaryLink = shape; - + this._initEvents(); - + if (typeof this.options.data != 'undefined') { this.setData(this.options.data); } }, - - _unitVariables: function () { + + _unitVariables: function() { this.data = { operators: {}, - links: {} + links: {}, }; this.objs = { layers: { @@ -119,158 +114,145 @@ $(function () { temporaryLink: null }; }, - - _initEvents: function () { - + + _initEvents: function() { + var self = this; - - this.element.mousemove(function (e) { + + this.element.mousemove(function(e) { var $this = $(this); var offset = $this.offset(); self._mousemove((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - this.element.click(function (e) { + + this.element.click(function(e) { var $this = $(this); var offset = $this.offset(); self._click((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - - this.objs.layers.operators.on('pointerdown mousedown touchstart', '.flowchart-operator', function (e) { + + + + this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function(e) { e.stopImmediatePropagation(); }); - - this.objs.layers.operators.on('click', '.flowchart-operator', function (e) { + + this.objs.layers.operators.on('click', '.flowchart-operator', function(e) { if ($(e.target).closest('.flowchart-operator-connector').length == 0) { self.selectOperator($(this).data('operator_id')); } }); - - this.objs.layers.operators.on('click', '.flowchart-operator-connector', function () { + + this.objs.layers.operators.on('click', '.flowchart-operator-connector', function() { var $this = $(this); if (self.options.canUserEditLinks) { self._connectorClicked($this.closest('.flowchart-operator').data('operator_id'), $this.data('connector'), $this.data('sub_connector'), $this.closest('.flowchart-operator-connector-set').data('connector_type')); } }); - - this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function (e) { + + this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function(e) { e.stopImmediatePropagation(); }); - - this.objs.layers.links.on('mouseover', '.flowchart-link', function () { + + this.objs.layers.links.on('mouseover', '.flowchart-link', function() { self._connecterMouseOver($(this).data('link_id')); }); - - this.objs.layers.links.on('mouseout', '.flowchart-link', function () { + + this.objs.layers.links.on('mouseout', '.flowchart-link', function() { self._connecterMouseOut($(this).data('link_id')); }); - - this.objs.layers.links.on('click', '.flowchart-link', function () { + + this.objs.layers.links.on('click', '.flowchart-link', function() { self.selectLink($(this).data('link_id')); }); - - this.objs.layers.operators.on('mouseover', '.flowchart-operator', function (e) { - self._operatorMouseOver($(this).data('operator_id')); - }); - - this.objs.layers.operators.on('mouseout', '.flowchart-operator', function (e) { - self._operatorMouseOut($(this).data('operator_id')); - }); - + + }, - - setData: function (data) { + + setData: function(data) { this._clearOperatorsLayer(); this.data.operatorTypes = {}; if (typeof data.operatorTypes != 'undefined') { - this.data.operatorTypes = data.operatorTypes; + this.data.operatorTypes = data.operatorTypes; } - - this.data.linkRestrictions = []; + + this.data.linkRestrictions = []; if(typeof data.linkRestrictions != 'undefined' && data.linkRestrictions.length>0) { this.data.linkRestrictions = data.linkRestrictions; } - + this.data.operators = {}; for (var operatorId in data.operators) { - if (data.operators.hasOwnProperty(operatorId)) { - this.createOperator(operatorId, data.operators[operatorId]); - } + this.createOperator(operatorId, data.operators[operatorId]); } - this.data.links = {}; for (var linkId in data.links) { - if (data.links.hasOwnProperty(linkId)) { - this.createLink(linkId, data.links[linkId]); - } + this.createLink(linkId, data.links[linkId]); } this.redrawLinksLayer(); }, - - addLink: function (linkData) { - while (typeof this.data.links[this.linkNum] != 'undefined') { + + addLink: function(linkData) { + while(typeof this.data.links[this.linkNum] != 'undefined') { this.linkNum++; } - + this.createLink(this.linkNum, linkData); return this.linkNum; }, - - createLink: function (linkId, linkDataOriginal) { + + createLink: function(linkId, linkDataOriginal) { var linkData = $.extend(true, {}, linkDataOriginal); if (!this.options.onLinkCreate(linkId, linkData)) { return; } - - var restrictionLinkIndex = this._indexOfLinkGranted(linkData); + + var restrictionLinkIndex = this._indexOfLinkGranted(linkData); if(restrictionLinkIndex == -1) { return; } - + var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - + var multipleLinksOnOutput = this.options.multipleLinksOnOutput; var multipleLinksOnInput = this.options.multipleLinksOnInput; if (!multipleLinksOnOutput || !multipleLinksOnInput) { for (var linkId2 in this.data.links) { - if (this.data.links.hasOwnProperty(linkId2)) { - var currentLink = this.data.links[linkId2]; - - var currentSubConnectors = this._getSubConnectors(currentLink); - var currentFromSubConnector = currentSubConnectors[0]; - var currentToSubConnector = currentSubConnectors[1]; - - if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { - this.deleteLink(linkId2); - continue; - } - if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { - this.deleteLink(linkId2); - } + var currentLink = this.data.links[linkId2]; + + var currentSubConnectors = this._getSubConnectors(currentLink); + var currentFromSubConnector = currentSubConnectors[0]; + var currentToSubConnector = currentSubConnectors[1]; + + if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { + this.deleteLink(linkId2); + continue; + } + if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { + this.deleteLink(linkId2); + continue; } } } - + this._autoCreateSubConnector(linkData.fromOperator, linkData.fromConnector, 'outputs', fromSubConnector); this._autoCreateSubConnector(linkData.toOperator, linkData.toConnector, 'inputs', toSubConnector); - - //try to colorize link with restriction link data + + //try to colorize link with restriction link data if(restrictionLinkIndex!=null) { var restriction = this.data.linkRestrictions[restrictionLinkIndex]; if(typeof restriction.color != 'undefined') { linkData.color = restriction.color; } } - + this.data.links[linkId] = linkData; this._drawLink(linkId); - this.options.onAfterChange('link_create'); }, - - /** Search into this.data.linkRestrictions if the given link is granted + + /** Search into this.data.linkRestrictions if the given link is granted * Return null if linkRestrictions is disabled (empty array) * Return -1 if the link is forbidden, and the index into the link restriction array otherwise */ @@ -293,51 +275,49 @@ $(function () { return -1; }, - - _autoCreateSubConnector: function (operator, connector, connectorType, subConnector) { + + _autoCreateSubConnector: function(operator, connector, connectorType, subConnector) { var connectorInfos = this.data.operators[operator].properties[connectorType][connector]; - if (connectorInfos.multiple) { + if (connectorInfos.multiple) { var fromFullElement = this.data.operators[operator].internal.els; var nbFromConnectors = this.data.operators[operator].internal.els.connectors[connector].length; for (var i = nbFromConnectors; i < subConnector + 2; i++) { - this._createSubConnector(connector, connectorInfos, fromFullElement); + this._createSubConnector(connector, connectorInfos, fromFullElement, connectorType); } } }, - - redrawLinksLayer: function () { + + redrawLinksLayer: function() { this._clearLinksLayer(); for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - this._drawLink(linkId); - } + this._drawLink(linkId); } }, - - _clearLinksLayer: function () { + + _clearLinksLayer: function() { this.objs.layers.links.empty(); this.objs.layers.operators.find('.flowchart-operator-connector-small-arrow').css('border-left-color', 'transparent'); }, - - _clearOperatorsLayer: function () { + + _clearOperatorsLayer: function() { this.objs.layers.operators.empty(); }, - - getConnectorPosition: function (operatorId, connectorId, subConnector) { + + getConnectorPosition: function(operatorId, connectorId, subConnector, connectorType) { var operatorData = this.data.operators[operatorId]; - var $connector = operatorData.internal.els.connectorArrows[connectorId][subConnector]; - + var $connector = operatorData.internal.els[connectorType].connectorArrows[connectorId][subConnector]; + var connectorOffset = $connector.offset(); var elementOffset = this.element.offset(); - + var x = (connectorOffset.left - elementOffset.left) / this.positionRatio; var width = parseInt($connector.css('border-top-width')); var y = (connectorOffset.top - elementOffset.top - 1) / this.positionRatio + parseInt($connector.css('border-left-width')); - + return {x: x, width: width, y: y}; }, - - getLinkMainColor: function (linkId) { + + getLinkMainColor: function(linkId) { var color = this.options.defaultLinkColor; var linkData = this.data.links[linkId]; if (typeof linkData.color != 'undefined') { @@ -345,51 +325,51 @@ $(function () { } return color; }, - - setLinkMainColor: function (linkId, color) { + + setLinkMainColor: function(linkId, color) { this.data.links[linkId].color = color; this.options.onAfterChange('link_change_main_color'); }, - - _drawLink: function (linkId) { + + _drawLink: function(linkId) { var linkData = this.data.links[linkId]; - + if (typeof linkData.internal == 'undefined') { linkData.internal = {}; } linkData.internal.els = {}; - + var fromOperatorId = linkData.fromOperator; var fromConnectorId = linkData.fromConnector; var toOperatorId = linkData.toOperator; var toConnectorId = linkData.toConnector; - + var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - + var color = this.getLinkMainColor(linkId); - + var fromOperator = this.data.operators[fromOperatorId]; var toOperator = this.data.operators[toOperatorId]; - - var fromSmallConnector = fromOperator.internal.els.connectorSmallArrows[fromConnectorId][fromSubConnector]; - var toSmallConnector = toOperator.internal.els.connectorSmallArrows[toConnectorId][toSubConnector]; - + + var fromSmallConnector = fromOperator.internal.els.outputs.connectorSmallArrows[fromConnectorId][fromSubConnector]; + var toSmallConnector = toOperator.internal.els.inputs.connectorSmallArrows[toConnectorId][toSubConnector]; + linkData.internal.els.fromSmallConnector = fromSmallConnector; linkData.internal.els.toSmallConnector = toSmallConnector; - + var overallGroup = document.createElementNS("http://www.w3.org/2000/svg", "g"); this.objs.layers.links[0].appendChild(overallGroup); linkData.internal.els.overallGroup = overallGroup; - + var mask = document.createElementNS("http://www.w3.org/2000/svg", "mask"); var maskId = "fc_mask_" + this.globalId + "_" + this.maskNum; this.maskNum++; mask.setAttribute("id", maskId); - + overallGroup.appendChild(mask); - + var shape = document.createElementNS("http://www.w3.org/2000/svg", "rect"); shape.setAttribute("x", "0"); shape.setAttribute("y", "0"); @@ -398,35 +378,38 @@ $(function () { shape.setAttribute("stroke", "none"); shape.setAttribute("fill", "white"); mask.appendChild(shape); - - var shape_polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); - shape_polygon.setAttribute("stroke", "none"); - shape_polygon.setAttribute("fill", "black"); - mask.appendChild(shape_polygon); - linkData.internal.els.mask = shape_polygon; - + + var shape = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); + shape.setAttribute("stroke", "none"); + shape.setAttribute("fill", "black"); + mask.appendChild(shape); + linkData.internal.els.mask = shape; + + var group = document.createElementNS("http://www.w3.org/2000/svg", "g"); group.setAttribute('class', 'flowchart-link'); group.setAttribute('data-link_id', linkId); overallGroup.appendChild(group); - - var shape_path = document.createElementNS("http://www.w3.org/2000/svg", "path"); - shape_path.setAttribute("stroke-width", this.options.linkWidth.toString()); - shape_path.setAttribute("fill", "none"); - group.appendChild(shape_path); - linkData.internal.els.path = shape_path; - - var shape_rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - shape_rect.setAttribute("stroke", "none"); - shape_rect.setAttribute("mask", "url(#" + maskId + ")"); - group.appendChild(shape_rect); - linkData.internal.els.rect = shape_rect; - + + + var shape = document.createElementNS("http://www.w3.org/2000/svg", "path"); + shape.setAttribute("stroke-width", this.options.linkWidth); + shape.setAttribute("fill", "none"); + group.appendChild(shape); + linkData.internal.els.path = shape; + + var shape = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + shape.setAttribute("stroke", "none"); + shape.setAttribute("mask", "url(#"+maskId+")"); + group.appendChild(shape); + linkData.internal.els.rect = shape; + + this._refreshLinkPositions(linkId); this.uncolorizeLink(linkId); }, - - _getSubConnectors: function (linkData) { + + _getSubConnectors: function(linkData) { var fromSubConnector = 0; if (typeof linkData.fromSubConnector != 'undefined') { fromSubConnector = linkData.fromSubConnector; @@ -436,146 +419,142 @@ $(function () { if (typeof linkData.toSubConnector != 'undefined') { toSubConnector = linkData.toSubConnector; } - + return [fromSubConnector, toSubConnector]; }, - - _refreshLinkPositions: function (linkId) { + + _refreshLinkPositions: function(linkId) { var linkData = this.data.links[linkId]; - + var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - - var fromPosition = this.getConnectorPosition(linkData.fromOperator, linkData.fromConnector, fromSubConnector); - var toPosition = this.getConnectorPosition(linkData.toOperator, linkData.toConnector, toSubConnector); - + + var fromPosition = this.getConnectorPosition(linkData.fromOperator, linkData.fromConnector, fromSubConnector, 'outputs'); + var toPosition = this.getConnectorPosition(linkData.toOperator, linkData.toConnector, toSubConnector, 'inputs'); + var fromX = fromPosition.x; var offsetFromX = fromPosition.width; var fromY = fromPosition.y; - + var toX = toPosition.x; var toY = toPosition.y; - + fromY += this.options.linkVerticalDecal; toY += this.options.linkVerticalDecal; - + var distanceFromArrow = this.options.distanceFromArrow; - - linkData.internal.els.mask.setAttribute("points", fromX + ',' + (fromY - offsetFromX - distanceFromArrow) + ' ' + (fromX + offsetFromX + distanceFromArrow) + ',' + fromY + ' ' + fromX + ',' + (fromY + offsetFromX + distanceFromArrow)); - - var bezierFromX = (fromX + offsetFromX + distanceFromArrow); - var bezierToX = toX + 1; - var bezierIntensity = Math.min(100, Math.max(Math.abs(bezierFromX - bezierToX) / 2, Math.abs(fromY - toY))); - - - linkData.internal.els.path.setAttribute("d", 'M' + bezierFromX + ',' + (fromY) + ' C' + (fromX + offsetFromX + distanceFromArrow + bezierIntensity) + ',' + fromY + ' ' + (toX - bezierIntensity) + ',' + toY + ' ' + bezierToX + ',' + toY); - + + linkData.internal.els.mask.setAttribute("points", fromX+','+(fromY - offsetFromX - distanceFromArrow)+' '+(fromX + offsetFromX + distanceFromArrow)+','+fromY+' '+fromX+','+(fromY + offsetFromX + distanceFromArrow)); + + var bezierFromX = (fromX+offsetFromX + distanceFromArrow); + var bezierToX = toX+1; + var bezierIntensity = Math.min(100,Math.max(Math.abs(bezierFromX-bezierToX)/2,Math.abs(fromY-toY))); + + + linkData.internal.els.path.setAttribute("d", 'M'+bezierFromX+','+(fromY)+' C'+(fromX + offsetFromX + distanceFromArrow + bezierIntensity)+','+fromY+' '+(toX - bezierIntensity)+','+toY+' '+bezierToX+','+toY); + linkData.internal.els.rect.setAttribute("x", fromX); linkData.internal.els.rect.setAttribute("y", fromY - this.options.linkWidth / 2); - linkData.internal.els.rect.setAttribute("width", offsetFromX + distanceFromArrow + 1); + linkData.internal.els.rect.setAttribute("width", offsetFromX + distanceFromArrow+1); linkData.internal.els.rect.setAttribute("height", this.options.linkWidth); - + }, - - getOperatorCompleteData: function (operatorData) { + + getOperatorCompleteData: function(operatorData) { if (typeof operatorData.internal == 'undefined') { operatorData.internal = {}; } this._refreshInternalProperties(operatorData); - var infos = $.extend(true, {}, operatorData.internal.properties); - - for (var connectorId_i in infos.inputs) { - if (infos.inputs.hasOwnProperty(connectorId_i)) { - if (infos.inputs[connectorId_i] == null) { - delete infos.inputs[connectorId_i]; - } + infos = $.extend(true, {}, operatorData.internal.properties); + + for (var connectorId in infos.inputs) { + if (infos.inputs[connectorId] == null) { + delete infos.inputs[connectorId]; } } - - for (var connectorId_o in infos.outputs) { - if (infos.outputs.hasOwnProperty(connectorId_o)) { - if (infos.outputs[connectorId_o] == null) { - delete infos.outputs[connectorId_o]; - } + + for (var connectorId in infos.outputs) { + if (infos.outputs[connectorId] == null) { + delete infos.outputs[connectorId]; } } - + if (typeof infos.class == 'undefined') { infos.class = this.options.defaultOperatorClass; } return infos; }, - - _getOperatorFullElement: function (operatorData) { + + _getOperatorFullElement: function(operatorData) { var infos = this.getOperatorCompleteData(operatorData); - + var $operator = $('
'); $operator.addClass(infos.class); - + var $operator_title = $('
'); - $operator_title.html(infos.title); + $operator_title.text(infos.title); $operator_title.appendTo($operator); - + var $operator_inputs_outputs = $('
'); - + + $operator_inputs_outputs.appendTo($operator); - + var $operator_inputs = $('
'); $operator_inputs.appendTo($operator_inputs_outputs); - + var $operator_outputs = $('
'); $operator_outputs.appendTo($operator_inputs_outputs); - + var self = this; - - var connectorArrows = {}; - var connectorSmallArrows = {}; - var connectorSets = {}; - var connectors = {}; - + var fullElement = { - operator: $operator, - title: $operator_title, - connectorSets: connectorSets, - connectors: connectors, - connectorArrows: connectorArrows, - connectorSmallArrows: connectorSmallArrows + operator: $operator, + title: $operator_title, + inputs: { + connectorSets: {}, + connectors: {}, + connectorArrows: {}, + connectorSmallArrows: {} + }, + outputs: { + connectorSets: {}, + connectors: {}, + connectorArrows: {}, + connectorSmallArrows: {} + } }; - + function addConnector(connectorKey, connectorInfos, $operator_container, connectorType) { var $operator_connector_set = $('
'); $operator_connector_set.data('connector_type', connectorType); $operator_connector_set.appendTo($operator_container); - - connectorArrows[connectorKey] = []; - connectorSmallArrows[connectorKey] = []; - connectors[connectorKey] = []; - connectorSets[connectorKey] = $operator_connector_set; - - self._createSubConnector(connectorKey, connectorInfos, fullElement); + + fullElement[connectorType].connectorArrows[connectorKey] = []; + fullElement[connectorType].connectorSmallArrows[connectorKey] = []; + fullElement[connectorType].connectors[connectorKey] = []; + fullElement[connectorType].connectorSets[connectorKey] = $operator_connector_set; + + self._createSubConnector(connectorKey, connectorInfos, fullElement, connectorType); } - - for (var key_i in infos.inputs) { - if (infos.inputs.hasOwnProperty(key_i)) { - addConnector(key_i, infos.inputs[key_i], $operator_inputs, 'inputs'); - } + + for (var key in infos.inputs) { + addConnector(key, infos.inputs[key], $operator_inputs, 'inputs'); } - - for (var key_o in infos.outputs) { - if (infos.outputs.hasOwnProperty(key_o)) { - addConnector(key_o, infos.outputs[key_o], $operator_outputs, 'outputs'); - } + + for (var key in infos.outputs) { + addConnector(key, infos.outputs[key], $operator_outputs, 'outputs'); } - + return fullElement; }, - - _createSubConnector: function (connectorKey, connectorInfos, fullElement) { - var $operator_connector_set = fullElement.connectorSets[connectorKey]; - - var subConnector = fullElement.connectors[connectorKey].length; - + + _createSubConnector: function(connectorKey, connectorInfos, fullElement, connectorType) { + var $operator_connector_set = fullElement[connectorType].connectorSets[connectorKey]; + + var subConnector = fullElement[connectorType].connectors[connectorKey].length; + var $operator_connector = $('
'); $operator_connector.appendTo($operator_connector_set); $operator_connector.data('connector', connectorKey); @@ -592,77 +571,74 @@ $(function () { var $operator_connector_small_arrow = $('
'); $operator_connector_small_arrow.appendTo($operator_connector); - fullElement.connectors[connectorKey].push($operator_connector); - fullElement.connectorArrows[connectorKey].push($operator_connector_arrow); - fullElement.connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); + fullElement[connectorType].connectors[connectorKey].push($operator_connector); + fullElement[connectorType].connectorArrows[connectorKey].push($operator_connector_arrow); + fullElement[connectorType].connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); }, - - getOperatorElement: function (operatorData) { + + getOperatorElement: function(operatorData) { var fullElement = this._getOperatorFullElement(operatorData); return fullElement.operator; }, - - addOperator: function (operatorData) { - while (typeof this.data.operators[this.operatorNum] != 'undefined') { + + addOperator: function(operatorData) { + while(typeof this.data.operators[this.operatorNum] != 'undefined') { this.operatorNum++; } - + this.createOperator(this.operatorNum, operatorData); return this.operatorNum; }, - - createOperator: function (operatorId, operatorData) { + + createOperator: function(operatorId, operatorData) { operatorData.internal = {}; this._refreshInternalProperties(operatorData); - + var fullElement = this._getOperatorFullElement(operatorData); if (!this.options.onOperatorCreate(operatorId, operatorData, fullElement)) { return false; } - + var grid = this.options.grid; - - if (grid) { - operatorData.top = Math.round(operatorData.top / grid) * grid; - operatorData.left = Math.round(operatorData.left / grid) * grid; - } - + + operatorData.top = Math.round(operatorData.top / grid) * grid; + operatorData.left = Math.round(operatorData.left / grid) * grid; + fullElement.operator.appendTo(this.objs.layers.operators); fullElement.operator.css({top: operatorData.top, left: operatorData.left}); fullElement.operator.data('operator_id', operatorId); - + this.data.operators[operatorId] = operatorData; this.data.operators[operatorId].internal.els = fullElement; - + if (operatorId == this.selectedOperatorId) { this._addSelectedClass(operatorId); } - + + var operatorData = this.data.operators[operatorId] ; + var self = this; - + function operatorChangedPosition(operator_id, pos) { operatorData.top = pos.top; operatorData.left = pos.left; for (var linkId in self.data.links) { - if (self.data.links.hasOwnProperty(linkId)) { - var linkData = self.data.links[linkId]; - if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { - self._refreshLinkPositions(linkId); - } + var linkData = self.data.links[linkId]; + if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { + self._refreshLinkPositions(linkId); } } } - + // Small fix has been added in order to manage eventual zoom // http://stackoverflow.com/questions/2930092/jquery-draggable-with-zoom-problem if (this.options.canUserMoveOperators) { var pointerX; var pointerY; fullElement.operator.draggable({ - containment: operatorData.internal.properties.uncontained ? false : this.element, handle: '.flowchart-operator-title', - start: function (e, ui) { + start: function(e, ui) { if (self.lastOutputConnectorClicked != null) { e.preventDefault(); return; @@ -671,60 +647,51 @@ $(function () { pointerX = (e.pageX - elementOffset.left) / self.positionRatio - parseInt($(e.target).css('left')); pointerY = (e.pageY - elementOffset.top) / self.positionRatio - parseInt($(e.target).css('top')); }, - drag: function (e, ui) { - if (self.options.grid) { - var grid = self.options.grid; - var elementOffset = self.element.offset(); - ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; - ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; - - if (!operatorData.internal.properties.uncontained) { - var $this = $(this); - ui.position.left = Math.min(Math.max(ui.position.left, 0), self.element.width() - $this.outerWidth()); - ui.position.top = Math.min(Math.max(ui.position.top, 0), self.element.height() - $this.outerHeight()); - } - - ui.offset.left = Math.round(ui.position.left + elementOffset.left); - ui.offset.top = Math.round(ui.position.top + elementOffset.top); - fullElement.operator.css({left: ui.position.left, top: ui.position.top}); - } + drag: function(e, ui){ + var grid = self.options.grid; + var elementOffset = self.element.offset(); + ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; + ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; + ui.offset.left = Math.round(ui.position.left + elementOffset.left); + ui.offset.top = Math.round(ui.position.top + elementOffset.top); + fullElement.operator.css({left: ui.position.left, top: ui.position.top}); operatorChangedPosition($(this).data('operator_id'), ui.position); }, - stop: function (e, ui) { + stop: function(e, ui){ self._unsetTemporaryLink(); var operatorId = $(this).data('operator_id'); operatorChangedPosition(operatorId, ui.position); fullElement.operator.css({ - height: 'auto' + height: 'auto' }); - + self.options.onOperatorMoved(operatorId, ui.position); self.options.onAfterChange('operator_moved'); - } + }, }); } - + this.options.onAfterChange('operator_create'); }, - - _connectorClicked: function (operator, connector, subConnector, connectorCategory) { + + _connectorClicked: function(operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { var d = new Date(); - // var currentTime = d.getTime(); + var currentTime = d.getTime(); this.lastOutputConnectorClicked = { - operator: operator, - connector: connector, - subConnector: subConnector, - grantedLinks: this._getGrantedLinks(operator, connector) + operator: operator, + connector: connector, + subConnector: subConnector, + grantedLinks: this._getGrantedLinks(operator, connector) }; this.objs.layers.temporaryLink.show(); - var position = this.getConnectorPosition(operator, connector, subConnector); + var position = this.getConnectorPosition(operator, connector, subConnector, connectorCategory); var x = position.x + position.width; var y = position.y; - this.objs.temporaryLink.setAttribute('x1', x.toString()); - this.objs.temporaryLink.setAttribute('y1', y.toString()); + this.objs.temporaryLink.setAttribute('x1', x); + this.objs.temporaryLink.setAttribute('y1', y); this._mousemove(x, y); - this._colorizeGrantedLinks(); + this._colorizeGrantedLinks(); } if (connectorCategory == 'inputs' && this.lastOutputConnectorClicked != null) { var linkData = { @@ -735,13 +702,13 @@ $(function () { toConnector: connector, toSubConnector: subConnector }; - + this._unsetTemporaryLink(); this.addLink(linkData); } }, - - _getGrantedLinks: function(operator, connector) { + + _getGrantedLinks: function(operator, connector) { if(this.data.linkRestrictions.length == 0) { return []; } @@ -758,7 +725,7 @@ $(function () { } var toOperator = that.data.operators[l.toOperator]; - var smallArrows = toOperator.internal.els.connectorSmallArrows[l.toConnector]; + var smallArrows = toOperator.internal.els.inputs.connectorSmallArrows[l.toConnector]; l.smallArrows = smallArrows.map(function(sa) { return {els: sa, oldColor: sa.css('border-left-color')}; @@ -793,38 +760,38 @@ $(function () { }, _unsetTemporaryLink: function () { - this._restoreGrantedLinksColor(); - this.lastOutputConnectorClicked = null; + this._restoreGrantedLinksColor(); + this.lastOutputConnectorClicked = null; this.objs.layers.temporaryLink.hide(); }, - - _mousemove: function (x, y, e) { + + _mousemove: function(x, y, e) { if (this.lastOutputConnectorClicked != null) { this.objs.temporaryLink.setAttribute('x2', x); this.objs.temporaryLink.setAttribute('y2', y); } }, - - _click: function (x, y, e) { + + _click: function(x, y, e) { var $target = $(e.target); if ($target.closest('.flowchart-operator-connector').length == 0) { this._unsetTemporaryLink(); } - + if ($target.closest('.flowchart-operator').length == 0) { this.unselectOperator(); } - + if ($target.closest('.flowchart-link').length == 0) { this.unselectLink(); } }, - - _removeSelectedClassOperators: function () { + + _removeSelectedClassOperators: function() { this.objs.layers.operators.find('.flowchart-operator').removeClass('selected'); }, - - unselectOperator: function () { + + unselectOperator: function() { if (this.selectedOperatorId != null) { if (!this.options.onOperatorUnselect()) { return; @@ -833,12 +800,12 @@ $(function () { this.selectedOperatorId = null; } }, - - _addSelectedClass: function (operatorId) { + + _addSelectedClass: function(operatorId) { this.data.operators[operatorId].internal.els.operator.addClass('selected'); }, - - selectOperator: function (operatorId) { + + selectOperator: function(operatorId) { if (!this.options.onOperatorSelect(operatorId)) { return; } @@ -847,80 +814,46 @@ $(function () { this._addSelectedClass(operatorId); this.selectedOperatorId = operatorId; }, - - addClassOperator: function (operatorId, className) { - this.data.operators[operatorId].internal.els.operator.addClass(className); - }, - - removeClassOperator: function (operatorId, className) { - this.data.operators[operatorId].internal.els.operator.removeClass(className); - }, - - removeClassOperators: function (className) { - this.objs.layers.operators.find('.flowchart-operator').removeClass(className); - }, - - _addHoverClassOperator: function (operatorId) { - this.data.operators[operatorId].internal.els.operator.addClass('hover'); - }, - - _removeHoverClassOperators: function () { - this.objs.layers.operators.find('.flowchart-operator').removeClass('hover'); - }, - - _operatorMouseOver: function (operatorId) { - if (!this.options.onOperatorMouseOver(operatorId)) { - return; - } - this._addHoverClassOperator(operatorId); - }, - - _operatorMouseOut: function (operatorId) { - if (!this.options.onOperatorMouseOut(operatorId)) { - return; - } - this._removeHoverClassOperators(); - }, - - getSelectedOperatorId: function () { + + getSelectedOperatorId: function() { return this.selectedOperatorId; }, - - getSelectedLinkId: function () { + + getSelectedLinkId: function() { return this.selectedLinkId; }, - + // Found here : http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - _shadeColor: function (color, percent) { - var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF; - return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); + _shadeColor: function(color, percent) { + var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; + return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1); }, - - colorizeLink: function (linkId, color) { + + colorizeLink: function(linkId, color) { var linkData = this.data.links[linkId]; linkData.internal.els.path.setAttribute('stroke', color); linkData.internal.els.rect.setAttribute('fill', color); linkData.internal.els.fromSmallConnector.css('border-left-color', color); linkData.internal.els.toSmallConnector.css('border-left-color', color); }, - - uncolorizeLink: function (linkId) { + + uncolorizeLink: function(linkId) { this.colorizeLink(linkId, this.getLinkMainColor(linkId)); }, - - _connecterMouseOver: function (linkId) { + + _connecterMouseOver: function(linkId) { if (this.selectedLinkId != linkId) { this.colorizeLink(linkId, this._shadeColor(this.getLinkMainColor(linkId), -0.4)); } }, - - _connecterMouseOut: function (linkId) { + + _connecterMouseOut: function(linkId) { if (this.selectedLinkId != linkId) { this.uncolorizeLink(linkId); } }, - - unselectLink: function () { + + unselectLink: function() { if (this.selectedLinkId != null) { if (!this.options.onLinkUnselect()) { return; @@ -929,8 +862,8 @@ $(function () { this.selectedLinkId = null; } }, - - selectLink: function (linkId) { + + selectLink: function(linkId) { this.unselectLink(); if (!this.options.onLinkSelect(linkId)) { return; @@ -939,22 +872,20 @@ $(function () { this.selectedLinkId = linkId; this.colorizeLink(linkId, this.options.defaultSelectedLinkColor); }, - - deleteOperator: function (operatorId) { + + deleteOperator: function(operatorId) { this._deleteOperator(operatorId, false); }, - - _deleteOperator: function (operatorId, replace) { + + _deleteOperator: function(operatorId, replace) { if (!this.options.onOperatorDelete(operatorId, replace)) { return false; } if (!replace) { for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var currentLink = this.data.links[linkId]; - if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { - this._deleteLink(linkId, true); - } + var currentLink = this.data.links[linkId]; + if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { + this._deleteLink(linkId, true); } } } @@ -963,19 +894,19 @@ $(function () { } this.data.operators[operatorId].internal.els.operator.remove(); delete this.data.operators[operatorId]; - + this.options.onAfterChange('operator_delete'); }, - - deleteLink: function (linkId) { + + deleteLink: function(linkId) { this._deleteLink(linkId, false); }, - - _deleteLink: function (linkId, forced) { + + _deleteLink: function(linkId, forced) { if (this.selectedLinkId == linkId) { this.unselectLink(); } - if (!this.options.onLinkDelete(linkId, forced)) { + if (!this.options.onLinkDelete(linkId, forced)) { if (!forced) { return; } @@ -988,18 +919,19 @@ $(function () { var toConnector = linkData.toConnector; linkData.internal.els.overallGroup.remove(); delete this.data.links[linkId]; - + this._cleanMultipleConnectors(fromOperator, fromConnector, 'from'); this._cleanMultipleConnectors(toOperator, toConnector, 'to'); - + this.options.onAfterChange('link_delete'); }, - - _cleanMultipleConnectors: function (operator, connector, linkFromTo) { - if (!this.data.operators[operator].properties[linkFromTo == 'from' ? 'outputs' : 'inputs'][connector].multiple) { + + _cleanMultipleConnectors: function(operator, connector, linkFromTo) { + var connectorType = linkFromTo == 'from' ? 'outputs' : 'inputs'; + if (!this.data.operators[operator].properties[connectorType][connector].multiple) { return; } - + var maxI = -1; var fromToOperator = linkFromTo + 'Operator'; var fromToConnector = linkFromTo + 'Connector'; @@ -1007,28 +939,26 @@ $(function () { var els = this.data.operators[operator].internal.els; var subConnectors = els.connectors[connector]; var nbSubConnectors = subConnectors.length; - + for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var linkData = this.data.links[linkId]; - if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { - if (maxI < linkData[fromToSubConnector]) { - maxI = linkData[fromToSubConnector]; - } + var linkData = this.data.links[linkId]; + if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { + if (maxI < linkData[fromToSubConnector]) { + maxI = linkData[fromToSubConnector]; } } } - + var nbToDelete = Math.min(nbSubConnectors - maxI - 2, nbSubConnectors - 1); for (var i = 0; i < nbToDelete; i++) { subConnectors[subConnectors.length - 1].remove(); subConnectors.pop(); - els.connectorArrows[connector].pop(); - els.connectorSmallArrows[connector].pop(); + els[connectorType].connectorArrows[connector].pop(); + els[connectorType].connectorSmallArrows[connector].pop(); } }, - - deleteSelected: function () { + + deleteSelected: function() { if (this.selectedLinkId != null) { this.deleteLink(this.selectedLinkId); } @@ -1036,36 +966,32 @@ $(function () { this.deleteOperator(this.selectedOperatorId); } }, - - setPositionRatio: function (positionRatio) { + + setPositionRatio: function(positionRatio) { this.positionRatio = positionRatio; }, - - getPositionRatio: function () { + + getPositionRatio: function() { return this.positionRatio; }, - - getData: function () { + + getData: function() { var keys = ['operators', 'links']; var data = {}; data.operators = $.extend(true, {}, this.data.operators); data.links = $.extend(true, {}, this.data.links); for (var keyI in keys) { - if (keys.hasOwnProperty(keyI)) { - var key = keys[keyI]; - for (var objId in data[key]) { - if (data[key].hasOwnProperty(objId)) { - delete data[key][objId].internal; - } - } + var key = keys[keyI]; + for (var objId in data[key]) { + delete data[key][objId].internal; } } data.operatorTypes = this.data.operatorTypes; return data; }, - - setOperatorTitle: function (operatorId, title) { - this.data.operators[operatorId].internal.els.title.html(title); + + setOperatorTitle: function(operatorId, title) { + this.data.operators[operatorId].internal.els.title.text(title); if (typeof this.data.operators[operatorId].properties == 'undefined') { this.data.operators[operatorId].properties = {}; } @@ -1073,20 +999,21 @@ $(function () { this._refreshInternalProperties(this.data.operators[operatorId]); this.options.onAfterChange('operator_title_change'); }, - - getOperatorTitle: function (operatorId) { + + getOperatorTitle: function(operatorId) { return this.data.operators[operatorId].internal.properties.title; }, - - setOperatorData: function (operatorId, operatorData) { + + setOperatorData: function(operatorId, operatorData) { var infos = this.getOperatorCompleteData(operatorData); for (var linkId in this.data.links) { - if (this.data.links.hasOwnProperty(linkId)) { - var linkData = this.data.links[linkId]; - if ((linkData.fromOperator == operatorId && typeof infos.outputs[linkData.fromConnector] == 'undefined') || - (linkData.toOperator == operatorId && typeof infos.inputs[linkData.toConnector] == 'undefined')) { + var linkData = this.data.links[linkId]; + if ((linkData.fromOperator == operatorId && + typeof infos.outputs[linkData.fromConnector] == 'undefined') || + (linkData.toOperator == operatorId && + typeof infos.inputs[linkData.toConnector] == 'undefined')) { this._deleteLink(linkId, true); - } + continue; } } this._deleteOperator(operatorId, true); @@ -1095,17 +1022,13 @@ $(function () { this.options.onAfterChange('operator_data_change'); }, - doesOperatorExists: function (operatorId) { - return typeof this.data.operators[operatorId] != 'undefined'; - }, - - getOperatorData: function (operatorId) { + getOperatorData: function(operatorId) { var data = $.extend(true, {}, this.data.operators[operatorId]); delete data.internal; return data; }, - - getOperatorFullProperties: function (operatorData) { + + getOperatorFullProperties: function(operatorData) { if (typeof operatorData.type != 'undefined') { var typeProperties = this.data.operatorTypes[operatorData.type]; var operatorProperties = {}; @@ -1113,13 +1036,14 @@ $(function () { operatorProperties = operatorData.properties; } return $.extend({}, typeProperties, operatorProperties); - } else { + } + else { return operatorData.properties; } }, - - _refreshInternalProperties: function (operatorData) { + + _refreshInternalProperties: function(operatorData) { operatorData.internal.properties = this.getOperatorFullProperties(operatorData); } }); -}); +}); \ No newline at end of file From 4675f9147bce6f59c728472551493f0e84b0984f Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Tue, 3 Jan 2017 16:09:24 +0100 Subject: [PATCH 05/14] Bug fix on link restrictions and coloration when operators ids doesn't match Change link restriction to use Type information replacing operators ids --- jquery.flowchart.js | 70 +++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 532f9e0..7fde4cf 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -265,9 +265,12 @@ $(function() { for(var i=0; i Date: Tue, 3 Jan 2017 16:29:06 +0100 Subject: [PATCH 06/14] Use arrows instead of small arrows for granted connectors highlight --- jquery.flowchart.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 7fde4cf..e451048 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -733,14 +733,14 @@ $(function() { for(var opId in this.data.operators) { var operator = this.data.operators[opId]; if(operator.type == link.toOperatorType) { - var smallArrows = operator.internal.els.inputs.connectorSmallArrows[link.toConnector]; - smallArrows = smallArrows.map(function(sa) { + var arrows = operator.internal.els.inputs.connectorArrows[link.toConnector]; + arrows = arrows.map(function(sa) { return {els: sa, oldColor: sa.css('border-left-color')}; }); grantedConnectors.push({ color: typeof link.color=='undefined' ? defaultLinkColor : link.color, - smallArrows: smallArrows + arrows: arrows }); } } @@ -754,7 +754,7 @@ $(function() { var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; grantedConnectors.forEach(function(l) { - l.smallArrows.forEach(function(sa) { + l.arrows.forEach(function(sa) { sa.els.css('border-left-color', l.color); }); }); @@ -766,7 +766,7 @@ $(function() { var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; grantedConnectors.forEach(function(l) { - l.smallArrows.forEach(function(sa) { + l.arrows.forEach(function(sa) { sa.els.css('border-left-color', sa.oldColor); }); }); From 628a995165e50b9fa7808f4bb6f3c0163297864b Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 11:48:02 +0100 Subject: [PATCH 07/14] bug fixes --- jquery.flowchart.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index e451048..ae7e3c1 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -679,6 +679,7 @@ $(function() { _connectorClicked: function(operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { + this._restoreGrantedConnectorsColor(); var d = new Date(); var currentTime = d.getTime(); this.lastOutputConnectorClicked = { @@ -726,10 +727,6 @@ $(function() { for(var l in grantedLinks) { var link = grantedLinks[l]; - if(typeof link.color == 'undefined') { - link.color = this.defaultLinkColor; - } - for(var opId in this.data.operators) { var operator = this.data.operators[opId]; if(operator.type == link.toOperatorType) { @@ -739,7 +736,7 @@ $(function() { }); grantedConnectors.push({ - color: typeof link.color=='undefined' ? defaultLinkColor : link.color, + color: typeof link.color=='undefined' ? this.options.defaultLinkColor : link.color, arrows: arrows }); } @@ -990,10 +987,12 @@ $(function() { }, getData: function() { - var keys = ['operators', 'links']; + var keys = ['operators', 'links', 'linkRestrictions']; var data = {}; data.operators = $.extend(true, {}, this.data.operators); data.links = $.extend(true, {}, this.data.links); + data.linkRestrictions = $.extend(true, [], this.data.linkRestrictions); + for (var keyI in keys) { var key = keys[keyI]; for (var objId in data[key]) { @@ -1060,4 +1059,5 @@ $(function() { operatorData.internal.properties = this.getOperatorFullProperties(operatorData); } }); -}); \ No newline at end of file +}); +//# sourceURL=jquery-flowchart.js \ No newline at end of file From ba5a62d25cd7e61153b8b12ef7b76a2de18f2390 Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 14:25:22 +0100 Subject: [PATCH 08/14] Merging flowchart from last source --- jquery.flowchart.js | 770 +++++++++++++++++++++++--------------------- 1 file changed, 398 insertions(+), 372 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index ae7e3c1..a76a501 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -1,7 +1,7 @@ -$(function() { +$(function () { // the widget definition, where "custom" is the namespace, // "colorize" the widget name - $.widget( "flowchart.flowchart", { + $.widget("flowchart.flowchart", { // default options options: { canUserEditLinks: true, @@ -16,35 +16,35 @@ $(function() { multipleLinksOnOutput: false, multipleLinksOnInput: false, linkVerticalDecal: 0, - onOperatorSelect: function(operatorId) { + onOperatorSelect: function (operatorId) { return true; }, - onOperatorUnselect: function() { + onOperatorUnselect: function () { return true; }, - onLinkSelect: function(linkId) { + onLinkSelect: function (linkId) { return true; }, - onLinkUnselect: function() { + onLinkUnselect: function () { return true; }, - onOperatorCreate: function(operatorId, operatorData, fullElement) { + onOperatorCreate: function (operatorId, operatorData, fullElement) { return true; }, - onLinkCreate: function(linkId, linkData) { + onLinkCreate: function (linkId, linkData) { return true; }, - onOperatorDelete: function(operatorId) { + onOperatorDelete: function (operatorId) { return true; }, - onLinkDelete: function(linkId, forced) { + onLinkDelete: function (linkId, forced) { return true; }, - onOperatorMoved: function(operatorId, position) { - + onOperatorMoved: function (operatorId, position) { + }, - onAfterChange: function(changeType) { - + onAfterChange: function (changeType) { + } }, data: null, @@ -57,29 +57,28 @@ $(function() { selectedLinkId: null, positionRatio: 1, globalId: null, - // the constructor - _create: function() { + _create: function () { if (typeof document.__flowchartNumber == 'undefined') { - document.__flowchartNumber = 0; + document.__flowchartNumber = 0; } else { - document.__flowchartNumber++; + document.__flowchartNumber++; } this.globalId = document.__flowchartNumber; - this._unitVariables(); - + this._unitVariables(); + this.element.addClass('flowchart-container'); - + this.objs.layers.links = $(''); this.objs.layers.links.appendTo(this.element); - + this.objs.layers.operators = $('
'); this.objs.layers.operators.appendTo(this.element); - + this.objs.layers.temporaryLink = $(''); this.objs.layers.temporaryLink.appendTo(this.element); - + var shape = document.createElementNS("http://www.w3.org/2000/svg", "line"); shape.setAttribute("x1", "0"); shape.setAttribute("y1", "0"); @@ -91,18 +90,19 @@ $(function() { shape.setAttribute("fill", "none"); this.objs.layers.temporaryLink[0].appendChild(shape); this.objs.temporaryLink = shape; - + this._initEvents(); - + if (typeof this.options.data != 'undefined') { this.setData(this.options.data); } }, - - _unitVariables: function() { + + _unitVariables: function () { this.data = { operators: {}, links: {}, + linkRestrictions: {} }; this.objs = { layers: { @@ -114,68 +114,67 @@ $(function() { temporaryLink: null }; }, - - _initEvents: function() { - + + _initEvents: function () { + var self = this; - - this.element.mousemove(function(e) { + + this.element.mousemove(function (e) { var $this = $(this); var offset = $this.offset(); self._mousemove((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - this.element.click(function(e) { + + this.element.click(function (e) { var $this = $(this); var offset = $this.offset(); self._click((e.pageX - offset.left) / self.positionRatio, (e.pageY - offset.top) / self.positionRatio, e); }); - - - - this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function(e) { + + + this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function (e) { e.stopImmediatePropagation(); }); - - this.objs.layers.operators.on('click', '.flowchart-operator', function(e) { + + this.objs.layers.operators.on('click', '.flowchart-operator', function (e) { if ($(e.target).closest('.flowchart-operator-connector').length == 0) { self.selectOperator($(this).data('operator_id')); } }); - - this.objs.layers.operators.on('click', '.flowchart-operator-connector', function() { + + this.objs.layers.operators.on('click', '.flowchart-operator-connector', function () { var $this = $(this); if (self.options.canUserEditLinks) { self._connectorClicked($this.closest('.flowchart-operator').data('operator_id'), $this.data('connector'), $this.data('sub_connector'), $this.closest('.flowchart-operator-connector-set').data('connector_type')); } }); - - this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function(e) { + + this.objs.layers.links.on('mousedown touchstart', '.flowchart-link', function (e) { e.stopImmediatePropagation(); }); - - this.objs.layers.links.on('mouseover', '.flowchart-link', function() { + + this.objs.layers.links.on('mouseover', '.flowchart-link', function () { self._connecterMouseOver($(this).data('link_id')); }); - - this.objs.layers.links.on('mouseout', '.flowchart-link', function() { + + this.objs.layers.links.on('mouseout', '.flowchart-link', function () { self._connecterMouseOut($(this).data('link_id')); }); - - this.objs.layers.links.on('click', '.flowchart-link', function() { + + this.objs.layers.links.on('click', '.flowchart-link', function () { self.selectLink($(this).data('link_id')); }); - - + + }, - - setData: function(data) { + + setData: function (data) { this._clearOperatorsLayer(); this.data.operatorTypes = {}; if (typeof data.operatorTypes != 'undefined') { - this.data.operatorTypes = data.operatorTypes; + this.data.operatorTypes = data.operatorTypes; } - + this.data.linkRestrictions = []; if(typeof data.linkRestrictions != 'undefined' && data.linkRestrictions.length>0) { this.data.linkRestrictions = data.linkRestrictions; @@ -183,29 +182,34 @@ $(function() { this.data.operators = {}; for (var operatorId in data.operators) { - this.createOperator(operatorId, data.operators[operatorId]); + if (data.operators.hasOwnProperty(operatorId)) { + this.createOperator(operatorId, data.operators[operatorId]); + } } + this.data.links = {}; for (var linkId in data.links) { - this.createLink(linkId, data.links[linkId]); + if (data.links.hasOwnProperty(linkId)) { + this.createLink(linkId, data.links[linkId]); + } } this.redrawLinksLayer(); }, - - addLink: function(linkData) { - while(typeof this.data.links[this.linkNum] != 'undefined') { + + addLink: function (linkData) { + while (typeof this.data.links[this.linkNum] != 'undefined') { this.linkNum++; } - + this.createLink(this.linkNum, linkData); return this.linkNum; }, - - createLink: function(linkId, linkDataOriginal) { + + createLink: function (linkId, linkDataOriginal) { var linkData = $.extend(true, {}, linkDataOriginal); if (!this.options.onLinkCreate(linkId, linkData)) { return; } - + var restrictionLinkIndex = this._indexOfLinkGranted(linkData); if(restrictionLinkIndex == -1) { return; @@ -214,31 +218,32 @@ $(function() { var subConnectors = this._getSubConnectors(linkData); var fromSubConnector = subConnectors[0]; var toSubConnector = subConnectors[1]; - + var multipleLinksOnOutput = this.options.multipleLinksOnOutput; var multipleLinksOnInput = this.options.multipleLinksOnInput; if (!multipleLinksOnOutput || !multipleLinksOnInput) { for (var linkId2 in this.data.links) { - var currentLink = this.data.links[linkId2]; - - var currentSubConnectors = this._getSubConnectors(currentLink); - var currentFromSubConnector = currentSubConnectors[0]; - var currentToSubConnector = currentSubConnectors[1]; - - if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { - this.deleteLink(linkId2); - continue; - } - if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { - this.deleteLink(linkId2); - continue; + if (this.data.links.hasOwnProperty(linkId2)) { + var currentLink = this.data.links[linkId2]; + + var currentSubConnectors = this._getSubConnectors(currentLink); + var currentFromSubConnector = currentSubConnectors[0]; + var currentToSubConnector = currentSubConnectors[1]; + + if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector && currentFromSubConnector == fromSubConnector) { + this.deleteLink(linkId2); + continue; + } + if (!multipleLinksOnInput && currentLink.toOperator == linkData.toOperator && currentLink.toConnector == linkData.toConnector && currentToSubConnector == toSubConnector) { + this.deleteLink(linkId2); + } } } } - + this._autoCreateSubConnector(linkData.fromOperator, linkData.fromConnector, 'outputs', fromSubConnector); this._autoCreateSubConnector(linkData.toOperator, linkData.toConnector, 'inputs', toSubConnector); - + //try to colorize link with restriction link data if(restrictionLinkIndex!=null) { var restriction = this.data.linkRestrictions[restrictionLinkIndex]; @@ -260,7 +265,7 @@ $(function() { if(this.data.linkRestrictions.length == 0) { return null; } - + var linkRestrictions = this.data.linkRestrictions; for(var i=0; i'); $operator.addClass(infos.class); - + var $operator_title = $('
'); - $operator_title.text(infos.title); + $operator_title.html(infos.title); $operator_title.appendTo($operator); - + var $operator_inputs_outputs = $('
'); - - + $operator_inputs_outputs.appendTo($operator); - + var $operator_inputs = $('
'); $operator_inputs.appendTo($operator_inputs_outputs); - + var $operator_outputs = $('
'); $operator_outputs.appendTo($operator_inputs_outputs); - + var self = this; - + + var connectorArrows = {}; + var connectorSmallArrows = {}; + var connectorSets = {}; + var connectors = {}; + var fullElement = { - operator: $operator, - title: $operator_title, - inputs: { - connectorSets: {}, - connectors: {}, - connectorArrows: {}, - connectorSmallArrows: {} - }, - outputs: { - connectorSets: {}, - connectors: {}, - connectorArrows: {}, - connectorSmallArrows: {} - } + operator: $operator, + title: $operator_title, + connectorSets: connectorSets, + connectors: connectors, + connectorArrows: connectorArrows, + connectorSmallArrows: connectorSmallArrows }; - + function addConnector(connectorKey, connectorInfos, $operator_container, connectorType) { var $operator_connector_set = $('
'); $operator_connector_set.data('connector_type', connectorType); $operator_connector_set.appendTo($operator_container); - - fullElement[connectorType].connectorArrows[connectorKey] = []; - fullElement[connectorType].connectorSmallArrows[connectorKey] = []; - fullElement[connectorType].connectors[connectorKey] = []; - fullElement[connectorType].connectorSets[connectorKey] = $operator_connector_set; - - self._createSubConnector(connectorKey, connectorInfos, fullElement, connectorType); + + connectorArrows[connectorKey] = []; + connectorSmallArrows[connectorKey] = []; + connectors[connectorKey] = []; + connectorSets[connectorKey] = $operator_connector_set; + + self._createSubConnector(connectorKey, connectorInfos, fullElement); } - - for (var key in infos.inputs) { - addConnector(key, infos.inputs[key], $operator_inputs, 'inputs'); + + for (var key_i in infos.inputs) { + if (infos.inputs.hasOwnProperty(key_i)) { + addConnector(key_i, infos.inputs[key_i], $operator_inputs, 'inputs'); + } } - - for (var key in infos.outputs) { - addConnector(key, infos.outputs[key], $operator_outputs, 'outputs'); + + for (var key_o in infos.outputs) { + if (infos.outputs.hasOwnProperty(key_o)) { + addConnector(key_o, infos.outputs[key_o], $operator_outputs, 'outputs'); + } } - + return fullElement; }, - - _createSubConnector: function(connectorKey, connectorInfos, fullElement, connectorType) { - var $operator_connector_set = fullElement[connectorType].connectorSets[connectorKey]; - - var subConnector = fullElement[connectorType].connectors[connectorKey].length; - + + _createSubConnector: function (connectorKey, connectorInfos, fullElement) { + var $operator_connector_set = fullElement.connectorSets[connectorKey]; + + var subConnector = fullElement.connectors[connectorKey].length; + var $operator_connector = $('
'); $operator_connector.appendTo($operator_connector_set); $operator_connector.data('connector', connectorKey); @@ -574,74 +582,77 @@ $(function() { var $operator_connector_small_arrow = $('
'); $operator_connector_small_arrow.appendTo($operator_connector); - fullElement[connectorType].connectors[connectorKey].push($operator_connector); - fullElement[connectorType].connectorArrows[connectorKey].push($operator_connector_arrow); - fullElement[connectorType].connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); + fullElement.connectors[connectorKey].push($operator_connector); + fullElement.connectorArrows[connectorKey].push($operator_connector_arrow); + fullElement.connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); }, - - getOperatorElement: function(operatorData) { + + getOperatorElement: function (operatorData) { var fullElement = this._getOperatorFullElement(operatorData); return fullElement.operator; }, - - addOperator: function(operatorData) { - while(typeof this.data.operators[this.operatorNum] != 'undefined') { + + addOperator: function (operatorData) { + while (typeof this.data.operators[this.operatorNum] != 'undefined') { this.operatorNum++; } - + this.createOperator(this.operatorNum, operatorData); return this.operatorNum; }, - - createOperator: function(operatorId, operatorData) { + + createOperator: function (operatorId, operatorData) { operatorData.internal = {}; this._refreshInternalProperties(operatorData); - + var fullElement = this._getOperatorFullElement(operatorData); if (!this.options.onOperatorCreate(operatorId, operatorData, fullElement)) { return false; } - + var grid = this.options.grid; - - operatorData.top = Math.round(operatorData.top / grid) * grid; - operatorData.left = Math.round(operatorData.left / grid) * grid; - + + if (grid) { + operatorData.top = Math.round(operatorData.top / grid) * grid; + operatorData.left = Math.round(operatorData.left / grid) * grid; + } + fullElement.operator.appendTo(this.objs.layers.operators); fullElement.operator.css({top: operatorData.top, left: operatorData.left}); fullElement.operator.data('operator_id', operatorId); - + this.data.operators[operatorId] = operatorData; this.data.operators[operatorId].internal.els = fullElement; - + if (operatorId == this.selectedOperatorId) { this._addSelectedClass(operatorId); } - - var operatorData = this.data.operators[operatorId] ; - + var self = this; - + function operatorChangedPosition(operator_id, pos) { operatorData.top = pos.top; operatorData.left = pos.left; for (var linkId in self.data.links) { - var linkData = self.data.links[linkId]; - if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { - self._refreshLinkPositions(linkId); + if (self.data.links.hasOwnProperty(linkId)) { + var linkData = self.data.links[linkId]; + if (linkData.fromOperator == operator_id || linkData.toOperator == operator_id) { + self._refreshLinkPositions(linkId); + } } } } - + // Small fix has been added in order to manage eventual zoom // http://stackoverflow.com/questions/2930092/jquery-draggable-with-zoom-problem if (this.options.canUserMoveOperators) { var pointerX; var pointerY; fullElement.operator.draggable({ + containment: operatorData.internal.properties.uncontained ? false : this.element, handle: '.flowchart-operator-title', - start: function(e, ui) { + start: function (e, ui) { if (self.lastOutputConnectorClicked != null) { e.preventDefault(); return; @@ -650,50 +661,59 @@ $(function() { pointerX = (e.pageX - elementOffset.left) / self.positionRatio - parseInt($(e.target).css('left')); pointerY = (e.pageY - elementOffset.top) / self.positionRatio - parseInt($(e.target).css('top')); }, - drag: function(e, ui){ - var grid = self.options.grid; - var elementOffset = self.element.offset(); - ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; - ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; - ui.offset.left = Math.round(ui.position.left + elementOffset.left); - ui.offset.top = Math.round(ui.position.top + elementOffset.top); - fullElement.operator.css({left: ui.position.left, top: ui.position.top}); + drag: function (e, ui) { + if (self.options.grid) { + var grid = self.options.grid; + var elementOffset = self.element.offset(); + ui.position.left = Math.round(((e.pageX - elementOffset.left) / self.positionRatio - pointerX) / grid) * grid; + ui.position.top = Math.round(((e.pageY - elementOffset.top) / self.positionRatio - pointerY) / grid) * grid; + + if (!operatorData.internal.properties.uncontained) { + var $this = $(this); + ui.position.left = Math.min(Math.max(ui.position.left, 0), self.element.width() - $this.outerWidth()); + ui.position.top = Math.min(Math.max(ui.position.top, 0), self.element.height() - $this.outerHeight()); + } + + ui.offset.left = Math.round(ui.position.left + elementOffset.left); + ui.offset.top = Math.round(ui.position.top + elementOffset.top); + fullElement.operator.css({left: ui.position.left, top: ui.position.top}); + } operatorChangedPosition($(this).data('operator_id'), ui.position); }, - stop: function(e, ui){ + stop: function (e, ui) { self._unsetTemporaryLink(); var operatorId = $(this).data('operator_id'); operatorChangedPosition(operatorId, ui.position); fullElement.operator.css({ - height: 'auto' + height: 'auto' }); - + self.options.onOperatorMoved(operatorId, ui.position); self.options.onAfterChange('operator_moved'); - }, + } }); } - + this.options.onAfterChange('operator_create'); }, - - _connectorClicked: function(operator, connector, subConnector, connectorCategory) { + + _connectorClicked: function (operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { this._restoreGrantedConnectorsColor(); var d = new Date(); - var currentTime = d.getTime(); + // var currentTime = d.getTime(); this.lastOutputConnectorClicked = { - operator: operator, - connector: connector, - subConnector: subConnector, - grantedConnectors: this._getGrantedConnectors(operator, connector) + operator: operator, + connector: connector, + subConnector: subConnector, + grantedConnectors: this._getGrantedConnectors(operator, connector) }; this.objs.layers.temporaryLink.show(); - var position = this.getConnectorPosition(operator, connector, subConnector, connectorCategory); + var position = this.getConnectorPosition(operator, connector, subConnector); var x = position.x + position.width; var y = position.y; - this.objs.temporaryLink.setAttribute('x1', x); - this.objs.temporaryLink.setAttribute('y1', y); + this.objs.temporaryLink.setAttribute('x1', x.toString()); + this.objs.temporaryLink.setAttribute('y1', y.toString()); this._mousemove(x, y); this._colorizeGrantedConnectors(); } @@ -767,42 +787,42 @@ $(function() { sa.els.css('border-left-color', sa.oldColor); }); }); - } + } }, _unsetTemporaryLink: function () { - this._restoreGrantedConnectorsColor(); - this.lastOutputConnectorClicked = null; + this._restoreGrantedConnectorsColor(); + this.lastOutputConnectorClicked = null; this.objs.layers.temporaryLink.hide(); }, - - _mousemove: function(x, y, e) { + + _mousemove: function (x, y, e) { if (this.lastOutputConnectorClicked != null) { this.objs.temporaryLink.setAttribute('x2', x); this.objs.temporaryLink.setAttribute('y2', y); } }, - - _click: function(x, y, e) { + + _click: function (x, y, e) { var $target = $(e.target); if ($target.closest('.flowchart-operator-connector').length == 0) { this._unsetTemporaryLink(); } - + if ($target.closest('.flowchart-operator').length == 0) { this.unselectOperator(); } - + if ($target.closest('.flowchart-link').length == 0) { this.unselectLink(); } }, - - _removeSelectedClassOperators: function() { + + _removeSelectedClassOperators: function () { this.objs.layers.operators.find('.flowchart-operator').removeClass('selected'); }, - - unselectOperator: function() { + + unselectOperator: function () { if (this.selectedOperatorId != null) { if (!this.options.onOperatorUnselect()) { return; @@ -811,12 +831,12 @@ $(function() { this.selectedOperatorId = null; } }, - - _addSelectedClass: function(operatorId) { + + _addSelectedClass: function (operatorId) { this.data.operators[operatorId].internal.els.operator.addClass('selected'); }, - - selectOperator: function(operatorId) { + + selectOperator: function (operatorId) { if (!this.options.onOperatorSelect(operatorId)) { return; } @@ -825,46 +845,46 @@ $(function() { this._addSelectedClass(operatorId); this.selectedOperatorId = operatorId; }, - - getSelectedOperatorId: function() { + + getSelectedOperatorId: function () { return this.selectedOperatorId; }, - - getSelectedLinkId: function() { + + getSelectedLinkId: function () { return this.selectedLinkId; }, - + // Found here : http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - _shadeColor: function(color, percent) { - var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF; - return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1); + _shadeColor: function (color, percent) { + var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF; + return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); }, - - colorizeLink: function(linkId, color) { + + colorizeLink: function (linkId, color) { var linkData = this.data.links[linkId]; linkData.internal.els.path.setAttribute('stroke', color); linkData.internal.els.rect.setAttribute('fill', color); linkData.internal.els.fromSmallConnector.css('border-left-color', color); linkData.internal.els.toSmallConnector.css('border-left-color', color); }, - - uncolorizeLink: function(linkId) { + + uncolorizeLink: function (linkId) { this.colorizeLink(linkId, this.getLinkMainColor(linkId)); }, - - _connecterMouseOver: function(linkId) { + + _connecterMouseOver: function (linkId) { if (this.selectedLinkId != linkId) { this.colorizeLink(linkId, this._shadeColor(this.getLinkMainColor(linkId), -0.4)); } }, - - _connecterMouseOut: function(linkId) { + + _connecterMouseOut: function (linkId) { if (this.selectedLinkId != linkId) { this.uncolorizeLink(linkId); } }, - - unselectLink: function() { + + unselectLink: function () { if (this.selectedLinkId != null) { if (!this.options.onLinkUnselect()) { return; @@ -873,8 +893,8 @@ $(function() { this.selectedLinkId = null; } }, - - selectLink: function(linkId) { + + selectLink: function (linkId) { this.unselectLink(); if (!this.options.onLinkSelect(linkId)) { return; @@ -883,20 +903,22 @@ $(function() { this.selectedLinkId = linkId; this.colorizeLink(linkId, this.options.defaultSelectedLinkColor); }, - - deleteOperator: function(operatorId) { + + deleteOperator: function (operatorId) { this._deleteOperator(operatorId, false); }, - - _deleteOperator: function(operatorId, replace) { + + _deleteOperator: function (operatorId, replace) { if (!this.options.onOperatorDelete(operatorId, replace)) { return false; } if (!replace) { for (var linkId in this.data.links) { - var currentLink = this.data.links[linkId]; - if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { - this._deleteLink(linkId, true); + if (this.data.links.hasOwnProperty(linkId)) { + var currentLink = this.data.links[linkId]; + if (currentLink.fromOperator == operatorId || currentLink.toOperator == operatorId) { + this._deleteLink(linkId, true); + } } } } @@ -905,19 +927,19 @@ $(function() { } this.data.operators[operatorId].internal.els.operator.remove(); delete this.data.operators[operatorId]; - + this.options.onAfterChange('operator_delete'); }, - - deleteLink: function(linkId) { + + deleteLink: function (linkId) { this._deleteLink(linkId, false); }, - - _deleteLink: function(linkId, forced) { + + _deleteLink: function (linkId, forced) { if (this.selectedLinkId == linkId) { this.unselectLink(); } - if (!this.options.onLinkDelete(linkId, forced)) { + if (!this.options.onLinkDelete(linkId, forced)) { if (!forced) { return; } @@ -930,19 +952,19 @@ $(function() { var toConnector = linkData.toConnector; linkData.internal.els.overallGroup.remove(); delete this.data.links[linkId]; - + this._cleanMultipleConnectors(fromOperator, fromConnector, 'from'); this._cleanMultipleConnectors(toOperator, toConnector, 'to'); - + this.options.onAfterChange('link_delete'); }, - - _cleanMultipleConnectors: function(operator, connector, linkFromTo) { - var connectorType = linkFromTo == 'from' ? 'outputs' : 'inputs'; + + _cleanMultipleConnectors: function (operator, connector, linkFromTo) { + var connectorType = linkFromTo == 'from' ? 'outputs' : 'inputs'; if (!this.data.operators[operator].properties[connectorType][connector].multiple) { return; } - + var maxI = -1; var fromToOperator = linkFromTo + 'Operator'; var fromToConnector = linkFromTo + 'Connector'; @@ -950,26 +972,28 @@ $(function() { var els = this.data.operators[operator].internal.els; var subConnectors = els.connectors[connector]; var nbSubConnectors = subConnectors.length; - + for (var linkId in this.data.links) { - var linkData = this.data.links[linkId]; - if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { - if (maxI < linkData[fromToSubConnector]) { - maxI = linkData[fromToSubConnector]; + if (this.data.links.hasOwnProperty(linkId)) { + var linkData = this.data.links[linkId]; + if (linkData[fromToOperator] == operator && linkData[fromToConnector] == connector) { + if (maxI < linkData[fromToSubConnector]) { + maxI = linkData[fromToSubConnector]; + } } } } - + var nbToDelete = Math.min(nbSubConnectors - maxI - 2, nbSubConnectors - 1); for (var i = 0; i < nbToDelete; i++) { subConnectors[subConnectors.length - 1].remove(); subConnectors.pop(); - els[connectorType].connectorArrows[connector].pop(); - els[connectorType].connectorSmallArrows[connector].pop(); + els.connectorArrows[connector].pop(); + els.connectorSmallArrows[connector].pop(); } }, - - deleteSelected: function() { + + deleteSelected: function () { if (this.selectedLinkId != null) { this.deleteLink(this.selectedLinkId); } @@ -977,16 +1001,16 @@ $(function() { this.deleteOperator(this.selectedOperatorId); } }, - - setPositionRatio: function(positionRatio) { + + setPositionRatio: function (positionRatio) { this.positionRatio = positionRatio; }, - - getPositionRatio: function() { + + getPositionRatio: function () { return this.positionRatio; }, - - getData: function() { + + getData: function () { var keys = ['operators', 'links', 'linkRestrictions']; var data = {}; data.operators = $.extend(true, {}, this.data.operators); @@ -994,17 +1018,21 @@ $(function() { data.linkRestrictions = $.extend(true, [], this.data.linkRestrictions); for (var keyI in keys) { - var key = keys[keyI]; - for (var objId in data[key]) { - delete data[key][objId].internal; + if (keys.hasOwnProperty(keyI)) { + var key = keys[keyI]; + for (var objId in data[key]) { + if (data[key].hasOwnProperty(objId)) { + delete data[key][objId].internal; + } + } } } data.operatorTypes = this.data.operatorTypes; return data; }, - - setOperatorTitle: function(operatorId, title) { - this.data.operators[operatorId].internal.els.title.text(title); + + setOperatorTitle: function (operatorId, title) { + this.data.operators[operatorId].internal.els.title.html(title); if (typeof this.data.operators[operatorId].properties == 'undefined') { this.data.operators[operatorId].properties = {}; } @@ -1012,21 +1040,20 @@ $(function() { this._refreshInternalProperties(this.data.operators[operatorId]); this.options.onAfterChange('operator_title_change'); }, - - getOperatorTitle: function(operatorId) { + + getOperatorTitle: function (operatorId) { return this.data.operators[operatorId].internal.properties.title; }, - - setOperatorData: function(operatorId, operatorData) { + + setOperatorData: function (operatorId, operatorData) { var infos = this.getOperatorCompleteData(operatorData); for (var linkId in this.data.links) { - var linkData = this.data.links[linkId]; - if ((linkData.fromOperator == operatorId && - typeof infos.outputs[linkData.fromConnector] == 'undefined') || - (linkData.toOperator == operatorId && - typeof infos.inputs[linkData.toConnector] == 'undefined')) { + if (this.data.links.hasOwnProperty(linkId)) { + var linkData = this.data.links[linkId]; + if ((linkData.fromOperator == operatorId && typeof infos.outputs[linkData.fromConnector] == 'undefined') || + (linkData.toOperator == operatorId && typeof infos.inputs[linkData.toConnector] == 'undefined')) { this._deleteLink(linkId, true); - continue; + } } } this._deleteOperator(operatorId, true); @@ -1034,14 +1061,14 @@ $(function() { this.redrawLinksLayer(); this.options.onAfterChange('operator_data_change'); }, - - getOperatorData: function(operatorId) { + + getOperatorData: function (operatorId) { var data = $.extend(true, {}, this.data.operators[operatorId]); delete data.internal; return data; }, - - getOperatorFullProperties: function(operatorData) { + + getOperatorFullProperties: function (operatorData) { if (typeof operatorData.type != 'undefined') { var typeProperties = this.data.operatorTypes[operatorData.type]; var operatorProperties = {}; @@ -1054,10 +1081,9 @@ $(function() { return operatorData.properties; } }, - - _refreshInternalProperties: function(operatorData) { + + _refreshInternalProperties: function (operatorData) { operatorData.internal.properties = this.getOperatorFullProperties(operatorData); } }); }); -//# sourceURL=jquery-flowchart.js \ No newline at end of file From ee7a7911cbe3ea44d93ef9825cf4de01a196763c Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 16:02:08 +0100 Subject: [PATCH 09/14] Merge complete --- jquery.flowchart.js | 210 ++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 103 deletions(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index a76a501..772b9ca 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -246,10 +246,10 @@ $(function () { //try to colorize link with restriction link data if(restrictionLinkIndex!=null) { - var restriction = this.data.linkRestrictions[restrictionLinkIndex]; - if(typeof restriction.color != 'undefined') { - linkData.color = restriction.color; - } + var restriction = this.data.linkRestrictions[restrictionLinkIndex]; + if(typeof restriction.color != 'undefined') { + linkData.color = restriction.color; + } } this.data.links[linkId] = linkData; @@ -262,26 +262,26 @@ $(function () { * Return -1 if the link is forbidden, and the index into the link restriction array otherwise */ _indexOfLinkGranted: function(linkData) { - if(this.data.linkRestrictions.length == 0) { - return null; - } - - var linkRestrictions = this.data.linkRestrictions; - - for(var i=0; i'); $operator_connector.appendTo($operator_connector_set); @@ -582,9 +585,9 @@ $(function () { var $operator_connector_small_arrow = $('
'); $operator_connector_small_arrow.appendTo($operator_connector); - fullElement.connectors[connectorKey].push($operator_connector); - fullElement.connectorArrows[connectorKey].push($operator_connector_arrow); - fullElement.connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); + fullElement[connectorType].connectors[connectorKey].push($operator_connector); + fullElement[connectorType].connectorArrows[connectorKey].push($operator_connector_arrow); + fullElement[connectorType].connectorSmallArrows[connectorKey].push($operator_connector_small_arrow); }, getOperatorElement: function (operatorData) { @@ -699,7 +702,7 @@ $(function () { _connectorClicked: function (operator, connector, subConnector, connectorCategory) { if (connectorCategory == 'outputs') { - this._restoreGrantedConnectorsColor(); + this._restoreGrantedConnectorsColor(); var d = new Date(); // var currentTime = d.getTime(); this.lastOutputConnectorClicked = { @@ -709,7 +712,7 @@ $(function () { grantedConnectors: this._getGrantedConnectors(operator, connector) }; this.objs.layers.temporaryLink.show(); - var position = this.getConnectorPosition(operator, connector, subConnector); + var position = this.getConnectorPosition(operator, connector, subConnector, connectorCategory); var x = position.x + position.width; var y = position.y; this.objs.temporaryLink.setAttribute('x1', x.toString()); @@ -733,60 +736,60 @@ $(function () { }, _getGrantedConnectors: function(operatorId, connector) { - var operatorType = this.data.operators[operatorId].type; - if(typeof operatorType=='undefined' || this.data.linkRestrictions.length==0) { - return []; - } - - var grantedLinks = this.data.linkRestrictions.filter(function(r) { - return operatorType==r.fromOperatorType && connector==r.fromConnector; - }); - - var grantedConnectors = []; - - for(var l in grantedLinks) { - var link = grantedLinks[l]; - - for(var opId in this.data.operators) { - var operator = this.data.operators[opId]; - if(operator.type == link.toOperatorType) { - var arrows = operator.internal.els.inputs.connectorArrows[link.toConnector]; - arrows = arrows.map(function(sa) { - return {els: sa, oldColor: sa.css('border-left-color')}; - }); - - grantedConnectors.push({ - color: typeof link.color=='undefined' ? this.options.defaultLinkColor : link.color, - arrows: arrows - }); - } - } - } - - return grantedConnectors; + var operatorType = this.data.operators[operatorId].type; + if(typeof operatorType=='undefined' || this.data.linkRestrictions.length==0) { + return []; + } + + var grantedLinks = this.data.linkRestrictions.filter(function(r) { + return operatorType==r.fromOperatorType && connector==r.fromConnector; + }); + + var grantedConnectors = []; + + for(var l in grantedLinks) { + var link = grantedLinks[l]; + + for(var opId in this.data.operators) { + var operator = this.data.operators[opId]; + if(operator.type == link.toOperatorType) { + var arrows = operator.internal.els.inputs.connectorArrows[link.toConnector]; + arrows = arrows.map(function(sa) { + return {els: sa, oldColor: sa.css('border-left-color')}; + }); + + grantedConnectors.push({ + color: typeof link.color=='undefined' ? this.options.defaultLinkColor : link.color, + arrows: arrows + }); + } + } + } + + return grantedConnectors; }, _colorizeGrantedConnectors: function() { - if(this.lastOutputConnectorClicked != null) { - var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; - - grantedConnectors.forEach(function(l) { - l.arrows.forEach(function(sa) { - sa.els.css('border-left-color', l.color); - }); - }); - } + if(this.lastOutputConnectorClicked != null) { + var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; + + grantedConnectors.forEach(function(l) { + l.arrows.forEach(function(sa) { + sa.els.css('border-left-color', l.color); + }); + }); + } }, - + _restoreGrantedConnectorsColor: function() { - if(this.lastOutputConnectorClicked != null) { - var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; - - grantedConnectors.forEach(function(l) { - l.arrows.forEach(function(sa) { - sa.els.css('border-left-color', sa.oldColor); - }); - }); + if(this.lastOutputConnectorClicked != null) { + var grantedConnectors = this.lastOutputConnectorClicked.grantedConnectors; + + grantedConnectors.forEach(function(l) { + l.arrows.forEach(function(sa) { + sa.els.css('border-left-color', sa.oldColor); + }); + }); } }, @@ -1016,7 +1019,7 @@ $(function () { data.operators = $.extend(true, {}, this.data.operators); data.links = $.extend(true, {}, this.data.links); data.linkRestrictions = $.extend(true, [], this.data.linkRestrictions); - + for (var keyI in keys) { if (keys.hasOwnProperty(keyI)) { var key = keys[keyI]; @@ -1087,3 +1090,4 @@ $(function () { } }); }); +//# sourceURL=jquery-flowchart.js \ No newline at end of file From d9402f2dff451834f7ef7e792a176d5b7ba5fd19 Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 16:16:15 +0100 Subject: [PATCH 10/14] merge forget --- jquery.flowchart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery.flowchart.js b/jquery.flowchart.js index 772b9ca..a865cba 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -132,7 +132,7 @@ $(function () { }); - this.objs.layers.operators.on('mousedown touchstart', '.flowchart-operator', function (e) { + this.objs.layers.operators.on('touchdown mousedown touchstart', '.flowchart-operator', function (e) { e.stopImmediatePropagation(); }); From a691562427cf86d50cd59c5b312619a6d084721a Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 16:19:34 +0100 Subject: [PATCH 11/14] revert old min file --- jquery.flowchart.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery.flowchart.min.js b/jquery.flowchart.min.js index b7c3755..8b64b38 100644 --- a/jquery.flowchart.min.js +++ b/jquery.flowchart.min.js @@ -1 +1 @@ -$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(a){return!0},onOperatorUnselect:function(){return!0},onOperatorMouseOver:function(a){return!0},onOperatorMouseOut:function(a){return!0},onLinkSelect:function(a){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(a,b,c){return!0},onLinkCreate:function(a,b){return!0},onOperatorDelete:function(a){return!0},onLinkDelete:function(a,b){return!0},onOperatorMoved:function(a,b){},onAfterChange:function(a){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var a=document.createElementNS("http://www.w3.org/2000/svg","line");a.setAttribute("x1","0"),a.setAttribute("y1","0"),a.setAttribute("x2","0"),a.setAttribute("y2","0"),a.setAttribute("stroke-dasharray","6,6"),a.setAttribute("stroke-width","4"),a.setAttribute("stroke","black"),a.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(a),this.objs.temporaryLink=a,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var a=this;this.element.mousemove(function(b){var c=$(this),d=c.offset();a._mousemove((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.element.click(function(b){var c=$(this),d=c.offset();a._click((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(a){a.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(b){0==$(b.target).closest(".flowchart-operator-connector").length&&a.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var b=$(this);a.options.canUserEditLinks&&a._connectorClicked(b.closest(".flowchart-operator").data("operator_id"),b.data("connector"),b.data("sub_connector"),b.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(a){a.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){a._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){a._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){a.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(b){a._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(b){a._operatorMouseOut($(this).data("operator_id"))})},setData:function(a){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof a.operatorTypes&&(this.data.operatorTypes=a.operatorTypes),this.data.linkRestrictions=[],"undefined"!=typeof a.linkRestrictions&&a.linkRestrictions.length>0&&(this.data.linkRestrictions=a.linkRestrictions),this.data.operators={};for(var b in a.operators)a.operators.hasOwnProperty(b)&&this.createOperator(b,a.operators[b]);this.data.links={};for(var c in a.links)a.links.hasOwnProperty(c)&&this.createLink(c,a.links[c]);this.redrawLinksLayer()},addLink:function(a){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,a),this.linkNum},createLink:function(a,b){var c=$.extend(!0,{},b);if(this.options.onLinkCreate(a,c)){var d=this._indexOfLinkGranted(c);if(d!=-1){var e=this._getSubConnectors(c),f=e[0],g=e[1],h=this.options.multipleLinksOnOutput,i=this.options.multipleLinksOnInput;if(!h||!i)for(var j in this.data.links)if(this.data.links.hasOwnProperty(j)){var k=this.data.links[j],l=this._getSubConnectors(k),m=l[0],n=l[1];if(!h&&k.fromOperator==c.fromOperator&&k.fromConnector==c.fromConnector&&m==f){this.deleteLink(j);continue}i||k.toOperator!=c.toOperator||k.toConnector!=c.toConnector||n!=g||this.deleteLink(j)}if(this._autoCreateSubConnector(c.fromOperator,c.fromConnector,"outputs",f),this._autoCreateSubConnector(c.toOperator,c.toConnector,"inputs",g),null!=d){var o=this.data.linkRestrictions[d];"undefined"!=typeof o.color&&(c.color=o.color)}this.data.links[a]=c,this._drawLink(a),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(a){if(0==this.data.linkRestrictions.length)return null;for(var b=this.data.linkRestrictions,c=0;c');e.data("connector_type",d),e.appendTo(c),i[a]=[],j[a]=[],l[a]=[],k[a]=e,h._createSubConnector(a,b,m)}var b=this.getOperatorCompleteData(a),c=$('
');c.addClass(b.class);var d=$('
');d.html(b.title),d.appendTo(c);var e=$('
');e.appendTo(c);var f=$('
');f.appendTo(e);var g=$('
');g.appendTo(e);var h=this,i={},j={},k={},l={},m={operator:c,title:d,connectorSets:k,connectors:l,connectorArrows:i,connectorSmallArrows:j};for(var o in b.inputs)b.inputs.hasOwnProperty(o)&&n(o,b.inputs[o],f,"inputs");for(var p in b.outputs)b.outputs.hasOwnProperty(p)&&n(p,b.outputs[p],g,"outputs");return m},_createSubConnector:function(a,b,c){var d=c.connectorSets[a],e=c.connectors[a].length,f=$('
');f.appendTo(d),f.data("connector",a),f.data("sub_connector",e);var g=$('
');g.text(b.label.replace("(:i)",e+1)),g.appendTo(f);var h=$('
');h.appendTo(f);var i=$('
');i.appendTo(f),c.connectors[a].push(f),c.connectorArrows[a].push(h),c.connectorSmallArrows[a].push(i)},getOperatorElement:function(a){var b=this._getOperatorFullElement(a);return b.operator},addOperator:function(a){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,a),this.operatorNum},createOperator:function(a,b){function f(a,c){b.top=c.top,b.left=c.left;for(var d in e.data.links)if(e.data.links.hasOwnProperty(d)){var f=e.data.links[d];f.fromOperator!=a&&f.toOperator!=a||e._refreshLinkPositions(d)}}b.internal={},this._refreshInternalProperties(b);var c=this._getOperatorFullElement(b);if(!this.options.onOperatorCreate(a,b,c))return!1;var d=this.options.grid;d&&(b.top=Math.round(b.top/d)*d,b.left=Math.round(b.left/d)*d),c.operator.appendTo(this.objs.layers.operators),c.operator.css({top:b.top,left:b.left}),c.operator.data("operator_id",a),this.data.operators[a]=b,this.data.operators[a].internal.els=c,a==this.selectedOperatorId&&this._addSelectedClass(a);var e=this;if(this.options.canUserMoveOperators){var g,h;c.operator.draggable({containment:!b.internal.properties.uncontained&&this.element,handle:".flowchart-operator-title",start:function(a,b){if(null!=e.lastOutputConnectorClicked)return void a.preventDefault();var c=e.element.offset();g=(a.pageX-c.left)/e.positionRatio-parseInt($(a.target).css("left")),h=(a.pageY-c.top)/e.positionRatio-parseInt($(a.target).css("top"))},drag:function(a,d){if(e.options.grid){var i=e.options.grid,j=e.element.offset();if(d.position.left=Math.round(((a.pageX-j.left)/e.positionRatio-g)/i)*i,d.position.top=Math.round(((a.pageY-j.top)/e.positionRatio-h)/i)*i,!b.internal.properties.uncontained){var k=$(this);d.position.left=Math.min(Math.max(d.position.left,0),e.element.width()-k.outerWidth()),d.position.top=Math.min(Math.max(d.position.top,0),e.element.height()-k.outerHeight())}d.offset.left=Math.round(d.position.left+j.left),d.offset.top=Math.round(d.position.top+j.top),c.operator.css({left:d.position.left,top:d.position.top})}f($(this).data("operator_id"),d.position)},stop:function(a,b){e._unsetTemporaryLink();var d=$(this).data("operator_id");f(d,b.position),c.operator.css({height:"auto"}),e.options.onOperatorMoved(d,b.position),e.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(a,b,c,d){if("outputs"==d){new Date;this.lastOutputConnectorClicked={operator:a,connector:b,subConnector:c,grantedLinks:this._getGrantedLinks(a,b)},this.objs.layers.temporaryLink.show();var f=this.getConnectorPosition(a,b,c),g=f.x+f.width,h=f.y;this.objs.temporaryLink.setAttribute("x1",g.toString()),this.objs.temporaryLink.setAttribute("y1",h.toString()),this._mousemove(g,h),this._colorizeGrantedLinks()}if("inputs"==d&&null!=this.lastOutputConnectorClicked){var i={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:a,toConnector:b,toSubConnector:c};this._unsetTemporaryLink(),this.addLink(i)}},_getGrantedLinks:function(a,b){if(0==this.data.linkRestrictions.length)return[];var c=this.data.linkRestrictions.filter(function(c){return a==c.fromOperator&&b==c.fromConnector}),d=this;return c.map(function(a){"undefined"==typeof a.color&&(a.color=defaultLinkColor);var b=d.data.operators[a.toOperator],c=b.internal.els.connectorSmallArrows[a.toConnector];return a.smallArrows=c.map(function(a){return{els:a,oldColor:a.css("border-left-color")}}),a})},_colorizeGrantedLinks:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(b){b.els.css("border-left-color",a.color)})})}},_restoreGrantedLinksColor:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedLinks;a.forEach(function(a){a.smallArrows.forEach(function(a){a.els.css("border-left-color",a.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedLinksColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(a,b,c){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",a),this.objs.temporaryLink.setAttribute("y2",b))},_click:function(a,b,c){var d=$(c.target);0==d.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==d.closest(".flowchart-operator").length&&this.unselectOperator(),0==d.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(a){this.data.operators[a].internal.els.operator.addClass("selected")},selectOperator:function(a){this.options.onOperatorSelect(a)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(a),this.selectedOperatorId=a)},addClassOperator:function(a,b){this.data.operators[a].internal.els.operator.addClass(b)},removeClassOperator:function(a,b){this.data.operators[a].internal.els.operator.removeClass(b)},removeClassOperators:function(a){this.objs.layers.operators.find(".flowchart-operator").removeClass(a)},_addHoverClassOperator:function(a){this.data.operators[a].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(a){this.options.onOperatorMouseOver(a)&&this._addHoverClassOperator(a)},_operatorMouseOut:function(a){this.options.onOperatorMouseOut(a)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(a,b){var c=parseInt(a.slice(1),16),d=b<0?0:255,e=b<0?b*-1:b,f=c>>16,g=c>>8&255,h=255&c;return"#"+(16777216+65536*(Math.round((d-f)*e)+f)+256*(Math.round((d-g)*e)+g)+(Math.round((d-h)*e)+h)).toString(16).slice(1)},colorizeLink:function(a,b){var c=this.data.links[a];c.internal.els.path.setAttribute("stroke",b),c.internal.els.rect.setAttribute("fill",b),c.internal.els.fromSmallConnector.css("border-left-color",b),c.internal.els.toSmallConnector.css("border-left-color",b)},uncolorizeLink:function(a){this.colorizeLink(a,this.getLinkMainColor(a))},_connecterMouseOver:function(a){this.selectedLinkId!=a&&this.colorizeLink(a,this._shadeColor(this.getLinkMainColor(a),-.4))},_connecterMouseOut:function(a){this.selectedLinkId!=a&&this.uncolorizeLink(a)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(a){this.unselectLink(),this.options.onLinkSelect(a)&&(this.unselectOperator(),this.selectedLinkId=a,this.colorizeLink(a,this.options.defaultSelectedLinkColor))},deleteOperator:function(a){this._deleteOperator(a,!1)},_deleteOperator:function(a,b){if(!this.options.onOperatorDelete(a,b))return!1;if(!b)for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var d=this.data.links[c];d.fromOperator!=a&&d.toOperator!=a||this._deleteLink(c,!0)}b||a!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[a].internal.els.operator.remove(),delete this.data.operators[a],this.options.onAfterChange("operator_delete")},deleteLink:function(a){this._deleteLink(a,!1)},_deleteLink:function(a,b){if(this.selectedLinkId==a&&this.unselectLink(),this.options.onLinkDelete(a,b)||b){this.colorizeLink(a,"transparent");var c=this.data.links[a],d=c.fromOperator,e=c.fromConnector,f=c.toOperator,g=c.toConnector;c.internal.els.overallGroup.remove(),delete this.data.links[a],this._cleanMultipleConnectors(d,e,"from"),this._cleanMultipleConnectors(f,g,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(a,b,c){if(this.data.operators[a].properties["from"==c?"outputs":"inputs"][b].multiple){var d=-1,e=c+"Operator",f=c+"Connector",g=c+"SubConnector",h=this.data.operators[a].internal.els,i=h.connectors[b],j=i.length;for(var k in this.data.links)if(this.data.links.hasOwnProperty(k)){var l=this.data.links[k];l[e]==a&&l[f]==b&&d'),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var r=$(this),o=r.offset();t._mousemove((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.element.click(function(e){var r=$(this),o=r.offset();t._click((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(e){t._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(e){t._operatorMouseOut($(this).data("operator_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var r in t.links)t.links.hasOwnProperty(r)&&this.createLink(r,t.links[r]);this.redrawLinksLayer()},addLink:function(t){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var r=$.extend(!0,{},e);if(this.options.onLinkCreate(t,r)){var o=this._getSubConnectors(r),n=o[0],i=o[1],a=this.options.multipleLinksOnOutput,s=this.options.multipleLinksOnInput;if(!a||!s)for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var p=this.data.links[l],c=this._getSubConnectors(p),u=c[0],h=c[1];if(!a&&p.fromOperator==r.fromOperator&&p.fromConnector==r.fromConnector&&u==n){this.deleteLink(l);continue}s||p.toOperator!=r.toOperator||p.toConnector!=r.toConnector||h!=i||this.deleteLink(l)}this._autoCreateSubConnector(r.fromOperator,r.fromConnector,"outputs",n),this._autoCreateSubConnector(r.toOperator,r.toConnector,"inputs",i),this.data.links[t]=r,this._drawLink(t),this.options.onAfterChange("link_create")}},_autoCreateSubConnector:function(t,e,r,o){var n=this.data.operators[t].properties[r][e];if(n.multiple)for(var i=this.data.operators[t].internal.els,a=this.data.operators[t].internal.els.connectors[e].length,s=a;o+2>s;s++)this._createSubConnector(e,n,i)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,r){var o=this.data.operators[t],n=o.internal.els.connectorArrows[e][r],i=n.offset(),a=this.element.offset(),s=(i.left-a.left)/this.positionRatio,l=parseInt(n.css("border-top-width")),p=(i.top-a.top-1)/this.positionRatio+parseInt(n.css("border-left-width"));return{x:s,width:l,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,r=this.data.links[t];return"undefined"!=typeof r.color&&(e=r.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];"undefined"==typeof e.internal&&(e.internal={}),e.internal.els={};var r=e.fromOperator,o=e.fromConnector,n=e.toOperator,i=e.toConnector,a=this._getSubConnectors(e),s=a[0],l=a[1],c=(this.getLinkMainColor(t),this.data.operators[r]),u=this.data.operators[n],h=c.internal.els.connectorSmallArrows[o][s],d=u.internal.els.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=d;var f=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(f),e.internal.els.overallGroup=f;var v=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,v.setAttribute("id",k),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.setAttribute("x","0"),m.setAttribute("y","0"),m.setAttribute("width","100%"),m.setAttribute("height","100%"),m.setAttribute("stroke","none"),m.setAttribute("fill","white"),v.appendChild(m);var C=document.createElementNS("http://www.w3.org/2000/svg","polygon");C.setAttribute("stroke","none"),C.setAttribute("fill","black"),v.appendChild(C),e.internal.els.mask=C;var O=document.createElementNS("http://www.w3.org/2000/svg","g");O.setAttribute("class","flowchart-link"),O.setAttribute("data-link_id",t),f.appendChild(O);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",this.options.linkWidth.toString()),w.setAttribute("fill","none"),O.appendChild(w),e.internal.els.path=w;var b=document.createElementNS("http://www.w3.org/2000/svg","rect");b.setAttribute("stroke","none"),b.setAttribute("mask","url(#"+k+")"),O.appendChild(b),e.internal.els.rect=b,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;"undefined"!=typeof t.fromSubConnector&&(e=t.fromSubConnector);var r=0;return"undefined"!=typeof t.toSubConnector&&(r=t.toSubConnector),[e,r]},_refreshLinkPositions:function(t){var e=this.data.links[t],r=this._getSubConnectors(e),o=r[0],n=r[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,o),a=this.getConnectorPosition(e.toOperator,e.toConnector,n),s=i.x,l=i.width,p=i.y,c=a.x,u=a.y;p+=this.options.linkVerticalDecal,u+=this.options.linkVerticalDecal;var h=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",s+","+(p-l-h)+" "+(s+l+h)+","+p+" "+s+","+(p+l+h));var d=s+l+h,f=c+1,v=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(p-u)));e.internal.els.path.setAttribute("d","M"+d+","+p+" C"+(s+l+h+v)+","+p+" "+(c-v)+","+u+" "+f+","+u),e.internal.els.rect.setAttribute("x",s),e.internal.els.rect.setAttribute("y",p-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+h+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){"undefined"==typeof t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var r in e.inputs)e.inputs.hasOwnProperty(r)&&null==e.inputs[r]&&delete e.inputs[r];for(var o in e.outputs)e.outputs.hasOwnProperty(o)&&null==e.outputs[o]&&delete e.outputs[o];return"undefined"==typeof e["class"]&&(e["class"]=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function d(t,e,r,o){var n=$('
');n.data("connector_type",o),n.appendTo(r),l[t]=[],p[t]=[],u[t]=[],c[t]=n,s._createSubConnector(t,e,h)}var e=this.getOperatorCompleteData(t),r=$('
');r.addClass(e["class"]);var o=$('
');o.html(e.title),o.appendTo(r);var n=$('
');n.appendTo(r);var i=$('
');i.appendTo(n);var a=$('
');a.appendTo(n);var s=this,l={},p={},c={},u={},h={operator:r,title:o,connectorSets:c,connectors:u,connectorArrows:l,connectorSmallArrows:p};for(var f in e.inputs)e.inputs.hasOwnProperty(f)&&d(f,e.inputs[f],i,"inputs");for(var v in e.outputs)e.outputs.hasOwnProperty(v)&&d(v,e.outputs[v],a,"outputs");return h},_createSubConnector:function(t,e,r){var o=r.connectorSets[t],n=r.connectors[t].length,i=$('
');i.appendTo(o),i.data("connector",t),i.data("sub_connector",n);var a=$('
');a.text(e.label.replace("(:i)",n+1)),a.appendTo(i);var s=$('
');s.appendTo(i);var l=$('
');l.appendTo(i),r.connectors[t].push(i),r.connectorArrows[t].push(s),r.connectorSmallArrows[t].push(l)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function i(t,r){e.top=r.top,e.left=r.left;for(var o in n.data.links)if(n.data.links.hasOwnProperty(o)){var i=n.data.links[o];(i.fromOperator==t||i.toOperator==t)&&n._refreshLinkPositions(o)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var o=this.options.grid;o&&(e.top=Math.round(e.top/o)*o,e.left=Math.round(e.left/o)*o),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var n=this;if(this.options.canUserMoveOperators){var a,s;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t,e){if(null!=n.lastOutputConnectorClicked)return void t.preventDefault();var r=n.element.offset();a=(t.pageX-r.left)/n.positionRatio-parseInt($(t.target).css("left")),s=(t.pageY-r.top)/n.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,o){if(n.options.grid){var l=n.options.grid,p=n.element.offset();if(o.position.left=Math.round(((t.pageX-p.left)/n.positionRatio-a)/l)*l,o.position.top=Math.round(((t.pageY-p.top)/n.positionRatio-s)/l)*l,!e.internal.properties.uncontained){var c=$(this);o.position.left=Math.min(Math.max(o.position.left,0),n.element.width()-c.outerWidth()),o.position.top=Math.min(Math.max(o.position.top,0),n.element.height()-c.outerHeight())}o.offset.left=Math.round(o.position.left+p.left),o.offset.top=Math.round(o.position.top+p.top),r.operator.css({left:o.position.left,top:o.position.top})}i($(this).data("operator_id"),o.position)},stop:function(t,e){n._unsetTemporaryLink();var o=$(this).data("operator_id");i(o,e.position),r.operator.css({height:"auto"}),n.options.onOperatorMoved(o,e.position),n.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,r,o){if("outputs"==o){new Date;this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:r},this.objs.layers.temporaryLink.show();var i=this.getConnectorPosition(t,e,r),a=i.x+i.width,s=i.y;this.objs.temporaryLink.setAttribute("x1",a.toString()),this.objs.temporaryLink.setAttribute("y1",s.toString()),this._mousemove(a,s)}if("inputs"==o&&null!=this.lastOutputConnectorClicked){var l={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:r};this.addLink(l),this._unsetTemporaryLink()}},_unsetTemporaryLink:function(){this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e,r){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,r){var o=$(r.target);0==o.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==o.closest(".flowchart-operator").length&&this.unselectOperator(),0==o.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},addClassOperator:function(t,e){this.data.operators[t].internal.els.operator.addClass(e)},removeClassOperator:function(t,e){this.data.operators[t].internal.els.operator.removeClass(e)},removeClassOperators:function(t){this.objs.layers.operators.find(".flowchart-operator").removeClass(t)},_addHoverClassOperator:function(t){this.data.operators[t].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(t){this.options.onOperatorMouseOver(t)&&this._addHoverClassOperator(t)},_operatorMouseOut:function(t){this.options.onOperatorMouseOut(t)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var r=parseInt(t.slice(1),16),o=0>e?0:255,n=0>e?-1*e:e,i=r>>16,a=r>>8&255,s=255&r;return"#"+(16777216+65536*(Math.round((o-i)*n)+i)+256*(Math.round((o-a)*n)+a)+(Math.round((o-s)*n)+s)).toString(16).slice(1)},colorizeLink:function(t,e){var r=this.data.links[t];r.internal.els.path.setAttribute("stroke",e),r.internal.els.rect.setAttribute("fill",e),r.internal.els.fromSmallConnector.css("border-left-color",e),r.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var o=this.data.links[r];(o.fromOperator==t||o.toOperator==t)&&this._deleteLink(r,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var r=this.data.links[t],o=r.fromOperator,n=r.fromConnector,i=r.toOperator,a=r.toConnector;r.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(o,n,"from"),this._cleanMultipleConnectors(i,a,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,r){if(this.data.operators[t].properties["from"==r?"outputs":"inputs"][e].multiple){var o=-1,n=r+"Operator",i=r+"Connector",a=r+"SubConnector",s=this.data.operators[t].internal.els,l=s.connectors[e],p=l.length;for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var u=this.data.links[c];u[n]==t&&u[i]==e&&od;d++)l[l.length-1].remove(),l.pop(),s.connectorArrows[e].pop(),s.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links);for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];for(var n in e[o])e[o].hasOwnProperty(n)&&delete e[o][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),"undefined"==typeof this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var r=this.getOperatorCompleteData(e);for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var n=this.data.links[o];(n.fromOperator==t&&"undefined"==typeof r.outputs[n.fromConnector]||n.toOperator==t&&"undefined"==typeof r.inputs[n.toConnector])&&this._deleteLink(o,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},doesOperatorExists:function(t){return"undefined"!=typeof this.data.operators[t]},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if("undefined"!=typeof t.type){var e=this.data.operatorTypes[t.type],r={};return"undefined"!=typeof t.properties&&(r=t.properties),$.extend({},e,r)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file From e190488c9c6d0b1fa1f980baa28f499540fa9a47 Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Fri, 27 Jan 2017 16:21:01 +0100 Subject: [PATCH 12/14] fix accent --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34594d5..83dbd81 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Contributors ------------ * Simone Gasparini - alias [@simmyg89](https://github.com/simmyg89) - for bug fixes and code formatting. * Guijin Ding - alias [@dingguijin](https://github.com/dingguijin) - for bug fixes. -* Fatih Marabaoglu - alias [@MonoLightTech](https://github.com/MFatihMAR) - for adding the uncontained parameter and improving the grid system. +* Fatih Marabaoğlu - alias [@MonoLightTech](https://github.com/MFatihMAR) - for adding the uncontained parameter and improving the grid system. * Peter Vavro - alias [@petervavro](https://github.com/petervavro) - for adding mouse events. * Mike Branham - alias [@Mike-Branham](https://github.com/Mike-Branham) - for bug fixes in the demo page. From 143c1f1ab4d012f75c16bc6f28dab067a9cb3f32 Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Thu, 16 Feb 2017 13:51:57 +0100 Subject: [PATCH 13/14] Prevent crash when operator and link restrictions are not synchronized (on some loads) Set flowchart operators width more flexible --- jquery.flowchart.css | 3 ++- jquery.flowchart.js | 19 +++++++++++-------- jquery.flowchart.min.css | 2 +- jquery.flowchart.min.js | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/jquery.flowchart.css b/jquery.flowchart.css index ac15f3f..7ae4fbe 100644 --- a/jquery.flowchart.css +++ b/jquery.flowchart.css @@ -106,7 +106,8 @@ .flowchart-operator { position: absolute; - width: 140px; + min-width: 140px; + max-width: 250px; border: 1px solid #CCCCCC; background: #FAFAFA; pointer-events: initial; diff --git a/jquery.flowchart.js b/jquery.flowchart.js index a865cba..f975a17 100644 --- a/jquery.flowchart.js +++ b/jquery.flowchart.js @@ -754,14 +754,17 @@ $(function () { var operator = this.data.operators[opId]; if(operator.type == link.toOperatorType) { var arrows = operator.internal.els.inputs.connectorArrows[link.toConnector]; - arrows = arrows.map(function(sa) { - return {els: sa, oldColor: sa.css('border-left-color')}; - }); - - grantedConnectors.push({ - color: typeof link.color=='undefined' ? this.options.defaultLinkColor : link.color, - arrows: arrows - }); + + if(arrows!=undefined) { + arrows = arrows.map(function(sa) { + return {els: sa, oldColor: sa.css('border-left-color')}; + }); + + grantedConnectors.push({ + color: typeof link.color=='undefined' ? this.options.defaultLinkColor : link.color, + arrows: arrows + }); + } } } } diff --git a/jquery.flowchart.min.css b/jquery.flowchart.min.css index 459a2d1..5eb05b9 100644 --- a/jquery.flowchart.min.css +++ b/jquery.flowchart.min.css @@ -1 +1 @@ -.flowchart-container{position:relative;overflow:hidden}.flowchart-links-layer,.flowchart-operators-layer,.flowchart-temporary-link-layer{position:absolute;top:0;left:0;width:100%;height:100%}.flowchart-operator-inputs .flowchart-operator-connector-arrow,.flowchart-operator-inputs .flowchart-operator-connector-small-arrow{left:-1px}.flowchart-operators-layer,.flowchart-temporary-link-layer{pointer-events:none}.flowchart-temporary-link-layer{display:none}.flowchart-link,.flowchart-operator{cursor:default}.flowchart-operator-connector{position:relative;padding-top:5px;padding-bottom:5px}.flowchart-operator-connector-label{font-size:small}.flowchart-operator-inputs .flowchart-operator-connector-label{margin-left:14px}.flowchart-operator-outputs .flowchart-operator-connector-label{text-align:right;margin-right:5px}.flowchart-operator-connector-arrow{width:0;height:0;border-top:10px solid transparent;border-bottom:10px solid transparent;border-left:10px solid #ccc;position:absolute;top:0}.flowchart-operator-connector-small-arrow{width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid transparent;position:absolute;top:5px;pointer-events:none}.flowchart-operator-connector:hover .flowchart-operator-connector-arrow{border-left:10px solid #999}.flowchart-operator-outputs .flowchart-operator-connector-arrow{right:-10px}.flowchart-operator-outputs .flowchart-operator-connector-small-arrow{right:-7px}.unselectable{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.flowchart-operator{position:absolute;width:140px;border:1px solid #CCC;background:#FAFAFA;pointer-events:initial}.flowchart-operator.hover{border-color:#999}.flowchart-operator.selected{border-color:#555}.flowchart-operator .flowchart-operator-title{width:100%;padding:5px;font-weight:700;box-sizing:border-box;border-bottom:1px solid #DDD;background:#F0F0F0;height:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:move}.flowchart-operator .flowchart-operator-inputs-outputs{display:table;width:100%;margin-top:5px;margin-bottom:5px}.flowchart-default-operator .flowchart-operator-outputs,.flowchart-operator .flowchart-operator-inputs{display:table-cell;width:50%} \ No newline at end of file +.flowchart-container{position:relative;overflow:hidden}.flowchart-links-layer,.flowchart-operators-layer,.flowchart-temporary-link-layer{position:absolute;top:0;left:0;width:100%;height:100%}.flowchart-operators-layer,.flowchart-temporary-link-layer{pointer-events:none}.flowchart-temporary-link-layer{display:none}.flowchart-link,.flowchart-operator{cursor:default}.flowchart-operator-connector{position:relative;padding-top:5px;padding-bottom:5px}.flowchart-operator-connector-label{font-size:small}.flowchart-operator-inputs .flowchart-operator-connector-label{margin-left:14px}.flowchart-operator-outputs .flowchart-operator-connector-label{text-align:right;margin-right:5px}.flowchart-operator-connector-arrow{width:0;height:0;border-top:10px solid transparent;border-bottom:10px solid transparent;border-left:10px solid #ccc;position:absolute;top:0}.flowchart-operator-connector-small-arrow{width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid transparent;position:absolute;top:5px;pointer-events:none}.flowchart-operator-connector:hover .flowchart-operator-connector-arrow{border-left:10px solid #999}.flowchart-operator-inputs .flowchart-operator-connector-arrow{left:-1px}.flowchart-operator-outputs .flowchart-operator-connector-arrow{right:-10px}.flowchart-operator-inputs .flowchart-operator-connector-small-arrow{left:-1px}.flowchart-operator-outputs .flowchart-operator-connector-small-arrow{right:-7px}.unselectable{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.flowchart-operator{position:absolute;min-width:140px;max-width:250px;border:1px solid #CCC;background:#FAFAFA;pointer-events:initial}.flowchart-operator.hover{border-color:#999}.flowchart-operator.selected{border-color:#555}.flowchart-operator .flowchart-operator-title{width:100%;padding:5px;font-weight:700;box-sizing:border-box;border-bottom:1px solid #DDD;background:#F0F0F0;height:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:move}.flowchart-operator .flowchart-operator-inputs-outputs{display:table;width:100%;margin-top:5px;margin-bottom:5px}.flowchart-operator .flowchart-operator-inputs,.flowchart-default-operator .flowchart-operator-outputs{display:table-cell;width:50%} \ No newline at end of file diff --git a/jquery.flowchart.min.js b/jquery.flowchart.min.js index 8b64b38..a2e962e 100644 --- a/jquery.flowchart.min.js +++ b/jquery.flowchart.min.js @@ -1 +1 @@ -$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(t){return!0},onOperatorUnselect:function(){return!0},onOperatorMouseOver:function(t){return!0},onOperatorMouseOut:function(t){return!0},onLinkSelect:function(t){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(t,e,r){return!0},onLinkCreate:function(t,e){return!0},onOperatorDelete:function(t){return!0},onLinkDelete:function(t,e){return!0},onOperatorMoved:function(t,e){},onAfterChange:function(t){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var r=$(this),o=r.offset();t._mousemove((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.element.click(function(e){var r=$(this),o=r.offset();t._click((e.pageX-o.left)/t.positionRatio,(e.pageY-o.top)/t.positionRatio,e)}),this.objs.layers.operators.on("pointerdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))}),this.objs.layers.operators.on("mouseover",".flowchart-operator",function(e){t._operatorMouseOver($(this).data("operator_id"))}),this.objs.layers.operators.on("mouseout",".flowchart-operator",function(e){t._operatorMouseOut($(this).data("operator_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var r in t.links)t.links.hasOwnProperty(r)&&this.createLink(r,t.links[r]);this.redrawLinksLayer()},addLink:function(t){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var r=$.extend(!0,{},e);if(this.options.onLinkCreate(t,r)){var o=this._getSubConnectors(r),n=o[0],i=o[1],a=this.options.multipleLinksOnOutput,s=this.options.multipleLinksOnInput;if(!a||!s)for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var p=this.data.links[l],c=this._getSubConnectors(p),u=c[0],h=c[1];if(!a&&p.fromOperator==r.fromOperator&&p.fromConnector==r.fromConnector&&u==n){this.deleteLink(l);continue}s||p.toOperator!=r.toOperator||p.toConnector!=r.toConnector||h!=i||this.deleteLink(l)}this._autoCreateSubConnector(r.fromOperator,r.fromConnector,"outputs",n),this._autoCreateSubConnector(r.toOperator,r.toConnector,"inputs",i),this.data.links[t]=r,this._drawLink(t),this.options.onAfterChange("link_create")}},_autoCreateSubConnector:function(t,e,r,o){var n=this.data.operators[t].properties[r][e];if(n.multiple)for(var i=this.data.operators[t].internal.els,a=this.data.operators[t].internal.els.connectors[e].length,s=a;o+2>s;s++)this._createSubConnector(e,n,i)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,r){var o=this.data.operators[t],n=o.internal.els.connectorArrows[e][r],i=n.offset(),a=this.element.offset(),s=(i.left-a.left)/this.positionRatio,l=parseInt(n.css("border-top-width")),p=(i.top-a.top-1)/this.positionRatio+parseInt(n.css("border-left-width"));return{x:s,width:l,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,r=this.data.links[t];return"undefined"!=typeof r.color&&(e=r.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];"undefined"==typeof e.internal&&(e.internal={}),e.internal.els={};var r=e.fromOperator,o=e.fromConnector,n=e.toOperator,i=e.toConnector,a=this._getSubConnectors(e),s=a[0],l=a[1],c=(this.getLinkMainColor(t),this.data.operators[r]),u=this.data.operators[n],h=c.internal.els.connectorSmallArrows[o][s],d=u.internal.els.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=d;var f=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(f),e.internal.els.overallGroup=f;var v=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,v.setAttribute("id",k),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","rect");m.setAttribute("x","0"),m.setAttribute("y","0"),m.setAttribute("width","100%"),m.setAttribute("height","100%"),m.setAttribute("stroke","none"),m.setAttribute("fill","white"),v.appendChild(m);var C=document.createElementNS("http://www.w3.org/2000/svg","polygon");C.setAttribute("stroke","none"),C.setAttribute("fill","black"),v.appendChild(C),e.internal.els.mask=C;var O=document.createElementNS("http://www.w3.org/2000/svg","g");O.setAttribute("class","flowchart-link"),O.setAttribute("data-link_id",t),f.appendChild(O);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",this.options.linkWidth.toString()),w.setAttribute("fill","none"),O.appendChild(w),e.internal.els.path=w;var b=document.createElementNS("http://www.w3.org/2000/svg","rect");b.setAttribute("stroke","none"),b.setAttribute("mask","url(#"+k+")"),O.appendChild(b),e.internal.els.rect=b,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;"undefined"!=typeof t.fromSubConnector&&(e=t.fromSubConnector);var r=0;return"undefined"!=typeof t.toSubConnector&&(r=t.toSubConnector),[e,r]},_refreshLinkPositions:function(t){var e=this.data.links[t],r=this._getSubConnectors(e),o=r[0],n=r[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,o),a=this.getConnectorPosition(e.toOperator,e.toConnector,n),s=i.x,l=i.width,p=i.y,c=a.x,u=a.y;p+=this.options.linkVerticalDecal,u+=this.options.linkVerticalDecal;var h=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",s+","+(p-l-h)+" "+(s+l+h)+","+p+" "+s+","+(p+l+h));var d=s+l+h,f=c+1,v=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(p-u)));e.internal.els.path.setAttribute("d","M"+d+","+p+" C"+(s+l+h+v)+","+p+" "+(c-v)+","+u+" "+f+","+u),e.internal.els.rect.setAttribute("x",s),e.internal.els.rect.setAttribute("y",p-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+h+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){"undefined"==typeof t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var r in e.inputs)e.inputs.hasOwnProperty(r)&&null==e.inputs[r]&&delete e.inputs[r];for(var o in e.outputs)e.outputs.hasOwnProperty(o)&&null==e.outputs[o]&&delete e.outputs[o];return"undefined"==typeof e["class"]&&(e["class"]=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function d(t,e,r,o){var n=$('
');n.data("connector_type",o),n.appendTo(r),l[t]=[],p[t]=[],u[t]=[],c[t]=n,s._createSubConnector(t,e,h)}var e=this.getOperatorCompleteData(t),r=$('
');r.addClass(e["class"]);var o=$('
');o.html(e.title),o.appendTo(r);var n=$('
');n.appendTo(r);var i=$('
');i.appendTo(n);var a=$('
');a.appendTo(n);var s=this,l={},p={},c={},u={},h={operator:r,title:o,connectorSets:c,connectors:u,connectorArrows:l,connectorSmallArrows:p};for(var f in e.inputs)e.inputs.hasOwnProperty(f)&&d(f,e.inputs[f],i,"inputs");for(var v in e.outputs)e.outputs.hasOwnProperty(v)&&d(v,e.outputs[v],a,"outputs");return h},_createSubConnector:function(t,e,r){var o=r.connectorSets[t],n=r.connectors[t].length,i=$('
');i.appendTo(o),i.data("connector",t),i.data("sub_connector",n);var a=$('
');a.text(e.label.replace("(:i)",n+1)),a.appendTo(i);var s=$('
');s.appendTo(i);var l=$('
');l.appendTo(i),r.connectors[t].push(i),r.connectorArrows[t].push(s),r.connectorSmallArrows[t].push(l)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function i(t,r){e.top=r.top,e.left=r.left;for(var o in n.data.links)if(n.data.links.hasOwnProperty(o)){var i=n.data.links[o];(i.fromOperator==t||i.toOperator==t)&&n._refreshLinkPositions(o)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var o=this.options.grid;o&&(e.top=Math.round(e.top/o)*o,e.left=Math.round(e.left/o)*o),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var n=this;if(this.options.canUserMoveOperators){var a,s;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t,e){if(null!=n.lastOutputConnectorClicked)return void t.preventDefault();var r=n.element.offset();a=(t.pageX-r.left)/n.positionRatio-parseInt($(t.target).css("left")),s=(t.pageY-r.top)/n.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,o){if(n.options.grid){var l=n.options.grid,p=n.element.offset();if(o.position.left=Math.round(((t.pageX-p.left)/n.positionRatio-a)/l)*l,o.position.top=Math.round(((t.pageY-p.top)/n.positionRatio-s)/l)*l,!e.internal.properties.uncontained){var c=$(this);o.position.left=Math.min(Math.max(o.position.left,0),n.element.width()-c.outerWidth()),o.position.top=Math.min(Math.max(o.position.top,0),n.element.height()-c.outerHeight())}o.offset.left=Math.round(o.position.left+p.left),o.offset.top=Math.round(o.position.top+p.top),r.operator.css({left:o.position.left,top:o.position.top})}i($(this).data("operator_id"),o.position)},stop:function(t,e){n._unsetTemporaryLink();var o=$(this).data("operator_id");i(o,e.position),r.operator.css({height:"auto"}),n.options.onOperatorMoved(o,e.position),n.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,r,o){if("outputs"==o){new Date;this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:r},this.objs.layers.temporaryLink.show();var i=this.getConnectorPosition(t,e,r),a=i.x+i.width,s=i.y;this.objs.temporaryLink.setAttribute("x1",a.toString()),this.objs.temporaryLink.setAttribute("y1",s.toString()),this._mousemove(a,s)}if("inputs"==o&&null!=this.lastOutputConnectorClicked){var l={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:r};this.addLink(l),this._unsetTemporaryLink()}},_unsetTemporaryLink:function(){this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e,r){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,r){var o=$(r.target);0==o.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==o.closest(".flowchart-operator").length&&this.unselectOperator(),0==o.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},addClassOperator:function(t,e){this.data.operators[t].internal.els.operator.addClass(e)},removeClassOperator:function(t,e){this.data.operators[t].internal.els.operator.removeClass(e)},removeClassOperators:function(t){this.objs.layers.operators.find(".flowchart-operator").removeClass(t)},_addHoverClassOperator:function(t){this.data.operators[t].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(t){this.options.onOperatorMouseOver(t)&&this._addHoverClassOperator(t)},_operatorMouseOut:function(t){this.options.onOperatorMouseOut(t)&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var r=parseInt(t.slice(1),16),o=0>e?0:255,n=0>e?-1*e:e,i=r>>16,a=r>>8&255,s=255&r;return"#"+(16777216+65536*(Math.round((o-i)*n)+i)+256*(Math.round((o-a)*n)+a)+(Math.round((o-s)*n)+s)).toString(16).slice(1)},colorizeLink:function(t,e){var r=this.data.links[t];r.internal.els.path.setAttribute("stroke",e),r.internal.els.rect.setAttribute("fill",e),r.internal.els.fromSmallConnector.css("border-left-color",e),r.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var o=this.data.links[r];(o.fromOperator==t||o.toOperator==t)&&this._deleteLink(r,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var r=this.data.links[t],o=r.fromOperator,n=r.fromConnector,i=r.toOperator,a=r.toConnector;r.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(o,n,"from"),this._cleanMultipleConnectors(i,a,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,r){if(this.data.operators[t].properties["from"==r?"outputs":"inputs"][e].multiple){var o=-1,n=r+"Operator",i=r+"Connector",a=r+"SubConnector",s=this.data.operators[t].internal.els,l=s.connectors[e],p=l.length;for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var u=this.data.links[c];u[n]==t&&u[i]==e&&od;d++)l[l.length-1].remove(),l.pop(),s.connectorArrows[e].pop(),s.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links);for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];for(var n in e[o])e[o].hasOwnProperty(n)&&delete e[o][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),"undefined"==typeof this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var r=this.getOperatorCompleteData(e);for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var n=this.data.links[o];(n.fromOperator==t&&"undefined"==typeof r.outputs[n.fromConnector]||n.toOperator==t&&"undefined"==typeof r.inputs[n.toConnector])&&this._deleteLink(o,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},doesOperatorExists:function(t){return"undefined"!=typeof this.data.operators[t]},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if("undefined"!=typeof t.type){var e=this.data.operatorTypes[t.type],r={};return"undefined"!=typeof t.properties&&(r=t.properties),$.extend({},e,r)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file +$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(){return!0},onOperatorUnselect:function(){return!0},onLinkSelect:function(){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(){return!0},onLinkCreate:function(){return!0},onOperatorDelete:function(){return!0},onLinkDelete:function(){return!0},onOperatorMoved:function(){},onAfterChange:function(){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){void 0===document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),void 0!==this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{},linkRestrictions:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var o=$(this),r=o.offset();t._mousemove((e.pageX-r.left)/t.positionRatio,(e.pageY-r.top)/t.positionRatio,e)}),this.element.click(function(e){var o=$(this),r=o.offset();t._click((e.pageX-r.left)/t.positionRatio,(e.pageY-r.top)/t.positionRatio,e)}),this.objs.layers.operators.on("touchdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},void 0!==t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.linkRestrictions=[],void 0!==t.linkRestrictions&&t.linkRestrictions.length>0&&(this.data.linkRestrictions=t.linkRestrictions),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var o in t.links)t.links.hasOwnProperty(o)&&this.createLink(o,t.links[o]);this.redrawLinksLayer()},addLink:function(t){for(;void 0!==this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var o=$.extend(!0,{},e);if(this.options.onLinkCreate(t,o)){var r=this._indexOfLinkGranted(o);if(-1!=r){var n=this._getSubConnectors(o),i=n[0],s=n[1],a=this.options.multipleLinksOnOutput,l=this.options.multipleLinksOnInput;if(!a||!l)for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var p=this.data.links[c],h=this._getSubConnectors(p),u=h[0],d=h[1];if(!a&&p.fromOperator==o.fromOperator&&p.fromConnector==o.fromConnector&&u==i){this.deleteLink(c);continue}l||p.toOperator!=o.toOperator||p.toConnector!=o.toConnector||d!=s||this.deleteLink(c)}if(this._autoCreateSubConnector(o.fromOperator,o.fromConnector,"outputs",i),this._autoCreateSubConnector(o.toOperator,o.toConnector,"inputs",s),null!=r){var f=this.data.linkRestrictions[r];void 0!==f.color&&(o.color=f.color)}this.data.links[t]=o,this._drawLink(t),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(t){if(0==this.data.linkRestrictions.length)return null;for(var e=this.data.linkRestrictions,o=0;oa;a++)this._createSubConnector(e,n,i,o)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,o,r){var n=this.data.operators[t],i=n.internal.els[r].connectorArrows[e][o],s=i.offset(),a=this.element.offset(),l=(s.left-a.left)/this.positionRatio,c=parseInt(i.css("border-top-width")),p=(s.top-a.top-1)/this.positionRatio+parseInt(i.css("border-left-width"));return{x:l,width:c,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,o=this.data.links[t];return void 0!==o.color&&(e=o.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];void 0===e.internal&&(e.internal={}),e.internal.els={};var o=e.fromOperator,r=e.fromConnector,n=e.toOperator,i=e.toConnector,s=this._getSubConnectors(e),a=s[0],l=s[1],c=(this.getLinkMainColor(t),this.data.operators[o]),p=this.data.operators[n],h=c.internal.els.outputs.connectorSmallArrows[r][a],u=p.internal.els.inputs.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=u;var d=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(d),e.internal.els.overallGroup=d;var f=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,f.setAttribute("id",k),d.appendChild(f);var v=document.createElementNS("http://www.w3.org/2000/svg","rect");v.setAttribute("x","0"),v.setAttribute("y","0"),v.setAttribute("width","100%"),v.setAttribute("height","100%"),v.setAttribute("stroke","none"),v.setAttribute("fill","white"),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","polygon");m.setAttribute("stroke","none"),m.setAttribute("fill","black"),f.appendChild(m),e.internal.els.mask=m;var C=document.createElementNS("http://www.w3.org/2000/svg","g");C.setAttribute("class","flowchart-link"),C.setAttribute("data-link_id",t),d.appendChild(C);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",""+this.options.linkWidth),w.setAttribute("fill","none"),C.appendChild(w),e.internal.els.path=w;var O=document.createElementNS("http://www.w3.org/2000/svg","rect");O.setAttribute("stroke","none"),O.setAttribute("mask","url(#"+k+")"),C.appendChild(O),e.internal.els.rect=O,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;void 0!==t.fromSubConnector&&(e=t.fromSubConnector);var o=0;return void 0!==t.toSubConnector&&(o=t.toSubConnector),[e,o]},_refreshLinkPositions:function(t){var e=this.data.links[t],o=this._getSubConnectors(e),r=o[0],n=o[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,r,"outputs"),s=this.getConnectorPosition(e.toOperator,e.toConnector,n,"inputs"),a=i.x,l=i.width,c=i.y,p=s.x,h=s.y;c+=this.options.linkVerticalDecal,h+=this.options.linkVerticalDecal;var u=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",a+","+(c-l-u)+" "+(a+l+u)+","+c+" "+a+","+(c+l+u));var d=a+l+u,f=p+1,k=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(c-h)));e.internal.els.path.setAttribute("d","M"+d+","+c+" C"+(a+l+u+k)+","+c+" "+(p-k)+","+h+" "+f+","+h),e.internal.els.rect.setAttribute("x",a),e.internal.els.rect.setAttribute("y",c-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+u+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){void 0===t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var o in e.inputs)e.inputs.hasOwnProperty(o)&&null==e.inputs[o]&&delete e.inputs[o];for(var r in e.outputs)e.outputs.hasOwnProperty(r)&&null==e.outputs[r]&&delete e.outputs[r];return void 0===e.class&&(e.class=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function e(t,e,o,r){var n=$('
');n.data("connector_type",r),n.appendTo(o),c[r].connectorArrows[t]=[],c[r].connectorSmallArrows[t]=[],c[r].connectors[t]=[],c[r].connectorSets[t]=n,l._createSubConnector(t,e,c,r)}var o=this.getOperatorCompleteData(t),r=$('
');r.addClass(o.class);var n=$('
');n.html(o.title),n.appendTo(r);var i=$('
');i.appendTo(r);var s=$('
');s.appendTo(i);var a=$('
');a.appendTo(i);var l=this,c={operator:r,title:n,inputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}},outputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}}};for(var p in o.inputs)o.inputs.hasOwnProperty(p)&&e(p,o.inputs[p],s,"inputs");for(var h in o.outputs)o.outputs.hasOwnProperty(h)&&e(h,o.outputs[h],a,"outputs");return c},_createSubConnector:function(t,e,o,r){var n=o[r].connectorSets[t],i=o[r].connectors[t].length,s=$('
');s.appendTo(n),s.data("connector",t),s.data("sub_connector",i);var a=$('
');a.text(e.label.replace("(:i)",i+1)),a.appendTo(s);var l=$('
');l.appendTo(s);var c=$('
');c.appendTo(s),o[r].connectors[t].push(s),o[r].connectorArrows[t].push(l),o[r].connectorSmallArrows[t].push(c)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;void 0!==this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function o(t,o){e.top=o.top,e.left=o.left;for(var r in i.data.links)if(i.data.links.hasOwnProperty(r)){var n=i.data.links[r];(n.fromOperator==t||n.toOperator==t)&&i._refreshLinkPositions(r)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var n=this.options.grid;n&&(e.top=Math.round(e.top/n)*n,e.left=Math.round(e.left/n)*n),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var i=this;if(this.options.canUserMoveOperators){var s,a;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t){if(null!=i.lastOutputConnectorClicked)return void t.preventDefault();var e=i.element.offset();s=(t.pageX-e.left)/i.positionRatio-parseInt($(t.target).css("left")),a=(t.pageY-e.top)/i.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,n){if(i.options.grid){var l=i.options.grid,c=i.element.offset();if(n.position.left=Math.round(((t.pageX-c.left)/i.positionRatio-s)/l)*l,n.position.top=Math.round(((t.pageY-c.top)/i.positionRatio-a)/l)*l,!e.internal.properties.uncontained){var p=$(this);n.position.left=Math.min(Math.max(n.position.left,0),i.element.width()-p.outerWidth()),n.position.top=Math.min(Math.max(n.position.top,0),i.element.height()-p.outerHeight())}n.offset.left=Math.round(n.position.left+c.left),n.offset.top=Math.round(n.position.top+c.top),r.operator.css({left:n.position.left,top:n.position.top})}o($(this).data("operator_id"),n.position)},stop:function(t,e){i._unsetTemporaryLink();var n=$(this).data("operator_id");o(n,e.position),r.operator.css({height:"auto"}),i.options.onOperatorMoved(n,e.position),i.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,o,r){if("outputs"==r){this._restoreGrantedConnectorsColor();{new Date}this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:o,grantedConnectors:this._getGrantedConnectors(t,e)},this.objs.layers.temporaryLink.show();var n=this.getConnectorPosition(t,e,o,r),i=n.x+n.width,s=n.y;this.objs.temporaryLink.setAttribute("x1",""+i),this.objs.temporaryLink.setAttribute("y1",""+s),this._mousemove(i,s),this._colorizeGrantedConnectors()}if("inputs"==r&&null!=this.lastOutputConnectorClicked){var a={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:o};this._unsetTemporaryLink(),this.addLink(a)}},_getGrantedConnectors:function(t,e){var o=this.data.operators[t].type;if(void 0===o||0==this.data.linkRestrictions.length)return[];var r=this.data.linkRestrictions.filter(function(t){return o==t.fromOperatorType&&e==t.fromConnector}),n=[];for(var i in r){var s=r[i];for(var a in this.data.operators){var l=this.data.operators[a];if(l.type==s.toOperatorType){var c=l.internal.els.inputs.connectorArrows[s.toConnector];void 0!=c&&(c=c.map(function(t){return{els:t,oldColor:t.css("border-left-color")}}),n.push({color:void 0===s.color?this.options.defaultLinkColor:s.color,arrows:c}))}}}return n},_colorizeGrantedConnectors:function(){if(null!=this.lastOutputConnectorClicked){var t=this.lastOutputConnectorClicked.grantedConnectors;t.forEach(function(t){t.arrows.forEach(function(e){e.els.css("border-left-color",t.color)})})}},_restoreGrantedConnectorsColor:function(){if(null!=this.lastOutputConnectorClicked){var t=this.lastOutputConnectorClicked.grantedConnectors;t.forEach(function(t){t.arrows.forEach(function(t){t.els.css("border-left-color",t.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedConnectorsColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,o){var r=$(o.target);0==r.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==r.closest(".flowchart-operator").length&&this.unselectOperator(),0==r.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var o=parseInt(t.slice(1),16),r=0>e?0:255,n=0>e?-1*e:e,i=o>>16,s=o>>8&255,a=255&o;return"#"+(16777216+65536*(Math.round((r-i)*n)+i)+256*(Math.round((r-s)*n)+s)+(Math.round((r-a)*n)+a)).toString(16).slice(1)},colorizeLink:function(t,e){var o=this.data.links[t];o.internal.els.path.setAttribute("stroke",e),o.internal.els.rect.setAttribute("fill",e),o.internal.els.fromSmallConnector.css("border-left-color",e),o.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var r=this.data.links[o];(r.fromOperator==t||r.toOperator==t)&&this._deleteLink(o,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var o=this.data.links[t],r=o.fromOperator,n=o.fromConnector,i=o.toOperator,s=o.toConnector;o.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(r,n,"from"),this._cleanMultipleConnectors(i,s,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,o){var r="from"==o?"outputs":"inputs";if(this.data.operators[t].properties[r][e].multiple){var n=-1,i=o+"Operator",s=o+"Connector",a=o+"SubConnector",l=this.data.operators[t].internal.els,c=l.connectors[e],p=c.length;for(var h in this.data.links)if(this.data.links.hasOwnProperty(h)){var u=this.data.links[h];u[i]==t&&u[s]==e&&nf;f++)c[c.length-1].remove(),c.pop(),l.connectorArrows[e].pop(),l.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links","linkRestrictions"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links),e.linkRestrictions=$.extend(!0,[],this.data.linkRestrictions);for(var o in t)if(t.hasOwnProperty(o)){var r=t[o];for(var n in e[r])e[r].hasOwnProperty(n)&&delete e[r][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),void 0===this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var o=this.getOperatorCompleteData(e);for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var n=this.data.links[r];(n.fromOperator==t&&void 0===o.outputs[n.fromConnector]||n.toOperator==t&&void 0===o.inputs[n.toConnector])&&this._deleteLink(r,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if(void 0!==t.type){var e=this.data.operatorTypes[t.type],o={};return void 0!==t.properties&&(o=t.properties),$.extend({},e,o)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file From 3d613fe8d9276032e7c4c00bb5527e604074e90a Mon Sep 17 00:00:00 2001 From: Rafael Pallares Date: Thu, 16 Feb 2017 13:55:56 +0100 Subject: [PATCH 14/14] Minimify css --- jquery.flowchart.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery.flowchart.min.js b/jquery.flowchart.min.js index a2e962e..a99d2f5 100644 --- a/jquery.flowchart.min.js +++ b/jquery.flowchart.min.js @@ -1 +1 @@ -$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(){return!0},onOperatorUnselect:function(){return!0},onLinkSelect:function(){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(){return!0},onLinkCreate:function(){return!0},onOperatorDelete:function(){return!0},onLinkDelete:function(){return!0},onOperatorMoved:function(){},onAfterChange:function(){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){void 0===document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var t=document.createElementNS("http://www.w3.org/2000/svg","line");t.setAttribute("x1","0"),t.setAttribute("y1","0"),t.setAttribute("x2","0"),t.setAttribute("y2","0"),t.setAttribute("stroke-dasharray","6,6"),t.setAttribute("stroke-width","4"),t.setAttribute("stroke","black"),t.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(t),this.objs.temporaryLink=t,this._initEvents(),void 0!==this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{},linkRestrictions:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var t=this;this.element.mousemove(function(e){var o=$(this),r=o.offset();t._mousemove((e.pageX-r.left)/t.positionRatio,(e.pageY-r.top)/t.positionRatio,e)}),this.element.click(function(e){var o=$(this),r=o.offset();t._click((e.pageX-r.left)/t.positionRatio,(e.pageY-r.top)/t.positionRatio,e)}),this.objs.layers.operators.on("touchdown mousedown touchstart",".flowchart-operator",function(t){t.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(e){0==$(e.target).closest(".flowchart-operator-connector").length&&t.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var e=$(this);t.options.canUserEditLinks&&t._connectorClicked(e.closest(".flowchart-operator").data("operator_id"),e.data("connector"),e.data("sub_connector"),e.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(t){t.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){t._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){t._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){t.selectLink($(this).data("link_id"))})},setData:function(t){this._clearOperatorsLayer(),this.data.operatorTypes={},void 0!==t.operatorTypes&&(this.data.operatorTypes=t.operatorTypes),this.data.linkRestrictions=[],void 0!==t.linkRestrictions&&t.linkRestrictions.length>0&&(this.data.linkRestrictions=t.linkRestrictions),this.data.operators={};for(var e in t.operators)t.operators.hasOwnProperty(e)&&this.createOperator(e,t.operators[e]);this.data.links={};for(var o in t.links)t.links.hasOwnProperty(o)&&this.createLink(o,t.links[o]);this.redrawLinksLayer()},addLink:function(t){for(;void 0!==this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,t),this.linkNum},createLink:function(t,e){var o=$.extend(!0,{},e);if(this.options.onLinkCreate(t,o)){var r=this._indexOfLinkGranted(o);if(-1!=r){var n=this._getSubConnectors(o),i=n[0],s=n[1],a=this.options.multipleLinksOnOutput,l=this.options.multipleLinksOnInput;if(!a||!l)for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var p=this.data.links[c],h=this._getSubConnectors(p),u=h[0],d=h[1];if(!a&&p.fromOperator==o.fromOperator&&p.fromConnector==o.fromConnector&&u==i){this.deleteLink(c);continue}l||p.toOperator!=o.toOperator||p.toConnector!=o.toConnector||d!=s||this.deleteLink(c)}if(this._autoCreateSubConnector(o.fromOperator,o.fromConnector,"outputs",i),this._autoCreateSubConnector(o.toOperator,o.toConnector,"inputs",s),null!=r){var f=this.data.linkRestrictions[r];void 0!==f.color&&(o.color=f.color)}this.data.links[t]=o,this._drawLink(t),this.options.onAfterChange("link_create")}}},_indexOfLinkGranted:function(t){if(0==this.data.linkRestrictions.length)return null;for(var e=this.data.linkRestrictions,o=0;oa;a++)this._createSubConnector(e,n,i,o)},redrawLinksLayer:function(){this._clearLinksLayer();for(var t in this.data.links)this.data.links.hasOwnProperty(t)&&this._drawLink(t)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(t,e,o,r){var n=this.data.operators[t],i=n.internal.els[r].connectorArrows[e][o],s=i.offset(),a=this.element.offset(),l=(s.left-a.left)/this.positionRatio,c=parseInt(i.css("border-top-width")),p=(s.top-a.top-1)/this.positionRatio+parseInt(i.css("border-left-width"));return{x:l,width:c,y:p}},getLinkMainColor:function(t){var e=this.options.defaultLinkColor,o=this.data.links[t];return void 0!==o.color&&(e=o.color),e},setLinkMainColor:function(t,e){this.data.links[t].color=e,this.options.onAfterChange("link_change_main_color")},_drawLink:function(t){var e=this.data.links[t];void 0===e.internal&&(e.internal={}),e.internal.els={};var o=e.fromOperator,r=e.fromConnector,n=e.toOperator,i=e.toConnector,s=this._getSubConnectors(e),a=s[0],l=s[1],c=(this.getLinkMainColor(t),this.data.operators[o]),p=this.data.operators[n],h=c.internal.els.outputs.connectorSmallArrows[r][a],u=p.internal.els.inputs.connectorSmallArrows[i][l];e.internal.els.fromSmallConnector=h,e.internal.els.toSmallConnector=u;var d=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(d),e.internal.els.overallGroup=d;var f=document.createElementNS("http://www.w3.org/2000/svg","mask"),k="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,f.setAttribute("id",k),d.appendChild(f);var v=document.createElementNS("http://www.w3.org/2000/svg","rect");v.setAttribute("x","0"),v.setAttribute("y","0"),v.setAttribute("width","100%"),v.setAttribute("height","100%"),v.setAttribute("stroke","none"),v.setAttribute("fill","white"),f.appendChild(v);var m=document.createElementNS("http://www.w3.org/2000/svg","polygon");m.setAttribute("stroke","none"),m.setAttribute("fill","black"),f.appendChild(m),e.internal.els.mask=m;var C=document.createElementNS("http://www.w3.org/2000/svg","g");C.setAttribute("class","flowchart-link"),C.setAttribute("data-link_id",t),d.appendChild(C);var w=document.createElementNS("http://www.w3.org/2000/svg","path");w.setAttribute("stroke-width",""+this.options.linkWidth),w.setAttribute("fill","none"),C.appendChild(w),e.internal.els.path=w;var O=document.createElementNS("http://www.w3.org/2000/svg","rect");O.setAttribute("stroke","none"),O.setAttribute("mask","url(#"+k+")"),C.appendChild(O),e.internal.els.rect=O,this._refreshLinkPositions(t),this.uncolorizeLink(t)},_getSubConnectors:function(t){var e=0;void 0!==t.fromSubConnector&&(e=t.fromSubConnector);var o=0;return void 0!==t.toSubConnector&&(o=t.toSubConnector),[e,o]},_refreshLinkPositions:function(t){var e=this.data.links[t],o=this._getSubConnectors(e),r=o[0],n=o[1],i=this.getConnectorPosition(e.fromOperator,e.fromConnector,r,"outputs"),s=this.getConnectorPosition(e.toOperator,e.toConnector,n,"inputs"),a=i.x,l=i.width,c=i.y,p=s.x,h=s.y;c+=this.options.linkVerticalDecal,h+=this.options.linkVerticalDecal;var u=this.options.distanceFromArrow;e.internal.els.mask.setAttribute("points",a+","+(c-l-u)+" "+(a+l+u)+","+c+" "+a+","+(c+l+u));var d=a+l+u,f=p+1,k=Math.min(100,Math.max(Math.abs(d-f)/2,Math.abs(c-h)));e.internal.els.path.setAttribute("d","M"+d+","+c+" C"+(a+l+u+k)+","+c+" "+(p-k)+","+h+" "+f+","+h),e.internal.els.rect.setAttribute("x",a),e.internal.els.rect.setAttribute("y",c-this.options.linkWidth/2),e.internal.els.rect.setAttribute("width",l+u+1),e.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(t){void 0===t.internal&&(t.internal={}),this._refreshInternalProperties(t);var e=$.extend(!0,{},t.internal.properties);for(var o in e.inputs)e.inputs.hasOwnProperty(o)&&null==e.inputs[o]&&delete e.inputs[o];for(var r in e.outputs)e.outputs.hasOwnProperty(r)&&null==e.outputs[r]&&delete e.outputs[r];return void 0===e.class&&(e.class=this.options.defaultOperatorClass),e},_getOperatorFullElement:function(t){function e(t,e,o,r){var n=$('
');n.data("connector_type",r),n.appendTo(o),c[r].connectorArrows[t]=[],c[r].connectorSmallArrows[t]=[],c[r].connectors[t]=[],c[r].connectorSets[t]=n,l._createSubConnector(t,e,c,r)}var o=this.getOperatorCompleteData(t),r=$('
');r.addClass(o.class);var n=$('
');n.html(o.title),n.appendTo(r);var i=$('
');i.appendTo(r);var s=$('
');s.appendTo(i);var a=$('
');a.appendTo(i);var l=this,c={operator:r,title:n,inputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}},outputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}}};for(var p in o.inputs)o.inputs.hasOwnProperty(p)&&e(p,o.inputs[p],s,"inputs");for(var h in o.outputs)o.outputs.hasOwnProperty(h)&&e(h,o.outputs[h],a,"outputs");return c},_createSubConnector:function(t,e,o,r){var n=o[r].connectorSets[t],i=o[r].connectors[t].length,s=$('
');s.appendTo(n),s.data("connector",t),s.data("sub_connector",i);var a=$('
');a.text(e.label.replace("(:i)",i+1)),a.appendTo(s);var l=$('
');l.appendTo(s);var c=$('
');c.appendTo(s),o[r].connectors[t].push(s),o[r].connectorArrows[t].push(l),o[r].connectorSmallArrows[t].push(c)},getOperatorElement:function(t){var e=this._getOperatorFullElement(t);return e.operator},addOperator:function(t){for(;void 0!==this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,t),this.operatorNum},createOperator:function(t,e){function o(t,o){e.top=o.top,e.left=o.left;for(var r in i.data.links)if(i.data.links.hasOwnProperty(r)){var n=i.data.links[r];(n.fromOperator==t||n.toOperator==t)&&i._refreshLinkPositions(r)}}e.internal={},this._refreshInternalProperties(e);var r=this._getOperatorFullElement(e);if(!this.options.onOperatorCreate(t,e,r))return!1;var n=this.options.grid;n&&(e.top=Math.round(e.top/n)*n,e.left=Math.round(e.left/n)*n),r.operator.appendTo(this.objs.layers.operators),r.operator.css({top:e.top,left:e.left}),r.operator.data("operator_id",t),this.data.operators[t]=e,this.data.operators[t].internal.els=r,t==this.selectedOperatorId&&this._addSelectedClass(t);var i=this;if(this.options.canUserMoveOperators){var s,a;r.operator.draggable({containment:e.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(t){if(null!=i.lastOutputConnectorClicked)return void t.preventDefault();var e=i.element.offset();s=(t.pageX-e.left)/i.positionRatio-parseInt($(t.target).css("left")),a=(t.pageY-e.top)/i.positionRatio-parseInt($(t.target).css("top"))},drag:function(t,n){if(i.options.grid){var l=i.options.grid,c=i.element.offset();if(n.position.left=Math.round(((t.pageX-c.left)/i.positionRatio-s)/l)*l,n.position.top=Math.round(((t.pageY-c.top)/i.positionRatio-a)/l)*l,!e.internal.properties.uncontained){var p=$(this);n.position.left=Math.min(Math.max(n.position.left,0),i.element.width()-p.outerWidth()),n.position.top=Math.min(Math.max(n.position.top,0),i.element.height()-p.outerHeight())}n.offset.left=Math.round(n.position.left+c.left),n.offset.top=Math.round(n.position.top+c.top),r.operator.css({left:n.position.left,top:n.position.top})}o($(this).data("operator_id"),n.position)},stop:function(t,e){i._unsetTemporaryLink();var n=$(this).data("operator_id");o(n,e.position),r.operator.css({height:"auto"}),i.options.onOperatorMoved(n,e.position),i.options.onAfterChange("operator_moved")}})}this.options.onAfterChange("operator_create")},_connectorClicked:function(t,e,o,r){if("outputs"==r){this._restoreGrantedConnectorsColor();{new Date}this.lastOutputConnectorClicked={operator:t,connector:e,subConnector:o,grantedConnectors:this._getGrantedConnectors(t,e)},this.objs.layers.temporaryLink.show();var n=this.getConnectorPosition(t,e,o,r),i=n.x+n.width,s=n.y;this.objs.temporaryLink.setAttribute("x1",""+i),this.objs.temporaryLink.setAttribute("y1",""+s),this._mousemove(i,s),this._colorizeGrantedConnectors()}if("inputs"==r&&null!=this.lastOutputConnectorClicked){var a={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:t,toConnector:e,toSubConnector:o};this._unsetTemporaryLink(),this.addLink(a)}},_getGrantedConnectors:function(t,e){var o=this.data.operators[t].type;if(void 0===o||0==this.data.linkRestrictions.length)return[];var r=this.data.linkRestrictions.filter(function(t){return o==t.fromOperatorType&&e==t.fromConnector}),n=[];for(var i in r){var s=r[i];for(var a in this.data.operators){var l=this.data.operators[a];if(l.type==s.toOperatorType){var c=l.internal.els.inputs.connectorArrows[s.toConnector];void 0!=c&&(c=c.map(function(t){return{els:t,oldColor:t.css("border-left-color")}}),n.push({color:void 0===s.color?this.options.defaultLinkColor:s.color,arrows:c}))}}}return n},_colorizeGrantedConnectors:function(){if(null!=this.lastOutputConnectorClicked){var t=this.lastOutputConnectorClicked.grantedConnectors;t.forEach(function(t){t.arrows.forEach(function(e){e.els.css("border-left-color",t.color)})})}},_restoreGrantedConnectorsColor:function(){if(null!=this.lastOutputConnectorClicked){var t=this.lastOutputConnectorClicked.grantedConnectors;t.forEach(function(t){t.arrows.forEach(function(t){t.els.css("border-left-color",t.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedConnectorsColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(t,e){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",t),this.objs.temporaryLink.setAttribute("y2",e))},_click:function(t,e,o){var r=$(o.target);0==r.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==r.closest(".flowchart-operator").length&&this.unselectOperator(),0==r.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.options.onOperatorUnselect())return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(t){this.data.operators[t].internal.els.operator.addClass("selected")},selectOperator:function(t){this.options.onOperatorSelect(t)&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(t),this.selectedOperatorId=t)},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(t,e){var o=parseInt(t.slice(1),16),r=0>e?0:255,n=0>e?-1*e:e,i=o>>16,s=o>>8&255,a=255&o;return"#"+(16777216+65536*(Math.round((r-i)*n)+i)+256*(Math.round((r-s)*n)+s)+(Math.round((r-a)*n)+a)).toString(16).slice(1)},colorizeLink:function(t,e){var o=this.data.links[t];o.internal.els.path.setAttribute("stroke",e),o.internal.els.rect.setAttribute("fill",e),o.internal.els.fromSmallConnector.css("border-left-color",e),o.internal.els.toSmallConnector.css("border-left-color",e)},uncolorizeLink:function(t){this.colorizeLink(t,this.getLinkMainColor(t))},_connecterMouseOver:function(t){this.selectedLinkId!=t&&this.colorizeLink(t,this._shadeColor(this.getLinkMainColor(t),-.4))},_connecterMouseOut:function(t){this.selectedLinkId!=t&&this.uncolorizeLink(t)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.options.onLinkUnselect())return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(t){this.unselectLink(),this.options.onLinkSelect(t)&&(this.unselectOperator(),this.selectedLinkId=t,this.colorizeLink(t,this.options.defaultSelectedLinkColor))},deleteOperator:function(t){this._deleteOperator(t,!1)},_deleteOperator:function(t,e){if(!this.options.onOperatorDelete(t,e))return!1;if(!e)for(var o in this.data.links)if(this.data.links.hasOwnProperty(o)){var r=this.data.links[o];(r.fromOperator==t||r.toOperator==t)&&this._deleteLink(o,!0)}e||t!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[t].internal.els.operator.remove(),delete this.data.operators[t],this.options.onAfterChange("operator_delete")},deleteLink:function(t){this._deleteLink(t,!1)},_deleteLink:function(t,e){if(this.selectedLinkId==t&&this.unselectLink(),this.options.onLinkDelete(t,e)||e){this.colorizeLink(t,"transparent");var o=this.data.links[t],r=o.fromOperator,n=o.fromConnector,i=o.toOperator,s=o.toConnector;o.internal.els.overallGroup.remove(),delete this.data.links[t],this._cleanMultipleConnectors(r,n,"from"),this._cleanMultipleConnectors(i,s,"to"),this.options.onAfterChange("link_delete")}},_cleanMultipleConnectors:function(t,e,o){var r="from"==o?"outputs":"inputs";if(this.data.operators[t].properties[r][e].multiple){var n=-1,i=o+"Operator",s=o+"Connector",a=o+"SubConnector",l=this.data.operators[t].internal.els,c=l.connectors[e],p=c.length;for(var h in this.data.links)if(this.data.links.hasOwnProperty(h)){var u=this.data.links[h];u[i]==t&&u[s]==e&&nf;f++)c[c.length-1].remove(),c.pop(),l.connectorArrows[e].pop(),l.connectorSmallArrows[e].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(t){this.positionRatio=t},getPositionRatio:function(){return this.positionRatio},getData:function(){var t=["operators","links","linkRestrictions"],e={};e.operators=$.extend(!0,{},this.data.operators),e.links=$.extend(!0,{},this.data.links),e.linkRestrictions=$.extend(!0,[],this.data.linkRestrictions);for(var o in t)if(t.hasOwnProperty(o)){var r=t[o];for(var n in e[r])e[r].hasOwnProperty(n)&&delete e[r][n].internal}return e.operatorTypes=this.data.operatorTypes,e},setOperatorTitle:function(t,e){this.data.operators[t].internal.els.title.html(e),void 0===this.data.operators[t].properties&&(this.data.operators[t].properties={}),this.data.operators[t].properties.title=e,this._refreshInternalProperties(this.data.operators[t]),this.options.onAfterChange("operator_title_change")},getOperatorTitle:function(t){return this.data.operators[t].internal.properties.title},setOperatorData:function(t,e){var o=this.getOperatorCompleteData(e);for(var r in this.data.links)if(this.data.links.hasOwnProperty(r)){var n=this.data.links[r];(n.fromOperator==t&&void 0===o.outputs[n.fromConnector]||n.toOperator==t&&void 0===o.inputs[n.toConnector])&&this._deleteLink(r,!0)}this._deleteOperator(t,!0),this.createOperator(t,e),this.redrawLinksLayer(),this.options.onAfterChange("operator_data_change")},getOperatorData:function(t){var e=$.extend(!0,{},this.data.operators[t]);return delete e.internal,e},getOperatorFullProperties:function(t){if(void 0!==t.type){var e=this.data.operatorTypes[t.type],o={};return void 0!==t.properties&&(o=t.properties),$.extend({},e,o)}return t.properties},_refreshInternalProperties:function(t){t.internal.properties=this.getOperatorFullProperties(t)}})}); \ No newline at end of file +$(function(){$.widget("flowchart.flowchart",{options:{canUserEditLinks:!0,canUserMoveOperators:!0,data:{},distanceFromArrow:3,defaultOperatorClass:"flowchart-default-operator",defaultLinkColor:"#3366ff",defaultSelectedLinkColor:"black",linkWidth:10,grid:20,multipleLinksOnOutput:!1,multipleLinksOnInput:!1,linkVerticalDecal:0,onOperatorSelect:function(){return!0},onOperatorUnselect:function(){return!0},onLinkSelect:function(){return!0},onLinkUnselect:function(){return!0},onOperatorCreate:function(){return!0},onLinkCreate:function(){return!0},onOperatorDelete:function(){return!0},onLinkDelete:function(){return!0},onOperatorMoved:function(){},onAfterChange:function(){}},data:null,objs:null,maskNum:0,linkNum:0,operatorNum:0,lastOutputConnectorClicked:null,selectedOperatorId:null,selectedLinkId:null,positionRatio:1,globalId:null,_create:function(){"undefined"==typeof document.__flowchartNumber?document.__flowchartNumber=0:document.__flowchartNumber++,this.globalId=document.__flowchartNumber,this._unitVariables(),this.element.addClass("flowchart-container"),this.objs.layers.links=$(''),this.objs.layers.links.appendTo(this.element),this.objs.layers.operators=$('
'),this.objs.layers.operators.appendTo(this.element),this.objs.layers.temporaryLink=$(''),this.objs.layers.temporaryLink.appendTo(this.element);var a=document.createElementNS("http://www.w3.org/2000/svg","line");a.setAttribute("x1","0"),a.setAttribute("y1","0"),a.setAttribute("x2","0"),a.setAttribute("y2","0"),a.setAttribute("stroke-dasharray","6,6"),a.setAttribute("stroke-width","4"),a.setAttribute("stroke","black"),a.setAttribute("fill","none"),this.objs.layers.temporaryLink[0].appendChild(a),this.objs.temporaryLink=a,this._initEvents(),"undefined"!=typeof this.options.data&&this.setData(this.options.data)},_unitVariables:function(){this.data={operators:{},links:{},linkRestrictions:{}},this.objs={layers:{operators:null,temporaryLink:null,links:null},linksContext:null,temporaryLink:null}},_initEvents:function(){var a=this;this.element.mousemove(function(b){var c=$(this),d=c.offset();a._mousemove((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.element.click(function(b){var c=$(this),d=c.offset();a._click((b.pageX-d.left)/a.positionRatio,(b.pageY-d.top)/a.positionRatio,b)}),this.objs.layers.operators.on("touchdown mousedown touchstart",".flowchart-operator",function(a){a.stopImmediatePropagation()}),this.objs.layers.operators.on("click",".flowchart-operator",function(b){0==$(b.target).closest(".flowchart-operator-connector").length&&a.selectOperator($(this).data("operator_id"))}),this.objs.layers.operators.on("click",".flowchart-operator-connector",function(){var b=$(this);a.options.canUserEditLinks&&a._connectorClicked(b.closest(".flowchart-operator").data("operator_id"),b.data("connector"),b.data("sub_connector"),b.closest(".flowchart-operator-connector-set").data("connector_type"))}),this.objs.layers.links.on("mousedown touchstart",".flowchart-link",function(a){a.stopImmediatePropagation()}),this.objs.layers.links.on("mouseover",".flowchart-link",function(){a._connecterMouseOver($(this).data("link_id"))}),this.objs.layers.links.on("mouseout",".flowchart-link",function(){a._connecterMouseOut($(this).data("link_id"))}),this.objs.layers.links.on("click",".flowchart-link",function(){a.selectLink($(this).data("link_id"))})},setData:function(a){this._clearOperatorsLayer(),this.data.operatorTypes={},"undefined"!=typeof a.operatorTypes&&(this.data.operatorTypes=a.operatorTypes),this.data.linkRestrictions=[],"undefined"!=typeof a.linkRestrictions&&a.linkRestrictions.length>0&&(this.data.linkRestrictions=a.linkRestrictions),this.data.operators={};for(var b in a.operators)a.operators.hasOwnProperty(b)&&this.createOperator(b,a.operators[b]);this.data.links={};for(var c in a.links)a.links.hasOwnProperty(c)&&this.createLink(c,a.links[c]);this.redrawLinksLayer()},addLink:function(a){for(;"undefined"!=typeof this.data.links[this.linkNum];)this.linkNum++;return this.createLink(this.linkNum,a),this.linkNum},createLink:function(a,b){var c=$.extend(!0,{},b);if(this.callbackEvent("linkCreate",[a,c])){var d=this._indexOfLinkGranted(c);if(-1!=d){var e=this._getSubConnectors(c),f=e[0],g=e[1],h=this.options.multipleLinksOnOutput,i=this.options.multipleLinksOnInput;if(!h||!i)for(var j in this.data.links)if(this.data.links.hasOwnProperty(j)){var k=this.data.links[j],l=this._getSubConnectors(k),m=l[0],n=l[1];if(!h&&k.fromOperator==c.fromOperator&&k.fromConnector==c.fromConnector&&m==f){this.deleteLink(j);continue}i||k.toOperator!=c.toOperator||k.toConnector!=c.toConnector||n!=g||this.deleteLink(j)}if(this._autoCreateSubConnector(c.fromOperator,c.fromConnector,"outputs",f),this._autoCreateSubConnector(c.toOperator,c.toConnector,"inputs",g),null!=d){var o=this.data.linkRestrictions[d];"undefined"!=typeof o.color&&(c.color=o.color)}this.data.links[a]=c,this._drawLink(a),this.callbackEvent("afterChange",["link_create"])}}},_indexOfLinkGranted:function(a){if(0==this.data.linkRestrictions.length)return null;for(var b=this.data.linkRestrictions,c=0;ch;h++)this._createSubConnector(b,e,f,c)},redrawLinksLayer:function(){this._clearLinksLayer();for(var a in this.data.links)this.data.links.hasOwnProperty(a)&&this._drawLink(a)},_clearLinksLayer:function(){this.objs.layers.links.empty(),this.objs.layers.operators.find(".flowchart-operator-connector-small-arrow").css("border-left-color","transparent")},_clearOperatorsLayer:function(){this.objs.layers.operators.empty()},getConnectorPosition:function(a,b,c,d){var e=this.data.operators[a],f=e.internal.els[d].connectorArrows[b][c],g=f.offset(),h=this.element.offset(),i=(g.left-h.left)/this.positionRatio,j=parseInt(f.css("border-top-width")),k=(g.top-h.top-1)/this.positionRatio+parseInt(f.css("border-left-width"));return{x:i,width:j,y:k}},getLinkMainColor:function(a){var b=this.options.defaultLinkColor,c=this.data.links[a];return"undefined"!=typeof c.color&&(b=c.color),b},setLinkMainColor:function(a,b){this.data.links[a].color=b,this.callbackEvent("afterChange",["link_change_main_color"])},_drawLink:function(a){var b=this.data.links[a];"undefined"==typeof b.internal&&(b.internal={}),b.internal.els={};var c=b.fromOperator,d=b.fromConnector,e=b.toOperator,f=b.toConnector,g=this._getSubConnectors(b),h=g[0],i=g[1],j=(this.getLinkMainColor(a),this.data.operators[c]),k=this.data.operators[e],l=j.internal.els.outputs.connectorSmallArrows[d][h],m=k.internal.els.inputs.connectorSmallArrows[f][i];b.internal.els.fromSmallConnector=l,b.internal.els.toSmallConnector=m;var n=document.createElementNS("http://www.w3.org/2000/svg","g");this.objs.layers.links[0].appendChild(n),b.internal.els.overallGroup=n;var o=document.createElementNS("http://www.w3.org/2000/svg","mask"),p="fc_mask_"+this.globalId+"_"+this.maskNum;this.maskNum++,o.setAttribute("id",p),n.appendChild(o);var q=document.createElementNS("http://www.w3.org/2000/svg","rect");q.setAttribute("x","0"),q.setAttribute("y","0"),q.setAttribute("width","100%"),q.setAttribute("height","100%"),q.setAttribute("stroke","none"),q.setAttribute("fill","white"),o.appendChild(q);var r=document.createElementNS("http://www.w3.org/2000/svg","polygon");r.setAttribute("stroke","none"),r.setAttribute("fill","black"),o.appendChild(r),b.internal.els.mask=r;var s=document.createElementNS("http://www.w3.org/2000/svg","g");s.setAttribute("class","flowchart-link"),s.setAttribute("data-link_id",a),n.appendChild(s);var t=document.createElementNS("http://www.w3.org/2000/svg","path");t.setAttribute("stroke-width",this.options.linkWidth.toString()),t.setAttribute("fill","none"),s.appendChild(t),b.internal.els.path=t;var u=document.createElementNS("http://www.w3.org/2000/svg","rect");u.setAttribute("stroke","none"),u.setAttribute("mask","url(#"+p+")"),s.appendChild(u),b.internal.els.rect=u,this._refreshLinkPositions(a),this.uncolorizeLink(a)},_getSubConnectors:function(a){var b=0;"undefined"!=typeof a.fromSubConnector&&(b=a.fromSubConnector);var c=0;return"undefined"!=typeof a.toSubConnector&&(c=a.toSubConnector),[b,c]},_refreshLinkPositions:function(a){var b=this.data.links[a],c=this._getSubConnectors(b),d=c[0],e=c[1],f=this.getConnectorPosition(b.fromOperator,b.fromConnector,d,"outputs"),g=this.getConnectorPosition(b.toOperator,b.toConnector,e,"inputs"),h=f.x,i=f.width,j=f.y,k=g.x,l=g.y;j+=this.options.linkVerticalDecal,l+=this.options.linkVerticalDecal;var m=this.options.distanceFromArrow;b.internal.els.mask.setAttribute("points",h+","+(j-i-m)+" "+(h+i+m)+","+j+" "+h+","+(j+i+m));var n=h+i+m,o=k+1,p=Math.min(100,Math.max(Math.abs(n-o)/2,Math.abs(j-l)));b.internal.els.path.setAttribute("d","M"+n+","+j+" C"+(h+i+m+p)+","+j+" "+(k-p)+","+l+" "+o+","+l),b.internal.els.rect.setAttribute("x",h),b.internal.els.rect.setAttribute("y",j-this.options.linkWidth/2),b.internal.els.rect.setAttribute("width",i+m+1),b.internal.els.rect.setAttribute("height",this.options.linkWidth)},getOperatorCompleteData:function(a){"undefined"==typeof a.internal&&(a.internal={}),this._refreshInternalProperties(a);var b=$.extend(!0,{},a.internal.properties);for(var c in b.inputs)b.inputs.hasOwnProperty(c)&&null==b.inputs[c]&&delete b.inputs[c];for(var d in b.outputs)b.outputs.hasOwnProperty(d)&&null==b.outputs[d]&&delete b.outputs[d];return"undefined"==typeof b.class&&(b.class=this.options.defaultOperatorClass),b},_getOperatorFullElement:function(a){function b(a,b,c,d){var e=$('
');e.data("connector_type",d),e.appendTo(c),j[d].connectorArrows[a]=[],j[d].connectorSmallArrows[a]=[],j[d].connectors[a]=[],j[d].connectorSets[a]=e,i._createSubConnector(a,b,j,d)}var c=this.getOperatorCompleteData(a),d=$('
');d.addClass(c.class);var e=$('
');e.html(c.title),e.appendTo(d);var f=$('
');f.appendTo(d);var g=$('
');g.appendTo(f);var h=$('
');h.appendTo(f);var i=this,j={operator:d,title:e,inputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}},outputs:{connectorSets:{},connectors:{},connectorArrows:{},connectorSmallArrows:{}}};for(var k in c.inputs)c.inputs.hasOwnProperty(k)&&b(k,c.inputs[k],g,"inputs");for(var l in c.outputs)c.outputs.hasOwnProperty(l)&&b(l,c.outputs[l],h,"outputs");return j},_createSubConnector:function(a,b,c,d){var e=c[d].connectorSets[a],f=c[d].connectors[a].length,g=$('
');g.appendTo(e),g.data("connector",a),g.data("sub_connector",f);var h=$('
');h.text(b.label.replace("(:i)",f+1)),h.appendTo(g);var i=$('
');i.appendTo(g);var j=$('
');j.appendTo(g),c[d].connectors[a].push(g),c[d].connectorArrows[a].push(i),c[d].connectorSmallArrows[a].push(j)},getOperatorElement:function(a){var b=this._getOperatorFullElement(a);return b.operator},addOperator:function(a){for(;"undefined"!=typeof this.data.operators[this.operatorNum];)this.operatorNum++;return this.createOperator(this.operatorNum,a),this.operatorNum},createOperator:function(a,b){function c(a,c){b.top=c.top,b.left=c.left;for(var d in f.data.links)if(f.data.links.hasOwnProperty(d)){var e=f.data.links[d];(e.fromOperator==a||e.toOperator==a)&&f._refreshLinkPositions(d)}}b.internal={},this._refreshInternalProperties(b);var d=this._getOperatorFullElement(b);if(!this.callbackEvent("operatorCreate",[a,b,d]))return!1;var e=this.options.grid;e&&(b.top=Math.round(b.top/e)*e,b.left=Math.round(b.left/e)*e),d.operator.appendTo(this.objs.layers.operators),d.operator.css({top:b.top,left:b.left}),d.operator.data("operator_id",a),this.data.operators[a]=b,this.data.operators[a].internal.els=d,a==this.selectedOperatorId&&this._addSelectedClass(a);var f=this;if(this.options.canUserMoveOperators){var g,h;d.operator.draggable({containment:b.internal.properties.uncontained?!1:this.element,handle:".flowchart-operator-title",start:function(a){if(null!=f.lastOutputConnectorClicked)return void a.preventDefault();var b=f.element.offset();g=(a.pageX-b.left)/f.positionRatio-parseInt($(a.target).css("left")),h=(a.pageY-b.top)/f.positionRatio-parseInt($(a.target).css("top"))},drag:function(a,e){if(f.options.grid){var i=f.options.grid,j=f.element.offset();if(e.position.left=Math.round(((a.pageX-j.left)/f.positionRatio-g)/i)*i,e.position.top=Math.round(((a.pageY-j.top)/f.positionRatio-h)/i)*i,!b.internal.properties.uncontained){var k=$(this);e.position.left=Math.min(Math.max(e.position.left,0),f.element.width()-k.outerWidth()),e.position.top=Math.min(Math.max(e.position.top,0),f.element.height()-k.outerHeight())}e.offset.left=Math.round(e.position.left+j.left),e.offset.top=Math.round(e.position.top+j.top),d.operator.css({left:e.position.left,top:e.position.top})}c($(this).data("operator_id"),e.position)},stop:function(a,b){f._unsetTemporaryLink();var e=$(this).data("operator_id");c(e,b.position),d.operator.css({height:"auto"}),f.callbackEvent("operatorMoved",[e,b.position]),f.callbackEvent("afterChange",["operator_moved"])}})}this.callbackEvent("afterChange",["operator_create"])},_connectorClicked:function(a,b,c,d){if("outputs"==d){this._restoreGrantedConnectorsColor();{new Date}this.lastOutputConnectorClicked={operator:a,connector:b,subConnector:c,grantedConnectors:this._getGrantedConnectors(a,b)},this.objs.layers.temporaryLink.show();var e=this.getConnectorPosition(a,b,c,d),f=e.x+e.width,g=e.y;this.objs.temporaryLink.setAttribute("x1",f.toString()),this.objs.temporaryLink.setAttribute("y1",g.toString()),this._mousemove(f,g),this._colorizeGrantedConnectors()}if("inputs"==d&&null!=this.lastOutputConnectorClicked){var h={fromOperator:this.lastOutputConnectorClicked.operator,fromConnector:this.lastOutputConnectorClicked.connector,fromSubConnector:this.lastOutputConnectorClicked.subConnector,toOperator:a,toConnector:b,toSubConnector:c};this._unsetTemporaryLink(),this.addLink(h)}},_getGrantedConnectors:function(a,b){var c=this.data.operators[a].type;if("undefined"==typeof c||0==this.data.linkRestrictions.length)return[];var d=this.data.linkRestrictions.filter(function(a){return c==a.fromOperatorType&&b==a.fromConnector}),e=[];for(var f in d){var g=d[f];for(var h in this.data.operators){var i=this.data.operators[h];if(i.type==g.toOperatorType){var j=i.internal.els.inputs.connectorArrows[g.toConnector];void 0!=j&&(j=j.map(function(a){return{els:a,oldColor:a.css("border-left-color")}}),e.push({color:"undefined"==typeof g.color?this.options.defaultLinkColor:g.color,arrows:j}))}}}return e},_colorizeGrantedConnectors:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedConnectors;a.forEach(function(a){a.arrows.forEach(function(b){b.els.css("border-left-color",a.color)})})}},_restoreGrantedConnectorsColor:function(){if(null!=this.lastOutputConnectorClicked){var a=this.lastOutputConnectorClicked.grantedConnectors;a.forEach(function(a){a.arrows.forEach(function(a){a.els.css("border-left-color",a.oldColor)})})}},_unsetTemporaryLink:function(){this._restoreGrantedConnectorsColor(),this.lastOutputConnectorClicked=null,this.objs.layers.temporaryLink.hide()},_mousemove:function(a,b){null!=this.lastOutputConnectorClicked&&(this.objs.temporaryLink.setAttribute("x2",a),this.objs.temporaryLink.setAttribute("y2",b))},_click:function(a,b,c){var d=$(c.target);0==d.closest(".flowchart-operator-connector").length&&this._unsetTemporaryLink(),0==d.closest(".flowchart-operator").length&&this.unselectOperator(),0==d.closest(".flowchart-link").length&&this.unselectLink()},_removeSelectedClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("selected")},unselectOperator:function(){if(null!=this.selectedOperatorId){if(!this.callbackEvent("operatorUnselect",[]))return;this._removeSelectedClassOperators(),this.selectedOperatorId=null}},_addSelectedClass:function(a){this.data.operators[a].internal.els.operator.addClass("selected")},callbackEvent:function(a,b){var c="on"+a.charAt(0).toUpperCase()+a.slice(1),d=this.options[c].apply(this,b);if(d!==!1){var e={result:d};this.element.trigger(a,b.concat([e])),d=e.result}return d},selectOperator:function(a){this.callbackEvent("operatorSelect",[a])&&(this.unselectLink(),this._removeSelectedClassOperators(),this._addSelectedClass(a),this.selectedOperatorId=a)},addClassOperator:function(a,b){this.data.operators[a].internal.els.operator.addClass(b)},removeClassOperator:function(a,b){this.data.operators[a].internal.els.operator.removeClass(b)},removeClassOperators:function(a){this.objs.layers.operators.find(".flowchart-operator").removeClass(a)},_addHoverClassOperator:function(a){this.data.operators[a].internal.els.operator.addClass("hover")},_removeHoverClassOperators:function(){this.objs.layers.operators.find(".flowchart-operator").removeClass("hover")},_operatorMouseOver:function(a){this.callbackEvent("operatorMouseOver",[a])&&this._addHoverClassOperator(a)},_operatorMouseOut:function(a){this.callbackEvent("operatorMouseOut",[a])&&this._removeHoverClassOperators()},getSelectedOperatorId:function(){return this.selectedOperatorId},getSelectedLinkId:function(){return this.selectedLinkId},_shadeColor:function(a,b){var c=parseInt(a.slice(1),16),d=0>b?0:255,e=0>b?-1*b:b,f=c>>16,g=c>>8&255,h=255&c;return"#"+(16777216+65536*(Math.round((d-f)*e)+f)+256*(Math.round((d-g)*e)+g)+(Math.round((d-h)*e)+h)).toString(16).slice(1)},colorizeLink:function(a,b){var c=this.data.links[a];c.internal.els.path.setAttribute("stroke",b),c.internal.els.rect.setAttribute("fill",b),c.internal.els.fromSmallConnector.css("border-left-color",b),c.internal.els.toSmallConnector.css("border-left-color",b)},uncolorizeLink:function(a){this.colorizeLink(a,this.getLinkMainColor(a))},_connecterMouseOver:function(a){this.selectedLinkId!=a&&this.colorizeLink(a,this._shadeColor(this.getLinkMainColor(a),-.4))},_connecterMouseOut:function(a){this.selectedLinkId!=a&&this.uncolorizeLink(a)},unselectLink:function(){if(null!=this.selectedLinkId){if(!this.callbackEvent("linkUnselect",[]))return;this.uncolorizeLink(this.selectedLinkId,this.options.defaultSelectedLinkColor),this.selectedLinkId=null}},selectLink:function(a){this.unselectLink(),this.callbackEvent("linkSelect",[a])&&(this.unselectOperator(),this.selectedLinkId=a,this.colorizeLink(a,this.options.defaultSelectedLinkColor))},deleteOperator:function(a){this._deleteOperator(a,!1)},_deleteOperator:function(a,b){if(!this.callbackEvent("operatorDelete",[a,b]))return!1;if(!b)for(var c in this.data.links)if(this.data.links.hasOwnProperty(c)){var d=this.data.links[c];(d.fromOperator==a||d.toOperator==a)&&this._deleteLink(c,!0)}b||a!=this.selectedOperatorId||this.unselectOperator(),this.data.operators[a].internal.els.operator.remove(),delete this.data.operators[a],this.callbackEvent("afterChange",["operator_delete"])},deleteLink:function(a){this._deleteLink(a,!1)},_deleteLink:function(a,b){if(this.selectedLinkId==a&&this.unselectLink(),this.callbackEvent("linkDelete",[a,b])||b){this.colorizeLink(a,"transparent");var c=this.data.links[a],d=c.fromOperator,e=c.fromConnector,f=c.toOperator,g=c.toConnector;c.internal.els.overallGroup.remove(),delete this.data.links[a],this._cleanMultipleConnectors(d,e,"from"),this._cleanMultipleConnectors(f,g,"to"),this.callbackEvent("afterChange",["link_delete"])}},_cleanMultipleConnectors:function(a,b,c){var d="from"==c?"outputs":"inputs";if(this.data.operators[a].properties[d][b].multiple){var e=-1,f=c+"Operator",g=c+"Connector",h=c+"SubConnector",i=this.data.operators[a].internal.els,j=i.connectors[b],k=j.length;for(var l in this.data.links)if(this.data.links.hasOwnProperty(l)){var m=this.data.links[l];m[f]==a&&m[g]==b&&eo;o++)j[j.length-1].remove(),j.pop(),i.connectorArrows[b].pop(),i.connectorSmallArrows[b].pop()}},deleteSelected:function(){null!=this.selectedLinkId&&this.deleteLink(this.selectedLinkId),null!=this.selectedOperatorId&&this.deleteOperator(this.selectedOperatorId)},setPositionRatio:function(a){this.positionRatio=a},getPositionRatio:function(){return this.positionRatio},getData:function(){var a=["operators","links","linkRestrictions"],b={};b.operators=$.extend(!0,{},this.data.operators),b.links=$.extend(!0,{},this.data.links),b.linkRestrictions=$.extend(!0,[],this.data.linkRestrictions);for(var c in a)if(a.hasOwnProperty(c)){var d=a[c];for(var e in b[d])b[d].hasOwnProperty(e)&&delete b[d][e].internal}return b.operatorTypes=this.data.operatorTypes,b},setOperatorTitle:function(a,b){this.data.operators[a].internal.els.title.html(b),"undefined"==typeof this.data.operators[a].properties&&(this.data.operators[a].properties={}),this.data.operators[a].properties.title=b,this._refreshInternalProperties(this.data.operators[a]),this.callbackEvent("afterChange",["operator_title_change"])},getOperatorTitle:function(a){return this.data.operators[a].internal.properties.title},setOperatorData:function(a,b){var c=this.getOperatorCompleteData(b);for(var d in this.data.links)if(this.data.links.hasOwnProperty(d)){var e=this.data.links[d];(e.fromOperator==a&&"undefined"==typeof c.outputs[e.fromConnector]||e.toOperator==a&&"undefined"==typeof c.inputs[e.toConnector])&&this._deleteLink(d,!0)}this._deleteOperator(a,!0),this.createOperator(a,b),this.redrawLinksLayer(),this.callbackEvent("afterChange",["operator_data_change"])},getOperatorData:function(a){var b=$.extend(!0,{},this.data.operators[a]);return delete b.internal,b},getOperatorFullProperties:function(a){if("undefined"!=typeof a.type){var b=this.data.operatorTypes[a.type],c={};return"undefined"!=typeof a.properties&&(c=a.properties),$.extend({},b,c)}return a.properties},_refreshInternalProperties:function(a){a.internal.properties=this.getOperatorFullProperties(a)}})}); \ No newline at end of file