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

Side by Side Diff: charted/lib/charts/cartesian_renderers/bar_chart_renderer.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 class BarChartRenderer extends CartesianRendererBase {
12 static const RADIUS = 2;
13
14 final Iterable<int> dimensionsUsingBand = const[0];
15 final bool alwaysAnimate;
16
17 @override
18 final String name = "bar-rdr";
19
20 BarChartRenderer({this.alwaysAnimate: false});
21
22 /// Returns false if the number of dimension axes on the area is 0.
23 /// Otherwise, the first dimension scale is used to render the chart.
24 @override
25 bool prepare(ChartArea area, ChartSeries series) {
26 _ensureAreaAndSeries(area, series);
27 return area is CartesianArea;
28 }
29
30 @override
31 void draw(Element element, {Future schedulePostRender}) {
32 _ensureReadyToDraw(element);
33
34 var verticalBars = !area.config.isLeftAxisPrimary;
35
36 var measuresCount = series.measures.length,
37 measureScale = area.measureScales(series).first,
38 dimensionScale = area.dimensionScales.first;
39
40 var rows = new List()
41 ..addAll(area.data.rows.map((e) =>
42 new List.generate(
43 measuresCount, (i) => e[series.measures.elementAt(i)])));
44
45 var dimensionVals = area.data.rows.map(
46 (row) => row.elementAt(area.config.dimensions.first)).toList();
47
48 var bars = new OrdinalScale()
49 ..domain = new Range(series.measures.length).toList()
50 ..rangeRoundBands([0, dimensionScale.rangeBand]);
51
52 // Create and update the bar groups.
53
54 var groups = root.selectAll('.bar-rdr-rowgroup').data(rows);
55 var animateBarGroups = alwaysAnimate || !groups.isEmpty;
56
57 groups.enter.append('g')
58 ..classed('bar-rdr-rowgroup')
59 ..attrWithCallback('transform', (d, i, c) => verticalBars ?
60 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
61 'translate(0, ${dimensionScale.scale(dimensionVals[i])})');
62 groups.attrWithCallback('data-row', (d, i, e) => i);
63 groups.exit.remove();
64
65 if (animateBarGroups) {
66 groups.transition()
67 ..attrWithCallback('transform', (d, i, c) => verticalBars ?
68 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
69 'translate(0, ${dimensionScale.scale(dimensionVals[i])})')
70 ..duration(theme.transitionDurationMilliseconds);
71 }
72
73 // TODO: Test interactions between stroke width and bar width.
74
75 var barWidth = bars.rangeBand.abs() -
76 theme.defaultSeparatorWidth - theme.defaultStrokeWidth,
77 strokeWidth = theme.defaultStrokeWidth,
78 strokeWidthOffset = strokeWidth ~/ 2;
79
80 // Create and update the bars
81 // Avoids animation on first render unless alwaysAnimate is set to true.
82
83 var bar = groups.selectAll('.bar-rdr-bar').dataWithCallback(
84 (d, i, c) => rows[i]),
85 scaled0 = measureScale.scale(0).round();
86
87 var getBarLength = (d) {
88 var scaledVal = measureScale.scale(d).round(),
89 ht = verticalBars
90 ? (d >= 0 ? scaled0 - scaledVal : scaledVal - scaled0)
91 : (d >= 0 ? scaledVal - scaled0 : scaled0 - scaledVal);
92 ht = ht - strokeWidth;
93 return (ht < 0) ? 0 : ht;
94 };
95 var getBarPos = (d) {
96 var scaledVal = measureScale.scale(d).round();
97 return verticalBars
98 ? (d >= 0 ? scaledVal : scaled0) + strokeWidthOffset
99 : (d >= 0 ? scaled0 : scaledVal) + strokeWidthOffset;
100 };
101 var buildPath = (d, int i, bool animate) {
102 if (d == null || d == 0) return '';
103 if (verticalBars) {
104 var fn = d > 0 ? topRoundedRect : bottomRoundedRect;
105 return fn(
106 bars.scale(i).toInt() + strokeWidthOffset,
107 animate ? rect.height : getBarPos(d),
108 barWidth, animate ? 0 : getBarLength(d), RADIUS);
109 } else {
110 var fn = d > 0 ? rightRoundedRect : leftRoundedRect;
111 return fn(
112 getBarPos(d), bars.scale(i).toInt() + strokeWidthOffset,
113 animate ? 0 : getBarLength(d), barWidth, RADIUS);
114 }
115 };
116
117 bar.enter.appendWithCallback((d, i, e) {
118 var rect = Namespace.createChildElement('path', e),
119 measure = series.measures.elementAt(i),
120 row = int.parse(e.dataset['row']),
121 color = colorForValue(measure, row),
122 filter = filterForValue(measure, row),
123 style = stylesForValue(measure, row);
124
125 if (!isNullOrEmpty(style)) {
126 rect.classes.addAll(style);
127 }
128 rect.classes.add('bar-rdr-bar');
129
130 rect.attributes
131 ..['d'] = buildPath(d, i, animateBarGroups)
132 ..['stroke-width'] = '${strokeWidth}px'
133 ..['fill'] = color
134 ..['stroke'] = color;
135
136 if (!isNullOrEmpty(filter)) {
137 rect.attributes['filter'] = filter;
138 }
139 if (!animateBarGroups) {
140 rect.attributes['data-column'] = '$measure';
141 }
142 return rect;
143 })
144 ..on('click', (d, i, e) => _event(mouseClickController, d, i, e))
145 ..on('mouseover', (d, i, e) => _event(mouseOverController, d, i, e))
146 ..on('mouseout', (d, i, e) => _event(mouseOutController, d, i, e));
147
148 if (animateBarGroups) {
149 bar.each((d, i, e) {
150 var measure = series.measures.elementAt(i),
151 row = int.parse(e.parent.dataset['row']),
152 color = colorForValue(measure, row),
153 filter = filterForValue(measure, row),
154 styles = stylesForValue(measure, row);
155 e.attributes
156 ..['data-column'] = '$measure'
157 ..['fill'] = color
158 ..['stroke'] = color;
159 e.classes
160 ..removeAll(ChartState.VALUE_CLASS_NAMES)
161 ..addAll(styles);
162 if (isNullOrEmpty(filter)) {
163 e.attributes.remove('filter');
164 } else {
165 e.attributes['filter'] = filter;
166 }
167 });
168
169 bar.transition()
170 ..attrWithCallback('d',
171 (d, i, e) => buildPath(d, i, false));
172 }
173
174 bar.exit.remove();
175 }
176
177 @override
178 void dispose() {
179 if (root == null) return;
180 root.selectAll('.bar-rdr-rowgroup').remove();
181 }
182
183 @override
184 double get bandInnerPadding {
185 assert(series != null && area != null);
186 var measuresCount = series.measures.length;
187 return measuresCount > 2 ? 1 - (measuresCount / (measuresCount + 1)) :
188 area.theme.getDimensionAxisTheme().axisBandInnerPadding;
189 }
190
191 @override
192 double get bandOuterPadding {
193 assert(series != null && area != null);
194 return area.theme.getDimensionAxisTheme().axisBandOuterPadding;
195 }
196
197 @override
198 void handleStateChanges(List<ChangeRecord> changes) {
199 var groups = host.querySelectorAll('.bar-rdr-rowgroup');
200 if (groups == null || groups.isEmpty) return;
201
202 for(int i = 0, len = groups.length; i < len; ++i) {
203 var group = groups.elementAt(i),
204 bars = group.querySelectorAll('.bar-rdr-bar'),
205 row = int.parse(group.dataset['row']);
206
207 for(int j = 0, barsCount = bars.length; j < barsCount; ++j) {
208 var bar = bars.elementAt(j),
209 column = int.parse(bar.dataset['column']),
210 color = colorForValue(column, row),
211 filter = filterForValue(column, row);
212
213 bar.classes.removeAll(ChartState.VALUE_CLASS_NAMES);
214 bar.classes.addAll(stylesForValue(column, row));
215 bar.attributes
216 ..['fill'] = color
217 ..['stroke'] = color;
218 if (isNullOrEmpty(filter)) {
219 bar.attributes.remove('filter');
220 } else {
221 bar.attributes['filter'] = filter;
222 }
223 }
224 }
225 }
226
227 void _event(StreamController controller, data, int index, Element e) {
228 if (controller == null) return;
229 var rowStr = e.parent.dataset['row'];
230 var row = rowStr != null ? int.parse(rowStr) : null;
231 controller.add(
232 new DefaultChartEventImpl(scope.event, area,
233 series, row, series.measures.elementAt(index), data));
234 }
235 }
OLDNEW
« no previous file with comments | « charted/lib/charts/behaviors/mouse_tracker.dart ('k') | charted/lib/charts/cartesian_renderers/bubble_chart_renderer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698