blob: 65794be06202e9326688f00d3f68cd0dbf861ab9 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/
part of charted.charts;
typedef bool FilterFunction(dynamic value);
/**
* Transforms the ChartData base on the specified FilterDefinitions. Each row
* of data will be tested by passing the value at target column to the filter
* function. If filter function returns false, the row will be filtered out.
* This transformer does not modify the column part of the input ChartData.
*/
class FilterTransformer extends ChangeNotifier
implements ChartDataTransform, ChartData {
final SubscriptionsDisposer _dataSubscriptions = new SubscriptionsDisposer();
Iterable<ChartColumnSpec> columns;
ObservableList<Iterable> rows = new ObservableList();
List<FilterDefinition> filterFunctions;
ChartData _data;
FilterTransformer(this.filterFunctions);
/**
* Transforms the input data with the list of [FilterDefinition] specified in
* the constructor. If the rows and columns are ObservableList in the data,
* changes in rows and columns in input data will trigger tranform to be
* performed again to update the output rows and columns.
*/
ChartData transform(ChartData data) {
_data = data;
_registerListeners();
_transform();
return this;
}
/** Registers listeners if data.rows or data.columns are Observable. */
_registerListeners() {
_dataSubscriptions.dispose();
if(_data is Observable) {
var observable = (_data as Observable);
_dataSubscriptions.add(observable.changes.listen((records) {
_transform();
// NOTE: Currently we're only passing the first change because the chart
// area just draw with the updated data. When we add partial update
// to chart area, we'll need to handle this better.
notifyChange(records.first);
}));
}
}
/**
* Performs the filter transform with _data. This is called on transform and
* onChange if the input ChartData is Observable.
*/
_transform() {
columns = _data.columns;
rows.clear();
for (var row in _data.rows) {
// Add the row if each value in target column passes the filter function.
if (filterFunctions.every((e) =>
e.filterFunc(row.elementAt(e.targetColumn)))) {
rows.add(row);
}
}
}
}
class FilterDefinition {
final FilterFunction filterFunc;
final int targetColumn;
FilterDefinition(this.targetColumn, this.filterFunc);
}