GUI -- Fixed intent perf GUI styling.
Change-Id: I552d3a50f7f4dd5bb1df7115c15eb6a04f538378
Showing
8 changed files
with
96 additions
and
314 deletions
... | @@ -37,10 +37,8 @@ import java.util.HashMap; | ... | @@ -37,10 +37,8 @@ import java.util.HashMap; |
37 | import java.util.LinkedList; | 37 | import java.util.LinkedList; |
38 | import java.util.List; | 38 | import java.util.List; |
39 | import java.util.Map; | 39 | import java.util.Map; |
40 | -import java.util.concurrent.ExecutorService; | ||
41 | -import java.util.concurrent.Executors; | ||
42 | 40 | ||
43 | -import static org.onlab.util.Tools.groupedThreads; | 41 | +import static org.onlab.util.SharedExecutors.getPoolThreadExecutor; |
44 | import static org.slf4j.LoggerFactory.getLogger; | 42 | import static org.slf4j.LoggerFactory.getLogger; |
45 | 43 | ||
46 | /** | 44 | /** |
... | @@ -78,18 +76,13 @@ public class IntentPerfCollector { | ... | @@ -78,18 +76,13 @@ public class IntentPerfCollector { |
78 | private Map<NodeId, Integer> nodeToIndex; | 76 | private Map<NodeId, Integer> nodeToIndex; |
79 | 77 | ||
80 | private NodeId nodeId; | 78 | private NodeId nodeId; |
81 | - private ExecutorService messageHandlingExecutor; | ||
82 | 79 | ||
83 | @Activate | 80 | @Activate |
84 | public void activate() { | 81 | public void activate() { |
85 | nodeId = clusterService.getLocalNode().id(); | 82 | nodeId = clusterService.getLocalNode().id(); |
86 | 83 | ||
87 | - // TODO: replace with shared executor | ||
88 | - messageHandlingExecutor = Executors.newSingleThreadExecutor( | ||
89 | - groupedThreads("onos/perf", "message-handler")); | ||
90 | - | ||
91 | communicationService.addSubscriber(SAMPLE, new InternalSampleCollector(), | 84 | communicationService.addSubscriber(SAMPLE, new InternalSampleCollector(), |
92 | - messageHandlingExecutor); | 85 | + getPoolThreadExecutor()); |
93 | 86 | ||
94 | nodes = clusterService.getNodes().toArray(new ControllerNode[]{}); | 87 | nodes = clusterService.getNodes().toArray(new ControllerNode[]{}); |
95 | Arrays.sort(nodes, (a, b) -> a.id().toString().compareTo(b.id().toString())); | 88 | Arrays.sort(nodes, (a, b) -> a.id().toString().compareTo(b.id().toString())); |
... | @@ -99,14 +92,13 @@ public class IntentPerfCollector { | ... | @@ -99,14 +92,13 @@ public class IntentPerfCollector { |
99 | nodeToIndex.put(nodes[i].id(), i); | 92 | nodeToIndex.put(nodes[i].id(), i); |
100 | } | 93 | } |
101 | 94 | ||
102 | - ui.setHeaders(getSampleHeaders()); | ||
103 | clearSamples(); | 95 | clearSamples(); |
96 | + ui.setCollector(this); | ||
104 | log.info("Started"); | 97 | log.info("Started"); |
105 | } | 98 | } |
106 | 99 | ||
107 | @Deactivate | 100 | @Deactivate |
108 | public void deactivate() { | 101 | public void deactivate() { |
109 | - messageHandlingExecutor.shutdown(); | ||
110 | communicationService.removeSubscriber(SAMPLE); | 102 | communicationService.removeSubscriber(SAMPLE); |
111 | log.info("Stopped"); | 103 | log.info("Stopped"); |
112 | } | 104 | } | ... | ... |
... | @@ -156,7 +156,7 @@ public class IntentPerfInstaller { | ... | @@ -156,7 +156,7 @@ public class IntentPerfInstaller { |
156 | private ExecutorService workers; | 156 | private ExecutorService workers; |
157 | private ApplicationId appId; | 157 | private ApplicationId appId; |
158 | private Listener listener; | 158 | private Listener listener; |
159 | - private boolean stopped; | 159 | + private boolean stopped = true; |
160 | 160 | ||
161 | private Timer reportTimer; | 161 | private Timer reportTimer; |
162 | 162 | ||
... | @@ -247,14 +247,19 @@ public class IntentPerfInstaller { | ... | @@ -247,14 +247,19 @@ public class IntentPerfInstaller { |
247 | } | 247 | } |
248 | 248 | ||
249 | public void start() { | 249 | public void start() { |
250 | + if (stopped) { | ||
251 | + stopped = false; | ||
250 | communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, START.getBytes())); | 252 | communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, START.getBytes())); |
251 | startTestRun(); | 253 | startTestRun(); |
252 | } | 254 | } |
255 | + } | ||
253 | 256 | ||
254 | public void stop() { | 257 | public void stop() { |
258 | + if (!stopped) { | ||
255 | communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, STOP.getBytes())); | 259 | communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, STOP.getBytes())); |
256 | stopTestRun(); | 260 | stopTestRun(); |
257 | } | 261 | } |
262 | + } | ||
258 | 263 | ||
259 | private void logConfig(String prefix) { | 264 | private void logConfig(String prefix) { |
260 | log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}", | 265 | log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}", |
... | @@ -282,7 +287,6 @@ public class IntentPerfInstaller { | ... | @@ -282,7 +287,6 @@ public class IntentPerfInstaller { |
282 | } | 287 | } |
283 | 288 | ||
284 | private void stopTestRun() { | 289 | private void stopTestRun() { |
285 | - stopped = true; | ||
286 | if (reporterTask != null) { | 290 | if (reporterTask != null) { |
287 | reporterTask.cancel(); | 291 | reporterTask.cancel(); |
288 | reporterTask = null; | 292 | reporterTask = null; |
... | @@ -293,6 +297,11 @@ public class IntentPerfInstaller { | ... | @@ -293,6 +297,11 @@ public class IntentPerfInstaller { |
293 | } catch (InterruptedException e) { | 297 | } catch (InterruptedException e) { |
294 | log.warn("Failed to stop worker", e); | 298 | log.warn("Failed to stop worker", e); |
295 | } | 299 | } |
300 | + | ||
301 | + sampleCollector.recordSample(0, 0); | ||
302 | + sampleCollector.recordSample(0, 0); | ||
303 | + stopped = true; | ||
304 | + | ||
296 | log.info("Stopped test run"); | 305 | log.info("Stopped test run"); |
297 | } | 306 | } |
298 | 307 | ... | ... |
... | @@ -36,9 +36,7 @@ import org.onosproject.ui.UiView; | ... | @@ -36,9 +36,7 @@ import org.onosproject.ui.UiView; |
36 | import java.util.Collection; | 36 | import java.util.Collection; |
37 | import java.util.HashSet; | 37 | import java.util.HashSet; |
38 | import java.util.List; | 38 | import java.util.List; |
39 | -import java.util.Random; | ||
40 | import java.util.Set; | 39 | import java.util.Set; |
41 | -import java.util.TimerTask; | ||
42 | 40 | ||
43 | import static java.util.Collections.synchronizedSet; | 41 | import static java.util.Collections.synchronizedSet; |
44 | 42 | ||
... | @@ -58,25 +56,11 @@ public class IntentPerfUi { | ... | @@ -58,25 +56,11 @@ public class IntentPerfUi { |
58 | private UiExtension uiExtension = new UiExtension(views, this::newHandlers, | 56 | private UiExtension uiExtension = new UiExtension(views, this::newHandlers, |
59 | getClass().getClassLoader()); | 57 | getClass().getClassLoader()); |
60 | 58 | ||
61 | - private List<String> headers = ImmutableList.of("One", "Two", "Three", "Four", "Five"); | 59 | + private IntentPerfCollector collector; |
62 | - | ||
63 | - private Random random = new Random(); | ||
64 | - private TimerTask task; | ||
65 | 60 | ||
66 | @Activate | 61 | @Activate |
67 | protected void activate() { | 62 | protected void activate() { |
68 | uiExtensionService.register(uiExtension); | 63 | uiExtensionService.register(uiExtension); |
69 | -// task = new TimerTask() { | ||
70 | -// @Override | ||
71 | -// public void run() { | ||
72 | -// Sample sample = new Sample(System.currentTimeMillis(), headers.size()); | ||
73 | -// for (int i = 0; i < headers.size(); i++) { | ||
74 | -// sample.data[i] = 25_000 + random.nextInt(20_000) - 5_000; | ||
75 | -// } | ||
76 | -// reportSample(sample); | ||
77 | -// } | ||
78 | -// }; | ||
79 | -// SharedExecutors.getTimer().scheduleAtFixedRate(task, 1000, 1000); | ||
80 | } | 64 | } |
81 | 65 | ||
82 | @Deactivate | 66 | @Deactivate |
... | @@ -96,12 +80,12 @@ public class IntentPerfUi { | ... | @@ -96,12 +80,12 @@ public class IntentPerfUi { |
96 | } | 80 | } |
97 | 81 | ||
98 | /** | 82 | /** |
99 | - * Sets the headers for the subsequently reported samples. | 83 | + * Binds the sample collector. |
100 | * | 84 | * |
101 | - * @param headers list of headers for future samples | 85 | + * @param collector list of headers for future samples |
102 | */ | 86 | */ |
103 | - public void setHeaders(List<String> headers) { | 87 | + public void setCollector(IntentPerfCollector collector) { |
104 | - this.headers = headers; | 88 | + this.collector = collector; |
105 | } | 89 | } |
106 | 90 | ||
107 | // Creates and returns session specific message handler. | 91 | // Creates and returns session specific message handler. |
... | @@ -122,22 +106,10 @@ public class IntentPerfUi { | ... | @@ -122,22 +106,10 @@ public class IntentPerfUi { |
122 | public void process(ObjectNode message) { | 106 | public void process(ObjectNode message) { |
123 | streamingEnabled = message.path("event").asText("unknown").equals("intentPerfStart"); | 107 | streamingEnabled = message.path("event").asText("unknown").equals("intentPerfStart"); |
124 | if (streamingEnabled) { | 108 | if (streamingEnabled) { |
125 | - sendHeaders(); | 109 | + sendInitData(); |
126 | } | 110 | } |
127 | } | 111 | } |
128 | 112 | ||
129 | - private void sendHeaders() { | ||
130 | - ArrayNode an = mapper.createArrayNode(); | ||
131 | - for (String header : headers) { | ||
132 | - an.add(header); | ||
133 | - } | ||
134 | - | ||
135 | - ObjectNode sn = mapper.createObjectNode(); | ||
136 | - sn.set("headers", an); | ||
137 | - | ||
138 | - connection().sendMessage("intentPerfHeaders", 0, sn); | ||
139 | - } | ||
140 | - | ||
141 | @Override | 113 | @Override |
142 | public void init(UiConnection connection, ServiceDirectory directory) { | 114 | public void init(UiConnection connection, ServiceDirectory directory) { |
143 | super.init(connection, directory); | 115 | super.init(connection, directory); |
... | @@ -152,18 +124,34 @@ public class IntentPerfUi { | ... | @@ -152,18 +124,34 @@ public class IntentPerfUi { |
152 | 124 | ||
153 | private void send(Sample sample) { | 125 | private void send(Sample sample) { |
154 | if (streamingEnabled) { | 126 | if (streamingEnabled) { |
127 | + connection().sendMessage("intentPerfSample", 0, sampleNode(sample)); | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + private void sendInitData() { | ||
132 | + ObjectNode rootNode = mapper.createObjectNode(); | ||
155 | ArrayNode an = mapper.createArrayNode(); | 133 | ArrayNode an = mapper.createArrayNode(); |
156 | - for (double d : sample.data) { | 134 | + ArrayNode sn = mapper.createArrayNode(); |
157 | - an.add(d); | 135 | + rootNode.set("headers", an); |
136 | + rootNode.set("samples", sn); | ||
137 | + | ||
138 | + collector.getSampleHeaders().forEach(an::add); | ||
139 | + collector.getSamples().forEach(s -> sn.add(sampleNode(s))); | ||
140 | + connection().sendMessage("intentPerfInit", 0, rootNode); | ||
158 | } | 141 | } |
159 | 142 | ||
160 | - ObjectNode sn = mapper.createObjectNode(); | 143 | + private ObjectNode sampleNode(Sample sample) { |
161 | - sn.put("time", sample.time); | 144 | + ObjectNode sampleNode = mapper.createObjectNode(); |
162 | - sn.set("data", an); | 145 | + ArrayNode an = mapper.createArrayNode(); |
146 | + sampleNode.put("time", sample.time); | ||
147 | + sampleNode.set("data", an); | ||
163 | 148 | ||
164 | - connection().sendMessage("intentPerfSample", 0, sn); | 149 | + for (double d : sample.data) { |
150 | + an.add(d); | ||
165 | } | 151 | } |
152 | + return sampleNode; | ||
166 | } | 153 | } |
154 | + | ||
167 | } | 155 | } |
168 | 156 | ||
169 | } | 157 | } | ... | ... |
1 | -date,value,node | ||
2 | -00:55:15,68.38,node1 | ||
3 | -00:55:15,55.61,node2 | ||
4 | -00:55:15,74.00,node3 | ||
5 | -00:55:30,74.20,node1 | ||
6 | -00:55:30,77.60,node2 | ||
7 | -00:55:30,74.80,node3 | ||
8 | -00:55:45,74.60,node1 | ||
9 | -00:55:45,72.80,node2 | ||
10 | -00:55:45,77.00,node3 | ||
11 | -00:56:00,73.60,node1 | ||
12 | -00:56:00,75.00,node2 | ||
13 | -00:56:00,76.98,node3 | ||
14 | -00:56:15,75.82,node1 | ||
15 | -00:56:15,75.40,node2 | ||
16 | -00:56:15,76.00,node3 | ||
17 | -00:56:30,75.60,node1 | ||
18 | -00:56:30,74.59,node2 | ||
19 | -00:56:30,74.01,node3 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -key,value,date | ||
2 | -Group1,37,00:23:00 | ||
3 | -Group2,12,00:23:00 | ||
4 | -Group3,46,00:23:00 | ||
5 | -Group1,32,00:23:05 | ||
6 | -Group2,19,00:23:05 | ||
7 | -Group3,42,00:23:05 | ||
8 | -Group1,45,00:23:10 | ||
9 | -Group2,16,00:23:10 | ||
10 | -Group3,44,00:23:10 | ||
11 | -Group1,24,00:23:15 | ||
12 | -Group2,52,00:23:15 | ||
13 | -Group3,64,00:23:15 | ||
14 | -Group1,34,00:23:20 | ||
15 | -Group2,62,00:23:20 | ||
16 | -Group3,74,00:23:20 | ||
17 | -Group1,34,00:23:25 | ||
18 | -Group2,62,00:23:25 | ||
19 | -Group3,74,00:23:25 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -22,9 +22,8 @@ svg { | ... | @@ -22,9 +22,8 @@ svg { |
22 | font: 12px sans-serif; | 22 | font: 12px sans-serif; |
23 | } | 23 | } |
24 | 24 | ||
25 | -.line { | 25 | +.line,.lineTotal { |
26 | fill: none; | 26 | fill: none; |
27 | - stroke: #000; | ||
28 | stroke-width: 2px; | 27 | stroke-width: 2px; |
29 | } | 28 | } |
30 | 29 | ||
... | @@ -37,16 +36,20 @@ svg { | ... | @@ -37,16 +36,20 @@ svg { |
37 | 36 | ||
38 | .light .axis path, | 37 | .light .axis path, |
39 | .light .axis line, | 38 | .light .axis line, |
39 | +.light .lineTotal { | ||
40 | + stroke: #333; | ||
41 | +} | ||
42 | + | ||
40 | .light .axis text { | 43 | .light .axis text { |
41 | - stroke: #999; | 44 | + fill: #333; |
42 | } | 45 | } |
43 | 46 | ||
44 | .dark .axis path, | 47 | .dark .axis path, |
45 | .dark .axis line, | 48 | .dark .axis line, |
46 | -.dark .axis text { | 49 | +.dark .lineTotal { |
47 | stroke: #eee; | 50 | stroke: #eee; |
48 | } | 51 | } |
49 | 52 | ||
50 | -.axis text { | 53 | +.dark .axis text { |
51 | - stroke-width: 0.3; | 54 | + fill: #eee; |
52 | } | 55 | } | ... | ... |
... | @@ -31,7 +31,7 @@ | ... | @@ -31,7 +31,7 @@ |
31 | 31 | ||
32 | // ========================== | 32 | // ========================== |
33 | 33 | ||
34 | - function createGraph(h) { | 34 | + function createGraph(h, samples) { |
35 | var stopped = false, | 35 | var stopped = false, |
36 | n = 243, | 36 | n = 243, |
37 | duration = 750, | 37 | duration = 750, |
... | @@ -75,7 +75,27 @@ | ... | @@ -75,7 +75,27 @@ |
75 | headers.forEach(function (h, li) { | 75 | headers.forEach(function (h, li) { |
76 | // Prime the data to match the headers and zero it out. | 76 | // Prime the data to match the headers and zero it out. |
77 | data[li] = d3.range(n).map(function() { return 0 }); | 77 | data[li] = d3.range(n).map(function() { return 0 }); |
78 | - theSample[li] = 0; | 78 | + |
79 | + if (li < headers.length - 1) { | ||
80 | + samples.forEach(function (s, i) { | ||
81 | + var di = dataIndex(s.time); | ||
82 | + if (di >= 0) { | ||
83 | + data[li][di] = s.data[li]; | ||
84 | + } | ||
85 | + }); | ||
86 | + | ||
87 | + data[li].forEach(function (d, i) { | ||
88 | + if (!d && i > 0) { | ||
89 | + data[li][i] = data[li][i - 1]; | ||
90 | + } | ||
91 | + }); | ||
92 | + } else { | ||
93 | + data[li].forEach(function (t, i) { | ||
94 | + for (var si = 0; si < headers.length - 1; si++) { | ||
95 | + data[li][i] = data[si][i]; | ||
96 | + } | ||
97 | + }); | ||
98 | + } | ||
79 | 99 | ||
80 | // Create the lines | 100 | // Create the lines |
81 | lines[li] = d3.svg.line() | 101 | lines[li] = d3.svg.line() |
... | @@ -88,15 +108,24 @@ | ... | @@ -88,15 +108,24 @@ |
88 | .attr("clip-path", "url(#intent-perf-clip)") | 108 | .attr("clip-path", "url(#intent-perf-clip)") |
89 | .append("path") | 109 | .append("path") |
90 | .datum(function () { return data[li]; }) | 110 | .datum(function () { return data[li]; }) |
91 | - .attr("id", "line" + li) | 111 | + .attr("id", "line" + li); |
92 | - .style("stroke", lineColor(li)) | 112 | + |
93 | - .attr("class", "line"); | 113 | + if (li < headers.length - 1) { |
114 | + paths[li].attr("class", "line").style("stroke", lineColor(li)); | ||
115 | + } else { | ||
116 | + paths[li].attr("class", "lineTotal"); | ||
117 | + } | ||
94 | }); | 118 | }); |
95 | 119 | ||
120 | + function dataIndex(time) { | ||
121 | + var delta = now.getTime() - time; | ||
122 | + var di = Math.round(n - 2 - (delta / duration)); | ||
123 | + // $log.info('now=' + now.getTime() + '; then=' + time + '; delta=' + delta + '; di=' + di + ';'); | ||
124 | + return di >= n || di < 0 ? -1 : di; | ||
125 | + } | ||
126 | + | ||
96 | function lineColor(li) { | 127 | function lineColor(li) { |
97 | - return li < headers.length - 1 ? | 128 | + return sus.cat7().getColor(li, false, ts.theme()); |
98 | - sus.cat7().getColor(li, false, ts.theme()) : | ||
99 | - ts.theme() === 'light' ? '#333' : '#eee'; | ||
100 | } | 129 | } |
101 | 130 | ||
102 | function tick() { | 131 | function tick() { |
... | @@ -130,13 +159,17 @@ | ... | @@ -130,13 +159,17 @@ |
130 | function start() { | 159 | function start() { |
131 | stopped = false; | 160 | stopped = false; |
132 | headers.forEach(function (h, li) { | 161 | headers.forEach(function (h, li) { |
133 | - theSample[li] = 0; | 162 | + theSample[li] = data[li][n-1]; |
134 | }); | 163 | }); |
135 | tick(); | 164 | tick(); |
136 | } | 165 | } |
137 | 166 | ||
138 | function stop() { | 167 | function stop() { |
139 | - stopped = true; | 168 | + headers.forEach(function (h, li) { |
169 | + theSample[li] = 0; | ||
170 | + }); | ||
171 | + // Schedule delayed stop to allow 0s to render. | ||
172 | + setTimeout(function () { stopped = true; }, 1000); | ||
140 | } | 173 | } |
141 | 174 | ||
142 | function resize(dim) { | 175 | function resize(dim) { |
... | @@ -190,7 +223,7 @@ | ... | @@ -190,7 +223,7 @@ |
190 | function createAndInitGraph(d) { | 223 | function createAndInitGraph(d) { |
191 | if (!graph) { | 224 | if (!graph) { |
192 | d.headers.push("total"); | 225 | d.headers.push("total"); |
193 | - graph = createGraph(d.headers); | 226 | + graph = createGraph(d.headers, d.samples); |
194 | } | 227 | } |
195 | graph.start(); | 228 | graph.start(); |
196 | } | 229 | } |
... | @@ -213,7 +246,7 @@ | ... | @@ -213,7 +246,7 @@ |
213 | 246 | ||
214 | function createHandlerMap() { | 247 | function createHandlerMap() { |
215 | handlerMap = { | 248 | handlerMap = { |
216 | - intentPerfHeaders: createAndInitGraph, | 249 | + intentPerfInit: createAndInitGraph, |
217 | intentPerfSample: recordSample | 250 | intentPerfSample: recordSample |
218 | }; | 251 | }; |
219 | } | 252 | } | ... | ... |
1 | -<!DOCTYPE html> | ||
2 | -<meta charset="utf-8"> | ||
3 | -<style> | ||
4 | - | ||
5 | - svg { | ||
6 | - font: 10px sans-serif; | ||
7 | - } | ||
8 | - | ||
9 | - .line { | ||
10 | - fill: none; | ||
11 | - stroke: darkgreen; | ||
12 | - stroke-width: 2px; | ||
13 | - } | ||
14 | - | ||
15 | - .axis path, | ||
16 | - .axis line { | ||
17 | - fill: none; | ||
18 | - stroke: #999; | ||
19 | - stroke-width: 2px; | ||
20 | - shape-rendering: crispEdges; | ||
21 | - } | ||
22 | - | ||
23 | -</style> | ||
24 | -<body> | ||
25 | -<script src="http://d3js.org/d3.v3.min.js"></script> | ||
26 | -<script> | ||
27 | - (function () { | ||
28 | - var cs = 0, | ||
29 | - samples = [ | ||
30 | - 89.53, | ||
31 | - 37515.81, | ||
32 | - 104609.6, | ||
33 | - 113105.11, | ||
34 | - 103194.74, | ||
35 | - 122151.63, | ||
36 | - 128623.9, | ||
37 | - 137325.33, | ||
38 | - 154897.31, | ||
39 | - 161235.07, | ||
40 | - 162025.4, | ||
41 | - 164902.64, | ||
42 | - 158196.26, | ||
43 | - 161072.44, | ||
44 | - 160792.54, | ||
45 | - 164692.44, | ||
46 | - 161979.74, | ||
47 | - 162137.4, | ||
48 | - 159325.19, | ||
49 | - 170465.44, | ||
50 | - 168186.46, | ||
51 | - 171152.34, | ||
52 | - 168221.02, | ||
53 | - 167440.73, | ||
54 | - 165003.39, | ||
55 | - 166855.18, | ||
56 | - 157268.79, | ||
57 | - 164087.54, | ||
58 | - 162265.21, | ||
59 | - 165990.16, | ||
60 | - 176364.01, | ||
61 | - 172064.07, | ||
62 | - 184872.24, | ||
63 | - 183249.8, | ||
64 | - 182282.47, | ||
65 | - 171475.11, | ||
66 | - 158880.58, | ||
67 | - 166016.69, | ||
68 | - 168233.16, | ||
69 | - 177759.92, | ||
70 | - 179742.87, | ||
71 | - 170819.44, | ||
72 | - 167577.73, | ||
73 | - 169479.9, | ||
74 | - 175544.89, | ||
75 | - 183792.01, | ||
76 | - 184689.52, | ||
77 | - 178503.87, | ||
78 | - 173219.27, | ||
79 | - 179085.49, | ||
80 | - 179700.54, | ||
81 | - 174281.17, | ||
82 | - 181353.08, | ||
83 | - 180173.14, | ||
84 | - 184093.16, | ||
85 | - 186011.5, | ||
86 | - 176952.79, | ||
87 | - 175319.2, | ||
88 | - 169001.05, | ||
89 | - 174545.12, | ||
90 | - 169156.29, | ||
91 | - 171804.3, | ||
92 | - 159155.54, | ||
93 | - 154709.96, | ||
94 | - 157263.97 | ||
95 | - ], | ||
96 | - theSample, | ||
97 | - headers = [ "Whole", "Half", "Third" ]; | ||
98 | - | ||
99 | - var n = 243, | ||
100 | - duration = 750, | ||
101 | - now = new Date(Date.now() - duration), | ||
102 | - data = []; | ||
103 | - | ||
104 | - headers.forEach(function (d, li) { | ||
105 | - data[li] = d3.range(n).map(function () { return 0; }); | ||
106 | - }); | ||
107 | - | ||
108 | - var margin = {top: 20, right: 100, bottom: 20, left: 100}, | ||
109 | - width = 960 - margin.right, | ||
110 | - height = 512 - margin.top - margin.bottom; | ||
111 | - | ||
112 | - var x = d3.time.scale() | ||
113 | - .domain([now - (n - 2) * duration, now - duration]) | ||
114 | - .range([0, width]); | ||
115 | - | ||
116 | - var y = d3.scale.linear() | ||
117 | - .domain([0, 200000]) | ||
118 | - .range([height, 0]); | ||
119 | - | ||
120 | - var svg = d3.select("body").append("p").append("svg") | ||
121 | - .attr("width", width + margin.left + margin.right) | ||
122 | - .attr("height", height + margin.top + margin.bottom) | ||
123 | - .append("g") | ||
124 | - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | ||
125 | - | ||
126 | - svg.append("defs").append("clipPath") | ||
127 | - .attr("id", "clip") | ||
128 | - .append("rect") | ||
129 | - .attr("width", width) | ||
130 | - .attr("height", height); | ||
131 | - | ||
132 | - var axis = svg.append("g") | ||
133 | - .attr("class", "x axis") | ||
134 | - .attr("transform", "translate(0," + height + ")") | ||
135 | - .call(x.axis = d3.svg.axis().scale(x).orient("bottom")); | ||
136 | - | ||
137 | - svg.append("g") | ||
138 | - .attr("class", "y axis") | ||
139 | - .call(d3.svg.axis().scale(y).orient("left")); | ||
140 | - | ||
141 | - svg.append("g") | ||
142 | - .attr("class", "y axis") | ||
143 | - .attr("transform", "translate(" + width + " ,0)") | ||
144 | - .call(d3.svg.axis().scale(y).orient("right")); | ||
145 | - | ||
146 | - var lines = [], paths = []; | ||
147 | - data.forEach(function (p, li) { | ||
148 | - lines[li]= d3.svg.line() | ||
149 | - .interpolate("basis") | ||
150 | - .x(function (d, i) { | ||
151 | - return x(now - (n - 1 - i) * duration); | ||
152 | - }) | ||
153 | - .y(function (d, i) { | ||
154 | - return y(d); | ||
155 | - }); | ||
156 | - | ||
157 | - paths[li] = svg.append("g") | ||
158 | - .attr("clip-path", "url(#clip)") | ||
159 | - .append("path") | ||
160 | - .datum(function () { return data[li]; }) | ||
161 | - .attr("id", "line" + li) | ||
162 | - .attr("class", "line"); | ||
163 | - }); | ||
164 | - | ||
165 | - var transition = d3.select({}).transition() | ||
166 | - .duration(750) | ||
167 | - .ease("linear"); | ||
168 | - | ||
169 | - function tick() { | ||
170 | - transition = transition.each(function () { | ||
171 | - // update the domains | ||
172 | - now = new Date(); | ||
173 | - x.domain([now - (n - 2) * duration, now - duration]); | ||
174 | - | ||
175 | - data.forEach(function (d, li) { | ||
176 | - // push the new most recent sample onto the back | ||
177 | - d.push(theSample[li]); | ||
178 | - | ||
179 | - // redraw the line and slide it left | ||
180 | - paths[li].attr("d", lines[li]).attr("transform", null); | ||
181 | - paths[li].transition().attr("transform", "translate(" + x(now - (n - 1) * duration) + ")"); | ||
182 | - | ||
183 | - // pop the old data point off the front | ||
184 | - d.shift(); | ||
185 | - }); | ||
186 | - | ||
187 | - // slide the x-axis left | ||
188 | - axis.call(x.axis); | ||
189 | - | ||
190 | - }).transition().each("start", tick); | ||
191 | - } | ||
192 | - | ||
193 | - function setSample() { | ||
194 | - var v = samples[cs++]; | ||
195 | - theSample = [ v, v/2, v/3 ]; | ||
196 | - } | ||
197 | - | ||
198 | - setSample(); | ||
199 | - setInterval(setSample, 1000); | ||
200 | - tick(); | ||
201 | - | ||
202 | - })() | ||
203 | -</script> | ||
204 | -</body> | ||
205 | -</html> |
-
Please register or login to post a comment