blob: c51af7a39d8655cfb15b54b00d49a88b7556ccf2 [file] [log] [blame]
Sean Condon83fc39f2018-04-19 18:56:13 +01001/*
Sean Condon5ca00262018-09-06 17:55:25 +01002 * Copyright 2018-present Open Networking Foundation
Sean Condon83fc39f2018-04-19 18:56:13 +01003 *
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 { Injectable } from '@angular/core';
Bhavesh72ead492018-07-19 16:29:18 +053017import { FnService } from '../util/fn.service';
Sean Condon5ca00262018-09-06 17:55:25 +010018import { LogService } from '../log.service';
Sean Condon83fc39f2018-04-19 18:56:13 +010019import * as gds from './glyphdata.service';
20import * as d3 from 'd3';
Bhavesh72ead492018-07-19 16:29:18 +053021import { SvgUtilService } from './svgutil.service';
Sean Condon83fc39f2018-04-19 18:56:13 +010022
23// constants
24const msgGS = 'GlyphService.';
25const rg = 'registerGlyphs(): ';
26const rgs = 'registerGlyphSet(): ';
27
28/**
29 * ONOS GUI -- SVG -- Glyph Service
30 */
Sean Condon5ca00262018-09-06 17:55:25 +010031@Injectable({
32 providedIn: 'root',
33})
Sean Condon83fc39f2018-04-19 18:56:13 +010034export class GlyphService {
35 // internal state
36 glyphs = d3.map();
Bhavesh72ead492018-07-19 16:29:18 +053037 api: Object;
Sean Condon83fc39f2018-04-19 18:56:13 +010038
39 constructor(
40 private fs: FnService,
Bhavesh72ead492018-07-19 16:29:18 +053041 // private gd: GlyphDataService,
42 private log: LogService,
43 private sus: SvgUtilService
Sean Condon83fc39f2018-04-19 18:56:13 +010044 ) {
45 this.clear();
46 this.init();
Bhavesh72ead492018-07-19 16:29:18 +053047 this.api = {
48 registerGlyphs: this.registerGlyphs,
49 registerGlyphSet: this.registerGlyphSet,
50 ids: this.ids,
51 glyph: this.glyph,
52 glyphDefined: this.glyphDefined,
53 loadDefs: this.loadDefs,
54 addGlyph: this.addGlyph,
55 };
Sean Condon83fc39f2018-04-19 18:56:13 +010056 this.log.debug('GlyphService constructed');
57 }
58
59 warn(msg: string): void {
60 this.log.warn(msgGS + msg);
61 }
62
63 addToMap(key, value, vbox, overwrite: boolean, dups) {
64 if (!overwrite && this.glyphs.get(key)) {
65 dups.push(key);
66 } else {
67 this.glyphs.set(key, { id: key, vb: vbox, d: value });
68 }
69 }
70
71 reportDups(dups: string[], which: string): boolean {
72 const ok: boolean = (dups.length === 0);
73 const msg = 'ID collision: ';
74
75 if (!ok) {
76 dups.forEach((id) => {
77 this.warn(which + msg + '"' + id + '"');
78 });
79 }
80 return ok;
81 }
82
83 reportMissVb(missing: string[], which: string): boolean {
84 const ok: boolean = (missing.length === 0);
85 const msg = 'Missing viewbox property: ';
86
87 if (!ok) {
88 missing.forEach((vbk) => {
89 this.warn(which + msg + '"' + vbk + '"');
90 });
91 }
92 return ok;
93 }
94
95 clear() {
96 // start with a fresh map
97 this.glyphs = d3.map();
98 }
99
100 init() {
101 this.log.info('Registering glyphs');
102 this.registerGlyphs(gds.logos);
103 this.registerGlyphSet(gds.glyphDataSet);
104 this.registerGlyphSet(gds.badgeDataSet);
105 this.registerGlyphs(gds.spriteData);
106 this.registerGlyphSet(gds.mojoDataSet);
107 this.registerGlyphs(gds.extraGlyphs);
108 }
109
110 registerGlyphs(data: Map<string, string>, overwrite: boolean = false): boolean {
111 const dups: string[] = [];
112 const missvb: string[] = [];
Sean Condon49e15be2018-05-16 16:58:29 +0100113 for (const [key, value] of data.entries()) {
Sean Condon83fc39f2018-04-19 18:56:13 +0100114 const vbk = '_' + key;
115 const vb = data.get(vbk);
116
117 if (key[0] !== '_') {
118 if (!vb) {
119 missvb.push(vbk);
120 continue;
121 }
122 this.addToMap(key, value, vb, overwrite, dups);
123 }
124 }
125 return this.reportDups(dups, rg) && this.reportMissVb(missvb, rg);
126 }
127
128 registerGlyphSet(data: Map<string, string>, overwrite: boolean = false): boolean {
129 const dups: string[] = [];
130 const vb: string = data.get('_viewbox');
131
132 if (!vb) {
133 this.warn(rgs + 'no "_viewbox" property found');
134 return false;
135 }
136
Sean Condon49e15be2018-05-16 16:58:29 +0100137 for (const [key, value] of data.entries()) {
Bhavesh72ead492018-07-19 16:29:18 +0530138 // angular.forEach(data, function (value, key) {
Sean Condon83fc39f2018-04-19 18:56:13 +0100139 if (key[0] !== '_') {
140 this.addToMap(key, value, vb, overwrite, dups);
141 }
142 }
143 return this.reportDups(dups, rgs);
144 }
145
146 ids() {
147 return this.glyphs.keys();
148 }
149
150 glyph(id) {
151 return this.glyphs.get(id);
152 }
153
154 glyphDefined(id) {
155 return this.glyphs.has(id);
156 }
157
158
159 /**
160 * Load definitions of a glyph
161 *
162 * Note: defs should be a D3 selection of a single <defs> element
163 */
164 loadDefs(defs, glyphIds: string[], noClear: boolean) {
165 const list = this.fs.isA(glyphIds) || this.ids();
166
167 if (!noClear) {
168 // remove all existing content
169 defs.html(null);
170 }
171
172 // load up the requested glyphs
173 list.forEach((id) => {
174 const g = this.glyph(id);
175 if (g) {
176 if (noClear) {
177 // quick exit if symbol is already present
178 // TODO: check if this should be a continue or break instead
179 if (defs.select('symbol#' + g.id).size() > 0) {
180 return;
181 }
182 }
183 defs.append('symbol')
Bhavesh72ead492018-07-19 16:29:18 +0530184 .attr('id', g.id)
185 .attr('viewBox', g.vb)
186 .append('path')
187 .attr('d', g.d);
Sean Condon83fc39f2018-04-19 18:56:13 +0100188 }
189 });
190 }
Bhavesh72ead492018-07-19 16:29:18 +0530191
192 addGlyph(elem: any, glyphId: string, size: number, overlay: any, trans: any) {
Sean Condon55c30532018-10-29 12:26:57 +0000193 const sz = size || 40;
194 const ovr = !!overlay;
195 const xns = this.fs.isA(trans);
196
197 const glyphUse = elem
198 .append('use')
199 .attr('width', sz)
200 .attr('height', sz)
201 .attr('class', 'glyph')
202 .attr('xlink:href', '#' + glyphId)
203 .classed('overlay', ovr);
Bhavesh72ead492018-07-19 16:29:18 +0530204
205 if (xns) {
Sean Condon55c30532018-10-29 12:26:57 +0000206 glyphUse.attr('transform', this.sus.translate(trans));
Bhavesh72ead492018-07-19 16:29:18 +0530207 }
Sean Condon55c30532018-10-29 12:26:57 +0000208
209 return glyphUse;
Bhavesh72ead492018-07-19 16:29:18 +0530210 }
Sean Condon83fc39f2018-04-19 18:56:13 +0100211}