UNPKG

webgme

Version:

Web-based Generic Modeling Environment

246 lines (198 loc) 9.89 kB
/*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; });