Committed by
Gerrit Code Review
GUI -- Augmented sprite JSON definition.
- refactored topoSprite.js to handle the changes. Change-Id: Ib0ed7dbacbc93777d8849bf82f52ad6ac974af2c
Showing
5 changed files
with
242 additions
and
47 deletions
... | @@ -542,46 +542,60 @@ | ... | @@ -542,46 +542,60 @@ |
542 | fill: #eee; | 542 | fill: #eee; |
543 | } | 543 | } |
544 | 544 | ||
545 | +/* ------------------------------------------------- */ | ||
545 | /* Sprite Layer */ | 546 | /* Sprite Layer */ |
546 | 547 | ||
548 | +#ov-topo svg #topo-sprites use { | ||
549 | + stroke-width: 1.0; | ||
550 | +} | ||
547 | #ov-topo svg #topo-sprites text { | 551 | #ov-topo svg #topo-sprites text { |
548 | text-anchor: middle; | 552 | text-anchor: middle; |
549 | font-size: 10pt; | 553 | font-size: 10pt; |
550 | font-style: italic; | 554 | font-style: italic; |
551 | } | 555 | } |
552 | 556 | ||
553 | -.light #ov-topo svg #topo-sprites .sprite1 use { | 557 | +.light #ov-topo svg #topo-sprites .gold1 use { |
554 | - stroke-width: 1.0; | 558 | + stroke: #da2; |
555 | - stroke: goldenrod; | ||
556 | fill: none; | 559 | fill: none; |
557 | } | 560 | } |
558 | -.dark #ov-topo svg #topo-sprites .sprite1 use { | 561 | +.dark #ov-topo svg #topo-sprites .gold1 use { |
559 | - stroke-width: 1.0; | ||
560 | stroke: #541; | 562 | stroke: #541; |
561 | fill: none; | 563 | fill: none; |
562 | } | 564 | } |
563 | - | 565 | +.light #ov-topo svg #topo-sprites .gold1 text { |
564 | -.light #ov-topo svg #topo-sprites .sprite1 text { | ||
565 | fill: #eda; | 566 | fill: #eda; |
566 | } | 567 | } |
567 | -.dark #ov-topo svg #topo-sprites .sprite1 text { | 568 | +.dark #ov-topo svg #topo-sprites .gold1 text { |
568 | fill: #543; | 569 | fill: #543; |
569 | } | 570 | } |
570 | 571 | ||
571 | -.light #ov-topo svg #topo-sprites .sprite2 use { | 572 | +.light #ov-topo svg #topo-sprites .blue1 use { |
572 | stroke: #bbd; | 573 | stroke: #bbd; |
573 | - stroke-width: 1.0; | ||
574 | fill: none; | 574 | fill: none; |
575 | } | 575 | } |
576 | -.dark #ov-topo svg #topo-sprites .sprite2 use { | 576 | +.dark #ov-topo svg #topo-sprites .blue1 use { |
577 | stroke: #445; | 577 | stroke: #445; |
578 | - stroke-width: 1.0; | ||
579 | fill: none; | 578 | fill: none; |
580 | } | 579 | } |
581 | - | 580 | +.light #ov-topo svg #topo-sprites .blue1 text { |
582 | -.light #ov-topo svg #topo-sprites .sprite2 text { | ||
583 | fill: #cce; | 581 | fill: #cce; |
584 | } | 582 | } |
585 | -.dark #ov-topo svg #topo-sprites .sprite2 text { | 583 | +.dark #ov-topo svg #topo-sprites .blue1 text { |
586 | fill: #446; | 584 | fill: #446; |
587 | } | 585 | } |
586 | + | ||
587 | +.light #ov-topo svg #topo-sprites .gray1 use { | ||
588 | + stroke: #bbb; | ||
589 | + fill: none; | ||
590 | +} | ||
591 | +.dark #ov-topo svg #topo-sprites .gray1 use { | ||
592 | + stroke: #333; | ||
593 | + fill: none; | ||
594 | +} | ||
595 | +.light #ov-topo svg #topo-sprites .gray1 text { | ||
596 | + fill: #ccc; | ||
597 | +} | ||
598 | +.dark #ov-topo svg #topo-sprites .gray1 text { | ||
599 | + fill: #444; | ||
600 | +} | ||
601 | + | ... | ... |
... | @@ -366,7 +366,7 @@ | ... | @@ -366,7 +366,7 @@ |
366 | } | 366 | } |
367 | ); | 367 | ); |
368 | spriteG = zoomLayer.append ('g').attr('id', 'topo-sprites'); | 368 | spriteG = zoomLayer.append ('g').attr('id', 'topo-sprites'); |
369 | - tspr.loadSprites(spriteG, $loc.search().sprites); | 369 | + tspr.loadSprites(spriteG, defs, $loc.search().sprites); |
370 | 370 | ||
371 | forceG = zoomLayer.append('g').attr('id', 'topo-force'); | 371 | forceG = zoomLayer.append('g').attr('id', 'topo-force'); |
372 | tfs.initForce(svg, forceG, uplink, dim); | 372 | tfs.initForce(svg, forceG, uplink, dim); | ... | ... |
... | @@ -16,47 +16,85 @@ | ... | @@ -16,47 +16,85 @@ |
16 | 16 | ||
17 | /* | 17 | /* |
18 | ONOS GUI -- Topology Sprite Module. | 18 | ONOS GUI -- Topology Sprite Module. |
19 | - Defines behavior for loading sprites. | 19 | + Defines behavior for loading sprites into the sprite layer. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | (function () { | 22 | (function () { |
23 | 'use strict'; | 23 | 'use strict'; |
24 | 24 | ||
25 | // injected refs | 25 | // injected refs |
26 | - var $log, $http, fs, sus, wss; | 26 | + var $log, $http, fs, gs, sus, wss; |
27 | 27 | ||
28 | var tssid = 'TopoSpriteService: '; | 28 | var tssid = 'TopoSpriteService: '; |
29 | 29 | ||
30 | // internal state | 30 | // internal state |
31 | - var spriteLayer; | 31 | + var spriteLayer, defsElement; |
32 | 32 | ||
33 | - function doSprite(def, item) { | 33 | + function registerPathsAsGlyphs(paths) { |
34 | - var g; | 34 | + var custom = {}, |
35 | + ids = []; | ||
35 | 36 | ||
36 | - function xfm(x, y, s) { | 37 | + function mkd(d) { |
37 | - return sus.translate([x,y]) + sus.scale(s, s); | 38 | + return fs.isA(d) ? d.join('') : d; |
38 | } | 39 | } |
39 | 40 | ||
40 | - g = spriteLayer.append('g') | 41 | + if (paths) { |
41 | - .classed(def['class'], true) | 42 | + paths.forEach(function (path) { |
42 | - .attr('transform', xfm(item.x, item.y, def.scale)); | 43 | + var tag = 'spr_' + path.tag; |
44 | + custom['_' + tag] = path.viewbox || '0 0 1000 1000'; | ||
45 | + custom[tag] = mkd(path.d); | ||
46 | + ids.push(tag); | ||
47 | + }); | ||
43 | 48 | ||
44 | - if (item.label) { | 49 | + gs.registerGlyphs(custom); |
45 | - g.append('text') | 50 | + gs.loadDefs(defsElement, ids, true); |
46 | - .text(item.label) | ||
47 | - .attr({ | ||
48 | - x: def.width / 2, | ||
49 | - y: def.height * def.textyoff | ||
50 | - }); | ||
51 | } | 51 | } |
52 | + } | ||
53 | + | ||
54 | + function labAttr(def) { | ||
55 | + var dim = def.dim || [1000,1000], | ||
56 | + w = dim[0], | ||
57 | + h = dim[1], | ||
58 | + dy = def.labelyoff || 1; | ||
59 | + | ||
60 | + return { x: w / 2, y: h * dy }; | ||
61 | + } | ||
62 | + | ||
63 | + function doSprite(spr, def) { | ||
64 | + var c = spr.class || 'gray1', | ||
65 | + p = spr.pos || [0,0], | ||
66 | + lab = spr.label, | ||
67 | + dim = def.dim || [1000,1000], | ||
68 | + w = dim[0], | ||
69 | + h = dim[1], | ||
70 | + use = def.glyph || 'spr_' + def.path, | ||
71 | + g = spriteLayer.append('g') | ||
72 | + .classed(c, true) | ||
73 | + .attr('transform', sus.translate(p)); | ||
52 | 74 | ||
53 | g.append('use').attr({ | 75 | g.append('use').attr({ |
54 | - width: def.width, | 76 | + width: w, |
55 | - height: def.height, | 77 | + height: h, |
56 | - 'xlink:href': '#' + def.use | 78 | + 'xlink:href': '#' + use |
57 | }); | 79 | }); |
80 | + | ||
81 | + if (lab) { | ||
82 | + g.append('text') | ||
83 | + .text(lab) | ||
84 | + .attr(labAttr(def)); | ||
85 | + } | ||
86 | + } | ||
87 | + | ||
88 | + function doLabel(label) { | ||
89 | + var c = label.class || 'gray1', | ||
90 | + p = label.pos || [0,0]; | ||
91 | + spriteLayer.append('text') | ||
92 | + .text(label.text) | ||
93 | + .attr('transform', sus.translate(p)) | ||
94 | + .classed(c, true); | ||
58 | } | 95 | } |
59 | 96 | ||
97 | + | ||
60 | // ========================== | 98 | // ========================== |
61 | // event handlers | 99 | // event handlers |
62 | 100 | ||
... | @@ -73,30 +111,49 @@ | ... | @@ -73,30 +111,49 @@ |
73 | // data for the requested sprite definition. | 111 | // data for the requested sprite definition. |
74 | function inData(payload) { | 112 | function inData(payload) { |
75 | var data = payload.data, | 113 | var data = payload.data, |
76 | - name = data && data.defn_name, | 114 | + name, desc, sprites, labels, |
77 | - desc = data && data.defn_desc, | 115 | + paths = {}, |
78 | defs = {}; | 116 | defs = {}; |
79 | 117 | ||
80 | if (!data) { | 118 | if (!data) { |
81 | $log.warn(tssid + 'No sprite data loaded.') | 119 | $log.warn(tssid + 'No sprite data loaded.') |
82 | return; | 120 | return; |
83 | } | 121 | } |
122 | + name = data.defn_name; | ||
123 | + desc = data.defn_desc; | ||
84 | 124 | ||
85 | $log.debug("Loading sprites...[" + name + "]", desc); | 125 | $log.debug("Loading sprites...[" + name + "]", desc); |
86 | 126 | ||
87 | - data.defn.forEach(function (d) { | 127 | + registerPathsAsGlyphs(data.paths); |
88 | - defs[d.id] = d; | ||
89 | - }); | ||
90 | 128 | ||
91 | - data.load.forEach(function (item) { | 129 | + if (data.defn) { |
92 | - doSprite(defs[item.id], item); | 130 | + data.defn.forEach(function (d) { |
93 | - }); | 131 | + defs[d.id] = d; |
132 | + }); | ||
133 | + } | ||
134 | + | ||
135 | + // pull out the sprite and label items | ||
136 | + if (data.load) { | ||
137 | + sprites = data.load.sprites; | ||
138 | + labels = data.load.labels; | ||
139 | + } | ||
140 | + | ||
141 | + if (sprites) { | ||
142 | + sprites.forEach(function (spr) { | ||
143 | + doSprite(spr, defs[spr.id]); | ||
144 | + }); | ||
145 | + } | ||
146 | + | ||
147 | + if (labels) { | ||
148 | + labels.forEach(doLabel); | ||
149 | + } | ||
94 | } | 150 | } |
95 | 151 | ||
96 | 152 | ||
97 | - function loadSprites(layer, defname) { | 153 | + function loadSprites(layer, defsElem, defname) { |
98 | var name = defname || 'sprites'; | 154 | var name = defname || 'sprites'; |
99 | spriteLayer = layer; | 155 | spriteLayer = layer; |
156 | + defsElement = defsElem; | ||
100 | 157 | ||
101 | $log.info(tssid + 'Requesting sprite definition ['+name+']...'); | 158 | $log.info(tssid + 'Requesting sprite definition ['+name+']...'); |
102 | 159 | ||
... | @@ -109,12 +166,14 @@ | ... | @@ -109,12 +166,14 @@ |
109 | 166 | ||
110 | angular.module('ovTopo') | 167 | angular.module('ovTopo') |
111 | .factory('TopoSpriteService', | 168 | .factory('TopoSpriteService', |
112 | - ['$log', '$http', 'FnService', 'SvgUtilService', 'WebSocketService', | 169 | + ['$log', '$http', 'FnService', 'GlyphService', |
170 | + 'SvgUtilService', 'WebSocketService', | ||
113 | 171 | ||
114 | - function (_$log_, _$http_, _fs_, _sus_, _wss_) { | 172 | + function (_$log_, _$http_, _fs_, _gs_, _sus_, _wss_) { |
115 | $log = _$log_; | 173 | $log = _$log_; |
116 | $http = _$http_; | 174 | $http = _$http_; |
117 | fs = _fs_; | 175 | fs = _fs_; |
176 | + gs = _gs_; | ||
118 | sus = _sus_; | 177 | sus = _sus_; |
119 | wss = _wss_; | 178 | wss = _wss_; |
120 | 179 | ... | ... |
1 | +{ | ||
2 | + "defn_name": "layout", | ||
3 | + "defn_desc": "Sample Layout Sprite Data", | ||
4 | + | ||
5 | + "_comment": [ | ||
6 | + "Sample sprite layout file, demonstrating user-defined outlines", | ||
7 | + "(1) Register on the server with ...", | ||
8 | + " onos-upload-sprites localhost layout.json", | ||
9 | + "(2) Load into topology view with ...", | ||
10 | + " http://localhost:8181/onos/ui/index.html#/topo?sprites=layout" | ||
11 | + ], | ||
12 | + | ||
13 | + "_comment_paths": [ | ||
14 | + "The 'paths' array contains custom path data.", | ||
15 | + "Note that viewbox defaults to [0 0 1000 1000], which is the logical", | ||
16 | + "coordinate space of the topology view." | ||
17 | + ], | ||
18 | + "paths": [ | ||
19 | + { | ||
20 | + "tag": "border", | ||
21 | + "d": "M0,0h1000v1000h-1000z", | ||
22 | + "_comment": "bounds of viewbox 0 0 1000 1000" | ||
23 | + }, | ||
24 | + { | ||
25 | + "tag": "multi", | ||
26 | + "d": [ | ||
27 | + "M500,500l-50,50v-200h100v200z", | ||
28 | + "M600,400h200v50h-200z" | ||
29 | + ], | ||
30 | + "_comment": "shows path constructed from multiple strings" | ||
31 | + }, | ||
32 | + { | ||
33 | + "tag": "triangle", | ||
34 | + "viewbox": "0 0 1 1", | ||
35 | + "d": "M.5,.2l.3,.6,h-.6z", | ||
36 | + "_comment": "defines its own viewbox" | ||
37 | + }, | ||
38 | + { | ||
39 | + "tag": "diamond", | ||
40 | + "viewbox": "0 0 1 1", | ||
41 | + "d": "M.2,.5l.3,-.3l.3,.3l-.3,.3z" | ||
42 | + } | ||
43 | + ], | ||
44 | + | ||
45 | + "_comment_defn": [ | ||
46 | + "The 'defn' array contains sprite definitions that combine", | ||
47 | + "path, dimensions, and label-offset into 'sprites' that can be", | ||
48 | + "replicated (stamped) in different positions in the view.", | ||
49 | + "", | ||
50 | + "The 'glyph' property refers to glyphs registered with the UI.", | ||
51 | + "Alternatively, the 'path' property refers to a custom path defined in", | ||
52 | + "the path array above. The 'dim' property provides the [width,height]", | ||
53 | + "bounds within which the glyph/path is drawn. The 'labelyoff' property", | ||
54 | + "defines the Y-offset of the label as a percentage from the top of the", | ||
55 | + "sprite; for example, 0.4 = 40%. The label is centered horizontally.", | ||
56 | + "", | ||
57 | + "Note that dimension (dim) defaults to [1000,1000] so that, by default,", | ||
58 | + "there is a 1:1 scale mapping of custom paths to the topology view." | ||
59 | + ], | ||
60 | + "defn": [ | ||
61 | + { | ||
62 | + "id": "border", | ||
63 | + "path": "border" | ||
64 | + }, | ||
65 | + { | ||
66 | + "id": "multi", | ||
67 | + "path": "multi" | ||
68 | + }, | ||
69 | + { | ||
70 | + "id": "small_tri", | ||
71 | + "path": "triangle", | ||
72 | + "dim":[80,80] | ||
73 | + }, | ||
74 | + { | ||
75 | + "id": "big_tri", | ||
76 | + "path": "triangle", | ||
77 | + "dim":[160,160] | ||
78 | + }, | ||
79 | + { | ||
80 | + "id": "subnet", | ||
81 | + "glyph": "cloud", | ||
82 | + "dim":[120,120], | ||
83 | + "labelyoff": 0.4 | ||
84 | + }, | ||
85 | + { | ||
86 | + "id": "subnet2", | ||
87 | + "glyph": "cloud", | ||
88 | + "dim":[200,200], | ||
89 | + "labelyoff": 0.4 | ||
90 | + } | ||
91 | + ], | ||
92 | + | ||
93 | + "_comment_load": [ | ||
94 | + "The 'load' object contains sprites and labels to load into the view.", | ||
95 | + "", | ||
96 | + "Items in the sprite list associate sprites with a position,", | ||
97 | + "style class, and optional label. Note that the coordinates of", | ||
98 | + "the position define the top-left corner of the sprite.", | ||
99 | + "Default 'pos' is [0,0]. Default 'class' is 'gray1'.", | ||
100 | + "", | ||
101 | + "Items in the label list associate labels with a position and", | ||
102 | + "style class. Note that the text is centered on the x-coordinate." | ||
103 | + ], | ||
104 | + "load": { | ||
105 | + "sprites": [ | ||
106 | + { "id": "border" }, | ||
107 | + { "id": "multi", "class": "gray1" }, | ||
108 | + { "id": "subnet", "pos":[-40,20], "label":"apples", "class": "blue1" }, | ||
109 | + { "id": "subnet", "pos":[400,40], "label":"bananas", "class": "blue1" }, | ||
110 | + { "id": "subnet", "pos":[840,60], "label":"cherries", "class": "blue1" }, | ||
111 | + { "id": "subnet2", "pos":[300,400], "class": "gray1" }, | ||
112 | + { "id": "small_tri", "pos":[10, 20] }, | ||
113 | + { "id": "small_tri", "pos":[110, 20] }, | ||
114 | + { "id": "small_tri", "pos":[210, 20] }, | ||
115 | + { "id": "small_tri", "pos":[310, 20] } | ||
116 | + ], | ||
117 | + "labels": [ | ||
118 | + { "pos":[500,940], "text":"Sample Layout", "class":"blue1" }, | ||
119 | + { "pos":[500,1000], "text":"Illustrating Sprites", "class":"gray1" } | ||
120 | + ] | ||
121 | + } | ||
122 | +} |
-
Please register or login to post a comment