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

Side by Side Diff: charted/lib/charts/layout_renderers/pie_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 PieChartRenderer extends LayoutRendererBase {
12 static const STATS_PERCENTAGE = 'percentage-only';
13 static const STATS_VALUE = 'value-only';
14 static const STATS_VALUE_PERCENTAGE = 'value-percentage';
15
16 final Iterable<int> dimensionsUsingBand = const[];
17 final String statsMode;
18 final num innerRadiusRatio;
19 final int maxSliceCount;
20 final String otherItemsLabel;
21 final String otherItemsColor;
22 final showLabels;
23 final sortDataByValue;
24
25 @override
26 final String name = "pie-rdr";
27
28 final List<ChartLegendItem> _legend = [];
29
30 Iterable otherRow;
31
32 PieChartRenderer({
33 num innerRadiusRatio: 0,
34 bool showLabels,
35 this.sortDataByValue: true,
36 this.statsMode: STATS_PERCENTAGE,
37 this.maxSliceCount: SMALL_INT_MAX,
38 this.otherItemsLabel: 'Other',
39 this.otherItemsColor: '#EEEEEE'})
40 : showLabels = showLabels == null ? innerRadiusRatio == 0 : showLabels,
41 innerRadiusRatio = innerRadiusRatio;
42
43 /// Returns false if the number of dimension axes != 0. Pie chart can only
44 /// be rendered on areas with no axes.
45 @override
46 bool prepare(ChartArea area, ChartSeries series) {
47 _ensureAreaAndSeries(area, series);
48 return area is LayoutArea;
49 }
50
51 @override
52 Iterable<ChartLegendItem> layout(
53 Element element, {Future schedulePostRender}) {
54 _ensureReadyToDraw(element);
55
56 var radius = math.min(rect.width, rect.height) / 2;
57 root.attr('transform', 'translate(${rect.width / 2}, ${rect.height / 2})');
58
59 // Pick only items that are valid - non-null and don't have null value
60 var measure = series.measures.first,
61 dimension = area.config.dimensions.first,
62 indices = new List.generate(area.data.rows.length, (i) => i);
63
64 // Sort row indices by value.
65 if (sortDataByValue) {
66 indices.sort((int a, int b) {
67 var aRow = area.data.rows.elementAt(a),
68 bRow = area.data.rows.elementAt(b),
69 aVal = (aRow == null || aRow.elementAt(measure) == null)
70 ? 0
71 : aRow.elementAt(measure),
72 bVal = (bRow == null || bRow.elementAt(measure) == null)
73 ? 0
74 : bRow.elementAt(measure);
75 return bVal.compareTo(aVal);
76 });
77 }
78
79 // Limit items to the passed maxSliceCount
80 if (indices.length > maxSliceCount) {
81 var displayed = indices.take(maxSliceCount).toList();
82 var otherItemsValue = 0;
83 for (int i = displayed.length; i < indices.length; ++i) {
84 var index = indices.elementAt(i),
85 row = area.data.rows.elementAt(index);
86 otherItemsValue += row == null || row.elementAt(measure) == null
87 ? 0
88 : row.elementAt(measure);
89 }
90 otherRow = new List(max([dimension, measure]) + 1)
91 ..[dimension] = otherItemsLabel
92 ..[measure] = otherItemsValue;
93 indices = displayed..add(SMALL_INT_MAX);
94 } else {
95 otherRow = null;
96 }
97
98 if (area.config.isRTL) {
99 indices = indices.reversed.toList();
100 }
101
102 var accessor = (d, i) {
103 var row = d == SMALL_INT_MAX ? otherRow : area.data.rows.elementAt(d);
104 return row == null || row.elementAt(measure) == null
105 ? 0
106 : row.elementAt(measure);
107 };
108 var data = (new PieLayout()..accessor = accessor).layout(indices),
109 arc = new SvgArc(
110 innerRadiusCallback: (d, i, e) => innerRadiusRatio * radius,
111 outerRadiusCallback: (d, i, e) => radius),
112 pie = root.selectAll('.pie-path').data(data);
113
114 pie.enter.append('path').classed('pie-path');
115 pie
116 ..each((d, i, e) {
117 var styles = stylesForData(d.data, i);
118 e.classes.removeAll(ChartState.VALUE_CLASS_NAMES);
119 if (!isNullOrEmpty(styles)) {
120 e.classes.addAll(styles);
121 }
122 e.attributes
123 ..['fill'] = colorForData(d.data, i)
124 ..['d'] = arc.path(d, i, host)
125 ..['stroke-width'] = '1px'
126 ..['stroke'] = '#ffffff';
127
128 e.append(
129 Namespace.createChildElement('text', e)
130 ..classes.add('pie-label'));
131 })
132 ..on('click', (d, i, e) => _event(mouseClickController, d, i, e))
133 ..on('mouseover', (d, i, e) => _event(mouseOverController, d, i, e))
134 ..on('mouseout', (d, i, e) => _event(mouseOutController, d, i, e));
135
136 pie.exit.remove();
137
138 _legend.clear();
139 var items = new List.generate(data.length, (i) {
140 SvgArcData d = data.elementAt(i);
141 Iterable row = d.data == SMALL_INT_MAX
142 ? otherRow
143 : area.data.rows.elementAt(d.data);
144
145 return new ChartLegendItem(index: d.data, color: colorForData(d.data, i),
146 label: row.elementAt(dimension), series: [series],
147 value: '${(((d.endAngle - d.startAngle) * 50) / math.PI).toStringAsFix ed(2)}%');
148 });
149 return _legend..addAll(area.config.isRTL ? items.reversed : items);
150 }
151
152 String colorForData(int row, int index) =>
153 colorForValue(row, isTail: row == SMALL_INT_MAX);
154
155 Iterable<String> stylesForData(int row, int i) =>
156 stylesForValue(row, isTail: row == SMALL_INT_MAX);
157
158 @override
159 handleStateChanges(List<ChangeRecord> changes) {
160 root.selectAll('.pie-path').each((d, i, e) {
161 var styles = stylesForData(d.data, i);
162 e.classes.removeAll(ChartState.VALUE_CLASS_NAMES);
163 if (!isNullOrEmpty(styles)) {
164 e.classes.addAll(styles);
165 }
166 e.attributes['fill'] = colorForData(d.data, i);
167 });
168 }
169
170 @override
171 void dispose() {
172 if (root == null) return;
173 root.selectAll('.pie-path').remove();
174 }
175
176 void _event(StreamController controller, data, int index, Element e) {
177 // Currently, events are not supported on "Other" pie
178 if (controller == null || data.data == SMALL_INT_MAX) return;
179 controller.add(new DefaultChartEventImpl(
180 scope.event, area, series, data.data, series.measures.first, data.value ));
181 }
182 }
OLDNEW
« no previous file with comments | « charted/lib/charts/layout_renderers/layout_base_renderer.dart ('k') | charted/lib/charts/src/cartesian_area_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698