blob: 9c246d9a7ffb6bf21df3d3422486d9810b497710 [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 Condon50855cf2018-12-23 15:37:42 +000025import {Device, LabelToggle, UiElement} from '../../models';
Sean Condon64ea7d22019-04-12 19:39:13 +010026import {IconService, LocMeta, LogService, MetaUi, SvgUtilService, ZoomUtils} from 'gui2-fw-lib';
Sean Condond88f3662019-04-03 16:35:30 +010027import {NodeVisual, SelectedEvent} from '../nodevisual';
Sean Condon50855cf2018-12-23 15:37:42 +000028import {animate, state, style, transition, trigger} from '@angular/animations';
Sean Condon1ae15802019-03-02 09:07:18 +000029import {LocationType} from '../../../backgroundsvg/backgroundsvg.component';
Sean Condon058804c2019-04-16 09:41:52 +010030import {TopologyService} from '../../../../topology.service';
Sean Condon0c577f62018-11-18 22:40:05 +000031
32/**
33 * The Device node in the force graph
34 *
35 * Note: here the selector is given square brackets [] so that it can be
36 * inserted in SVG element like a directive
37 */
38@Component({
39 selector: '[onos-devicenodesvg]',
40 templateUrl: './devicenodesvg.component.html',
41 styleUrls: ['./devicenodesvg.component.css'],
Sean Condon50855cf2018-12-23 15:37:42 +000042 changeDetection: ChangeDetectionStrategy.Default,
43 animations: [
44 trigger('deviceLabelToggle', [
45 state('0', style({ // none
46 width: '36px',
47 })),
48 state('1, 2', // id
49 style({ width: '{{ txtWidth }}'}),
50 { params: {'txtWidth': '36px'}}
51 ), // default
52 transition('0 => 1', animate('250ms ease-in')),
53 transition('1 => 2', animate('250ms ease-in')),
54 transition('* => 0', animate('250ms ease-out'))
55 ]),
56 trigger('deviceLabelToggleTxt', [
57 state('0', style( {
58 opacity: 0,
59 })),
60 state( '1,2', style({
61 opacity: 1.0
62 })),
63 transition('0 => 1', animate('250ms ease-in')),
64 transition('* => 0', animate('250ms ease-out'))
65 ])
66 ]
Sean Condon0c577f62018-11-18 22:40:05 +000067})
Sean Condon058804c2019-04-16 09:41:52 +010068export class DeviceNodeSvgComponent extends NodeVisual implements OnInit, OnChanges {
Sean Condon0c577f62018-11-18 22:40:05 +000069 @Input() device: Device;
70 @Input() scale: number = 1.0;
Sean Condonff85fbe2019-03-16 14:28:46 +000071 @Input() labelToggle: LabelToggle.Enum = LabelToggle.Enum.NONE;
Sean Condon058804c2019-04-16 09:41:52 +010072 @Input() colorMuted: boolean = false;
73 @Input() colorTheme: string = 'light';
Sean Condond88f3662019-04-03 16:35:30 +010074 @Output() selectedEvent = new EventEmitter<SelectedEvent>();
Sean Condon0c577f62018-11-18 22:40:05 +000075 textWidth: number = 36;
Sean Condon058804c2019-04-16 09:41:52 +010076 panelColor: string = '#9ebedf';
77
Sean Condon0c577f62018-11-18 22:40:05 +000078 constructor(
79 protected log: LogService,
Sean Condon59d31372019-02-02 20:07:00 +000080 private is: IconService,
Sean Condon64ea7d22019-04-12 19:39:13 +010081 protected sus: SvgUtilService,
Sean Condon058804c2019-04-16 09:41:52 +010082 protected ts: TopologyService,
Sean Condon0c577f62018-11-18 22:40:05 +000083 private ref: ChangeDetectorRef
84 ) {
Sean Condon021f0fa2018-12-06 23:31:11 -080085 super();
Sean Condon0c577f62018-11-18 22:40:05 +000086 }
87
Sean Condon058804c2019-04-16 09:41:52 +010088 ngOnInit(): void {
89 this.panelColor = this.panelColour();
90 }
91
Sean Condon0c577f62018-11-18 22:40:05 +000092 /**
93 * Called by parent (forcesvg) when a change happens
94 *
95 * There is a difficulty in passing the SVG text object to the animation
96 * directly, to get its width, so we capture it here and update textWidth
97 * local variable here and use it in the animation
98 */
99 ngOnChanges(changes: SimpleChanges) {
100 if (changes['device']) {
101 if (!this.device.x) {
102 this.device.x = 0;
103 this.device.y = 0;
104 }
Sean Condon058804c2019-04-16 09:41:52 +0100105 // The master might have changed - recalculate color
106 this.panelColor = this.panelColour();
107 }
108
109 if (changes['colorMuted']) {
110 this.colorMuted = changes['colorMuted'].currentValue;
111 this.panelColor = this.panelColour();
Sean Condon0c577f62018-11-18 22:40:05 +0000112 }
Sean Condon0c577f62018-11-18 22:40:05 +0000113 this.ref.markForCheck();
114 }
Sean Condon50855cf2018-12-23 15:37:42 +0000115
116 /**
117 * Calculate the text length in advance as well as possible
118 *
119 * The length of SVG text cannot be exactly estimated, because depending on
120 * the letters kerning might mean that it is shorter or longer than expected
121 *
122 * This takes the approach of 8px width per letter of this size, that on average
123 * evens out over words. A word like 'ilj' will be much shorter than 'wm0'
124 * because of kerning
125 *
126 *
127 * In addition in the template, the <svg:text> properties
128 * textLength and lengthAdjust ensure that the text becomes long with extra
129 * wide spacing created as necessary.
130 *
131 * Other approaches like getBBox() of the text
132 */
133 labelTextLen() {
134 if (this.labelToggle === 1) {
Sean Condon1ae15802019-03-02 09:07:18 +0000135 return this.device.id.length * 8;
136 } else if (this.labelToggle === 2 && this.device &&
137 this.device.props.name && this.device.props.name.trim().length > 0) {
138 return this.device.props.name.length * 8;
Sean Condon50855cf2018-12-23 15:37:42 +0000139 } else {
140 return 0;
141 }
142 }
Sean Condon59d31372019-02-02 20:07:00 +0000143
144 deviceIcon(): string {
145 if (this.device.props && this.device.props.uiType) {
146 this.is.loadIconDef(this.device.props.uiType);
147 return this.device.props.uiType;
148 } else {
149 return 'm_' + this.device.type;
150 }
151 }
Sean Condon64ea7d22019-04-12 19:39:13 +0100152
153 /**
154 * Get a colour for the banner of the nth panel
155 * @param idx The index of the panel (0-6)
156 */
Sean Condon058804c2019-04-16 09:41:52 +0100157 panelColour(): string {
158 const idx = this.ts.instancesIndex.get(this.device.master);
159 return this.sus.cat7().getColor(idx, this.colorMuted, this.colorTheme);
Sean Condon64ea7d22019-04-12 19:39:13 +0100160 }
Sean Condon0c577f62018-11-18 22:40:05 +0000161}