blob: cc002eae1b1285454b6c6a3eb6c817673e677967 [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();
List<ChartColumnSpec> columns;
ObservableList<List> 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 transform 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);
}