Fix Bug 2121: NG-UI uses unmaintained Chokidar version
[osm/NG-UI.git] / src / app / instances / ns-topology / NSTopologyComponent.ts
1 /*
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 /* eslint-disable */
22 import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
23 import { ActivatedRoute } from '@angular/router';
24 import { Router } from '@angular/router';
25 import { TranslateService } from '@ngx-translate/core';
26 import { ERRORDATA } from 'CommonModel';
27 import * as d3 from 'd3';
28 import { environment } from 'environment';
29 import * as HttpStatus from 'http-status-codes';
30 import { CCI, DF, VLC, VNFPROFILE } from 'NSDModel';
31 import { COMPOSERNODES, CONNECTIONPOINT, NSD, NSDVLD, NSINFO, NSInstanceDetails, NSINSTANCENODES, VLINFO, VNFRINFO } from 'NSInstanceModel';
32 import { GRAPHDETAILS, Tick, TickPath } from 'NSTopologyModel';
33 import { RestService } from 'src/services/RestService';
34 import { 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 */
47 export 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   // eslint-disable-next-line @typescript-eslint/no-explicit-any
91   private svg: any;
92   /** Contains forced node animations @private */
93   // eslint-disable-next-line @typescript-eslint/no-explicit-any
94   private force: any;
95   /** Contains path information of the node */
96   // eslint-disable-next-line @typescript-eslint/no-explicit-any
97   private path: any;
98   /** Contains node network @private */
99   // eslint-disable-next-line @typescript-eslint/no-explicit-any
100   private network: any;
101   /** Contains node square @private */
102   // eslint-disable-next-line @typescript-eslint/no-explicit-any
103   private square: any;
104   /** Contains node circle @private */
105   // eslint-disable-next-line @typescript-eslint/no-explicit-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   // eslint-disable-next-line @typescript-eslint/no-explicit-any
127   private gSquare: any;
128   /** Rendered nodes represent network @private */
129   // eslint-disable-next-line @typescript-eslint/no-explicit-any
130   private gNetwork: any;
131   /** Rendered nodes represent network @private */
132   // eslint-disable-next-line @typescript-eslint/no-explicit-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     this.nsIdentifier = this.activatedRoute.snapshot.paramMap.get('id');
150     this.generateData();
151   }
152   /** Event to freeze the animation @public */
153   public onFreeze(): void {
154     this.classApplied = !this.classApplied;
155     const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
156     d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
157     if (alreadyFixedIsActive) {
158       this.force.stop();
159     }
160     this.forceSimulationActive = alreadyFixedIsActive;
161     this.nodes.forEach((d: COMPOSERNODES): void => {
162       d.fx = (alreadyFixedIsActive) ? null : d.x;
163       d.fy = (alreadyFixedIsActive) ? null : d.y;
164     });
165     if (alreadyFixedIsActive) {
166       this.force.restart();
167     }
168   }
169   /** Events handles when dragended @public */
170   public toggleSidebar(): void {
171     this.sideBarOpened = !this.sideBarOpened;
172     this.deselectAllNodes();
173     this.showRightSideInfo(true, false, false);
174   }
175   /** Get the default Configuration of containers @private */
176   private getGraphContainerAttr(): GRAPHDETAILS {
177     return {
178       width: 700,
179       height: 400,
180       nodeHeight: 50,
181       nodeWidth: 35,
182       textX: -35,
183       textY: 30,
184       radius: 5,
185       distance: 50,
186       strength: -500,
187       forcex: 2,
188       forcey: 2,
189       sourcePaddingYes: 17,
190       sourcePaddingNo: 12,
191       targetPaddingYes: 4,
192       targetPaddingNo: 3,
193       alphaTarget: 0.3,
194       imageX: -25,
195       imageY: -25,
196       shiftKeyCode: 17
197     };
198   }
199   /** Show the right-side information @private */
200   private showRightSideInfo(nsDetails: boolean, vlDetails: boolean, vnfrDeails: boolean): void {
201     this.isShowNSDetails = nsDetails;
202     this.isShowVLetails = vlDetails;
203     this.isShowVNFRDetails = vnfrDeails;
204   }
205   /** De-select all the selected nodes @private */
206   private deselectAllNodes(): void {
207     this.square.select('image').classed(this.activeClass, false);
208     this.network.select('image').classed(this.activeClass, false);
209     this.circle.select('image').classed(this.activeClass, false);
210   }
211   /** Prepare all the information for node creation @private */
212   private generateData(): void {
213     this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.nsIdentifier)
214       .subscribe((nsData: NSInstanceDetails): void => {
215         this.nsData = nsData;
216         this.nsInfo = {
217           nsInstanceID: nsData._id,
218           nsName: nsData.name,
219           nsOperationalStatus: nsData['operational-status'],
220           nsConfigStatus: nsData['config-status'],
221           nsDetailedStatus: nsData['detailed-status'],
222           nsResourceOrchestrator: nsData['resource-orchestrator']
223         };
224         if (this.nsData['constituent-vnfr-ref'] !== undefined) {
225           this.generateVNFRCPNodes();
226         }
227         if (this.nsData.vld !== undefined) {
228           this.generateVLDNetworkNodes();
229         }
230         setTimeout((): void => {
231           this.pushAllNodes();
232           this.generateVNFDCP();
233           this.generateVLDCP();
234           this.isLoadingResults = false;
235           this.createNode(this.nodes, this.links);
236         }, this.TIMEOUT);
237       }, (error: ERRORDATA): void => {
238         this.isLoadingResults = false;
239         if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
240           this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
241             // Catch Navigation Error
242         });
243         } else {
244           this.restService.handleError(error, 'get');
245         }
246       });
247   }
248   /** Fetching all the VNFR Information @private */
249   private generateVNFRCPNodes(): void {
250     this.nsData['constituent-vnfr-ref'].forEach((vnfdrID: string): void => {
251       this.restService.getResource(environment.VNFINSTANCES_URL + '/' + vnfdrID).subscribe((vndfrDetail: NSD): void => {
252         this.nodes.push({
253           id: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
254           nodeTypeRef: 'vnfd',
255           cp: vndfrDetail['connection-point'],
256           vdur: vndfrDetail.vdur,
257           nsID: vndfrDetail['nsr-id-ref'],
258           vnfdID: vndfrDetail['vnfd-id'],
259           vimID: vndfrDetail['vim-account-id'],
260           vndfrID: vndfrDetail.id,
261           ipAddress: vndfrDetail['ip-address'],
262           memberIndex: vndfrDetail['member-vnf-index-ref'],
263           vnfdRef: vndfrDetail['vnfd-ref'],
264           selectorId: 'nsInst-' + vndfrDetail.id
265         });
266         // Fetching all the connection point of VNF & Interface
267         vndfrDetail['connection-point'].forEach((cp: CONNECTIONPOINT): void => {
268           this.nodes.push({
269             id: cp.name + ':' + vndfrDetail['member-vnf-index-ref'],
270             vndfCPRef: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'],
271             nodeTypeRef: 'cp',
272             name: cp.name
273           });
274         });
275       }, (error: ERRORDATA): void => {
276         this.restService.handleError(error, 'get');
277       });
278     });
279   }
280   /** Fetching all the VLD/Network Information @private */
281   private generateVLDNetworkNodes(): void {
282     this.nsdData = this.nsData.nsd;
283     this.nsdData['virtual-link-desc'].forEach((ref: NSDVLD): void => {
284       this.nodes.push({
285         id: ref.id,
286         nodeTypeRef: 'vld',
287         name: ref.id,
288         type: ref.type,
289         vnfdCP: this.nsdData.df,
290         vimNetworkName: ref['vim-network-name'],
291         selectorId: 'nsInst-' + ref.id
292       });
293     });
294   }
295   /** Pushing connection points of path/links nodes @private */
296   private pushAllNodes(): void {
297     this.nodes.forEach((nodeList: NSINSTANCENODES): void => {
298       if (nodeList.nodeTypeRef === 'vnfd') {
299         this.vnfdNodes.push(nodeList);
300       } else if (nodeList.nodeTypeRef === 'vld') {
301         this.vldNodes.push(nodeList);
302       } else if (nodeList.nodeTypeRef === 'cp') {
303         this.cpNodes.push(nodeList);
304       }
305     });
306   }
307   /** Get CP position based on vndf @private */
308   private generateVNFDCP(): void {
309     this.vnfdNodes.forEach((list: NSINSTANCENODES): void => {
310       const vndfPos: number = this.nodes.map((e: NSINSTANCENODES): string => { return e.id; }).indexOf(list.id);
311       this.cpCount = 0;
312       this.nodes.forEach((res: NSINSTANCENODES): void => {
313         if (res.nodeTypeRef === 'cp' && res.vndfCPRef === list.id) {
314           this.links.push({ source: this.nodes[vndfPos], target: this.nodes[this.cpCount] });
315         }
316         this.cpCount++;
317       });
318     });
319   }
320   /** Get CP position based on vld @private */
321   private generateVLDCP(): void {
322     let vldPos: number = 0;
323     this.vldNodes.forEach((list: NSINSTANCENODES): void => {
324       if (!isNullOrUndefined(list.vnfdCP)) {
325         list.vnfdCP.forEach((cpRef: DF): void => {
326           cpRef['vnf-profile'].forEach((vnfProfile: VNFPROFILE): void => {
327             vnfProfile['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
328               resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
329                 this.cpCount = 0;
330                 this.nodes.forEach((res: NSINSTANCENODES): void => {
331                   if (res.nodeTypeRef === 'cp' &&
332                     res.id === resultCCI['constituent-cpd-id'] + ':' + resultCCI['constituent-base-element-id']) {
333                     this.links.push({ source: this.nodes[vldPos], target: this.nodes[this.cpCount] });
334                   }
335                   this.cpCount++;
336                 });
337               });
338             });
339           });
340         });
341         vldPos++;
342       }
343     });
344   }
345   /** Node is created and render at D3 region @private */
346   private createNode(nodes: NSINSTANCENODES[], links: {}[]): void {
347     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
348     d3.selectAll('svg#graphContainer > *').remove();
349     d3.select(window).on('keydown', (): void => { this.keyDown(); });
350     d3.select(window).on('keyup', (): void => { this.keyUp(); });
351     this.svg = d3.select('#graphContainer')
352       .attr('oncontextmenu', 'return false;')
353       .attr('width', graphContainerAttr.width)
354       .attr('height', graphContainerAttr.height);
355     this.force = d3.forceSimulation()
356       .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
357       .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
358       .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
359         graphContainerAttr.height / graphContainerAttr.forcey))
360       .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
361       .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
362       .on('tick', (): void => { this.tick(); });
363     // handles to link and node element groups
364     this.path = this.svg.append('svg:g').selectAll('path');
365     this.network = this.svg.append('svg:g').selectAll('network');
366     this.square = this.svg.append('svg:g').selectAll('rect');
367     this.circle = this.svg.append('svg:g').selectAll('circle');
368     this.restart(nodes, links);
369   }
370   /** Update force layout (called automatically each iteration) @private */
371   private tick(): void {
372     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
373     // draw directed edges with proper padding from node centers
374     this.path.attr('class', 'link').attr('d', (d: Tick): string => {
375       const deltaX: number = d.target.x - d.source.x;
376       const deltaY: number = d.target.y - d.source.y;
377       const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
378       const normX: number = deltaX / dist;
379       const normY: number = deltaY / dist;
380       const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
381       const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
382       const sourceX: number = d.source.x + (sourcePadding * normX);
383       const sourceY: number = d.source.y + (sourcePadding * normY);
384       const targetX: number = d.target.x - (targetPadding * normX);
385       const targetY: number = d.target.y - (targetPadding * normY);
386       return `M${sourceX},${sourceY}L${targetX},${targetY}`;
387     });
388     this.network.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
389     this.square.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
390     this.circle.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
391   }
392   /** Update graph (called when needed) @private */
393   private restart(nodes: NSINSTANCENODES[], links: {}[]): void {
394     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
395     this.path = this.path.data(links);
396     const vnfdNodes: {}[] = []; const vldNodes: {}[] = []; const cpNodes: {}[] = []; // NB: Nodes are known by id, not by index!
397     nodes.forEach((nodeList: NSINSTANCENODES): void => {
398       if (nodeList.nodeTypeRef === 'vnfd') { vnfdNodes.push(nodeList); }
399       else if (nodeList.nodeTypeRef === 'vld') { vldNodes.push(nodeList); }
400       else if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); }
401     });
402     this.square = this.square.data(vnfdNodes, (d: COMPOSERNODES): string => d.id);
403     this.network = this.network.data(vldNodes, (d: COMPOSERNODES): string => d.id);
404     this.circle = this.circle.data(cpNodes, (d: COMPOSERNODES): string => d.id);
405     this.resetAndCreateNodes();
406     this.force.nodes(nodes).force('link').links(links); //Set the graph in motion
407     this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
408   }
409   /** Rest and create nodes @private */
410   private resetAndCreateNodes(): void {
411     this.path.exit().remove();
412     this.square.exit().remove();
413     this.network.exit().remove();
414     this.circle.exit().remove();
415     // eslint-disable-next-line @typescript-eslint/no-explicit-any
416     const gPath: any = this.path.enter().append('svg:path').attr('class', 'link');
417     this.getgSquare();
418     this.getgNetwork();
419     this.getgCircle();
420     this.square = this.gSquare.merge(this.square);
421     this.network = this.gNetwork.merge(this.network);
422     this.path = gPath.merge(this.path);
423     this.circle = this.gCircle.merge(this.circle);
424   }
425   /** Events handles when Shift Click to perform create cp @private */
426   // eslint-disable-next-line @typescript-eslint/no-explicit-any
427   private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
428     this.selectNodeExclusive(nodeSelected, d);
429   }
430   /** Selected nodes @private */
431   // eslint-disable-next-line @typescript-eslint/no-explicit-any
432   private selectNodeExclusive(nodeSelected: any, d: COMPOSERNODES): void {
433     const alreadyIsActive: boolean = nodeSelected.select('#' + d.selectorId).classed(this.activeClass);
434     this.deselectAllNodes();
435     nodeSelected.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
436     if (d.nodeTypeRef === 'vld' && !alreadyIsActive) {
437       this.virtualLink = {
438         id: d.id,
439         name: d.name,
440         type: d.type,
441         shortName: d.shortName,
442         vimNetworkName: d.vimNetworkName
443       };
444       this.showRightSideInfo(false, true, false);
445     } else if (d.nodeTypeRef === 'vnfd' && !alreadyIsActive) {
446       this.vnfr = {
447         vimID: d.vimID,
448         _id: d.vndfrID,
449         ip: d.ipAddress,
450         nsrID: d.nsID,
451         id: d.selectorId,
452         vnfdRef: d.vnfdRef,
453         vnfdId: d.vnfdID,
454         memberIndex: d.memberIndex
455       };
456       this.showRightSideInfo(false, false, true);
457     } else {
458       this.showRightSideInfo(true, false, false);
459     }
460   }
461   /** Setting all the square/vnf attributes of nodes @private */
462   private getgSquare(): void {
463     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
464     this.gSquare = this.square.enter().append('svg:g');
465     this.gSquare.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
466     this.gSquare.append('svg:image')
467       .style('opacity', 1)
468       .attr('x', graphContainerAttr.imageX)
469       .attr('y', graphContainerAttr.imageY)
470       .call(this.onDragDrop())
471       .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
472       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
473       .attr('xlink:href', 'assets/images/VNFD.svg')
474       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.gSquare, d); this.onNodeClickToggleSidebar(); });
475     this.gSquare.append('svg:text')
476       .attr('class', 'node_text')
477       .attr('y', graphContainerAttr.textY)
478       .text((d: COMPOSERNODES): string => d.id);
479   }
480   /** Settings all the network attributes of nodes @private */
481   private getgNetwork(): void {
482     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
483     this.gNetwork = this.network.enter().append('svg:g');
484     this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
485     this.gNetwork.append('svg:image')
486       .style('opacity', 1)
487       .attr('x', graphContainerAttr.imageX)
488       .attr('y', graphContainerAttr.imageY)
489       .call(this.onDragDrop())
490       .attr('id', (d: COMPOSERNODES): string => { return d.selectorId; })
491       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
492       .attr('xlink:href', 'assets/images/VL.svg')
493       .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.gNetwork, d); this.onNodeClickToggleSidebar(); });
494     this.gNetwork.append('svg:text')
495       .attr('class', 'node_text')
496       .attr('y', graphContainerAttr.textY)
497       .text((d: COMPOSERNODES): string => d.name);
498   }
499   /** Settings all the connection point attributes of nodes @private */
500   private getgCircle(): void {
501     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
502     this.gCircle = this.circle.enter().append('svg:g');
503     this.gCircle.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
504     this.gCircle.append('svg:image')
505       .style('opacity', 1)
506       .attr('x', graphContainerAttr.imageX)
507       .attr('y', graphContainerAttr.imageY)
508       .call(this.onDragDrop())
509       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
510       .attr('xlink:href', 'assets/images/CP.svg');
511     this.gCircle.append('svg:text')
512       .attr('class', 'node_text')
513       .attr('y', graphContainerAttr.textY)
514       .text((d: COMPOSERNODES): string => d.name);
515   }
516   /** drag event @private */
517   // eslint-disable-next-line @typescript-eslint/no-explicit-any
518   private onDragDrop(): any {
519     return d3.drag().filter(this.dragFilter)
520       .on('start', this.dragstarted)
521       .on('drag', this.dragged)
522       .on('end', this.dragended);
523   }
524   /** Key press event @private */
525   private keyDown(): void {
526     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
527     if (this.lastKeyDown !== -1) { return; }
528     this.lastKeyDown = d3.event.keyCode;
529     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
530       this.gSquare.call(d3.drag()
531         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
532       );
533       this.gNetwork.call(d3.drag()
534         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
535       );
536       this.gCircle.call(d3.drag()
537         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
538       );
539       this.svg.classed('ctrl', true);
540     }
541   }
542   /** Key realse event @private */
543   private keyUp(): void {
544     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
545     this.lastKeyDown = -1;
546     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
547       this.gSquare.on('.drag', null);
548       this.gNetwork.on('.drag', null);
549       this.gCircle.on('.drag', null);
550       this.svg.classed('ctrl', false);
551     }
552   }
553   /** Events handles when to drag using filter for the keys @private */
554   private dragFilter(): boolean {
555     return d3.event.ctrlKey && !d3.event.button;
556   }
557   /** Events handles when dragstarted @private */
558   private dragstarted(d: COMPOSERNODES): void {
559     d.fx = d.x;
560     d.fy = d.y;
561   }
562   /** Events handles when dragged @private */
563   private dragged(d: COMPOSERNODES): void {
564     d.fx = d.x = d3.event.x;
565     d.fy = d.y = d3.event.y;
566   }
567   /** Events handles when dragended @private */
568   private dragended(d: COMPOSERNODES): void {
569     if (this.forceSimulationActive) {
570       d.fx = null;
571       d.fy = null;
572     } else {
573       d.fx = d.x;
574       d.fy = d.y;
575       this.forceSimulationActive = false;
576     }
577   }
578   /** Events handles when node single click   @private */
579   private onNodeClickToggleSidebar(): void {
580     this.sideBarOpened = true;
581   }
582 }