blob: 0c1eff3dc2dfa8e2ebe0fb6fa1edbdb5f98075f5 [file] [log] [blame]
Sean Condon83fc39f2018-04-19 18:56:13 +01001/*
2 * Copyright 2015-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 { Injectable } from '@angular/core';
Bhavesh72ead492018-07-19 16:29:18 +053017import { FnService } from '../util/fn.service';
Sean Condon83fc39f2018-04-19 18:56:13 +010018import { LogService } from '../../log.service';
19import * 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 */
31@Injectable()
32export class GlyphService {
33 // internal state
34 glyphs = d3.map();
Bhavesh72ead492018-07-19 16:29:18 +053035 api: Object;
Sean Condon83fc39f2018-04-19 18:56:13 +010036
37 constructor(
38 private fs: FnService,
Bhavesh72ead492018-07-19 16:29:18 +053039 // private gd: GlyphDataService,
40 private log: LogService,
41 private sus: SvgUtilService
Sean Condon83fc39f2018-04-19 18:56:13 +010042 ) {
43 this.clear();
44 this.init();
Bhavesh72ead492018-07-19 16:29:18 +053045 this.api = {
46 registerGlyphs: this.registerGlyphs,
47 registerGlyphSet: this.registerGlyphSet,
48 ids: this.ids,
49 glyph: this.glyph,
50 glyphDefined: this.glyphDefined,
51 loadDefs: this.loadDefs,
52 addGlyph: this.addGlyph,
53 };
Sean Condon83fc39f2018-04-19 18:56:13 +010054 this.log.debug('GlyphService constructed');
55 }
56
57 warn(msg: string): void {
58 this.log.warn(msgGS + msg);
59 }
60
61 addToMap(key, value, vbox, overwrite: boolean, dups) {
62 if (!overwrite && this.glyphs.get(key)) {
63 dups.push(key);
64 } else {
65 this.glyphs.set(key, { id: key, vb: vbox, d: value });
66 }
67 }
68
69 reportDups(dups: string[], which: string): boolean {
70 const ok: boolean = (dups.length === 0);
71 const msg = 'ID collision: ';
72
73 if (!ok) {
74 dups.forEach((id) => {
75 this.warn(which + msg + '"' + id + '"');
76 });
77 }
78 return ok;
79 }
80
81 reportMissVb(missing: string[], which: string): boolean {
82 const ok: boolean = (missing.length === 0);
83 const msg = 'Missing viewbox property: ';
84
85 if (!ok) {
86 missing.forEach((vbk) => {
87 this.warn(which + msg + '"' + vbk + '"');
88 });
89 }
90 return ok;
91 }
92
93 clear() {
94 // start with a fresh map
95 this.glyphs = d3.map();
96 }
97
98 init() {
99 this.log.info('Registering glyphs');
100 this.registerGlyphs(gds.logos);
101 this.registerGlyphSet(gds.glyphDataSet);
102 this.registerGlyphSet(gds.badgeDataSet);
103 this.registerGlyphs(gds.spriteData);
104 this.registerGlyphSet(gds.mojoDataSet);
105 this.registerGlyphs(gds.extraGlyphs);
106 }
107
108 registerGlyphs(data: Map<string, string>, overwrite: boolean = false): boolean {
109 const dups: string[] = [];
110 const missvb: string[] = [];
Sean Condon49e15be2018-05-16 16:58:29 +0100111 for (const [key, value] of data.entries()) {
Sean Condon83fc39f2018-04-19 18:56:13 +0100112 const vbk = '_' + key;
113 const vb = data.get(vbk);
114
115 if (key[0] !== '_') {
116 if (!vb) {
117 missvb.push(vbk);
118 continue;
119 }
120 this.addToMap(key, value, vb, overwrite, dups);
121 }
122 }
123 return this.reportDups(dups, rg) && this.reportMissVb(missvb, rg);
124 }
125
126 registerGlyphSet(data: Map<string, string>, overwrite: boolean = false): boolean {
127 const dups: string[] = [];
128 const vb: string = data.get('_viewbox');
129
130 if (!vb) {
131 this.warn(rgs + 'no "_viewbox" property found');
132 return false;
133 }
134
Sean Condon49e15be2018-05-16 16:58:29 +0100135 for (const [key, value] of data.entries()) {
Bhavesh72ead492018-07-19 16:29:18 +0530136 // angular.forEach(data, function (value, key) {
Sean Condon83fc39f2018-04-19 18:56:13 +0100137 if (key[0] !== '_') {
138 this.addToMap(key, value, vb, overwrite, dups);
139 }
140 }
141 return this.reportDups(dups, rgs);
142 }
143
144 ids() {
145 return this.glyphs.keys();
146 }
147
148 glyph(id) {
149 return this.glyphs.get(id);
150 }
151
152 glyphDefined(id) {
153 return this.glyphs.has(id);
154 }
155
156
157 /**
158 * Load definitions of a glyph
159 *
160 * Note: defs should be a D3 selection of a single <defs> element
161 */
162 loadDefs(defs, glyphIds: string[], noClear: boolean) {
163 const list = this.fs.isA(glyphIds) || this.ids();
164
165 if (!noClear) {
166 // remove all existing content
167 defs.html(null);
168 }
169
170 // load up the requested glyphs
171 list.forEach((id) => {
172 const g = this.glyph(id);
173 if (g) {
174 if (noClear) {
175 // quick exit if symbol is already present
176 // TODO: check if this should be a continue or break instead
177 if (defs.select('symbol#' + g.id).size() > 0) {
178 return;
179 }
180 }
181 defs.append('symbol')
Bhavesh72ead492018-07-19 16:29:18 +0530182 .attr('id', g.id)
183 .attr('viewBox', g.vb)
184 .append('path')
185 .attr('d', g.d);
Sean Condon83fc39f2018-04-19 18:56:13 +0100186 }
187 });
188 }
Bhavesh72ead492018-07-19 16:29:18 +0530189
190 addGlyph(elem: any, glyphId: string, size: number, overlay: any, trans: any) {
191 const sz = size || 40,
192 ovr = !!overlay,
193 xns = this.fs.isA(trans),
194 atr = {
195 width: sz,
196 height: sz,
197 'class': 'glyph',
198 'xlink:href': '#' + glyphId,
199 };
200
201 if (xns) {
202 atr.class = this.sus.translate(trans);
203 }
204 return elem.append('use').attr(atr).classed('overlay', ovr);
205 }
Sean Condon83fc39f2018-04-19 18:56:13 +0100206}