Skip to content

Commit

Permalink
added multiple connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
sdrdis committed May 14, 2016
1 parent f99d5fd commit 89ffa95
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 38 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,17 @@ http://sebastien.drouyer.com/jquery.flowchart-demo/
* __title__
* __class:__ css classes added to the operator DOM object. If undefined, default value is the same as `defaultOperatorClass`.
* __inputs:__ Hash defining the box's input connectors. The keys define the connectors ID and the values define each connector's information as follow:
* __label__
* __label__: Label of the connector. If the connector is __multiple__, '(:i)' is replaced by the subconnector ID.
* __multiple__: (optional) If `true`, whenever a link is created on the connector, another connector (called subconnector) is created. See the [multiple connectors demo](http://sebastien.drouyer.com/jquery.flowchart-demo/#multiple).
* __outputs:__ Hash defining the box's output connectors. Same structure as `inputs`.

* __links:__ Hash defining the links between your operators in your flow chart. The keys define the link ID and the value define each link's information as follow:
* __from_operator:__ ID of the operator the link comes from.
* __from_connector:__ ID of the connector the link comes from.
* __to_operator:__ ID of the operator the link goes to.
* __to_connector:__ ID of the connector the link goes to.
* __fromOperator:__ ID of the operator the link comes from.
* __fromConnector:__ ID of the connector the link comes from.
* __fromSubConnector:__ (optional) If it is a multiple connector, which subconnector is it.
* __toOperator:__ ID of the operator the link goes to.
* __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`.

* __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`).
Expand Down
176 changes: 144 additions & 32 deletions jquery.flowchart.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ $(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('connector_type'));
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'));
}
});

Expand Down Expand Up @@ -200,28 +200,51 @@ $(function() {
if (!this.options.onLinkCreate(linkId, linkData)) {
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];
if (!multipleLinksOnOutput && currentLink.fromOperator == linkData.fromOperator && currentLink.fromConnector == linkData.fromConnector) {

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) {
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);

this.data.links[linkId] = linkData;
this._drawLink(linkId);

this.options.onAfterChange('link_create');
},

_autoCreateSubConnector: function(operator, connector, connectorType, subConnector) {
var connectorInfos = this.data.operators[operator].properties[connectorType][connector];
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);
}
}
},

redrawLinksLayer: function() {
this._clearLinksLayer();
Expand All @@ -239,9 +262,9 @@ $(function() {
this.objs.layers.operators.empty();
},

getConnectorPosition: function(operatorId, connectorId) {
getConnectorPosition: function(operatorId, connectorId, subConnector) {
var operatorData = this.data.operators[operatorId];
var $connector = operatorData.internal.els.connectorArrows[connectorId];
var $connector = operatorData.internal.els.connectorArrows[connectorId][subConnector];

var connectorOffset = $connector.offset();
var elementOffset = this.element.offset();
Expand Down Expand Up @@ -279,14 +302,18 @@ $(function() {
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];
var toSmallConnector = toOperator.internal.els.connectorSmallArrows[toConnectorId];
var fromSmallConnector = fromOperator.internal.els.connectorSmallArrows[fromConnectorId][fromSubConnector];
var toSmallConnector = toOperator.internal.els.connectorSmallArrows[toConnectorId][toSubConnector];

linkData.internal.els.fromSmallConnector = fromSmallConnector;
linkData.internal.els.toSmallConnector = toSmallConnector;
Expand Down Expand Up @@ -340,13 +367,30 @@ $(function() {
this._refreshLinkPositions(linkId);
this.uncolorizeLink(linkId);
},

_getSubConnectors: function(linkData) {
var fromSubConnector = 0;
if (typeof linkData.fromSubConnector != 'undefined') {
fromSubConnector = linkData.fromSubConnector;
}

var toSubConnector = 0;
if (typeof linkData.toSubConnector != 'undefined') {
toSubConnector = linkData.toSubConnector;
}

return [fromSubConnector, toSubConnector];
},

_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);
var toPosition = this.getConnectorPosition(linkData.toOperator, linkData.toConnector);
var fromPosition = this.getConnectorPosition(linkData.fromOperator, linkData.fromConnector, fromSubConnector);
var toPosition = this.getConnectorPosition(linkData.toOperator, linkData.toConnector, toSubConnector);

var fromX = fromPosition.x;
var offsetFromX = fromPosition.width;
Expand Down Expand Up @@ -426,25 +470,22 @@ $(function() {

var connectorArrows = {};
var connectorSmallArrows = {};
var connectorSets = {};
var connectors = {};

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 = $('<div class="flowchart-operator-connector"></div>');
$operator_connector.appendTo($operator_container);
$operator_connector.data('connector', connectorKey);
$operator_connector.data('connector_type', connectorType);

var $operator_connector_label = $('<div class="flowchart-operator-connector-label"></div>');
$operator_connector_label.text(connectorInfos.label);
$operator_connector_label.appendTo($operator_connector);

var $operator_connector_arrow = $('<div class="flowchart-operator-connector-arrow"></div>');
var $operator_connector_set = $('<div class="flowchart-operator-connector-set"></div>');
$operator_connector_set.data('connector_type', connectorType);
$operator_connector_set.appendTo($operator_container);

$operator_connector_arrow.appendTo($operator_connector);

var $operator_connector_small_arrow = $('<div class="flowchart-operator-connector-small-arrow"></div>');
$operator_connector_small_arrow.appendTo($operator_connector);

connectorArrows[connectorKey] = $operator_connector_arrow;
connectorSmallArrows[connectorKey] = $operator_connector_small_arrow;
connectorArrows[connectorKey] = [];
connectorSmallArrows[connectorKey] = [];
connectors[connectorKey] = [];
connectorSets[connectorKey] = $operator_connector_set;

self._createSubConnector(connectorKey, connectorInfos, fullElement);
}

for (var key in infos.inputs) {
Expand All @@ -455,7 +496,33 @@ $(function() {
addConnector(key, infos.outputs[key], $operator_outputs, 'outputs');
}

return {operator: $operator, title: $operator_title, connectorArrows: connectorArrows, connectorSmallArrows: connectorSmallArrows};
return fullElement;
},

_createSubConnector: function(connectorKey, connectorInfos, fullElement) {
var $operator_connector_set = fullElement.connectorSets[connectorKey];

var subConnector = fullElement.connectors[connectorKey].length;

var $operator_connector = $('<div class="flowchart-operator-connector"></div>');
$operator_connector.appendTo($operator_connector_set);
$operator_connector.data('connector', connectorKey);
$operator_connector.data('sub_connector', subConnector);

var $operator_connector_label = $('<div class="flowchart-operator-connector-label"></div>');
$operator_connector_label.text(connectorInfos.label.replace('(:i)', subConnector + 1));
$operator_connector_label.appendTo($operator_connector);

var $operator_connector_arrow = $('<div class="flowchart-operator-connector-arrow"></div>');

$operator_connector_arrow.appendTo($operator_connector);

var $operator_connector_small_arrow = $('<div class="flowchart-operator-connector-small-arrow"></div>');
$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);
},

getOperatorElement: function(operatorData) {
Expand Down Expand Up @@ -543,6 +610,10 @@ $(function() {
self._unsetTemporaryLink();
var operatorId = $(this).data('operator_id');
operatorChangedPosition(operatorId, ui.position);
fullElement.operator.css({
height: 'auto'
});

self.options.onOperatorMoved(operatorId, ui.position);
self.options.onAfterChange('operator_moved');
},
Expand All @@ -552,13 +623,13 @@ $(function() {
this.options.onAfterChange('operator_create');
},

_connectorClicked: function(operator, connector, connectorCategory) {
_connectorClicked: function(operator, connector, subConnector, connectorCategory) {
if (connectorCategory == 'outputs') {
var d = new Date();
var currentTime = d.getTime();
this.lastOutputConnectorClicked = {operator: operator, connector: connector};
this.lastOutputConnectorClicked = {operator: operator, connector: connector, subConnector: subConnector};
this.objs.layers.temporaryLink.show();
var position = this.getConnectorPosition(operator, connector);
var position = this.getConnectorPosition(operator, connector, subConnector);
var x = position.x + position.width;
var y = position.y;
this.objs.temporaryLink.setAttribute('x1', x);
Expand All @@ -569,8 +640,10 @@ $(function() {
var linkData = {
fromOperator: this.lastOutputConnectorClicked.operator,
fromConnector: this.lastOutputConnectorClicked.connector,
fromSubConnector: this.lastOutputConnectorClicked.subConnector,
toOperator: operator,
toConnector: connector
toConnector: connector,
toSubConnector: subConnector
};

this.addLink(linkData);
Expand Down Expand Up @@ -730,11 +803,50 @@ $(function() {
}
}
this.colorizeLink(linkId, 'transparent');
this.data.links[linkId].internal.els.overallGroup.remove();
var linkData = this.data.links[linkId];
var fromOperator = linkData.fromOperator;
var fromConnector = linkData.fromConnector;
var toOperator = linkData.toOperator;
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) {
return;
}

var maxI = -1;
var fromToOperator = linkFromTo + 'Operator';
var fromToConnector = linkFromTo + 'Connector';
var fromToSubConnector = linkFromTo + 'SubConnector';
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];
}
}
}

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();
}
},

deleteSelected: function() {
if (this.selectedLinkId != null) {
Expand Down
Loading

0 comments on commit 89ffa95

Please sign in to comment.