blob: 668f25107f26645b6931b162824ce9283af1237c [file] [log] [blame]
kumaran.m3b4814a2020-05-01 19:48:54 +05301/*
2 Copyright 2020 TATA ELXSI
3
4 Licensed under the Apache License, Version 2.0 (the 'License');
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
17 */
18/**
19 * @file NS Topology Component
20 */
21/* tslint:disable:no-increment-decrement */
22import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
23import { ActivatedRoute } from '@angular/router';
24import { Router } from '@angular/router';
25import { TranslateService } from '@ngx-translate/core';
26import { ERRORDATA } from 'CommonModel';
27import * as d3 from 'd3';
28import { environment } from 'environment';
29import * as HttpStatus from 'http-status-codes';
Barath Kumar R063a3f12020-12-29 16:35:09 +053030import { CCI, DF, VLC, VNFPROFILE } from 'NSDModel';
kumaran.m3b4814a2020-05-01 19:48:54 +053031import { COMPOSERNODES, CONNECTIONPOINT, NSD, NSDVLD, NSINFO, NSInstanceDetails, NSINSTANCENODES, VLINFO, VNFRINFO } from 'NSInstanceModel';
32import { GRAPHDETAILS, Tick, TickPath } from 'NSTopologyModel';
33import { RestService } from 'src/services/RestService';
34import { isNullOrUndefined } from 'util';
35
36/**
37 * Creating component
38 * @Component takes NSTopologyComponent.html as template url
39 */
40@Component({
41 selector: 'app-ns-topology',
42 templateUrl: './NSTopologyComponent.html',
43 styleUrls: ['./NSTopologyComponent.scss'],
44 encapsulation: ViewEncapsulation.None
45})
46/** Exporting a class @exports NSTopologyComponent */
47export class NSTopologyComponent {
48 /** Injector to invoke other services @public */
49 public injector: Injector;
50 /** View child contains graphContainer ref @public */
51 @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
52 /** Holds the basic information of NS @public */
53 public nsInfo: NSINFO;
54 /** Contains tranlsate instance @private */
55 public translateService: TranslateService;
56 /** Add the activeclass for the selected @public */
57 public activeClass: string = 'active';
58 /** Add the fixed class for the freeze @public */
59 public fixedClass: string = 'fixed';
60 /** Check the loading results @public */
61 public isLoadingResults: boolean = true;
62 /** Give the message for the loading @public */
63 public message: string = 'PLEASEWAIT';
64 /** Assign the forcesimulation active @public */
65 public forceSimulationActive: boolean = false;
66 /** Assign pinned class for the button when freezed @public */
67 public classApplied: boolean = false;
68 /** Contains sidebar open status @public */
69 public sideBarOpened: boolean = true;
70 /** Need to show the NS Details @public */
71 public isShowNSDetails: boolean = true;
72 /** Need to show the VL Details @public */
73 public isShowVLetails: boolean = false;
74 /** Need to show the VNFR Details @public */
75 public isShowVNFRDetails: boolean = false;
76 /** Show right side info of Virtual Link @public */
77 public virtualLink: VLINFO;
78 /** Show right side info of Virtual Link @public */
79 public vnfr: VNFRINFO;
80
81 /** Contains lastkeypressed instance @private */
82 private lastKeyDown: number = -1;
83 /** Instance of the rest service @private */
84 private restService: RestService;
85 /** Holds the instance of AuthService class of type AuthService @private */
86 private activatedRoute: ActivatedRoute;
87 /** Holds the NS Id @private */
88 private nsIdentifier: string;
89 /** Contains SVG attributes @private */
90 // tslint:disable-next-line:no-any
91 private svg: any;
92 /** Contains forced node animations @private */
93 // tslint:disable-next-line:no-any
94 private force: any;
95 /** Contains path information of the node */
96 // tslint:disable-next-line:no-any
97 private path: any;
98 /** Contains node network @private */
99 // tslint:disable-next-line:no-any
100 private network: any;
101 /** Contains node square @private */
102 // tslint:disable-next-line:no-any
103 private square: any;
104 /** Contains node circle @private */
105 // tslint:disable-next-line:no-any
106 private circle: any;
107 /** Contains the NS information @private */
108 private nsData: NSInstanceDetails;
109 /** Contains NDS information of a descriptors */
110 private nsdData: NSD;
111 /** Contains node information @private */
112 private nodes: NSINSTANCENODES[] = [];
113 /** Contains links information @private */
114 private links: {}[] = [];
115 /** holds cp count/iteration @private */
116 private cpCount: number;
117 /** VNFD nodes @private */
118 private vnfdNodes: {}[] = [];
119 /** VLD nodes @private */
120 private vldNodes: {}[] = [];
121 /** Connection CP nodes @private */
122 private cpNodes: {}[] = [];
123 /** Set timeout @private */
124 private TIMEOUT: number = 2000;
125 /** Rendered nodes represent vnf @private */
126 // tslint:disable-next-line:no-any
127 private gSquare: any;
128 /** Rendered nodes represent network @private */
129 // tslint:disable-next-line:no-any
130 private gNetwork: any;
131 /** Rendered nodes represent network @private */
132 // tslint:disable-next-line:no-any
133 private gCircle: any;
134 /** Service holds the router information @private */
135 private router: Router;
136
137 constructor(injector: Injector) {
138 this.injector = injector;
139 this.restService = this.injector.get(RestService);
140 this.activatedRoute = this.injector.get(ActivatedRoute);
141 this.translateService = this.injector.get(TranslateService);
142 this.router = this.injector.get(Router);
143 }
144
145 /**
146 * Lifecyle Hooks the trigger before component is instantiate @public
147 */
148 public ngOnInit(): void {
149 // tslint:disable-next-line:no-backbone-get-set-outside-model
150 this.nsIdentifier = this.activatedRoute.snapshot.paramMap.get('id');
151 this.generateData();
152 }
153 /** Event to freeze the animation @public */
154 public onFreeze(): void {
155 this.classApplied = !this.classApplied;
156 const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
157 d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
158 if (alreadyFixedIsActive) {
159 this.force.stop();
160 }
161 this.forceSimulationActive = alreadyFixedIsActive;
Barath Kumar R063a3f12020-12-29 16:35:09 +0530162 this.nodes.forEach((d: COMPOSERNODES): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530163 d.fx = (alreadyFixedIsActive) ? null : d.x;
164 d.fy = (alreadyFixedIsActive) ? null : d.y;
165 });
166 if (alreadyFixedIsActive) {
167 this.force.restart();
168 }
169 }
170 /** Events handles when dragended @public */
171 public toggleSidebar(): void {
172 this.sideBarOpened = !this.sideBarOpened;
173 this.deselectAllNodes();
174 this.showRightSideInfo(true, false, false);
175 }
176 /** Get the default Configuration of containers @private */
177 private getGraphContainerAttr(): GRAPHDETAILS {
178 return {
179 width: 700,
180 height: 400,
181 nodeHeight: 50,
182 nodeWidth: 35,
183 textX: -35,
184 textY: 30,
185 radius: 5,
186 distance: 50,
187 strength: -500,
188 forcex: 2,
189 forcey: 2,
190 sourcePaddingYes: 17,
191 sourcePaddingNo: 12,
192 targetPaddingYes: 4,
193 targetPaddingNo: 3,
194 alphaTarget: 0.3,
195 imageX: -25,
196 imageY: -25,
197 shiftKeyCode: 17
198 };
199 }
200 /** Show the right-side information @private */
201 private showRightSideInfo(nsDetails: boolean, vlDetails: boolean, vnfrDeails: boolean): void {
202 this.isShowNSDetails = nsDetails;
203 this.isShowVLetails = vlDetails;
204 this.isShowVNFRDetails = vnfrDeails;
205 }
206 /** De-select all the selected nodes @private */
207 private deselectAllNodes(): void {
208 this.square.select('image').classed(this.activeClass, false);
209 this.network.select('image').classed(this.activeClass, false);
210 this.circle.select('image').classed(this.activeClass, false);
211 }
212 /** Prepare all the information for node creation @private */
213 private generateData(): void {
Barath Kumar R063a3f12020-12-29 16:35:09 +0530214 this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.nsIdentifier)
215 .subscribe((nsData: NSInstanceDetails): void => {
216 this.nsData = nsData;
217 this.nsInfo = {
218 nsInstanceID: nsData._id,
219 nsName: nsData.name,
220 nsOperationalStatus: nsData['operational-status'],
221 nsConfigStatus: nsData['config-status'],
222 nsDetailedStatus: nsData['detailed-status'],
223 nsResourceOrchestrator: nsData['resource-orchestrator']
224 };
225 if (this.nsData['constituent-vnfr-ref'] !== undefined) {
226 this.generateVNFRCPNodes();
227 }
228 if (this.nsData.vld !== undefined) {
229 this.generateVLDNetworkNodes();
230 }
231 setTimeout((): void => {
232 this.pushAllNodes();
233 this.generateVNFDCP();
234 this.generateVLDCP();
235 this.isLoadingResults = false;
236 this.createNode(this.nodes, this.links);
237 }, this.TIMEOUT);
238 }, (error: ERRORDATA): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530239 this.isLoadingResults = false;
Barath Kumar R063a3f12020-12-29 16:35:09 +0530240 if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
241 this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
242 } else {
243 this.restService.handleError(error, 'get');
244 }
245 });
kumaran.m3b4814a2020-05-01 19:48:54 +0530246 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530247 /** Fetching all the VNFR Information @private */
248 private generateVNFRCPNodes(): void {
Barath Kumar R063a3f12020-12-29 16:35:09 +0530249 this.nsData['constituent-vnfr-ref'].forEach((vnfdrID: string): void => {
250 this.restService.getResource(environment.VNFINSTANCES_URL + '/' + vnfdrID).subscribe((vndfrDetail: NSD): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530251 this.nodes.push({
252 id: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
253 nodeTypeRef: 'vnfd',
254 cp: vndfrDetail['connection-point'],
255 vdur: vndfrDetail.vdur,
kumaran.m3b4814a2020-05-01 19:48:54 +0530256 nsID: vndfrDetail['nsr-id-ref'],
257 vnfdID: vndfrDetail['vnfd-id'],
258 vimID: vndfrDetail['vim-account-id'],
259 vndfrID: vndfrDetail.id,
260 ipAddress: vndfrDetail['ip-address'],
261 memberIndex: vndfrDetail['member-vnf-index-ref'],
262 vnfdRef: vndfrDetail['vnfd-ref'],
263 selectorId: 'nsInst-' + vndfrDetail.id
264 });
265 // Fetching all the connection point of VNF & Interface
Barath Kumar R063a3f12020-12-29 16:35:09 +0530266 vndfrDetail['connection-point'].forEach((cp: CONNECTIONPOINT): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530267 this.nodes.push({
268 id: cp.name + ':' + vndfrDetail['member-vnf-index-ref'],
269 vndfCPRef: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
270 nodeTypeRef: 'cp',
271 name: cp.name
272 });
273 });
Barath Kumar R063a3f12020-12-29 16:35:09 +0530274 }, (error: ERRORDATA): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530275 this.restService.handleError(error, 'get');
276 });
277 });
278 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530279 /** Fetching all the VLD/Network Information @private */
280 private generateVLDNetworkNodes(): void {
281 this.nsdData = this.nsData.nsd;
Barath Kumar R063a3f12020-12-29 16:35:09 +0530282 this.nsdData['virtual-link-desc'].forEach((ref: NSDVLD): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530283 this.nodes.push({
284 id: ref.id,
285 nodeTypeRef: 'vld',
Barath Kumar R063a3f12020-12-29 16:35:09 +0530286 name: ref.id,
kumaran.m3b4814a2020-05-01 19:48:54 +0530287 type: ref.type,
Barath Kumar R063a3f12020-12-29 16:35:09 +0530288 vnfdCP: this.nsdData.df,
kumaran.m3b4814a2020-05-01 19:48:54 +0530289 vimNetworkName: ref['vim-network-name'],
kumaran.m3b4814a2020-05-01 19:48:54 +0530290 selectorId: 'nsInst-' + ref.id
291 });
292 });
293 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530294 /** Pushing connection points of path/links nodes @private */
295 private pushAllNodes(): void {
Barath Kumar R063a3f12020-12-29 16:35:09 +0530296 this.nodes.forEach((nodeList: NSINSTANCENODES): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530297 if (nodeList.nodeTypeRef === 'vnfd') {
298 this.vnfdNodes.push(nodeList);
299 } else if (nodeList.nodeTypeRef === 'vld') {
300 this.vldNodes.push(nodeList);
301 } else if (nodeList.nodeTypeRef === 'cp') {
302 this.cpNodes.push(nodeList);
303 }
304 });
305 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530306 /** Get CP position based on vndf @private */
307 private generateVNFDCP(): void {
Barath Kumar R063a3f12020-12-29 16:35:09 +0530308 this.vnfdNodes.forEach((list: NSINSTANCENODES): void => {
309 const vndfPos: number = this.nodes.map((e: NSINSTANCENODES): string => { return e.id; }).indexOf(list.id);
kumaran.m3b4814a2020-05-01 19:48:54 +0530310 this.cpCount = 0;
Barath Kumar R063a3f12020-12-29 16:35:09 +0530311 this.nodes.forEach((res: NSINSTANCENODES): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530312 if (res.nodeTypeRef === 'cp' && res.vndfCPRef === list.id) {
313 this.links.push({ source: this.nodes[vndfPos], target: this.nodes[this.cpCount] });
314 }
315 this.cpCount++;
316 });
317 });
318 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530319 /** Get CP position based on vld @private */
320 private generateVLDCP(): void {
321 let vldPos: number = 0;
Barath Kumar R063a3f12020-12-29 16:35:09 +0530322 this.vldNodes.forEach((list: NSINSTANCENODES): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530323 if (!isNullOrUndefined(list.vnfdCP)) {
Barath Kumar R063a3f12020-12-29 16:35:09 +0530324 list.vnfdCP.forEach((cpRef: DF): void => {
325 cpRef['vnf-profile'].forEach((vnfProfile: VNFPROFILE): void => {
326 vnfProfile['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
327 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
328 this.cpCount = 0;
329 this.nodes.forEach((res: NSINSTANCENODES): void => {
330 if (res.nodeTypeRef === 'cp' &&
331 res.id === resultCCI['constituent-cpd-id'] + ':' + resultCCI['constituent-base-element-id']) {
332 this.links.push({ source: this.nodes[vldPos], target: this.nodes[this.cpCount] });
333 }
334 this.cpCount++;
335 });
336 });
337 });
kumaran.m3b4814a2020-05-01 19:48:54 +0530338 });
339 });
340 vldPos++;
341 }
342 });
343 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530344 /** Node is created and render at D3 region @private */
345 private createNode(nodes: NSINSTANCENODES[], links: {}[]): void {
346 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
347 d3.selectAll('svg#graphContainer > *').remove();
Barath Kumar R063a3f12020-12-29 16:35:09 +0530348 d3.select(window).on('keydown', (): void => { this.keyDown(); });
349 d3.select(window).on('keyup', (): void => { this.keyUp(); });
kumaran.m3b4814a2020-05-01 19:48:54 +0530350 this.svg = d3.select('#graphContainer')
351 .attr('oncontextmenu', 'return false;')
352 .attr('width', graphContainerAttr.width)
353 .attr('height', graphContainerAttr.height);
354 this.force = d3.forceSimulation()
355 .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
Barath Kumar R063a3f12020-12-29 16:35:09 +0530356 .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
kumaran.m3b4814a2020-05-01 19:48:54 +0530357 .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
358 graphContainerAttr.height / graphContainerAttr.forcey))
359 .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
360 .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
Barath Kumar R063a3f12020-12-29 16:35:09 +0530361 .on('tick', (): void => { this.tick(); });
kumaran.m3b4814a2020-05-01 19:48:54 +0530362 // handles to link and node element groups
363 this.path = this.svg.append('svg:g').selectAll('path');
364 this.network = this.svg.append('svg:g').selectAll('network');
365 this.square = this.svg.append('svg:g').selectAll('rect');
366 this.circle = this.svg.append('svg:g').selectAll('circle');
367 this.restart(nodes, links);
368 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530369 /** Update force layout (called automatically each iteration) @private */
370 private tick(): void {
371 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
372 // draw directed edges with proper padding from node centers
Barath Kumar R063a3f12020-12-29 16:35:09 +0530373 this.path.attr('class', 'link').attr('d', (d: Tick): string => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530374 const deltaX: number = d.target.x - d.source.x;
375 const deltaY: number = d.target.y - d.source.y;
376 const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
377 const normX: number = deltaX / dist;
378 const normY: number = deltaY / dist;
379 const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
380 const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
381 const sourceX: number = d.source.x + (sourcePadding * normX);
382 const sourceY: number = d.source.y + (sourcePadding * normY);
383 const targetX: number = d.target.x - (targetPadding * normX);
384 const targetY: number = d.target.y - (targetPadding * normY);
385 return `M${sourceX},${sourceY}L${targetX},${targetY}`;
386 });
Barath Kumar R063a3f12020-12-29 16:35:09 +0530387 this.network.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
388 this.square.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
389 this.circle.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
kumaran.m3b4814a2020-05-01 19:48:54 +0530390 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530391 /** Update graph (called when needed) @private */
392 private restart(nodes: NSINSTANCENODES[], links: {}[]): void {
393 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
394 this.path = this.path.data(links);
395 const vnfdNodes: {}[] = []; const vldNodes: {}[] = []; const cpNodes: {}[] = []; // NB: Nodes are known by id, not by index!
Barath Kumar R063a3f12020-12-29 16:35:09 +0530396 nodes.forEach((nodeList: NSINSTANCENODES): void => {
kumaran.m3b4814a2020-05-01 19:48:54 +0530397 if (nodeList.nodeTypeRef === 'vnfd') { vnfdNodes.push(nodeList); }
398 else if (nodeList.nodeTypeRef === 'vld') { vldNodes.push(nodeList); }
399 else if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); }
400 });
Barath Kumar R063a3f12020-12-29 16:35:09 +0530401 this.square = this.square.data(vnfdNodes, (d: COMPOSERNODES): string => d.id);
402 this.network = this.network.data(vldNodes, (d: COMPOSERNODES): string => d.id);
403 this.circle = this.circle.data(cpNodes, (d: COMPOSERNODES): string => d.id);
kumaran.m3b4814a2020-05-01 19:48:54 +0530404 this.resetAndCreateNodes();
405 this.force.nodes(nodes).force('link').links(links); //Set the graph in motion
406 this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
407 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530408 /** Rest and create nodes @private */
409 private resetAndCreateNodes(): void {
410 this.path.exit().remove();
411 this.square.exit().remove();
412 this.network.exit().remove();
413 this.circle.exit().remove();
414 // tslint:disable-next-line:no-any
415 const gPath: any = this.path.enter().append('svg:path').attr('class', 'link');
416 this.getgSquare();
417 this.getgNetwork();
418 this.getgCircle();
419 this.square = this.gSquare.merge(this.square);
420 this.network = this.gNetwork.merge(this.network);
421 this.path = gPath.merge(this.path);
422 this.circle = this.gCircle.merge(this.circle);
423 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530424 /** Events handles when Shift Click to perform create cp @private */
425 // tslint:disable-next-line: no-any
426 private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
427 this.selectNodeExclusive(nodeSelected, d);
428 }
429 /** Selected nodes @private */
430 // tslint:disable-next-line: no-any
431 private selectNodeExclusive(nodeSelected: any, d: COMPOSERNODES): void {
432 const alreadyIsActive: boolean = nodeSelected.select('#' + d.selectorId).classed(this.activeClass);
433 this.deselectAllNodes();
434 nodeSelected.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
435 if (d.nodeTypeRef === 'vld' && !alreadyIsActive) {
436 this.virtualLink = {
437 id: d.id,
438 name: d.name,
439 type: d.type,
440 shortName: d.shortName,
441 vimNetworkName: d.vimNetworkName
442 };
443 this.showRightSideInfo(false, true, false);
444 } else if (d.nodeTypeRef === 'vnfd' && !alreadyIsActive) {
445 this.vnfr = {
446 vimID: d.vimID,
447 _id: d.vndfrID,
448 ip: d.ipAddress,
449 nsrID: d.nsID,
450 id: d.selectorId,
451 vnfdRef: d.vnfdRef,
452 vnfdId: d.vnfdID,
453 memberIndex: d.memberIndex
454 };
455 this.showRightSideInfo(false, false, true);
456 } else {
457 this.showRightSideInfo(true, false, false);
458 }
459 }
460 /** Setting all the square/vnf attributes of nodes @private */
461 private getgSquare(): void {
462 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
463 this.gSquare = this.square.enter().append('svg:g');
464 this.gSquare.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
465 this.gSquare.append('svg:image')
466 .style('opacity', 1)
467 .attr('x', graphContainerAttr.imageX)
468 .attr('y', graphContainerAttr.imageY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530469 .call(this.onDragDrop())
470 .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
kumaran.m3b4814a2020-05-01 19:48:54 +0530471 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
472 .attr('xlink:href', 'assets/images/VNFD.svg')
Barath Kumar R063a3f12020-12-29 16:35:09 +0530473 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.gSquare, d); this.onNodeClickToggleSidebar(); });
kumaran.m3b4814a2020-05-01 19:48:54 +0530474 this.gSquare.append('svg:text')
475 .attr('class', 'node_text')
476 .attr('y', graphContainerAttr.textY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530477 .text((d: COMPOSERNODES): string => d.id);
kumaran.m3b4814a2020-05-01 19:48:54 +0530478 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530479 /** Settings all the network attributes of nodes @private */
480 private getgNetwork(): void {
481 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
482 this.gNetwork = this.network.enter().append('svg:g');
483 this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
484 this.gNetwork.append('svg:image')
485 .style('opacity', 1)
486 .attr('x', graphContainerAttr.imageX)
487 .attr('y', graphContainerAttr.imageY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530488 .call(this.onDragDrop())
489 .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
kumaran.m3b4814a2020-05-01 19:48:54 +0530490 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
491 .attr('xlink:href', 'assets/images/VL.svg')
Barath Kumar R063a3f12020-12-29 16:35:09 +0530492 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.gNetwork, d); this.onNodeClickToggleSidebar(); });
kumaran.m3b4814a2020-05-01 19:48:54 +0530493 this.gNetwork.append('svg:text')
494 .attr('class', 'node_text')
495 .attr('y', graphContainerAttr.textY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530496 .text((d: COMPOSERNODES): string => d.name);
kumaran.m3b4814a2020-05-01 19:48:54 +0530497 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530498 /** Settings all the connection point attributes of nodes @private */
499 private getgCircle(): void {
500 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
501 this.gCircle = this.circle.enter().append('svg:g');
502 this.gCircle.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
503 this.gCircle.append('svg:image')
504 .style('opacity', 1)
505 .attr('x', graphContainerAttr.imageX)
506 .attr('y', graphContainerAttr.imageY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530507 .call(this.onDragDrop())
kumaran.m3b4814a2020-05-01 19:48:54 +0530508 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
509 .attr('xlink:href', 'assets/images/CP.svg');
510 this.gCircle.append('svg:text')
511 .attr('class', 'node_text')
512 .attr('y', graphContainerAttr.textY)
Barath Kumar R063a3f12020-12-29 16:35:09 +0530513 .text((d: COMPOSERNODES): string => d.name);
kumaran.m3b4814a2020-05-01 19:48:54 +0530514 }
Barath Kumar R063a3f12020-12-29 16:35:09 +0530515 /** drag event @private */
516 // tslint:disable-next-line: no-any
517 private onDragDrop(): any {
518 return d3.drag().filter(this.dragFilter)
519 .on('start', this.dragstarted)
520 .on('drag', this.dragged)
521 .on('end', this.dragended);
522 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530523 /** Key press event @private */
524 private keyDown(): void {
525 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
526 if (this.lastKeyDown !== -1) { return; }
527 this.lastKeyDown = d3.event.keyCode;
528 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
529 this.gSquare.call(d3.drag()
530 .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
531 );
532 this.gNetwork.call(d3.drag()
533 .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
534 );
535 this.gCircle.call(d3.drag()
536 .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
537 );
538 this.svg.classed('ctrl', true);
539 }
540 }
541 /** Key realse event @private */
542 private keyUp(): void {
543 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
544 this.lastKeyDown = -1;
545 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
546 this.gSquare.on('.drag', null);
547 this.gNetwork.on('.drag', null);
548 this.gCircle.on('.drag', null);
549 this.svg.classed('ctrl', false);
550 }
551 }
Barath Kumar R063a3f12020-12-29 16:35:09 +0530552 /** Events handles when to drag using filter for the keys @private */
553 private dragFilter(): boolean {
554 return d3.event.ctrlKey && !d3.event.button;
555 }
kumaran.m3b4814a2020-05-01 19:48:54 +0530556 /** Events handles when dragstarted @private */
557 private dragstarted(d: COMPOSERNODES): void {
558 d.fx = d.x;
559 d.fy = d.y;
560 }
561 /** Events handles when dragged @private */
562 private dragged(d: COMPOSERNODES): void {
563 d.fx = d.x = d3.event.x;
564 d.fy = d.y = d3.event.y;
565 }
566 /** Events handles when dragended @private */
567 private dragended(d: COMPOSERNODES): void {
568 if (this.forceSimulationActive) {
569 d.fx = null;
570 d.fy = null;
571 } else {
572 d.fx = d.x;
573 d.fy = d.y;
574 this.forceSimulationActive = false;
575 }
576 }
577 /** Events handles when node single click @private */
578 private onNodeClickToggleSidebar(): void {
579 this.sideBarOpened = true;
580 }
581}