2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import * as _ from "lodash";
27 import {CompositionCiServicePathLink} from "app/models/graph/graph-links/composition-graph-links/composition-ci-service-path-link";
28 import {Requirement, Capability} from "app/models";
29 import {Injectable} from "@angular/core";
34 export class CommonGraphUtils {
40 public safeApply = (scope:ng.IScope, fn:any) => { //todo remove to general utils
41 let phase = scope.$root.$$phase;
42 if (phase == '$apply' || phase == '$digest') {
43 if (fn && (typeof(fn) === 'function')) {
52 * Draw node on the graph
54 * @param compositionGraphNode
56 * @returns {CollectionElements}
58 public addNodeToGraph(cy:Cy.Instance, compositionGraphNode:CommonNodeBase, position?:Cy.Position):Cy.CollectionElements {
60 let node = cy.add(<Cy.ElementDefinition> {
63 data: compositionGraphNode,
64 classes: compositionGraphNode.classes
67 this.initNodeTooltip(node);
72 * The function will create a component instance node by the componentInstance position.
73 * If the node is UCPE the function will create all cp lan&wan for the ucpe
75 * @param compositionGraphNode
76 * @returns {Cy.CollectionElements}
78 public addComponentInstanceNodeToGraph(cy:Cy.Instance, compositionGraphNode:CompositionCiNodeBase):Cy.CollectionElements {
81 x: +compositionGraphNode.componentInstance.posX,
82 y: +compositionGraphNode.componentInstance.posY
85 let node = this.addNodeToGraph(cy, compositionGraphNode, nodePosition);
90 * Add service path link to graph - only draw the link
94 public insertServicePathLinkToGraph = (cy:Cy.Instance, link:CompositionCiServicePathLink) => {
95 let linkElement = cy.add({
100 this.initServicePathTooltip(linkElement, link);
104 * Returns function for the link tooltip content
105 * @param {Relationship} linkRelation
106 * @param {Requirement} requirement
107 * @param {Capability} capability
108 * @returns {() => string}
111 private _getLinkTooltipContent(linkRelation:Relationship, requirement?:Requirement, capability?:Capability):string {
112 return '<div class="line">' +
113 '<span class="req-cap-label">R: </span>' +
114 '<span>' + (requirement ? requirement.getTitle() : linkRelation.relation.requirement) + '</span>' +
116 '<div class="line">' +
117 '<div class="sprite-new link-tooltip-arrow"></div>' +
118 '<span class="req-cap-label">C: </span>' +
119 '<span>' + (capability ? capability.getTitle() : linkRelation.relation.capability) + '</span>' +
124 * This function will init qtip tooltip on the link
125 * @param linkElement - the link we want the tooltip to apply on,
127 * @param getLinkRequirementCapability
128 * link - the link obj
130 public initLinkTooltip(linkElement:Cy.CollectionElements, link:Relationship, getLinkRequirementCapability:Function) {
131 const content = () => this._getLinkTooltipContent(link); // base tooltip content without owner names
132 const render = (event, api) => {
133 // on render (called once at first show), get the link requirement and capability and change to full tooltip content (with owner names)
134 getLinkRequirementCapability().then((linkReqCap) => {
135 const fullContent = () => this._getLinkTooltipContent(link, linkReqCap.requirement, linkReqCap.capability);
136 api.set('content.text', fullContent);
139 linkElement.qtip(this.prepareInitTooltipData({content, events: {render}}));
147 public initServicePathTooltip(linkElement:Cy.CollectionElements, link:CompositionCiServicePathLink) {
148 let content = function () {
149 return '<div class="line">' +
150 '<div>' + link.pathName + '</div>' +
153 linkElement.qtip(this.prepareInitTooltipData({content}));
156 private prepareInitTooltipData(options?:Object) {
161 adjust: {x: 0, y: 0},
165 classes: 'qtip-dark qtip-rounded qtip-custom link-qtip',
175 hide: {event: 'mouseout mousedown'},
181 public HTMLCoordsToCytoscapeCoords(cytoscapeBoundingBox:Cy.Extent, mousePos:Cy.Position):Cy.Position {
182 return {x: mousePos.x + cytoscapeBoundingBox.x1, y: mousePos.y + cytoscapeBoundingBox.y1}
186 public getCytoscapeNodePosition = (cy:Cy.Instance, event:DragEvent | MouseEvent):Cy.Position => {
187 let targetOffset = $(event.target).offset();
188 if(event instanceof DragEvent) {
189 targetOffset = $('canvas').offset();
192 let x = (event.pageX - targetOffset.left) / cy.zoom();
193 let y = (event.pageY - targetOffset.top) / cy.zoom();
195 return this.HTMLCoordsToCytoscapeCoords(cy.extent(), {
202 public getNodePosition(node:Cy.CollectionFirstNode):Cy.Position {
203 let nodePosition = node.relativePoint();
204 if (node.data().isUcpe) { //UCPEs use bounding box and not relative point.
205 nodePosition = {x: node.boundingbox().x1, y: node.boundingbox().y1};
212 * Generic function that can be used for any html elements overlaid on canvas
213 * Returns the html position of a node on canvas, including left palette and header offsets. Option to pass in additional offset to add to return position.
215 * @param additionalOffset
216 * @returns {Cy.Position}
218 public getNodePositionWithOffset = (node:Cy.CollectionFirstNode, additionalOffset?:Cy.Position): Cy.Position => {
219 if(!additionalOffset) additionalOffset = {x: 0, y:0};
221 let nodePosition = node.renderedPosition();
222 let posWithOffset:Cy.Position = {
223 x: nodePosition.x + GraphUIObjects.DIAGRAM_PALETTE_WIDTH_OFFSET + additionalOffset.x,
224 y: nodePosition.y + GraphUIObjects.COMPOSITION_HEADER_OFFSET + additionalOffset.y
226 return posWithOffset;
230 * return true/false if first node contains in second - this used in order to verify is node is entirely inside ucpe
235 public isFirstBoxContainsInSecondBox(firstBox:Cy.BoundingBox, secondBox:Cy.BoundingBox) {
237 return firstBox.x1 > secondBox.x1 && firstBox.x2 < secondBox.x2 && firstBox.y1 > secondBox.y1 && firstBox.y2 < secondBox.y2;
247 public getLinkableNodes(cy:Cy.Instance, node:Cy.CollectionFirstNode):Array<CompositionCiNodeBase> {
248 let compatibleNodes = [];
249 _.each(cy.nodes(), (tempNode)=> {
250 if (this.nodeLocationsCompatible(node, tempNode)) {
251 compatibleNodes.push(tempNode.data());
254 return compatibleNodes;
258 * Checks whether node locations are compatible in reference to UCPEs.
259 * Returns true if both nodes are in UCPE or both nodes out, or one node is UCPEpart.
263 public nodeLocationsCompatible(node1:Cy.CollectionFirstNode, node2:Cy.CollectionFirstNode) {
264 return (this.isFirstBoxContainsInSecondBox(node1.boundingbox(), node2.boundingbox()));
268 * This function will init qtip tooltip on the node
269 * @param node - the node we want the tooltip to apply on
271 public initNodeTooltip(node:Cy.CollectionNodes) {
274 content: function () {
275 return this.data('name');
280 adjust: {x: 0, y: -5}
283 classes: 'qtip-dark qtip-rounded qtip-custom',
293 hide: {event: 'mouseout mousedown'},
297 if (node.data().isUcpePart) { //fix tooltip positioning for UCPE-cps
298 opts.position.adjust = {x: 0, y: 20};