Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: charted/lib/charts/src/layout_area_impl.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //
2 // Copyright 2014 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 //
8
9 part of charted.charts;
10
11 /// Creates an empty area and provides generic API for interaction with layout
12 /// based charts.
13 class DefaultLayoutAreaImpl implements LayoutArea {
14 /// Disposer for all change stream subscriptions related to data.
15 final _dataEventsDisposer = new SubscriptionsDisposer();
16
17 /// Disposer for all change stream subscriptions related to config.
18 final _configEventsDisposer = new SubscriptionsDisposer();
19
20 @override
21 final Element host;
22
23 @override
24 final bool useRowColoring = true;
25
26 @override
27 final ChartState state;
28
29 @override
30 _ChartAreaLayout layout = new _ChartAreaLayout();
31
32 @override
33 Selection upperBehaviorPane;
34
35 @override
36 Selection lowerBehaviorPane;
37
38 @override
39 bool isReady = false;
40
41 @override
42 ChartTheme theme;
43
44 ChartData _data;
45 ChartConfig _config;
46 bool _autoUpdate = false;
47
48 SelectionScope _scope;
49 Selection _svg;
50 Selection visualization;
51
52 ChartSeries _series;
53 LayoutRenderer _renderer;
54
55 bool _pendingLegendUpdate = false;
56 List<ChartBehavior> _behaviors = new List<ChartBehavior>();
57
58 SubscriptionsDisposer _rendererDisposer = new SubscriptionsDisposer();
59 StreamController<ChartEvent> _valueMouseOverController;
60 StreamController<ChartEvent> _valueMouseOutController;
61 StreamController<ChartEvent> _valueMouseClickController;
62
63 DefaultLayoutAreaImpl(
64 this.host,
65 ChartData data,
66 ChartConfig config,
67 this._autoUpdate,
68 this.state) {
69 assert(host != null);
70 assert(isNotInline(host));
71
72 this.data = data;
73 this.config = config;
74 theme = new QuantumChartTheme();
75
76 Transition.defaultEasingType = theme.transitionEasingType;
77 Transition.defaultEasingMode = theme.transitionEasingMode;
78 Transition.defaultDurationMilliseconds =
79 theme.transitionDurationMilliseconds;
80 }
81
82 void dispose() {
83 _configEventsDisposer.dispose();
84 _dataEventsDisposer.dispose();
85 _config.legend.dispose();
86 }
87
88 static bool isNotInline(Element e) =>
89 e != null && e.getComputedStyle().display != 'inline';
90
91 /// Set new data for this chart. If [value] is [Observable], subscribes to
92 /// changes and updates the chart when data changes.
93 @override
94 set data(ChartData value) {
95 _data = value;
96 _dataEventsDisposer.dispose();
97
98 if (autoUpdate && _data != null && _data is Observable) {
99 _dataEventsDisposer.add((_data as Observable).changes.listen((_) {
100 draw();
101 }));
102 }
103 }
104
105 @override
106 ChartData get data => _data;
107
108 /// Set new config for this chart. If [value] is [Observable], subscribes to
109 /// changes and updates the chart when series or dimensions change.
110 @override
111 set config(ChartConfig value) {
112 _config = value;
113 _configEventsDisposer.dispose();
114 _pendingLegendUpdate = true;
115
116 if (_config != null && _config is Observable) {
117 _configEventsDisposer.add((_config as Observable).changes.listen((_) {
118 _pendingLegendUpdate = true;
119 draw();
120 }));
121 }
122 }
123
124 @override
125 ChartConfig get config => _config;
126
127 @override
128 set autoUpdate(bool value) {
129 if (_autoUpdate != value) {
130 _autoUpdate = value;
131 this.data = _data;
132 this.config = _config;
133 }
134 }
135
136 @override
137 bool get autoUpdate => _autoUpdate;
138
139 /// Computes the size of chart and if changed from the previous time
140 /// size was computed, sets attributes on svg element
141 Rect _computeChartSize() {
142 int width = host.clientWidth,
143 height = host.clientHeight;
144
145 if (config.minimumSize != null) {
146 width = max([width, config.minimumSize.width]);
147 height = max([height, config.minimumSize.height]);
148 }
149
150 AbsoluteRect padding = theme.padding;
151 num paddingLeft = config.isRTL ? padding.end : padding.start;
152 Rect current = new Rect(paddingLeft, padding.top,
153 width - (padding.start + padding.end),
154 height - (padding.top + padding.bottom));
155 if (layout.chartArea == null || layout.chartArea != current) {
156 var transform = 'translate(${paddingLeft},${padding.top})';
157
158 visualization.first.attributes['transform'] = transform;
159 lowerBehaviorPane.first.attributes['transform'] = transform;
160 upperBehaviorPane.first.attributes['transform'] = transform;
161
162 _svg.attr('width', width.toString());
163 _svg.attr('height', height.toString());
164 layout.chartArea = current;
165 layout.renderArea = current;
166 layout._axes.clear();
167 }
168
169 return layout.chartArea;
170 }
171
172 @override
173 draw({bool preRender:false, Future schedulePostRender}) {
174 assert(data != null && config != null);
175 assert(config.series != null && config.series.isNotEmpty);
176
177 // One time initialization.
178 // Each [ChartArea] has it's own [SelectionScope]
179 if (_scope == null) {
180 _scope = new SelectionScope.element(host);
181 _svg = _scope.append('svg:svg')..classed('chart-canvas');
182
183 lowerBehaviorPane = _svg.append('g')..classed('lower-render-pane');
184 visualization = _svg.append('g')..classed('chart-render-pane');
185 upperBehaviorPane = _svg.append('g')..classed('upper-render-pane');
186
187 if (_behaviors.isNotEmpty) {
188 _behaviors.forEach(
189 (b) => b.init(this, upperBehaviorPane, lowerBehaviorPane));
190 }
191 }
192
193 // Compute chart sizes and filter out unsupported series
194 _computeChartSize();
195 var series = config.series.firstWhere(
196 (s) => s.renderer.prepare(this, s), orElse: () => null),
197 group = visualization.first.querySelector('.series-group');
198
199 // We need atleast one matching series.
200 assert(series != null);
201
202 // Create a group for rendering, if it was not already done.
203 if (group == null) {
204 group = Namespace.createChildElement('g', visualization.first)
205 ..classes.add('series-group');
206 visualization.first.append(group);
207 }
208
209 // If we previously displayed a series, verify that we are
210 // still using the same renderer. Otherwise, dispose the older one.
211 if (_renderer != null && series.renderer != _renderer) {
212 _rendererDisposer.dispose();
213 }
214
215 // Save and subscribe to events on the the current renderer.
216 _renderer = series.renderer;
217 if (_renderer is ChartRendererBehaviorSource) {
218 _rendererDisposer.addAll([
219 _renderer.onValueClick.listen((ChartEvent e) {
220 if (state != null) {
221 if (state.isSelected(e.row)) {
222 state.unselect(e.row);
223 } else {
224 state.select(e.row);
225 }
226 }
227 if (_valueMouseClickController != null) {
228 _valueMouseClickController.add(e);
229 }
230 }),
231 _renderer.onValueMouseOver.listen((ChartEvent e) {
232 if (state != null) {
233 state.preview = e.row;
234 }
235 if (_valueMouseOverController != null) {
236 _valueMouseOverController.add(e);
237 }
238 }),
239 _renderer.onValueMouseOut.listen((ChartEvent e) {
240 if (state != null) {
241 if (e.row == state.preview) {
242 state.hovered = null;
243 }
244 }
245 if (_valueMouseOutController != null) {
246 _valueMouseOutController.add(e);
247 }
248 })
249 ]);
250 }
251
252 Iterable<ChartLegendItem> legend =
253 _renderer.layout(group, schedulePostRender:schedulePostRender);
254
255 // Notify on the stream that the chart has been updated.
256 isReady = true;
257
258 // Save the list of valid series and initialize axes.
259 _series = series;
260
261 // Updates the legend if required.
262 _config.legend.update(legend, this);
263 }
264
265 @override
266 Stream<ChartEvent> get onMouseUp =>
267 host.onMouseUp
268 .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
269
270 @override
271 Stream<ChartEvent> get onMouseDown =>
272 host.onMouseDown
273 .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
274
275 @override
276 Stream<ChartEvent> get onMouseOver =>
277 host.onMouseOver
278 .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
279
280 @override
281 Stream<ChartEvent> get onMouseOut =>
282 host.onMouseOut
283 .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
284
285 @override
286 Stream<ChartEvent> get onMouseMove =>
287 host.onMouseMove
288 .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
289
290 @override
291 Stream<ChartEvent> get onValueClick {
292 if (_valueMouseClickController == null) {
293 _valueMouseClickController = new StreamController.broadcast(sync: true);
294 }
295 return _valueMouseClickController.stream;
296 }
297
298 @override
299 Stream<ChartEvent> get onValueMouseOver {
300 if (_valueMouseOverController == null) {
301 _valueMouseOverController = new StreamController.broadcast(sync: true);
302 }
303 return _valueMouseOverController.stream;
304 }
305
306 @override
307 Stream<ChartEvent> get onValueMouseOut {
308 if (_valueMouseOutController == null) {
309 _valueMouseOutController = new StreamController.broadcast(sync: true);
310 }
311 return _valueMouseOutController.stream;
312 }
313
314 @override
315 void addChartBehavior(ChartBehavior behavior) {
316 if (behavior == null || _behaviors.contains(behavior)) return;
317 _behaviors.add(behavior);
318 if (upperBehaviorPane != null && lowerBehaviorPane != null) {
319 behavior.init(this, upperBehaviorPane, lowerBehaviorPane);
320 }
321 }
322
323 @override
324 void removeChartBehavior(ChartBehavior behavior) {
325 if (behavior == null || !_behaviors.contains(behavior)) return;
326 if (upperBehaviorPane != null && lowerBehaviorPane != null) {
327 behavior.dispose();
328 }
329 _behaviors.remove(behavior);
330 }
331 }
OLDNEW
« no previous file with comments | « charted/lib/charts/src/chart_state_impl.dart ('k') | charted/lib/charts/themes/quantum_theme.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698