blob: 6e1d2198ed2a2c46617bff4051932f9d8f5c1898 [file] [log] [blame]
Sean Condon50855cf2018-12-23 15:37:42 +00001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
16import {
17 ChangeDetectorRef,
18 Component, EventEmitter,
19 Input, OnChanges, Output, SimpleChanges,
20} from '@angular/core';
21import {Link, LinkHighlight, UiElement} from '../../models';
Sean Condona3ad7792020-01-04 19:26:34 +000022import {LogService} from 'gui2-fw-lib/public_api';
Sean Condond88f3662019-04-03 16:35:30 +010023import {NodeVisual, SelectedEvent} from '../nodevisual';
Sean Condon50855cf2018-12-23 15:37:42 +000024import {animate, state, style, transition, trigger} from '@angular/animations';
25
26interface Point {
27 x: number;
28 y: number;
29}
30
Sean Condon4e55c802019-12-03 22:13:34 +000031/*
32 * LinkSvgComponent gets its data from 2 sources - the force SVG regionData (which
33 * gives the Link below), and other state data here.
34 */
Sean Condon50855cf2018-12-23 15:37:42 +000035@Component({
36 selector: '[onos-linksvg]',
37 templateUrl: './linksvg.component.html',
38 styleUrls: ['./linksvg.component.css'],
39 animations: [
40 trigger('linkLabelVisible', [
41 state('true', style( {
42 opacity: 1.0,
43 })),
44 state( 'false', style({
45 opacity: 0
46 })),
47 transition('false => true', animate('500ms ease-in')),
48 transition('true => false', animate('1000ms ease-out'))
49 ])
50 ]
51})
52export class LinkSvgComponent extends NodeVisual implements OnChanges {
53 @Input() link: Link;
Sean Condon4e55c802019-12-03 22:13:34 +000054 @Input() linkHighlight: LinkHighlight;
Sean Condon91481822019-01-01 13:56:14 +000055 @Input() highlightsEnabled: boolean = true;
Sean Condon1ae15802019-03-02 09:07:18 +000056 @Input() scale = 1.0;
Sean Condon50855cf2018-12-23 15:37:42 +000057 isHighlighted: boolean = false;
Sean Condond88f3662019-04-03 16:35:30 +010058 @Output() selectedEvent = new EventEmitter<SelectedEvent>();
Sean Condon50855cf2018-12-23 15:37:42 +000059 @Output() enhancedEvent = new EventEmitter<Link>();
60 enhanced: boolean = false;
61 labelPosSrc: Point = {x: 0, y: 0};
62 labelPosTgt: Point = {x: 0, y: 0};
Sean Condon5f7d3bc2019-04-15 11:18:34 +010063 lastTimer: any;
Sean Condon50855cf2018-12-23 15:37:42 +000064
65 constructor(
66 protected log: LogService,
67 private ref: ChangeDetectorRef
68 ) {
69 super();
70 }
71
72 ngOnChanges(changes: SimpleChanges) {
73 if (changes['linkHighlight']) {
74 const hl: LinkHighlight = changes['linkHighlight'].currentValue;
Sean Condon00e56d02020-02-28 09:50:04 +000075 if (hl === undefined) {
76 return;
77 }
Sean Condon5f7d3bc2019-04-15 11:18:34 +010078 clearTimeout(this.lastTimer);
Sean Condon50855cf2018-12-23 15:37:42 +000079 this.isHighlighted = true;
Sean Condon4e55c802019-12-03 22:13:34 +000080 this.log.debug('Link highlighted', this.link.id);
81
Sean Condon64ea7d22019-04-12 19:39:13 +010082 if (hl.fadems > 0) {
Sean Condon5f7d3bc2019-04-15 11:18:34 +010083 this.lastTimer = setTimeout(() => {
Sean Condon64ea7d22019-04-12 19:39:13 +010084 this.isHighlighted = false;
Sean Condon4e55c802019-12-03 22:13:34 +000085 this.linkHighlight = <LinkHighlight>{};
Sean Condon64ea7d22019-04-12 19:39:13 +010086 this.ref.markForCheck();
Sean Condon4e55c802019-12-03 22:13:34 +000087 }, this.linkHighlight.fadems); // Disappear slightly before next one comes in
Sean Condon64ea7d22019-04-12 19:39:13 +010088 }
Sean Condon50855cf2018-12-23 15:37:42 +000089 }
90
91 this.ref.markForCheck();
92 }
93
Sean Condon4e55c802019-12-03 22:13:34 +000094 highlightAsString(): string {
95 if (this.linkHighlight && this.linkHighlight.css) {
96 return this.linkHighlight.css;
97 }
98 return '';
99 }
100
Sean Condon50855cf2018-12-23 15:37:42 +0000101 enhance() {
Sean Condon91481822019-01-01 13:56:14 +0000102 if (!this.highlightsEnabled) {
103 return;
104 }
Sean Condon50855cf2018-12-23 15:37:42 +0000105 this.enhancedEvent.emit(this.link);
106 this.enhanced = true;
107 this.repositionLabels();
108 setTimeout(() => {
109 this.enhanced = false;
110 this.ref.markForCheck();
111 }, 1000);
112 }
113
114 /**
Sean Condon1ae15802019-03-02 09:07:18 +0000115 * We want to place the label for the port about 40 px from the node.
Sean Condon50855cf2018-12-23 15:37:42 +0000116 * If the distance between the nodes is less than 100, then just place the
117 * label 1/3 of the way from the node
118 */
119 repositionLabels(): void {
120 const x1: number = this.link.source.x;
121 const y1: number = this.link.source.y;
122 const x2: number = this.link.target.x;
123 const y2: number = this.link.target.y;
124
125 const dist = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
126 const offset = dist > 100 ? 40 : dist / 3;
127 this.labelPosSrc = <Point>{
128 x: x1 + (x2 - x1) * offset / dist,
129 y: y1 + (y2 - y1) * offset / dist
130 };
131
132 this.labelPosTgt = <Point>{
133 x: x2 - (x2 - x1) * offset / dist,
134 y: y2 - (y2 - y1) * offset / dist
135 };
136 }
137
138 /**
139 * For the 14pt font we are using, the average width seems to be about 8px
140 * @param text The string we want to calculate a width for
141 */
142 textLength(text: string) {
143 return text.length * 8;
144 }
145}