Showing
2 changed files
with
162 additions
and
48 deletions
... | @@ -15,7 +15,7 @@ | ... | @@ -15,7 +15,7 @@ |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* | 17 | /* |
18 | - Alternate Sample module file to illustrate framework integration. | 18 | + Sample module file to illustrate framework integration. |
19 | 19 | ||
20 | @author Simon Hunt | 20 | @author Simon Hunt |
21 | */ | 21 | */ |
... | @@ -23,9 +23,24 @@ | ... | @@ -23,9 +23,24 @@ |
23 | (function (onos) { | 23 | (function (onos) { |
24 | 'use strict'; | 24 | 'use strict'; |
25 | 25 | ||
26 | - var svg; | 26 | + var pi = Math.PI, |
27 | - | 27 | + svg, |
28 | - | 28 | + dotG, |
29 | + nCircles = 12, | ||
30 | + circleData = [], | ||
31 | + dotId = 0, | ||
32 | + angle = 360 / nCircles, | ||
33 | + baseAngle = -90 - angle, | ||
34 | + groupRadius = 120, | ||
35 | + dotRadius = 24, | ||
36 | + dotMoveMs = 800, | ||
37 | + dotAppearMs = 300, | ||
38 | + dotEase = 'elastic', | ||
39 | + colorScale = d3.scale.linear() | ||
40 | + .domain([-pi/2, 2*pi/4, 3*pi/2]) | ||
41 | + .range(['green', 'goldenrod', 'blue']); | ||
42 | + | ||
43 | + // set the size of the SVG layer to match that of the view | ||
29 | function sizeSvg(view) { | 44 | function sizeSvg(view) { |
30 | svg.attr({ | 45 | svg.attr({ |
31 | width: view.width(), | 46 | width: view.width(), |
... | @@ -33,63 +48,169 @@ | ... | @@ -33,63 +48,169 @@ |
33 | }); | 48 | }); |
34 | } | 49 | } |
35 | 50 | ||
36 | - // NOTE: view is a view-token data structure: | ||
37 | - // { | ||
38 | - // vid: 'view-id', | ||
39 | - // nid: 'nav-id', | ||
40 | - // $div: ... // d3 selection of dom view div. | ||
41 | - // } | ||
42 | - | ||
43 | // gets invoked only the first time the view is loaded | 51 | // gets invoked only the first time the view is loaded |
44 | function preload(view, ctx) { | 52 | function preload(view, ctx) { |
53 | + // prepare our SVG layer... | ||
45 | svg = view.$div.append('svg'); | 54 | svg = view.$div.append('svg'); |
46 | sizeSvg(view); | 55 | sizeSvg(view); |
56 | + dotG = svg.append('g').attr('id', 'dots'); | ||
47 | } | 57 | } |
48 | 58 | ||
59 | + // gets invoked just before our view is loaded | ||
49 | function reset(view) { | 60 | function reset(view) { |
50 | - // clear our svg of all objects | 61 | + // clear dot group and reset circle data |
51 | - svg.html(''); | 62 | + dotG.html(''); |
63 | + circleData = []; | ||
64 | + // also clear text, if any | ||
65 | + svg.selectAll('text').remove(); | ||
52 | } | 66 | } |
53 | 67 | ||
54 | - function load(view, ctx) { | 68 | + function updateCirclePositions(view, addNew) { |
55 | - var fill = 'red', | 69 | + var w = view.width(), |
56 | - stroke = 'black', | 70 | + h = view.height(), |
57 | - ctxText = ctx ? 'Context is "' + ctx + '"' : 'No Context'; | 71 | + ox = w / 2, |
72 | + oy = h / 2; | ||
73 | + | ||
74 | + // reposition existing dots | ||
75 | + circleData.forEach(function (c, i) { | ||
76 | + var inc = addNew ? 1 : 0, | ||
77 | + theta = ((i + inc) * angle + baseAngle) * pi/180, | ||
78 | + dx = Math.cos(theta) * groupRadius, | ||
79 | + dy = Math.sin(theta) * groupRadius, | ||
80 | + x = ox + dx, | ||
81 | + y = oy + dy; | ||
82 | + if (!addNew && i === 0) { | ||
83 | + x = ox; | ||
84 | + y = oy; | ||
85 | + } | ||
86 | + c.cx = x; | ||
87 | + c.cy = y; | ||
88 | + c.rgb = colorScale(theta); | ||
89 | + }); | ||
90 | + | ||
91 | + if (addNew) { | ||
92 | + // introduce a new dot | ||
93 | + circleData.unshift({ | ||
94 | + cx: ox, | ||
95 | + cy: oy, | ||
96 | + id: dotId++ | ||
97 | + }); | ||
98 | + } | ||
99 | + | ||
100 | + // +1 to account for the circle in the center.. | ||
101 | + if (circleData.length > nCircles + 1) { | ||
102 | + circleData.splice(nCircles + 1, 1); | ||
103 | + } | ||
104 | + } | ||
58 | 105 | ||
59 | - svg.append('circle') | 106 | + function doCircles(view) { |
107 | + var ox = view.width() / 2, | ||
108 | + oy = view.height() / 2, | ||
109 | + stroke = 'black', | ||
110 | + fill = 'red', | ||
111 | + hoverFill = 'magenta'; | ||
112 | + | ||
113 | + // move existing circles, and add a new one | ||
114 | + updateCirclePositions(view, true); | ||
115 | + | ||
116 | + var circ = dotG.selectAll('circle') | ||
117 | + .data(circleData, function (d) { return d.id; }); | ||
118 | + | ||
119 | + // operate on existing elements | ||
120 | + circ.on('mouseover', null) | ||
121 | + .on('mouseout', null) | ||
122 | + .on('click', null) | ||
123 | + .transition() | ||
124 | + .duration(dotMoveMs) | ||
125 | + .ease(dotEase) | ||
60 | .attr({ | 126 | .attr({ |
61 | - cx: view.width() / 2, | 127 | + cx: function (d) { return d.cx; }, |
62 | - cy: view.height() / 2, | 128 | + cy: function (d) { return d.cy; } |
63 | - r: 30 | ||
64 | }) | 129 | }) |
65 | .style({ | 130 | .style({ |
66 | - fill: fill, | 131 | + cursor: 'default', |
67 | - stroke: stroke, | 132 | + fill: function (d) { return d.rgb; } |
68 | - 'stroke-width': 3.5 | ||
69 | }); | 133 | }); |
70 | 134 | ||
71 | - svg.append('text') | 135 | + // operate on entering elements |
72 | - .text(ctxText) | 136 | + circ.enter() |
137 | + .append('circle') | ||
73 | .attr({ | 138 | .attr({ |
74 | - x: 20, | 139 | + cx: function (d) { return d.cx; }, |
75 | - y: '1.5em' | 140 | + cy: function (d) { return d.cy; }, |
141 | + r: 0 | ||
76 | }) | 142 | }) |
77 | .style({ | 143 | .style({ |
78 | - fill: 'darkgreen', | 144 | + fill: fill, |
79 | - 'font-size': '20pt' | 145 | + stroke: stroke, |
80 | - }); | 146 | + 'stroke-width': 3.5, |
147 | + cursor: 'pointer', | ||
148 | + opacity: 0 | ||
149 | + }) | ||
150 | + .on('mouseover', function (d) { | ||
151 | + d3.select(this).style('fill', hoverFill); | ||
152 | + }) | ||
153 | + .on('mouseout', function (d) { | ||
154 | + d3.select(this).style('fill', fill); | ||
155 | + }) | ||
156 | + .on('click', function (d) { | ||
157 | + setTimeout(function() { | ||
158 | + doCircles(view, true); | ||
159 | + }, 10); | ||
160 | + }) | ||
161 | + .transition() | ||
162 | + .delay(dotMoveMs) | ||
163 | + .duration(dotAppearMs) | ||
164 | + .attr('r', dotRadius) | ||
165 | + .style('opacity', 1); | ||
166 | + | ||
167 | + // operate on exiting elements | ||
168 | + circ.exit() | ||
169 | + .transition() | ||
170 | + .duration(750) | ||
171 | + .style('opacity', 0) | ||
172 | + .attr({ | ||
173 | + cx: ox, | ||
174 | + cy: oy, | ||
175 | + r: groupRadius - dotRadius | ||
176 | + }) | ||
177 | + .remove(); | ||
178 | + } | ||
179 | + | ||
180 | + function load(view, ctx) { | ||
181 | + var ctxText = ctx ? 'Context is "' + ctx + '"' : ''; | ||
182 | + | ||
183 | + // display our view context | ||
184 | + if (ctxText) { | ||
185 | + svg.append('text') | ||
186 | + .text(ctxText) | ||
187 | + .attr({ | ||
188 | + x: 20, | ||
189 | + y: '1.5em' | ||
190 | + }) | ||
191 | + .style({ | ||
192 | + fill: 'darkgreen', | ||
193 | + 'font-size': '20pt' | ||
194 | + }); | ||
195 | + } | ||
196 | + | ||
197 | + doCircles(view); | ||
81 | } | 198 | } |
82 | 199 | ||
83 | function resize(view, ctx) { | 200 | function resize(view, ctx) { |
84 | sizeSvg(view); | 201 | sizeSvg(view); |
85 | - svg.selectAll('circle') | 202 | + updateCirclePositions(view); |
86 | - .attr({ | 203 | + |
87 | - cx: view.width() / 2, | 204 | + // move exiting dots into new positions, relative to view size |
88 | - cy: view.height() / 2 | 205 | + var circ = dotG.selectAll('circle') |
206 | + .data(circleData, function (d) { return d.id; }); | ||
207 | + circ.attr({ | ||
208 | + cx: function (d) { return d.cx; }, | ||
209 | + cy: function (d) { return d.cy; } | ||
89 | }); | 210 | }); |
90 | } | 211 | } |
91 | 212 | ||
92 | - // == register views here, with links to lifecycle callbacks | 213 | + // == register our view here, with links to lifecycle callbacks |
93 | 214 | ||
94 | onos.ui.addView('sample', { | 215 | onos.ui.addView('sample', { |
95 | preload: preload, | 216 | preload: preload, |
... | @@ -98,5 +219,4 @@ | ... | @@ -98,5 +219,4 @@ |
98 | resize: resize | 219 | resize: resize |
99 | }); | 220 | }); |
100 | 221 | ||
101 | - | ||
102 | }(ONOS)); | 222 | }(ONOS)); | ... | ... |
... | @@ -15,7 +15,7 @@ | ... | @@ -15,7 +15,7 @@ |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* | 17 | /* |
18 | - Sample module file to illustrate framework integration. | 18 | + Alternate sample module file to illustrate framework integration. |
19 | 19 | ||
20 | @author Simon Hunt | 20 | @author Simon Hunt |
21 | */ | 21 | */ |
... | @@ -33,13 +33,6 @@ | ... | @@ -33,13 +33,6 @@ |
33 | }); | 33 | }); |
34 | } | 34 | } |
35 | 35 | ||
36 | - // NOTE: view is a view-token data structure: | ||
37 | - // { | ||
38 | - // vid: 'view-id', | ||
39 | - // nid: 'nav-id', | ||
40 | - // $div: ... // d3 selection of dom view div. | ||
41 | - // } | ||
42 | - | ||
43 | // gets invoked only the first time the view is loaded | 36 | // gets invoked only the first time the view is loaded |
44 | function preload(view, ctx) { | 37 | function preload(view, ctx) { |
45 | svg = view.$div.append('svg'); | 38 | svg = view.$div.append('svg'); |
... | @@ -52,8 +45,8 @@ | ... | @@ -52,8 +45,8 @@ |
52 | } | 45 | } |
53 | 46 | ||
54 | function load(view, ctx) { | 47 | function load(view, ctx) { |
55 | - var fill = 'blue', | 48 | + var fill = 'teal', |
56 | - stroke = 'grey'; | 49 | + stroke = 'black'; |
57 | 50 | ||
58 | svg.append('circle') | 51 | svg.append('circle') |
59 | .attr({ | 52 | .attr({ |
... | @@ -64,7 +57,8 @@ | ... | @@ -64,7 +57,8 @@ |
64 | .style({ | 57 | .style({ |
65 | fill: fill, | 58 | fill: fill, |
66 | stroke: stroke, | 59 | stroke: stroke, |
67 | - 'stroke-width': 3.5 | 60 | + 'stroke-width': 1.5, |
61 | + opacity: 0.5 | ||
68 | }); | 62 | }); |
69 | } | 63 | } |
70 | 64 | ... | ... |
-
Please register or login to post a comment