Simon Hunt

GUI -- Created sample subnet sprite layout (clouds.json).

- Made paths, defn, load mandatory properties of the sprite definition file.
- (layout.json still a WIP)

Change-Id: I323a7ec7317f0837ff3319d67956cb4f836405eb
...@@ -555,7 +555,7 @@ ...@@ -555,7 +555,7 @@
555 } 555 }
556 556
557 .light #ov-topo svg #topo-sprites .gold1 use { 557 .light #ov-topo svg #topo-sprites .gold1 use {
558 - stroke: #da2; 558 + stroke: #fda;
559 fill: none; 559 fill: none;
560 } 560 }
561 .dark #ov-topo svg #topo-sprites .gold1 use { 561 .dark #ov-topo svg #topo-sprites .gold1 use {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
32 // internal state 32 // internal state
33 var spriteLayer, defsElement; 33 var spriteLayer, defsElement;
34 34
35 +
35 function registerPathsAsGlyphs(paths) { 36 function registerPathsAsGlyphs(paths) {
36 var custom = {}, 37 var custom = {},
37 ids = []; 38 ids = [];
...@@ -40,21 +41,25 @@ ...@@ -40,21 +41,25 @@
40 return fs.isA(d) ? d.join('') : d; 41 return fs.isA(d) ? d.join('') : d;
41 } 42 }
42 43
43 - if (paths) { 44 + paths.forEach(function (path) {
44 - paths.forEach(function (path) { 45 + var tag = 'spr_' + path.tag;
45 - var tag = 'spr_' + path.tag;
46 - custom['_' + tag] = path.viewbox || '0 0 1000 1000';
47 - custom[tag] = mkd(path.d);
48 - ids.push(tag);
49 - });
50 46
51 - gs.registerGlyphs(custom); 47 + if (path.glyph) {
52 - gs.loadDefs(defsElement, ids, true); 48 + // assumption is that we are using a built-in glyph
53 - } 49 + return;
50 + }
51 +
52 + custom['_' + tag] = path.viewbox || '0 0 1000 1000';
53 + custom[tag] = mkd(path.d);
54 + ids.push(tag);
55 + });
56 +
57 + gs.registerGlyphs(custom);
58 + gs.loadDefs(defsElement, ids, true);
54 } 59 }
55 60
56 61
57 - function doSprite(spr, def, pstrk) { 62 + function doSprite(spr, def, pmeta) {
58 var c = spr.class || 'gray1', 63 var c = spr.class || 'gray1',
59 p = spr.pos || [0,0], 64 p = spr.pos || [0,0],
60 lab = spr.label, 65 lab = spr.label,
...@@ -64,7 +69,6 @@ ...@@ -64,7 +69,6 @@
64 dy = def.labelyoff || 1, 69 dy = def.labelyoff || 1,
65 sc = def.scale, 70 sc = def.scale,
66 xfm = sus.translate(p), 71 xfm = sus.translate(p),
67 - useId = def.glyph || 'spr_' + def.path,
68 g, attr, use, style; 72 g, attr, use, style;
69 73
70 if (sc) { 74 if (sc) {
...@@ -78,14 +82,14 @@ ...@@ -78,14 +82,14 @@
78 attr = { 82 attr = {
79 width: w, 83 width: w,
80 height: h, 84 height: h,
81 - 'xlink:href': '#' + useId 85 + 'xlink:href': '#' + pmeta.u
82 }; 86 };
83 87
84 use = g.append('use').attr(attr); 88 use = g.append('use').attr(attr);
85 89
86 - if (pstrk) { 90 + if (pmeta.s) {
87 style = {}; 91 style = {};
88 - angular.forEach(pstrk, function (value, key) { 92 + angular.forEach(pmeta.s, function (value, key) {
89 style['stroke-' + key] = value; 93 style['stroke-' + key] = value;
90 }); 94 });
91 use.style(style); 95 use.style(style);
...@@ -127,47 +131,66 @@ ...@@ -127,47 +131,66 @@
127 // data for the requested sprite definition. 131 // data for the requested sprite definition.
128 function inData(payload) { 132 function inData(payload) {
129 var data = payload.data, 133 var data = payload.data,
130 - name, desc, sprites, labels, alpha, 134 + name, desc, pfx, sprites, labels, alpha,
131 - pathstrokes = {}, 135 + paths, defn, load,
132 - defs = {}; 136 + pathmeta = {},
137 + defs = {},
138 + warn = [];
133 139
134 if (!data) { 140 if (!data) {
135 - $log.warn(tssid + 'No sprite data loaded.') 141 + $log.warn(tssid + 'No sprite data loaded.');
136 return; 142 return;
137 } 143 }
138 name = data.defn_name; 144 name = data.defn_name;
139 desc = data.defn_desc; 145 desc = data.defn_desc;
146 + paths = data.paths;
147 + defn = data.defn;
148 + load = data.load;
149 + pfx = tssid + '[' + name + ']: ';
140 150
141 $log.debug("Loading sprites...[" + name + "]", desc); 151 $log.debug("Loading sprites...[" + name + "]", desc);
142 152
143 - if (data.paths) { 153 + function no(what) {
144 - registerPathsAsGlyphs(data.paths); 154 + warn.push(pfx + 'No ' + what + ' property defined');
145 - data.paths.forEach(function (p) {
146 - pathstrokes[p.tag] = p.stroke;
147 - });
148 } 155 }
149 156
150 - if (data.defn) { 157 + if (!paths) no('paths');
151 - data.defn.forEach(function (d) { 158 + if (!defn) no('defn');
152 - defs[d.id] = d; 159 + if (!load) no('load');
153 - }); 160 +
161 + if (warn.length) {
162 + $log.error(warn.join('\n'));
163 + return;
154 } 164 }
155 165
156 - // pull out the sprite and label items 166 + // any custom paths need to be added to the glyph DB, and imported
157 - if (data.load) { 167 + registerPathsAsGlyphs(paths);
158 - sprites = data.load.sprites; 168 +
159 - labels = data.load.labels; 169 + paths.forEach(function (p) {
160 - alpha = data.load.alpha; 170 + pathmeta[p.tag] = {
161 - if (alpha) { 171 + s: p.stroke,
162 - spriteLayer.style('opacity', alpha); 172 + u: p.glyph || 'spr_' + p.tag
163 - } 173 + };
174 + });
175 +
176 + defn.forEach(function (d) {
177 + defs[d.id] = d;
178 + });
179 +
180 + // sprites, labels and alpha are each optional components of the load
181 + sprites = load.sprites;
182 + labels = load.labels;
183 + alpha = load.alpha;
184 +
185 + if (alpha) {
186 + spriteLayer.style('opacity', alpha);
164 } 187 }
165 188
166 if (sprites) { 189 if (sprites) {
167 sprites.forEach(function (spr) { 190 sprites.forEach(function (spr) {
168 var def = defs[spr.id], 191 var def = defs[spr.id],
169 - pstrk = def.path && pathstrokes[def.path]; 192 + pmeta = pathmeta[def.path];
170 - doSprite(spr, def, pstrk); 193 + doSprite(spr, def, pmeta);
171 }); 194 });
172 } 195 }
173 196
......
1 +{
2 + "defn_name": "clouds",
3 + "defn_desc": "Sample Subnet Cloud layout",
4 +
5 + "_comment": [
6 + "Sample cloud sprite layout",
7 + "(1) Register on the server with ...",
8 + " onos-upload-sprites localhost clouds.json",
9 + "(2) Load into topology view with ...",
10 + " http://localhost:8181/onos/ui/index.html#/topo?sprites=clouds"
11 + ],
12 +
13 + "paths": [
14 + {
15 + "tag": "cloud-dashed",
16 + "stroke": {
17 + "width": 0.8,
18 + "dasharray": [4,2]
19 + },
20 + "glyph": "cloud"
21 + },
22 + {
23 + "tag": "cloud-solid",
24 + "stroke": {
25 + "width": 1
26 + },
27 + "glyph": "cloud"
28 + }
29 + ],
30 +
31 + "defn": [
32 + {
33 + "id": "subnetA",
34 + "path": "cloud-dashed",
35 + "dim": [400,400],
36 + "labelyoff": 0.35
37 + },
38 + {
39 + "id": "subnetB",
40 + "path": "cloud-solid",
41 + "dim": [600,600],
42 + "labelyoff": 0.35
43 + }
44 + ],
45 +
46 + "load": {
47 + "sprites": [
48 + { "id": "subnetA", "pos":[-200,40], "label":"apples", "class":"blue1" },
49 + { "id": "subnetA", "pos":[250,40], "label":"bananas", "class":"blue1" },
50 + { "id": "subnetA", "pos":[700,40], "label":"cherries", "class":"blue1" },
51 + { "id": "subnetB", "pos":[-200,400], "label":"Menlo Park", "class":"gold1" },
52 + { "id": "subnetB", "pos":[500,400], "label":"Stanford", "class":"gold1" }
53 + ],
54 + "labels": [
55 + { "pos":[0,50], "text":"Sample Subnets", "size":1.4 }
56 + ]
57 + }
58 +
59 +}
...@@ -18,16 +18,18 @@ ...@@ -18,16 +18,18 @@
18 "paths": [ 18 "paths": [
19 { 19 {
20 "tag": "border", 20 "tag": "border",
21 - "d": "M0,0h1000v1000h-1000z", 21 + "viewbox": "0 0 1 1",
22 - "_comment": "bounds of viewbox 0 0 1000 1000" 22 + "d": "M0,0h1v1h-1z",
23 + "_comment": "path defined in single string"
23 }, 24 },
24 { 25 {
25 - "tag": "multi", 26 + "tag": "banner",
27 + "viewbox": "0 0 4 8",
26 "d": [ 28 "d": [
27 - "M500,500l-50,50v-200h100v200z", 29 + "M0,0h4v6l-2,-2l-2,2z",
28 - "M600,400h200v50h-200z" 30 + "M1,6h2v2h-2z"
29 ], 31 ],
30 - "_comment": "shows path constructed from multiple strings" 32 + "_comment": "path defined in multiple strings"
31 }, 33 },
32 { 34 {
33 "tag": "triangle", 35 "tag": "triangle",
...@@ -49,18 +51,20 @@ ...@@ -49,18 +51,20 @@
49 "", 51 "",
50 "The 'glyph' property refers to glyphs registered with the UI.", 52 "The 'glyph' property refers to glyphs registered with the UI.",
51 "Alternatively, the 'path' property refers to a custom path defined in", 53 "Alternatively, the 'path' property refers to a custom path defined in",
52 - "the path array above. The 'dim' property provides the [width,height]", 54 + " the path array above.",
53 - "bounds within which the glyph/path is drawn. The 'labelyoff' property", 55 + "The 'dim' property provides the [width,height] bounds within which the",
54 - "defines the Y-offset of the label as a percentage from the top of the", 56 + " glyph/path is drawn. (default is [40,40])",
55 - "sprite; for example, 0.4 = 40%. The label is centered horizontally.", 57 + "The 'labelyoff' property defines the Y-offset of the label as a",
56 - "", 58 + " percentage from the top of the sprite; for example, 0.4 = 40%. The",
57 - "Note that dimension (dim) defaults to [40,40] which is the", 59 + " label is centered horizontally.",
58 - "approximate size of a device icon." 60 + "The 'scale' property (default is 1) defines the scaling factor, which",
61 + " is applied after the sprite has been translated to its position."
59 ], 62 ],
60 "defn": [ 63 "defn": [
61 { 64 {
62 "id": "border", 65 "id": "border",
63 - "path": "border" 66 + "path": "border",
67 + "dim":[1000,1000]
64 }, 68 },
65 { 69 {
66 "id": "multi", 70 "id": "multi",
...@@ -103,6 +107,7 @@ ...@@ -103,6 +107,7 @@
103 ], 107 ],
104 "load": { 108 "load": {
105 "sprites": [ 109 "sprites": [
110 + { "id": "border", "class": "gold1" },
106 { "id": "subnet", "pos":[-40,20], "label":"apples", "class": "blue1" }, 111 { "id": "subnet", "pos":[-40,20], "label":"apples", "class": "blue1" },
107 { "id": "subnet", "pos":[400,40], "label":"bananas", "class": "blue1" }, 112 { "id": "subnet", "pos":[400,40], "label":"bananas", "class": "blue1" },
108 { "id": "subnet", "pos":[840,60], "label":"cherries", "class": "blue1" }, 113 { "id": "subnet", "pos":[840,60], "label":"cherries", "class": "blue1" },
......