123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- /**
- * Licensed Materials - Property of IBM IBM Cognos Products: Modeling UI (C) Copyright IBM Corp. 2016, 2020
- * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP
- * Schedule Contract with IBM Corp.
- */
- define([
- 'jquery',
- 'underscore',
- 'bi/glass/app/util/View',
- './DiagramNode',
- './DiagramLink',
- './util/StringUtils',
- './util/Queue',
- '../InternalBridge'
- ], function ($, _, View, DiagramNode, DiagramLink, StringUtils, Queue, InternalBridge) {
- var d3;
- var MAX_ZOOM_SCALE = 6;
- var MIN_ZOOM_SCALE = 0.2
- // Ensures that nodes in diagram move away from each other
- var D3_FORCE_CHARGE = -1000;
- // ... but not too much
- var D3_FORCE_CHARGE_DISTANCE = 450;
- // Ensures connected nodes stay together at this distance
- var D3_FORCE_LINK_DISTANCE = 300;
- // Ensures that links do not drag nodes away from the dropped spot
- var D3_FORCE_LINK_STRENGTH = 0;
- var ModelDiagramView = View.extend({
- _d3ForceContext: null,
- _SVGContext: null,
- /*--D3 DATA--*/
- // List of current Nodes
- _nodeList: [],
- // List of current Links
- _linkList: [],
- _selectedNodeList: [],
- /*--INTERNAL DATA--*/
- // Saves positional information of nodes for Drag-n-Drop undo/redo and so on
- _nodePosition: {},
- // Which nodes (by identifier) are connected to which
- // nodes (as array of identifiers)
- _adjacencyList: {},
- _diagramContentProvider: null,
- initialNodes: null,
- initialLinks: null,
- /**
- * Initialize the diagram view. Requires "options._diagramContentProvider" to be defined
- *
- * @param {object}
- * options - custom options to add to the diagram view
- * @param {object}
- * options._diagramContentProvider - [REQUIRED] Provides implementation of a diagram content provider API
- * @param {array}
- * options.initialNodes - Initial nodes wanted in the diagram on first load
- * @param {array}
- * options.initialLinks - Initial links wanted in the diagram on first load
- */
- init: function (options) {
- ModelDiagramView.inherited('init', this, arguments);
- _.extend(this, options);
- d3 = options.d3;
- this._initializeD3();
- },
- _handleWindowKeyDown: function (e) {
- // To handle escape key during rename.
- if (e.which === 27) {
- this._onInputBlur();
- }
- },
- remove: function () {
- this._d3ForceContext && this._d3ForceContext.stop();
- window.removeEventListener('keydown', this._handleWindowKeyDown);
- ModelDiagramView.inherited('remove', this);
- this._SVGContext.empty();
- this.$el.empty();
- },
-
- _initializeD3: function () {
- var zoomAndPan = this.diagramStore.zoomAndPan;
- this._SVGContext = d3.select(this.$el[0]).append('svg').attr('width', '100%').attr('height', '100%');
- this._SVGContext.on('click', function() {
- if (d3.event.defaultPrevented) return; // dragged
-
- this.diagramStore.clickContainer();
- }.bind(this));
-
- this._SVGContext.call(d3.zoom().transform, d3.zoomIdentity.translate(zoomAndPan.translate[0], zoomAndPan.translate[1]).scale(zoomAndPan.scale));
- this._SVGContext.call(d3.zoom().scaleExtent([MIN_ZOOM_SCALE, MAX_ZOOM_SCALE]).filter(this._zoomFilter.bind(this)).on('zoom', this._onPan.bind(this))).on('dblclick.zoom', null);
- this._SVGContext.diagramContainer = this._SVGContext.append('svg:g').attr('class', 'mui-diagram-container');
- this._SVGContext.diagramContainer.append('svg:g').attr('class', 'mui-link-container');
- this._SVGContext.diagramContainer.append('svg:g').attr('class', 'mui-node-container');
- this._SVGContext.diagramContainer.append('svg:g').attr('class', 'mui-link-upper-container');
- this._SVGContext.diagramContainer.append('svg:g').attr('class', 'mui-node-upper-container');
- this._handleWindowKeyDown = this._handleWindowKeyDown.bind(this);
- window.addEventListener('keydown', this._handleWindowKeyDown);
- },
- _zoomFilter: function() {
- // Ignore right-click events, since it should open context menu, else check wheel events
- return !d3.event.button && (d3.event.type !== 'wheel' || !d3.event.ctrlKey);
- },
- _onPan: function() {
- var transform = d3.event.transform;
- var scale = d3.event.sourceEvent && d3.event.sourceEvent.type === 'wheel' ? transform.k : this.diagramStore.zoomAndPan.scale;
- this.diagramStore.setZoomAndPan({
- scale: scale,
- translate: [transform.x, transform.y]
- });
- // remove the rename input if it exists and save changes
- this._onInputBlur();
- this.diagramStore.hideContextMenu();
- },
- /**
- * Displays the cardinality of a link between nodes
- */
- showCardinality: function (isVisible) {
- this.$el.removeClass('mui-diagram-cardinality-displayed');
- if (isVisible) {
- this.$el.addClass('mui-diagram-cardinality-displayed');
- }
- },
- isAnimating: function () {
- return this._isAnimating;
- },
- /**
- * Will hide any nodes in the diagram that are more than the number of stops away from the selected node.
- */
- showDegreesOfSeparation: function () {
- var allNodeIDs = _.pluck(this._nodeList, 'identifier');
- var selectedNodes = this.$el.find('.mui-diagram-selected');
- if (this.diagramStore.isContextMode) {
- // This is to cope with proposal diagram view
- if (this.diagramStore.allVisibleNodes) {
- this.allVisibleNodes = this.diagramStore.allVisibleNodes;
- }
- this._fadeTo(this.allVisibleNodes);
- this._fadeTo(_.difference(allNodeIDs, this.allVisibleNodes), true);
- } else if (this.diagramStore.areAllNodesVisible) {
- this.allVisibleNodes = allNodeIDs;
- this._fadeTo(allNodeIDs);
- // When no node selected, all nodes are set to faded.
- } else if (selectedNodes.length === 0) {
- this._fadeTo(allNodeIDs, true);
- return;
- // FOR EACH 'exploreNode'
- } else {
- this.allVisibleNodes = [];
- _.each(selectedNodes, function (exploreNode) {
- exploreNode = ($(exploreNode).attr('class') || '').split(' ');
- exploreNode = _.without(exploreNode, 'mui-diagram-node', 'mui-reference-node', 'mui-diagram-selected');
- exploreNode = exploreNode.toString();
- var visibleNodes = (!this._adjacencyList[exploreNode]) ? [exploreNode] : _.uniq(this._getAdjacentNodes(this.diagramStore.degreesOfSeparation, exploreNode));
- this.allVisibleNodes = _.union(this.allVisibleNodes, visibleNodes);
- }.bind(this));
- this._fadeTo(this.allVisibleNodes);
- this._fadeTo(_.difference(allNodeIDs, this.allVisibleNodes), true);
- }
- // Bring the selected node into the front, so that it won't be covered by other visible nodes.
- this.bringNodesToFront(this.$el.find('.mui-diagram-selected'));
- },
- _fadeTo: function (nodeIds, toFade) {
- var nodesToBack = [];
- var nodesToFront = [];
- var linksToFront = [];
- var linksToBack = [];
- if (nodeIds && nodeIds.length > 0) {
- for (var i=0; i<nodeIds.length; i++) {
- var nodeId = nodeIds[i];
- var $el = this.$el.find('.mui-diagram-node.' + nodeId);
- if (toFade) {
- if (this.diagramStore.isContextMode) {
- $el.find('.mui-diagram-node-content').hide();
- $el.find('.mui-diagram-node-box').hide();
- $el.find('.mui-diagram-table-details').hide();
- } else {
- $el.find('.mui-diagram-node-content').show().addClass('faded');
- $el.find('.mui-diagram-node-box').show().addClass('faded');
- $el.find('.mui-diagram-table-details').show().addClass('faded');
- }
- nodesToBack.push($el);
- } else {
- $el.find('.mui-diagram-node-content').show().removeClass('faded');
- $el.find('.mui-diagram-node-box').show().removeClass('faded');
- $el.find('.mui-diagram-table-details').show().removeClass('faded');
- nodesToFront.push($el);
- }
- var links = this.$el.find('.mui-diagram-link.' + nodeId);
- for (var idx=0; idx<links.length; idx++) {
- var link = links[idx];
- var visibleLink = _.intersection($(link).attr('class').split(' '), this.allVisibleNodes).length === 2;
- var isFaded = $(link).hasClass('faded');
- if (!toFade && visibleLink) {
- $(link).show();
- isFaded && $(link).removeClass('faded');
- linksToFront.push($(link));
- } else if (toFade) {
- if (this.diagramStore.isContextMode) {
- linksToBack.push($(link).hide());
- } else {
- linksToBack.push($(link).show().addClass('faded'));
- }
- }
- }
- }
- }
- this.bringLinksToBack(linksToBack);
- this.bringNodesToBack(nodesToBack);
- this.bringLinksToFront(linksToFront);
- this.bringNodesToFront(nodesToFront);
- },
- /**
- * Bring the selected nodes to the front of the view
- *
- * @param nodes
- *
- */
- bringNodesToFront: function (nodes) {
- this.$el.find('.mui-node-upper-container').append(nodes);
- },
- bringLinksToFront: function (links) {
- this.$el.find('.mui-link-upper-container').append(links);
- },
- bringNodesToBack: function (nodes) {
- this.$el.find('.mui-node-container').append(nodes);
- },
- bringLinksToBack: function (links) {
- this.$el.find('.mui-link-container').append(links);
- },
- /**
- * Will return a list of nodes that are within the number of stops to a selected node
- *
- * @param {string}
- * stops - The number of stops (levels) to explore
- * @param {string}
- * selectedNode - The root node the function is exploring
- */
- _getAdjacentNodes: function (stops, selectedNode) {
- var q = new Queue();
- var visitedNodes = [];
- var node;
- var depth = stops;
- // variables to keep track of when to decrease depth
- var countToDepthIncrease = 1,
- nextCountToDepthIncrease = 0;
- q.enqueue(selectedNode);
- while(!q.isEmpty() && depth >= 0) {
- node = q.dequeue();
- // don't need to re-process nodes
- if(!_.contains(visitedNodes, node)) {
- // mark node as visited
- visitedNodes = _.union(visitedNodes, node);
- // add adjacent nodes to queue to be processed
- var adjacencyList = this._adjacencyList[node] || [];
- for(var i = 0; i < adjacencyList.length; i++) {
- q.enqueue(adjacencyList[i]);
- nextCountToDepthIncrease++;
- }
- }
- // if we've processed everything from the previous depth,
- // move to next level of the graph
- if(--countToDepthIncrease === 0) {
- countToDepthIncrease = nextCountToDepthIncrease;
- nextCountToDepthIncrease = 0;
- depth--;
- }
- }
- return visitedNodes;
- },
- /**
- * Add a new node to the diagram
- *
- * @param {object}
- * moserObject - A node object that should be added to the diagram
- */
- addNode: function (moserObject, options, droppedPosition) {
- if (this.diagramStore.droppedPosition && !this.diagramStore.isDnD) {
- var id = moserObject.getIdentifier();
- if (moserObject !== this.diagramStore.contextMenuFromMoserObject
- && this.allVisibleNodes.indexOf(id) > -1) {
- this.diagramStore.setPosition(moserObject);
- }
- }
- if (!this._hasPosition(moserObject)) {
- this._withNewNodes = true;
- }
- _.extend(options, {
- contentProvider: this._diagramContentProvider,
- moserObject: moserObject,
- fixed: this._hasPosition(moserObject),
- position: this._getPosition(moserObject, droppedPosition),
- moserModule: this.moserModule,
- isDetailsVisible: this.diagramStore.isDetailsVisible,
- tableRowCount: this.diagramStore.getObjectRowCount(moserObject),
- statisticsLoading: this.diagramStore.getObjectStatisticsLoading(moserObject)
- });
- var newNode = new DiagramNode(options);
- this._nodeList.push(newNode);
- },
- /**
- * Add a new link to the diagram
- *
- * @param {object}
- * linkObj - A link object that should be added to the diagram
- */
- addLink: function (linkObj) {
- if (!linkObj.left || !linkObj.right) {
- return;
- }
- var leftID = linkObj.left.ref,
- rightID = linkObj.right.ref,
- useSpec = this.moserModule.getUseSpec(),
- leftRefObject = linkObj.left.getReferencedObject(),
- rightRefObject = linkObj.right.getReferencedObject(),
- leftIsFromPackage = InternalBridge.moserUtils.isPartOfPackage(leftRefObject),
- rightIsFromPackage = InternalBridge.moserUtils.isPartOfPackage(rightRefObject);
- if( leftIsFromPackage ){
- leftID = InternalBridge.moserUtils.getUseSpecByRef(leftRefObject, linkObj.left.ref).identifier;
- }
- if( rightIsFromPackage ){
- rightID = InternalBridge.moserUtils.getUseSpecByRef(rightRefObject, linkObj.right.ref).identifier;
- }
- var linkSource = _.find(this._nodeList, function (ele) {
- return leftID === ele.identifier;
- });
- var linkTarget = _.find(this._nodeList, function (ele) {
- return rightID === ele.identifier;
- });
- if (!linkSource || !linkTarget) {
- return;
- }
- var currentDiagramLink = _.find(this._linkList, function (ele){
- return linkObj.identifier === ele.id;
- });
- if (currentDiagramLink) {
- currentDiagramLink.addARepresentedLink({
- linkObj: linkObj,
- left: linkObj.left,
- link: linkObj.link,
- right: linkObj.right
- });
- } else {
- var newLink = new DiagramLink({
- source: linkSource,
- target: linkTarget,
- instanceType: linkObj.instanceType ? linkObj.instanceType.value() : 'copy',
- id: linkObj.identifier,
- moserModule: this.moserModule,
- moserObject: linkObj,
- severityInfo: InternalBridge.validationUtils.getHighestSeverityErrorInfo(linkObj)
- });
- newLink.addARepresentedLink({
- linkObj: linkObj,
- left: linkObj.left,
- link: linkObj.link,
- right: linkObj.right
- });
- linkSource.addAdjacentLink(newLink.id);
- linkTarget.addAdjacentLink(newLink.id);
- this._linkList.push(newLink);
- }
- this._adjacencyList[leftID] = this._adjacencyList[leftID] || [];
- this._adjacencyList[rightID] = this._adjacencyList[rightID] || [];
- // prevent bloat of the adjacencyList - don't need duplicates
- if (!_.contains(this._adjacencyList[leftID], rightID)) {
- this._adjacencyList[leftID].push(rightID);
- }
- if (!_.contains(this._adjacencyList[rightID], leftID)) {
- this._adjacencyList[rightID].push(leftID);
- }
- },
- /**
- * Programmatically selects a node in the diagram (when selecting a node from somewhere OTHER than the diagram)
- *
- * @param {array}
- * identifiers - An array of strings of node IDs to be selected
- */
- selectNodes: function () {
- var selectedNodeIdentifiers = _.map(this.diagramStore.selection, function (node) { return node.getIdentifier(); });
- this.$el.find('.mui-diagram-selected').removeClass('mui-diagram-selected');
- selectedNodeIdentifiers.forEach(function (id) {
- this.$el.find('.mui-diagram-node.' + id).addClass('mui-diagram-selected');
- }.bind(this));
-
- this._selectedNodeList = this._nodeList.filter(function(ele) { return selectedNodeIdentifiers.indexOf(ele.identifier) !== -1 });
- },
- _update: function () {
- this._d3ForceContext = d3.forceSimulation(this._nodeList)
- .force('charge', d3.forceManyBody().strength(D3_FORCE_CHARGE).distanceMax(D3_FORCE_CHARGE_DISTANCE))
- .force('link', d3.forceLink(this._linkList)
- .strength(D3_FORCE_LINK_STRENGTH)
- .distance(D3_FORCE_LINK_DISTANCE))
- .alpha(this._withNewNodes ? 0.1 : 0)
- .restart();
- var links = this._diagramContentProvider.drawLinks(this._SVGContext, this._linkList);
- var nodes = this._diagramContentProvider.drawNodes(this._SVGContext, this._nodeList);
- var self = this;
-
- nodes.call(d3.drag().on('start', function(e) {
- this.diagramStore.hideContextMenu();
- d3.event.sourceEvent.stopPropagation();
- }.bind(this)).on('drag', function (d) {
- if (this._selectedNodeList.indexOf(d) !== -1) {
- this._selectedNodeList.forEach(function(node) {
- node.x += d3.event.dx;
- node.y += d3.event.dy;
- });
- } else {
- d.x += d3.event.dx;
- d.y += d3.event.dy;
- }
- this._diagramContentProvider.animateNodeTick(nodes);
- this._diagramContentProvider.animateLinkTick(links);
- }.bind(this)).on('end', function (d) {
-
- if (this._selectedNodeList.indexOf(d) === -1) {
- this._setPosition(d.moserObject, {
- x: d.x,
- y: d.y
- });
- } else {
- this._selectedNodeList.forEach(function(node) {
- this._setPosition(node.moserObject, {
- x: node.x,
- y: node.y
- });
- }.bind(this));
- }
- }.bind(this)));
- if (this._withNewNodes && !this._isAnimating) {
- this._isAnimating = true;
- }
- this._d3ForceContext.on('tick', function () {
- self._diagramContentProvider.animateNodeTick(nodes);
- self._diagramContentProvider.animateLinkTick(links);
- nodes.each(function (n) {
- if (self._d3ForceContext.alpha() < 0.01) {
- n.fx = n.x;
- n.fy = n.y;
-
- self._setPosition(n.moserObject, {
- x: n.x,
- y: n.y
- });
- self._d3ForceContext.stop();
- self._isAnimating = false;
- self._withNewNodes = false;
- }
- });
- });
- this.redraw();
- },
- render: function (moserModule) {
- if (this._isAnimating) {
- this.redraw();
- return;
- }
-
- this._nodeList = [];
- this._linkList = [];
- // first add nodes for packages
- var diagramNodes = this.diagramStore.diagramNodes;
- diagramNodes.packages.forEach(function (p) {
- this.addNode(p, {
- filter: false,
- instanceType: 'package',
- isValid: true
- }, this.diagramStore.droppedPosition);
- }.bind(this));
- // then add nodes for query subject not in packages
- diagramNodes.querySubjects.forEach(function (qs) {
- this.addNode(qs, {
- filter: qs.getFilter().length,
- instanceType: qs.instanceType ? qs.instanceType.value() : 'copy',
- isValid: InternalBridge.validationUtils.isValid(qs),
- severityInfo: InternalBridge.validationUtils.getHighestSeverityErrorInfo(qs)
- }, this.diagramStore.droppedPosition);
- }.bind(this));
- // last add links
- this._adjacencyList = {};
- moserModule.getRelationship().forEach(function (link) {
- this.addLink(link);
- }.bind(this));
- this.diagramStore.setDroppedPosition();
- this.diagramStore.setIsDnD(false);
- this._update();
- },
- /**
- * Position offset provides some randomness in the dropping of node positions to prevent them from "flying off"
- */
- _positionOffset: function () {
- return Math.floor(500 * (Math.random() - 0.5));
- },
- _getOffsetPosition: function (nodePosition) {
- var zoomAndPan = this.diagramStore.zoomAndPan;
- return {
- x: (nodePosition.x + this._positionOffset() - zoomAndPan.translate[0]) / zoomAndPan.scale,
- y: (nodePosition.y + this._positionOffset() - zoomAndPan.translate[1]) / zoomAndPan.scale
- };
- },
- /**
- * Calculates the position of any new nodes that are dropped to the diagram, otherwise they are placed in the middle/
- */
- _getPosition: function (moserObject, droppedPosition) {
- if (this._hasPosition(moserObject)) {
- return this.diagramStore.getPosition(moserObject);
- }
- var defaultPosition = droppedPosition || {
- x: (this.$el.width() / 2),
- y: (this.$el.height() / 2)
- };
- return this._getOffsetPosition(defaultPosition);
- },
- _hasPosition: function (moserObject) {
- var position = this.diagramStore.getPosition(moserObject);
- return position.x != null && position.y != null;
- },
- _setPosition: function (moserObject, nodePosition, withOffset) {
- this.diagramStore.setPosition(moserObject, withOffset ? this._getOffsetPosition(nodePosition) : nodePosition);
- },
- /**
- * Show the input box on the diagram over the node that
- * will be renamed and send changes to model
- */
- captureRename : function () {
- var focusedNode = d3.select(this.$el.find('.mui-diagram-selected')[0]);
- // occasionally get context menu without node focus
- if (focusedNode.size() === 0 || !this.diagramStore.isRenameActive) {
- return;
- }
- var nodeData;
- var nodeList = this._nodeList;
- for (var i = 0; i < nodeList.length; i++) {
- if (nodeList[i].identifier === focusedNode.node().__data__.identifier) {
- nodeData = nodeList[i];
- break;
- }
- }
- this._drawInputBoxRename(focusedNode);
- if (nodeData) {
- // put existing title in input box
- this.$inputBox.val(nodeData.label).focus().select();
- this._pushRenameToModel(focusedNode, nodeData.moserObject);
- }
- },
- /**
- * Find a matching node to call the rename action on
- *
- * @param identifier
- * The identifier of the node that is to be
- * renamed
- */
- searchNodeListRename : function (newName, identifier) {
- var self = this;
- this._nodeList.forEach(function (node) {
- if (node.identifier === identifier) {
- self._renameNode(newName, node);
- }
- });
- },
- /**
- * Rename the actual diagram node
- *
- * @param newName
- * @param node
- */
- _renameNode : function (newName, node) {
- node.setLabel(newName);
- this.$el.find('.mui-diagram-node.' + node.identifier + ' text')
- .text(newName);
- this._shortenLabel(node.identifier);
- },
- /**
- * Capture the new name of the query subject and push
- * changes to model and tree
- */
- _pushRenameToModel : function (focusedNode, moserObject) {
- // change text of diagram node and propagate any
- // changes to fancytree on focus change
- var self = this;
- var modelInfo =
- {
- model: self._diagramContentProvider._model,
- node: focusedNode
- };
- this.$inputBox.blur(modelInfo, function () {
- self._onInputBlur(moserObject);
- }).keypress(modelInfo, function (e) {
- if (e.which === 13) {
- self._onInputBlur(moserObject);
- }
- });
- },
- _onInputBlur : function (moserObject) {
- if (this.$inputBox && this.$inputBox.length > 0) {
- this.$inputBox.remove();
- this.$imputBox = null;
- this.diagramStore.setRenameActive(false);
- if (moserObject) {
- this.diagramStore.setLabel(moserObject, this.$inputBox.val());
- }
- }
- },
- /**
- * Draw and size the input box used for diagram rename
- * action
- */
- _drawInputBoxRename : function (focusedNode) {
- var node = this.$el.find('.mui-diagram-selected');
- var bboxNode = node.find('.mui-diagram-node-box')[0].getBoundingClientRect();
- var bboxSVG = this.$el.offset();
- var renameLeft = bboxNode.left - bboxSVG.left;
- var renameTop = bboxNode.top - bboxSVG.top;
- var textSize = focusedNode.select('text').style('font-size')
- .replace(/[^-\d\.]/g, '') * this.diagramStore.zoomAndPan.scale;
- // change size of input box if filter icon is
- // visible
- //
- // 0.9 = % of node width used for input box when
- // filter icon is not present
- //
- // 0.78 = % of node width used for input box when
- // filter icon is present
- var widthOffset = 0.9;
- if (node[0].__data__.filter) {
- widthOffset = 0.78;
- }
- // add and size the input box based on the zoom
- // level
- //
- // 0.05 = % of node width used to give a buffer on
- // left of input box (between edge of node and start
- // of the input)
- //
- // 0.25 = % of node height used to buffer top of
- // input box (between top of node and input)
- this.$inputBox = $('<input class=\'mui-diagram-rename\' type=\'text\' style=\'position:absolute; left:'
- + (renameLeft + bboxNode.width * 0.05)
- + 'px; top:'
- + (renameTop + bboxNode.height * 0.25)
- + 'px; width:'
- + (bboxNode.width * widthOffset)
- + 'px; height:'
- + (bboxNode.height / 2)
- + 'px; font-size: '
- + textSize + 'px;\'>');
- this.$el.find('svg').before(this.$inputBox);
- },
- /**
- * Properly shorten the label for the given identifier's
- * node
- *
- * @param identifier
- * A valid querySubject identifier
- */
- _shortenLabel : function (identifier) {
- var node = d3.select(this.$el.find('.mui-diagram-node.' + identifier)[0]);
- this.$el.find('.mui-diagram-node.' + identifier + ' text')[0].textContent = StringUtils
- .shortenTextMidEllipsis(
- node.data()[0].label, StringUtils.getMaxDiagramLabelLength(node.data()[0].filter, node.data()[0].label));
- },
- /**
- * Update the diagram node's styling based on new properties
- *
- * @param node
- * The node
- */
- updateNodeStyling: function (node) {
- if (node) {
- // find matching node in diagram node list
- var n = _.find(this._nodeList, function (ele) {
- return ele.identifier === node.identifier;
- });
- if (n) {
- // set properties on matching diagram node
- n.setInstanceType(node.instanceType);
- n.setHidden(node.hidden);
- // update style on node to reflect new data
- this._diagramContentProvider.styleNode(d3.select(this.$el.find('.mui-diagram-node.' + n.identifier)[0]));
- }
- }
- },
- updateLinkStyling: function (relationship) {
- if (relationship) {
- // find matching link in diagram link list
- var l = _.find(this._linkList, function (ele) {
- return ele.identifier === relationship.identifier;
- });
- if (l) {
- l.setInstanceType(relationship.instanceType);
- this._diagramContentProvider.styleLink(d3.select(this.$el.find('.mui-diagram-link.' + l.identifier)[0]));
- }
- }
- },
- // To simulate react update
- redraw: function () {
- var zoomAndPan = this.diagramStore.zoomAndPan;
- var transform = d3.zoomTransform(this._SVGContext.node());
- transform.k = zoomAndPan.scale;
- transform.x = zoomAndPan.translate[0];
- transform.y = zoomAndPan.translate[1];
- d3.zoom().transform(this._SVGContext, transform);
- this._SVGContext.diagramContainer.attr('transform', 'translate(' + zoomAndPan.translate + ') ' + 'scale(' + zoomAndPan.scale + ')');
- this.selectNodes();
- this.showCardinality(this.diagramStore.isCardinalityVisible);
- this.showDegreesOfSeparation(this.diagramStore.degreesOfSeparation);
- this.captureRename();
- }
- });
- return ModelDiagramView;
- });
|