blob: 4f06137da8d1a5d9b0991b1509ec330927844798 [file] [log] [blame]
Sean Condon0c577f62018-11-18 22:40:05 +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 {
Sean Condon50855cf2018-12-23 15:37:42 +000017 ChangeDetectionStrategy,
Sean Condon0c577f62018-11-18 22:40:05 +000018 ChangeDetectorRef,
19 Component,
Sean Condon50855cf2018-12-23 15:37:42 +000020 EventEmitter,
Sean Condon0c577f62018-11-18 22:40:05 +000021 Input,
Sean Condon058804c2019-04-16 09:41:52 +010022 OnChanges, OnInit, Output,
Sean Condon0c577f62018-11-18 22:40:05 +000023 SimpleChanges,
Sean Condon0c577f62018-11-18 22:40:05 +000024} from '@angular/core';
Sean Condon590b34b2019-12-04 18:44:37 +000025import {
26 Badge,
27 Device,
28 LabelToggle,
29} from '../../models';
30import {IconService, LogService, SvgUtilService} from 'gui2-fw-lib';
Sean Condond88f3662019-04-03 16:35:30 +010031import {NodeVisual, SelectedEvent} from '../nodevisual';
Sean Condon50855cf2018-12-23 15:37:42 +000032import {animate, state, style, transition, trigger} from '@angular/animations';
Sean Condon058804c2019-04-16 09:41:52 +010033import {TopologyService} from '../../../../topology.service';
Sean Condon0c577f62018-11-18 22:40:05 +000034
35/**
36 * The Device node in the force graph
37 *
38 * Note: here the selector is given square brackets [] so that it can be
39 * inserted in SVG element like a directive
40 */
41@Component({
42 selector: '[onos-devicenodesvg]',
43 templateUrl: './devicenodesvg.component.html',
44 styleUrls: ['./devicenodesvg.component.css'],
Sean Condon50855cf2018-12-23 15:37:42 +000045 changeDetection: ChangeDetectionStrategy.Default,
46 animations: [
47 trigger('deviceLabelToggle', [
48 state('0', style({ // none
49 width: '36px',
50 })),
51 state('1, 2', // id
52 style({ width: '{{ txtWidth }}'}),
53 { params: {'txtWidth': '36px'}}
54 ), // default
55 transition('0 => 1', animate('250ms ease-in')),
56 transition('1 => 2', animate('250ms ease-in')),
57 transition('* => 0', animate('250ms ease-out'))
58 ]),
59 trigger('deviceLabelToggleTxt', [
60 state('0', style( {
61 opacity: 0,
62 })),
63 state( '1,2', style({
64 opacity: 1.0
65 })),
66 transition('0 => 1', animate('250ms ease-in')),
67 transition('* => 0', animate('250ms ease-out'))
68 ])
69 ]
Sean Condon0c577f62018-11-18 22:40:05 +000070})
Sean Condon058804c2019-04-16 09:41:52 +010071export class DeviceNodeSvgComponent extends NodeVisual implements OnInit, OnChanges {
Sean Condon0c577f62018-11-18 22:40:05 +000072 @Input() device: Device;
73 @Input() scale: number = 1.0;
Sean Condonff85fbe2019-03-16 14:28:46 +000074 @Input() labelToggle: LabelToggle.Enum = LabelToggle.Enum.NONE;
Sean Condon058804c2019-04-16 09:41:52 +010075 @Input() colorMuted: boolean = false;
76 @Input() colorTheme: string = 'light';
Sean Condon590b34b2019-12-04 18:44:37 +000077 @Input() badge: Badge;
Sean Condond88f3662019-04-03 16:35:30 +010078 @Output() selectedEvent = new EventEmitter<SelectedEvent>();
Sean Condon0c577f62018-11-18 22:40:05 +000079 textWidth: number = 36;
Sean Condon058804c2019-04-16 09:41:52 +010080 panelColor: string = '#9ebedf';
81
Sean Condon0c577f62018-11-18 22:40:05 +000082 constructor(
83 protected log: LogService,
Sean Condon59d31372019-02-02 20:07:00 +000084 private is: IconService,
Sean Condon64ea7d22019-04-12 19:39:13 +010085 protected sus: SvgUtilService,
Sean Condon058804c2019-04-16 09:41:52 +010086 protected ts: TopologyService,
Sean Condon0c577f62018-11-18 22:40:05 +000087 private ref: ChangeDetectorRef
88 ) {
Sean Condon021f0fa2018-12-06 23:31:11 -080089 super();
Sean Condon0c577f62018-11-18 22:40:05 +000090 }
91
Sean Condon058804c2019-04-16 09:41:52 +010092 ngOnInit(): void {
93 this.panelColor = this.panelColour();
94 }
95
Sean Condon0c577f62018-11-18 22:40:05 +000096 /**
97 * Called by parent (forcesvg) when a change happens
98 *
99 * There is a difficulty in passing the SVG text object to the animation
100 * directly, to get its width, so we capture it here and update textWidth
101 * local variable here and use it in the animation
102 */
103 ngOnChanges(changes: SimpleChanges) {
104 if (changes['device']) {
105 if (!this.device.x) {
106 this.device.x = 0;
107 this.device.y = 0;
108 }
Sean Condon058804c2019-04-16 09:41:52 +0100109 // The master might have changed - recalculate color
110 this.panelColor = this.panelColour();
111 }
112
113 if (changes['colorMuted']) {
114 this.colorMuted = changes['colorMuted'].currentValue;
115 this.panelColor = this.panelColour();
Sean Condon0c577f62018-11-18 22:40:05 +0000116 }
Sean Condon590b34b2019-12-04 18:44:37 +0000117
118 if (changes['badge']) {
119 this.badge = changes['badge'].currentValue;
120 }
Sean Condon0c577f62018-11-18 22:40:05 +0000121 }
Sean Condon50855cf2018-12-23 15:37:42 +0000122
123 /**
124 * Calculate the text length in advance as well as possible
125 *
126 * The length of SVG text cannot be exactly estimated, because depending on
127 * the letters kerning might mean that it is shorter or longer than expected
128 *
129 * This takes the approach of 8px width per letter of this size, that on average
130 * evens out over words. A word like 'ilj' will be much shorter than 'wm0'
131 * because of kerning
132 *
133 *
134 * In addition in the template, the <svg:text> properties
135 * textLength and lengthAdjust ensure that the text becomes long with extra
136 * wide spacing created as necessary.
137 *
138 * Other approaches like getBBox() of the text
139 */
140 labelTextLen() {
141 if (this.labelToggle === 1) {
Sean Condon1ae15802019-03-02 09:07:18 +0000142 return this.device.id.length * 8;
143 } else if (this.labelToggle === 2 && this.device &&
144 this.device.props.name && this.device.props.name.trim().length > 0) {
145 return this.device.props.name.length * 8;
Sean Condon50855cf2018-12-23 15:37:42 +0000146 } else {
147 return 0;
148 }
149 }
Sean Condon59d31372019-02-02 20:07:00 +0000150
151 deviceIcon(): string {
152 if (this.device.props && this.device.props.uiType) {
153 this.is.loadIconDef(this.device.props.uiType);
154 return this.device.props.uiType;
155 } else {
156 return 'm_' + this.device.type;
157 }
158 }
Sean Condon64ea7d22019-04-12 19:39:13 +0100159
160 /**
161 * Get a colour for the banner of the nth panel
162 * @param idx The index of the panel (0-6)
163 */
Sean Condon058804c2019-04-16 09:41:52 +0100164 panelColour(): string {
165 const idx = this.ts.instancesIndex.get(this.device.master);
166 return this.sus.cat7().getColor(idx, this.colorMuted, this.colorTheme);
Sean Condon64ea7d22019-04-12 19:39:13 +0100167 }
Sean Condon0c577f62018-11-18 22:40:05 +0000168}