blob: ce6bd469537a1db69dd1db2a09c058459077b91e [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,
22 OnChanges, Output,
23 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 Condon1ae15802019-03-02 09:07:18 +000026import {IconService, LocMeta, LogService, MetaUi, ZoomUtils} from 'gui2-fw-lib';
Sean Condon021f0fa2018-12-06 23:31:11 -080027import {NodeVisual} 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 Condon0c577f62018-11-18 22:40:05 +000030
31/**
32 * The Device node in the force graph
33 *
34 * Note: here the selector is given square brackets [] so that it can be
35 * inserted in SVG element like a directive
36 */
37@Component({
38 selector: '[onos-devicenodesvg]',
39 templateUrl: './devicenodesvg.component.html',
40 styleUrls: ['./devicenodesvg.component.css'],
Sean Condon50855cf2018-12-23 15:37:42 +000041 changeDetection: ChangeDetectionStrategy.Default,
42 animations: [
43 trigger('deviceLabelToggle', [
44 state('0', style({ // none
45 width: '36px',
46 })),
47 state('1, 2', // id
48 style({ width: '{{ txtWidth }}'}),
49 { params: {'txtWidth': '36px'}}
50 ), // default
51 transition('0 => 1', animate('250ms ease-in')),
52 transition('1 => 2', animate('250ms ease-in')),
53 transition('* => 0', animate('250ms ease-out'))
54 ]),
55 trigger('deviceLabelToggleTxt', [
56 state('0', style( {
57 opacity: 0,
58 })),
59 state( '1,2', style({
60 opacity: 1.0
61 })),
62 transition('0 => 1', animate('250ms ease-in')),
63 transition('* => 0', animate('250ms ease-out'))
64 ])
65 ]
Sean Condon0c577f62018-11-18 22:40:05 +000066})
Sean Condon021f0fa2018-12-06 23:31:11 -080067export class DeviceNodeSvgComponent extends NodeVisual implements OnChanges {
Sean Condon0c577f62018-11-18 22:40:05 +000068 @Input() device: Device;
69 @Input() scale: number = 1.0;
Sean Condonff85fbe2019-03-16 14:28:46 +000070 @Input() labelToggle: LabelToggle.Enum = LabelToggle.Enum.NONE;
Sean Condon50855cf2018-12-23 15:37:42 +000071 @Output() selectedEvent = new EventEmitter<UiElement>();
Sean Condon0c577f62018-11-18 22:40:05 +000072 textWidth: number = 36;
Sean Condon0c577f62018-11-18 22:40:05 +000073 constructor(
74 protected log: LogService,
Sean Condon59d31372019-02-02 20:07:00 +000075 private is: IconService,
Sean Condon0c577f62018-11-18 22:40:05 +000076 private ref: ChangeDetectorRef
77 ) {
Sean Condon021f0fa2018-12-06 23:31:11 -080078 super();
Sean Condon0c577f62018-11-18 22:40:05 +000079 }
80
81 /**
82 * Called by parent (forcesvg) when a change happens
83 *
84 * There is a difficulty in passing the SVG text object to the animation
85 * directly, to get its width, so we capture it here and update textWidth
86 * local variable here and use it in the animation
87 */
88 ngOnChanges(changes: SimpleChanges) {
89 if (changes['device']) {
90 if (!this.device.x) {
91 this.device.x = 0;
92 this.device.y = 0;
93 }
94 }
Sean Condon0c577f62018-11-18 22:40:05 +000095 this.ref.markForCheck();
96 }
Sean Condon50855cf2018-12-23 15:37:42 +000097
98 /**
99 * Calculate the text length in advance as well as possible
100 *
101 * The length of SVG text cannot be exactly estimated, because depending on
102 * the letters kerning might mean that it is shorter or longer than expected
103 *
104 * This takes the approach of 8px width per letter of this size, that on average
105 * evens out over words. A word like 'ilj' will be much shorter than 'wm0'
106 * because of kerning
107 *
108 *
109 * In addition in the template, the <svg:text> properties
110 * textLength and lengthAdjust ensure that the text becomes long with extra
111 * wide spacing created as necessary.
112 *
113 * Other approaches like getBBox() of the text
114 */
115 labelTextLen() {
116 if (this.labelToggle === 1) {
Sean Condon1ae15802019-03-02 09:07:18 +0000117 return this.device.id.length * 8;
118 } else if (this.labelToggle === 2 && this.device &&
119 this.device.props.name && this.device.props.name.trim().length > 0) {
120 return this.device.props.name.length * 8;
Sean Condon50855cf2018-12-23 15:37:42 +0000121 } else {
122 return 0;
123 }
124 }
Sean Condon59d31372019-02-02 20:07:00 +0000125
126 deviceIcon(): string {
127 if (this.device.props && this.device.props.uiType) {
128 this.is.loadIconDef(this.device.props.uiType);
129 return this.device.props.uiType;
130 } else {
131 return 'm_' + this.device.type;
132 }
133 }
Sean Condon1ae15802019-03-02 09:07:18 +0000134
135 resetNodeLocation(): void {
136 this.log.debug('Resetting device', this.device.id, this.device.type);
137 let origLoc: MetaUi;
138
139 if (!this.device.location || this.device.location.locType === LocationType.NONE) {
140 // No location - nothing to do
141 return;
142 } else if (this.device.location.locType === LocationType.GEO) {
143 origLoc = ZoomUtils.convertGeoToCanvas(<LocMeta>{
144 lng: this.device.location.longOrX,
145 lat: this.device.location.latOrY
146 });
147 } else if (this.device.location.locType === LocationType.GRID) {
148 origLoc = ZoomUtils.convertXYtoGeo(
149 this.device.location.longOrX, this.device.location.latOrY);
150 }
151 this.device.metaUi = origLoc;
152 this.device['fx'] = origLoc.x;
153 this.device['fy'] = origLoc.y;
154 }
Sean Condon0c577f62018-11-18 22:40:05 +0000155}