webgme
Version:
Web-based Generic Modeling Environment
246 lines (198 loc) • 9.89 kB
JavaScript
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
/**
* @author rkereskenyi / https://github.com/rkereskenyi
*/
define(['js/logger'], function (Logger) {
'use strict';
var ConnectionRouteManagerBasic,
DESIGNERITEM_SUBCOMPONENT_SEPARATOR = '_x_';
ConnectionRouteManagerBasic = function (options) {
var loggerName = (options && options.loggerName) || 'gme:Widgets:DiagramDesigner:ConnectionRouteManagerBasic';
this.logger = (options && options.logger) || Logger.create(loggerName, WebGMEGlobal.gmeConfig.client.log);
this.diagramDesigner = options ? options.diagramDesigner : null;
if (this.diagramDesigner === undefined || this.diagramDesigner === null) {
this.logger.error('Trying to initialize a ConnectionRouteManagerBasic without a canvas...');
throw ('ConnectionRouteManagerBasic can not be created');
}
this.logger.debug('ConnectionRouteManagerBasic ctor finished');
};
ConnectionRouteManagerBasic.prototype.initialize = function () {
};
ConnectionRouteManagerBasic.prototype.destroy = function () {
};
ConnectionRouteManagerBasic.prototype.redrawConnections = function (idList) {
var i;
this.logger.debug('Redraw connection request: ' + idList.length);
//NOTE: here it is not enough to update the connections the canvas asked for
//because updating one connections' endpoint (connection area switch) can cause
//other connections to be redrawn that was originally not requested to do so
idList = this.diagramDesigner.connectionIds.slice(0);
//1 - update all the connection endpoint connectable area information
this._updateEndpointInfo(idList);
//2 - we have each connection end connectability info
//find the closest areas for each connection
for (i = 0; i < idList.length; i += 1) {
this._updateConnectionCoordinates(idList[i]);
}
//need to return the IDs of the connections that was really
//redrawn or any other visual property chenged (width, etc)
return idList;
};
ConnectionRouteManagerBasic.prototype._updateEndpointInfo = function (idList) {
var i = idList.length,
connId,
canvas = this.diagramDesigner,
srcObjId,
srcSubCompId,
dstObjId,
dstSubCompId,
connectionMetaInfo;
this.endpointConnectionAreaInfo = {};
//first update the available connection endpoint coordinates
while (i--) {
connId = idList[i];
srcObjId = canvas.connectionEndIDs[connId].srcObjId;
srcSubCompId = canvas.connectionEndIDs[connId].srcSubCompId;
dstObjId = canvas.connectionEndIDs[connId].dstObjId;
dstSubCompId = canvas.connectionEndIDs[connId].dstSubCompId;
connectionMetaInfo = canvas.items[connId].getMetaInfo();
this._getEndpointConnectionAreas(srcObjId, srcSubCompId, false, connectionMetaInfo);
this._getEndpointConnectionAreas(dstObjId, dstSubCompId, true, connectionMetaInfo);
}
};
ConnectionRouteManagerBasic.prototype._getEndpointConnectionAreas = function (objId, subCompId, isEnd,
connectionMetaInfo) {
var longid = subCompId ? objId + DESIGNERITEM_SUBCOMPONENT_SEPARATOR + subCompId : objId,
res,
canvas = this.diagramDesigner,
j,
designerItem;
if (this.endpointConnectionAreaInfo.hasOwnProperty(longid) === false) {
this.endpointConnectionAreaInfo[longid] = [];
if (subCompId === undefined ||
(subCompId !== undefined && this.diagramDesigner._itemSubcomponentsMap[objId] &&
this.diagramDesigner._itemSubcomponentsMap[objId].indexOf(subCompId) !== -1)) {
designerItem = canvas.items[objId];
res = designerItem.getConnectionAreas(subCompId, isEnd, connectionMetaInfo) || [];
j = res.length;
while (j--) {
this.endpointConnectionAreaInfo[longid].push({
x: res[j].x1 + (res[j].x2 - res[j].x1) / 2,
y: res[j].y1 + (res[j].y2 - res[j].y1) / 2
});
}
}
}
};
ConnectionRouteManagerBasic.prototype._updateConnectionCoordinates = function (connectionId) {
var canvas = this.diagramDesigner,
srcObjId = canvas.connectionEndIDs[connectionId].srcObjId,
srcSubCompId = canvas.connectionEndIDs[connectionId].srcSubCompId,
dstObjId = canvas.connectionEndIDs[connectionId].dstObjId,
dstSubCompId = canvas.connectionEndIDs[connectionId].dstSubCompId,
sId = srcSubCompId ? srcObjId + DESIGNERITEM_SUBCOMPONENT_SEPARATOR + srcSubCompId : srcObjId,
tId = dstSubCompId ? dstObjId + DESIGNERITEM_SUBCOMPONENT_SEPARATOR + dstSubCompId : dstObjId,
segmentPoints = canvas.items[connectionId].segmentPoints,
sourceConnectionPoints = this.endpointConnectionAreaInfo[sId] || [],
targetConnectionPoints = this.endpointConnectionAreaInfo[tId] || [],
sourceCoordinates = null,
targetCoordinates = null,
closestConnPoints,
connectionPathPoints = [],
len,
i;
if (sourceConnectionPoints.length > 0 && targetConnectionPoints.length > 0) {
closestConnPoints = this._getClosestPoints(sourceConnectionPoints, targetConnectionPoints,
segmentPoints);
if (srcObjId === dstObjId && srcSubCompId === dstSubCompId &&
closestConnPoints[0] === closestConnPoints[1]) {
// Same source and destination point - try to scoot it over..
if (closestConnPoints[0] === closestConnPoints[1]) {
closestConnPoints[1] = (closestConnPoints[0] + 1) % sourceConnectionPoints.length;
}
}
sourceCoordinates = sourceConnectionPoints[closestConnPoints[0]];
targetCoordinates = targetConnectionPoints[closestConnPoints[1]];
//source point
connectionPathPoints.push(sourceCoordinates);
//segment points
if (segmentPoints && segmentPoints.length > 0) {
len = segmentPoints.length;
for (i = 0; i < len; i += 1) {
connectionPathPoints.push({
x: segmentPoints[i][0],
y: segmentPoints[i][1]
});
}
} else {
if (srcObjId === dstObjId && srcSubCompId === dstSubCompId) {
//self connection, insert fake points
connectionPathPoints.push({
x: sourceCoordinates.x + 100,
y: sourceCoordinates.y - 100
});
connectionPathPoints.push({
x: sourceCoordinates.x + 200,
y: sourceCoordinates.y
});
connectionPathPoints.push({
x: sourceCoordinates.x + 100,
y: sourceCoordinates.y + 100
});
}
}
//end point
connectionPathPoints.push(targetCoordinates);
}
canvas.items[connectionId].setConnectionRenderData(connectionPathPoints);
};
//figure out the shortest side to choose between the two
ConnectionRouteManagerBasic.prototype._getClosestPoints = function (srcConnectionPoints, tgtConnectionPoints,
segmentPoints) {
var i,
j,
dx,
dy,
srcP,
tgtP,
minLength = -1,
cLength;
if (segmentPoints && segmentPoints.length > 0) {
for (i = 0; i < srcConnectionPoints.length; i += 1) {
for (j = 0; j < tgtConnectionPoints.length; j += 1) {
dx = {
src: Math.abs(srcConnectionPoints[i].x - segmentPoints[0][0]),
tgt: Math.abs(tgtConnectionPoints[j].x - segmentPoints[segmentPoints.length - 1][0])
};
dy = {
src: Math.abs(srcConnectionPoints[i].y - segmentPoints[0][1]),
tgt: Math.abs(tgtConnectionPoints[j].y - segmentPoints[segmentPoints.length - 1][1])
};
cLength = Math.sqrt(dx.src * dx.src + dy.src * dy.src) +
Math.sqrt(dx.tgt * dx.tgt + dy.tgt * dy.tgt);
if (minLength === -1 || minLength > cLength) {
minLength = cLength;
srcP = i;
tgtP = j;
}
}
}
} else {
for (i = 0; i < srcConnectionPoints.length; i += 1) {
for (j = 0; j < tgtConnectionPoints.length; j += 1) {
dx = Math.abs(srcConnectionPoints[i].x - tgtConnectionPoints[j].x);
dy = Math.abs(srcConnectionPoints[i].y - tgtConnectionPoints[j].y);
cLength = Math.sqrt(dx * dx + dy * dy);
if (minLength === -1 || minLength > cLength) {
minLength = cLength;
srcP = i;
tgtP = j;
}
}
}
}
return [srcP, tgtP];
};
return ConnectionRouteManagerBasic;
});