| OLD | NEW |
| 1 // | 1 // |
| 2 // Copyright 2014 Google Inc. All rights reserved. | 2 // Copyright 2014 Google Inc. All rights reserved. |
| 3 // | 3 // |
| 4 // Use of this source code is governed by a BSD-style | 4 // Use of this source code is governed by a BSD-style |
| 5 // license that can be found in the LICENSE file or at | 5 // license that can be found in the LICENSE file or at |
| 6 // https://developers.google.com/open-source/licenses/bsd | 6 // https://developers.google.com/open-source/licenses/bsd |
| 7 // | 7 // |
| 8 | 8 |
| 9 part of charted.charts; | 9 part of charted.charts; |
| 10 | 10 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 ChartConfig _config; | 77 ChartConfig _config; |
| 78 bool _autoUpdate = false; | 78 bool _autoUpdate = false; |
| 79 | 79 |
| 80 SelectionScope _scope; | 80 SelectionScope _scope; |
| 81 Selection _svg; | 81 Selection _svg; |
| 82 Selection visualization; | 82 Selection visualization; |
| 83 | 83 |
| 84 Iterable<ChartSeries> _series; | 84 Iterable<ChartSeries> _series; |
| 85 | 85 |
| 86 bool _pendingLegendUpdate = false; | 86 bool _pendingLegendUpdate = false; |
| 87 bool _pendingAxisConfigUpdate = false; |
| 87 List<ChartBehavior> _behaviors = new List<ChartBehavior>(); | 88 List<ChartBehavior> _behaviors = new List<ChartBehavior>(); |
| 88 Map<ChartSeries, _ChartSeriesInfo> _seriesInfoCache = new Map(); | 89 Map<ChartSeries, _ChartSeriesInfo> _seriesInfoCache = new Map(); |
| 89 | 90 |
| 90 StreamController<ChartEvent> _valueMouseOverController; | 91 StreamController<ChartEvent> _valueMouseOverController; |
| 91 StreamController<ChartEvent> _valueMouseOutController; | 92 StreamController<ChartEvent> _valueMouseOutController; |
| 92 StreamController<ChartEvent> _valueMouseClickController; | 93 StreamController<ChartEvent> _valueMouseClickController; |
| 93 StreamController<ChartArea> _chartAxesUpdatedController; | 94 StreamController<ChartArea> _chartAxesUpdatedController; |
| 94 | 95 |
| 95 DefaultCartesianAreaImpl( | 96 DefaultCartesianAreaImpl( |
| 96 this.host, | 97 this.host, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 _valueMouseOutController = null; | 129 _valueMouseOutController = null; |
| 129 } | 130 } |
| 130 if (_valueMouseClickController != null) { | 131 if (_valueMouseClickController != null) { |
| 131 _valueMouseClickController.close(); | 132 _valueMouseClickController.close(); |
| 132 _valueMouseClickController = null; | 133 _valueMouseClickController = null; |
| 133 } | 134 } |
| 134 if (_chartAxesUpdatedController != null) { | 135 if (_chartAxesUpdatedController != null) { |
| 135 _chartAxesUpdatedController.close(); | 136 _chartAxesUpdatedController.close(); |
| 136 _chartAxesUpdatedController = null; | 137 _chartAxesUpdatedController = null; |
| 137 } | 138 } |
| 139 if (_behaviors.isNotEmpty) { |
| 140 _behaviors.forEach((behavior) => behavior.dispose()); |
| 141 } |
| 138 } | 142 } |
| 139 | 143 |
| 140 static bool isNotInline(Element e) => | 144 static bool isNotInline(Element e) => |
| 141 e != null && e.getComputedStyle().display != 'inline'; | 145 e != null && e.getComputedStyle().display != 'inline'; |
| 142 | 146 |
| 143 /// Set new data for this chart. If [value] is [Observable], subscribes to | 147 /// Set new data for this chart. If [value] is [Observable], subscribes to |
| 144 /// changes and updates the chart when data changes. | 148 /// changes and updates the chart when data changes. |
| 145 @override | 149 @override |
| 146 set data(ChartData value) { | 150 set data(ChartData value) { |
| 147 _data = value; | 151 _data = value; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 159 @override | 163 @override |
| 160 ChartData get data => _data; | 164 ChartData get data => _data; |
| 161 | 165 |
| 162 /// Set new config for this chart. If [value] is [Observable], subscribes to | 166 /// Set new config for this chart. If [value] is [Observable], subscribes to |
| 163 /// changes and updates the chart when series or dimensions change. | 167 /// changes and updates the chart when series or dimensions change. |
| 164 @override | 168 @override |
| 165 set config(ChartConfig value) { | 169 set config(ChartConfig value) { |
| 166 _config = value; | 170 _config = value; |
| 167 _configEventsDisposer.dispose(); | 171 _configEventsDisposer.dispose(); |
| 168 _pendingLegendUpdate = true; | 172 _pendingLegendUpdate = true; |
| 173 _pendingAxisConfigUpdate = true; |
| 169 | 174 |
| 170 if (_config != null && _config is Observable) { | 175 if (_config != null && _config is Observable) { |
| 171 _configEventsDisposer.add((_config as Observable).changes.listen((_) { | 176 _configEventsDisposer.add((_config as Observable).changes.listen((_) { |
| 177 _pendingAxisConfigUpdate = true; |
| 172 _pendingLegendUpdate = true; | 178 _pendingLegendUpdate = true; |
| 173 draw(); | 179 draw(); |
| 174 })); | 180 })); |
| 175 } | 181 } |
| 176 } | 182 } |
| 177 | 183 |
| 178 @override | 184 @override |
| 179 ChartConfig get config => _config; | 185 ChartConfig get config => _config; |
| 180 | 186 |
| 181 @override | 187 @override |
| (...skipping 11 matching lines...) Expand all Loading... |
| 193 /// Gets measure axis from cache - creates a new instance of _ChartAxis | 199 /// Gets measure axis from cache - creates a new instance of _ChartAxis |
| 194 /// if one was not already created for the given [axisId]. | 200 /// if one was not already created for the given [axisId]. |
| 195 DefaultChartAxisImpl _getMeasureAxis(String axisId) { | 201 DefaultChartAxisImpl _getMeasureAxis(String axisId) { |
| 196 _measureAxes.putIfAbsent(axisId, () { | 202 _measureAxes.putIfAbsent(axisId, () { |
| 197 var axisConf = config.getMeasureAxis(axisId), | 203 var axisConf = config.getMeasureAxis(axisId), |
| 198 axis = axisConf != null | 204 axis = axisConf != null |
| 199 ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf) | 205 ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf) |
| 200 : new DefaultChartAxisImpl(this); | 206 : new DefaultChartAxisImpl(this); |
| 201 return axis; | 207 return axis; |
| 202 }); | 208 }); |
| 209 |
| 203 return _measureAxes[axisId]; | 210 return _measureAxes[axisId]; |
| 204 } | 211 } |
| 205 | 212 |
| 206 /// Gets a dimension axis from cache - creates a new instance of _ChartAxis | 213 /// Gets a dimension axis from cache - creates a new instance of _ChartAxis |
| 207 /// if one was not already created for the given dimension [column]. | 214 /// if one was not already created for the given dimension [column]. |
| 208 DefaultChartAxisImpl _getDimensionAxis(int column) { | 215 DefaultChartAxisImpl _getDimensionAxis(int column) { |
| 209 _dimensionAxes.putIfAbsent(column, () { | 216 _dimensionAxes.putIfAbsent(column, () { |
| 210 var axisConf = config.getDimensionAxis(column), | 217 var axisConf = config.getDimensionAxis(column), |
| 211 axis = axisConf != null | 218 axis = axisConf != null |
| 212 ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf) | 219 ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf) |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 'translate(${layout.renderArea.x},${layout.renderArea.y})'; | 317 'translate(${layout.renderArea.x},${layout.renderArea.y})'; |
| 311 | 318 |
| 312 selection.each((ChartSeries s, _, Element group) { | 319 selection.each((ChartSeries s, _, Element group) { |
| 313 _ChartSeriesInfo info = _seriesInfoCache[s]; | 320 _ChartSeriesInfo info = _seriesInfoCache[s]; |
| 314 if (info == null) { | 321 if (info == null) { |
| 315 info = _seriesInfoCache[s] = new _ChartSeriesInfo(this, s); | 322 info = _seriesInfoCache[s] = new _ChartSeriesInfo(this, s); |
| 316 } | 323 } |
| 317 info.check(); | 324 info.check(); |
| 318 group.attributes['transform'] = transform; | 325 group.attributes['transform'] = transform; |
| 319 (s.renderer as CartesianRenderer) | 326 (s.renderer as CartesianRenderer) |
| 320 .draw(group, schedulePostRender: schedulePostRender); | 327 ?.draw(group, schedulePostRender: schedulePostRender); |
| 321 }); | 328 }); |
| 322 | 329 |
| 323 // A series that was rendered earlier isn't there anymore, remove it | 330 // A series that was rendered earlier isn't there anymore, remove it |
| 324 selection.exit | 331 selection.exit |
| 325 ..each((ChartSeries s, _, __) { | 332 ..each((ChartSeries s, _, __) { |
| 326 var info = _seriesInfoCache.remove(s); | 333 var info = _seriesInfoCache.remove(s); |
| 327 if (info != null) { | 334 if (info != null) { |
| 328 info.dispose(); | 335 info.dispose(); |
| 329 } | 336 } |
| 330 }) | 337 }) |
| 331 ..remove(); | 338 ..remove(); |
| 332 | 339 |
| 333 // Notify on the stream that the chart has been updated. | 340 // Notify on the stream that the chart has been updated. |
| 334 isReady = true; | 341 isReady = true; |
| 335 if (_chartAxesUpdatedController != null) { | 342 if (_chartAxesUpdatedController != null) { |
| 336 _chartAxesUpdatedController.add(this); | 343 _chartAxesUpdatedController.add(this); |
| 337 } | 344 } |
| 338 }); | 345 }); |
| 339 | 346 |
| 340 // Save the list of valid series and initialize axes. | 347 // Save the list of valid series and initialize axes. |
| 341 _series = series; | 348 _series = series; |
| 349 _updateAxisConfig(); |
| 342 _initAxes(preRender: preRender); | 350 _initAxes(preRender: preRender); |
| 343 | 351 |
| 344 // Render the chart, now that the axes layer is already in DOM. | 352 // Render the chart, now that the axes layer is already in DOM. |
| 345 axesDomainCompleter.complete(); | 353 axesDomainCompleter.complete(); |
| 346 | 354 |
| 347 // Updates the legend if required. | 355 // Updates the legend if required. |
| 348 _updateLegend(); | 356 _updateLegend(); |
| 349 } | 357 } |
| 350 | 358 |
| 351 String _orientRTL(String orientation) => orientation; | 359 String _orientRTL(String orientation) => orientation; |
| 352 | 360 |
| 353 /// Initialize the axes - required even if the axes are not being displayed. | 361 /// Initialize the axes - required even if the axes are not being displayed. |
| 354 _initAxes({bool preRender: false}) { | 362 _initAxes({bool preRender: false}) { |
| 355 Map measureAxisUsers = <String, Iterable<ChartSeries>>{}; | 363 Map measureAxisUsers = <String, Iterable<ChartSeries>>{}; |
| 364 var keysToRemove = _measureAxes.keys.toList(); |
| 356 | 365 |
| 357 // Create necessary measures axes. | 366 // Create necessary measures axes. |
| 358 // If measure axes were not configured on the series, default is used. | 367 // If measure axes were not configured on the series, default is used. |
| 359 _series.forEach((ChartSeries s) { | 368 _series.forEach((ChartSeries s) { |
| 360 var measureAxisIds = | 369 var measureAxisIds = |
| 361 isNullOrEmpty(s.measureAxisIds) ? MEASURE_AXIS_IDS : s.measureAxisIds; | 370 isNullOrEmpty(s.measureAxisIds) ? MEASURE_AXIS_IDS : s.measureAxisIds; |
| 362 measureAxisIds.forEach((axisId) { | 371 measureAxisIds.forEach((axisId) { |
| 372 if (keysToRemove.contains(axisId)) { |
| 373 keysToRemove.remove(axisId); |
| 374 } |
| 363 _getMeasureAxis(axisId); // Creates axis if required | 375 _getMeasureAxis(axisId); // Creates axis if required |
| 364 var users = measureAxisUsers[axisId]; | 376 var users = measureAxisUsers[axisId]; |
| 365 if (users == null) { | 377 if (users == null) { |
| 366 measureAxisUsers[axisId] = [s]; | 378 measureAxisUsers[axisId] = [s]; |
| 367 } else { | 379 } else { |
| 368 users.add(s); | 380 users.add(s); |
| 369 } | 381 } |
| 370 }); | 382 }); |
| 371 }); | 383 }); |
| 372 | 384 |
| 385 for (var key in keysToRemove) { |
| 386 _measureAxes.remove(key); |
| 387 } |
| 388 |
| 373 // Now that we know a list of series using each measure axis, configure | 389 // Now that we know a list of series using each measure axis, configure |
| 374 // the input domain of each axis. | 390 // the input domain of each axis. |
| 375 measureAxisUsers.forEach((id, listOfSeries) { | 391 measureAxisUsers.forEach((id, listOfSeries) { |
| 376 var sampleCol = listOfSeries.first.measures.first, | 392 var sampleCol = listOfSeries.first.measures.first, |
| 377 sampleColSpec = data.columns.elementAt(sampleCol), | 393 sampleColSpec = data.columns.elementAt(sampleCol), |
| 378 axis = _getMeasureAxis(id); | 394 axis = _getMeasureAxis(id); |
| 379 List domain; | 395 List domain; |
| 380 | 396 |
| 381 if (sampleColSpec.useOrdinalScale) { | 397 if (sampleColSpec.useOrdinalScale) { |
| 382 throw new UnsupportedError( | 398 throw new UnsupportedError( |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 index: i, | 588 index: i, |
| 573 label: data.columns.elementAt(i).label, | 589 label: data.columns.elementAt(i).label, |
| 574 series: s, | 590 series: s, |
| 575 color: theme.getColorForKey(i))); | 591 color: theme.getColorForKey(i))); |
| 576 }); | 592 }); |
| 577 | 593 |
| 578 _config.legend.update(legend, this); | 594 _config.legend.update(legend, this); |
| 579 _pendingLegendUpdate = false; | 595 _pendingLegendUpdate = false; |
| 580 } | 596 } |
| 581 | 597 |
| 598 // Updates the AxisConfig, if configuration chagned since the last time the |
| 599 // AxisConfig was updated. |
| 600 _updateAxisConfig() { |
| 601 if (!_pendingAxisConfigUpdate) return; |
| 602 _series.forEach((ChartSeries s) { |
| 603 var measureAxisIds = |
| 604 isNullOrEmpty(s.measureAxisIds) ? MEASURE_AXIS_IDS : s.measureAxisIds; |
| 605 measureAxisIds.forEach((axisId) { |
| 606 var axis = _getMeasureAxis(axisId); // Creates axis if required |
| 607 axis.config = config.getMeasureAxis(axisId); |
| 608 }); |
| 609 }); |
| 610 |
| 611 int dimensionAxesCount = useTwoDimensionAxes ? 2 : 1; |
| 612 config.dimensions.take(dimensionAxesCount).forEach((int column) { |
| 613 var axis = _getDimensionAxis(column); |
| 614 axis.config = config.getDimensionAxis(column); |
| 615 }); |
| 616 |
| 617 _pendingAxisConfigUpdate = false; |
| 618 } |
| 619 |
| 582 @override | 620 @override |
| 583 Stream<ChartEvent> get onMouseUp => | 621 Stream<ChartEvent> get onMouseUp => |
| 584 host.onMouseUp.map((MouseEvent e) => new DefaultChartEventImpl(e, this)); | 622 host.onMouseUp.map((MouseEvent e) => new DefaultChartEventImpl(e, this)); |
| 585 | 623 |
| 586 @override | 624 @override |
| 587 Stream<ChartEvent> get onMouseDown => host.onMouseDown | 625 Stream<ChartEvent> get onMouseDown => host.onMouseDown |
| 588 .map((MouseEvent e) => new DefaultChartEventImpl(e, this)); | 626 .map((MouseEvent e) => new DefaultChartEventImpl(e, this)); |
| 589 | 627 |
| 590 @override | 628 @override |
| 591 Stream<ChartEvent> get onMouseOver => host.onMouseOver | 629 Stream<ChartEvent> get onMouseOver => host.onMouseOver |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 } | 771 } |
| 734 } | 772 } |
| 735 _renderer = _series.renderer; | 773 _renderer = _series.renderer; |
| 736 } | 774 } |
| 737 | 775 |
| 738 dispose() { | 776 dispose() { |
| 739 _renderer?.dispose(); | 777 _renderer?.dispose(); |
| 740 _disposer.dispose(); | 778 _disposer.dispose(); |
| 741 } | 779 } |
| 742 } | 780 } |
| OLD | NEW |