Web charts common update (#111)

pull/117/head
Brett Morgan 6 years ago committed by GitHub
parent eac7833d1d
commit 3af5bbf125
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1 @@
build/

@ -0,0 +1,32 @@
include: package:pedantic/analysis_options.yaml
analyzer:
# strong-mode:
# implicit-casts: false
# implicit-dynamic: false
linter:
rules:
- avoid_types_on_closure_parameters
- avoid_void_async
- await_only_futures
- camel_case_types
- cancel_subscriptions
- close_sinks
# TODO(domesticmouse): rename constants
# - constant_identifier_names
- control_flow_in_finally
- empty_statements
# TODO(domesticmouse): implement hashCode methods
# - hash_and_equals
- implementation_imports
- non_constant_identifier_names
- package_api_docs
- package_names
- package_prefixed_library_names
- test_types_in_equals
- throw_in_finally
- unnecessary_brace_in_string_interps
- unnecessary_getters_setters
- unnecessary_new
- unnecessary_statements

@ -37,7 +37,6 @@ class BarChart extends OrdinalCartesianChart {
@override @override
SeriesRenderer<String> makeDefaultRenderer() { SeriesRenderer<String> makeDefaultRenderer() {
return new BarRenderer<String>() return BarRenderer<String>()..rendererId = SeriesRenderer.defaultRendererId;
..rendererId = SeriesRenderer.defaultRendererId;
} }
} }

@ -33,9 +33,9 @@ class BarLabelDecorator<D> extends BarRendererDecorator<D> {
static const _defaultLabelPadding = 5; static const _defaultLabelPadding = 5;
static const _defaultLabelAnchor = BarLabelAnchor.start; static const _defaultLabelAnchor = BarLabelAnchor.start;
static final _defaultInsideLabelStyle = static final _defaultInsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.white); TextStyleSpec(fontSize: 12, color: Color.white);
static final _defaultOutsideLabelStyle = static final _defaultOutsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.black); TextStyleSpec(fontSize: 12, color: Color.black);
/// Configures [TextStyleSpec] for labels placed inside the bars. /// Configures [TextStyleSpec] for labels placed inside the bars.
final TextStyleSpec insideLabelStyleSpec; final TextStyleSpec insideLabelStyleSpec;

@ -37,7 +37,7 @@ import 'base_bar_renderer_element.dart' show BaseBarRendererElement;
/// ///
/// In grouped stacked mode, this list will contain a combination of domain /// In grouped stacked mode, this list will contain a combination of domain
/// value and series category. /// value and series category.
const domainValuesKey = const AttributeKey<Set>('BarLaneRenderer.domainValues'); const domainValuesKey = AttributeKey<Set>('BarLaneRenderer.domainValues');
/// Renders series data as a series of bars with lanes. /// Renders series data as a series of bars with lanes.
/// ///
@ -63,17 +63,16 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
/// as the data was given to the chart. For the case where both grouping and /// as the data was given to the chart. For the case where both grouping and
/// stacking are disabled, this means that bars for data later in the series /// stacking are disabled, this means that bars for data later in the series
/// will be drawn "on top of" bars earlier in the series. /// will be drawn "on top of" bars earlier in the series.
final _barLaneStackMap = new LinkedHashMap<String, List<AnimatedBar<D>>>(); final _barLaneStackMap = LinkedHashMap<String, List<AnimatedBar<D>>>();
/// Store a map of flags to track whether all measure values for a given /// Store a map of flags to track whether all measure values for a given
/// domain value are null, for every series on the chart. /// domain value are null, for every series on the chart.
final _allMeasuresForDomainNullMap = new LinkedHashMap<D, bool>(); final _allMeasuresForDomainNullMap = LinkedHashMap<D, bool>();
factory BarLaneRenderer({BarLaneRendererConfig config, String rendererId}) { factory BarLaneRenderer({BarLaneRendererConfig config, String rendererId}) {
rendererId ??= 'bar'; rendererId ??= 'bar';
config ??= new BarLaneRendererConfig(); config ??= BarLaneRendererConfig();
return new BarLaneRenderer._internal( return BarLaneRenderer._internal(config: config, rendererId: rendererId);
config: config, rendererId: rendererId);
} }
BarLaneRenderer._internal({BarLaneRendererConfig config, String rendererId}) BarLaneRenderer._internal({BarLaneRendererConfig config, String rendererId})
@ -86,11 +85,11 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
_allMeasuresForDomainNullMap.clear(); _allMeasuresForDomainNullMap.clear();
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
final domainFn = series.domainFn; final domainFn = series.domainFn;
final measureFn = series.rawMeasureFn; final measureFn = series.rawMeasureFn;
final domainValues = new Set<D>(); final domainValues = Set<D>();
for (var barIndex = 0; barIndex < series.data.length; barIndex++) { for (var barIndex = 0; barIndex < series.data.length; barIndex++) {
final domain = domainFn(barIndex); final domain = domainFn(barIndex);
@ -118,7 +117,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
super.update(seriesList, isAnimatingThisDraw); super.update(seriesList, isAnimatingThisDraw);
// Add gray bars to render under every bar stack. // Add gray bars to render under every bar stack.
seriesList.forEach((ImmutableSeries<D> series) { seriesList.forEach((series) {
Set<D> domainValues = series.getAttr(domainValuesKey) as Set<D>; Set<D> domainValues = series.getAttr(domainValuesKey) as Set<D>;
final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>; final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;
@ -133,14 +132,14 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
// Create a fake series for [BarLabelDecorator] to use when looking up the // Create a fake series for [BarLabelDecorator] to use when looking up the
// index of each datum. // index of each datum.
final laneSeries = new MutableSeries<D>.clone(seriesList[0]); final laneSeries = MutableSeries<D>.clone(seriesList[0]);
laneSeries.data = []; laneSeries.data = [];
// Don't render any labels on the swim lanes. // Don't render any labels on the swim lanes.
laneSeries.labelAccessorFn = (int index) => ''; laneSeries.labelAccessorFn = (index) => '';
var laneSeriesIndex = 0; var laneSeriesIndex = 0;
domainValues.forEach((D domainValue) { domainValues.forEach((domainValue) {
// Skip adding any background bars if they will be covered up by the // Skip adding any background bars if they will be covered up by the
// domain-spanning null bar. // domain-spanning null bar.
if (_allMeasuresForDomainNullMap[domainValue] == true) { if (_allMeasuresForDomainNullMap[domainValue] == true) {
@ -168,8 +167,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
barStackMapKey, () => <AnimatedBar<D>>[]); barStackMapKey, () => <AnimatedBar<D>>[]);
// If we already have an AnimatingBar for that index, use it. // If we already have an AnimatingBar for that index, use it.
var animatingBar = barStackList.firstWhere( var animatingBar = barStackList.firstWhere((bar) => bar.key == barKey,
(AnimatedBar bar) => bar.key == barKey,
orElse: () => null); orElse: () => null);
// If we don't have any existing bar element, create a new bar and have // If we don't have any existing bar element, create a new bar and have
@ -183,7 +181,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
previousBarGroupWeight: previousBarGroupWeight, previousBarGroupWeight: previousBarGroupWeight,
barGroupWeight: barGroupWeight, barGroupWeight: barGroupWeight,
color: (config as BarLaneRendererConfig).backgroundBarColor, color: (config as BarLaneRendererConfig).backgroundBarColor,
details: new BarRendererElement<D>(), details: BarRendererElement<D>(),
domainValue: domainValue, domainValue: domainValue,
domainAxis: domainAxis, domainAxis: domainAxis,
domainWidth: domainAxis.rangeBand.round(), domainWidth: domainAxis.rangeBand.round(),
@ -212,7 +210,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
previousBarGroupWeight: previousBarGroupWeight, previousBarGroupWeight: previousBarGroupWeight,
barGroupWeight: barGroupWeight, barGroupWeight: barGroupWeight,
color: (config as BarLaneRendererConfig).backgroundBarColor, color: (config as BarLaneRendererConfig).backgroundBarColor,
details: new BarRendererElement<D>(), details: BarRendererElement<D>(),
domainValue: domainValue, domainValue: domainValue,
domainAxis: domainAxis, domainAxis: domainAxis,
domainWidth: domainAxis.rangeBand.round(), domainWidth: domainAxis.rangeBand.round(),
@ -252,15 +250,15 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
// Create a fake series for [BarLabelDecorator] to use when looking up the // Create a fake series for [BarLabelDecorator] to use when looking up the
// index of each datum. We don't care about any other series values for // index of each datum. We don't care about any other series values for
// the merged lanes, so just clone the first series. // the merged lanes, so just clone the first series.
final mergedSeries = new MutableSeries<D>.clone(seriesList[0]); final mergedSeries = MutableSeries<D>.clone(seriesList[0]);
mergedSeries.data = []; mergedSeries.data = [];
// Add a label accessor that returns the empty lane label. // Add a label accessor that returns the empty lane label.
mergedSeries.labelAccessorFn = mergedSeries.labelAccessorFn =
(int index) => (config as BarLaneRendererConfig).emptyLaneLabel; (index) => (config as BarLaneRendererConfig).emptyLaneLabel;
var mergedSeriesIndex = 0; var mergedSeriesIndex = 0;
_allMeasuresForDomainNullMap.forEach((D domainValue, bool allNull) { _allMeasuresForDomainNullMap.forEach((domainValue, allNull) {
if (allNull) { if (allNull) {
// Add a fake datum to the series for [BarLabelDecorator]. // Add a fake datum to the series for [BarLabelDecorator].
final datum = {'index': mergedSeriesIndex}; final datum = {'index': mergedSeriesIndex};
@ -274,8 +272,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
barStackMapKey, () => <AnimatedBar<D>>[]); barStackMapKey, () => <AnimatedBar<D>>[]);
// If we already have an AnimatingBar for that index, use it. // If we already have an AnimatingBar for that index, use it.
var animatingBar = barStackList.firstWhere( var animatingBar = barStackList.firstWhere((bar) => bar.key == barKey,
(AnimatedBar bar) => bar.key == barKey,
orElse: () => null); orElse: () => null);
// If we don't have any existing bar element, create a new bar and have // If we don't have any existing bar element, create a new bar and have
@ -289,7 +286,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
previousBarGroupWeight: previousBarGroupWeight, previousBarGroupWeight: previousBarGroupWeight,
barGroupWeight: barGroupWeight, barGroupWeight: barGroupWeight,
color: (config as BarLaneRendererConfig).backgroundBarColor, color: (config as BarLaneRendererConfig).backgroundBarColor,
details: new BarRendererElement<D>(), details: BarRendererElement<D>(),
domainValue: domainValue, domainValue: domainValue,
domainAxis: domainAxis, domainAxis: domainAxis,
domainWidth: domainAxis.rangeBand.round(), domainWidth: domainAxis.rangeBand.round(),
@ -318,7 +315,7 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
previousBarGroupWeight: previousBarGroupWeight, previousBarGroupWeight: previousBarGroupWeight,
barGroupWeight: barGroupWeight, barGroupWeight: barGroupWeight,
color: (config as BarLaneRendererConfig).backgroundBarColor, color: (config as BarLaneRendererConfig).backgroundBarColor,
details: new BarRendererElement<D>(), details: BarRendererElement<D>(),
domainValue: domainValue, domainValue: domainValue,
domainAxis: domainAxis, domainAxis: domainAxis,
domainWidth: domainAxis.rangeBand.round(), domainWidth: domainAxis.rangeBand.round(),
@ -352,13 +349,12 @@ class BarLaneRenderer<D> extends BarRenderer<D> {
/// Paints the current bar data on the canvas. /// Paints the current bar data on the canvas.
@override @override
void paint(ChartCanvas canvas, double animationPercent) { void paint(ChartCanvas canvas, double animationPercent) {
_barLaneStackMap.forEach((String stackKey, List<AnimatedBar<D>> barStack) { _barLaneStackMap.forEach((stackKey, barStack) {
// Turn this into a list so that the getCurrentBar isn't called more than // Turn this into a list so that the getCurrentBar isn't called more than
// once for each animationPercent if the barElements are iterated more // once for each animationPercent if the barElements are iterated more
// than once. // than once.
List<BarRendererElement<D>> barElements = barStack List<BarRendererElement<D>> barElements = barStack
.map((AnimatedBar<D> animatingBar) => .map((animatingBar) => animatingBar.getCurrentBar(animationPercent))
animatingBar.getCurrentBar(animationPercent))
.toList(); .toList();
paintBar(canvas, animationPercent, barElements); paintBar(canvas, animationPercent, barElements);

@ -75,8 +75,7 @@ class BarLaneRendererConfig extends BarRendererConfig<String> {
@override @override
BarLaneRenderer<String> build() { BarLaneRenderer<String> build() {
return new BarLaneRenderer<String>( return BarLaneRenderer<String>(config: this, rendererId: customRendererId);
config: this, rendererId: customRendererId);
} }
@override @override

@ -52,8 +52,8 @@ class BarRenderer<D>
factory BarRenderer({BarRendererConfig config, String rendererId}) { factory BarRenderer({BarRendererConfig config, String rendererId}) {
rendererId ??= 'bar'; rendererId ??= 'bar';
config ??= new BarRendererConfig(); config ??= BarRendererConfig();
return new BarRenderer.internal(config: config, rendererId: rendererId); return BarRenderer.internal(config: config, rendererId: rendererId);
} }
/// This constructor is protected because it is used by child classes, which /// This constructor is protected because it is used by child classes, which
@ -99,20 +99,20 @@ class BarRenderer<D>
Point<double> chartPosition; Point<double> chartPosition;
if (renderingVertically) { if (renderingVertically) {
chartPosition = new Point<double>( chartPosition = Point<double>(
(bounds.left + (bounds.width / 2)).toDouble(), bounds.top.toDouble()); (bounds.left + (bounds.width / 2)).toDouble(), bounds.top.toDouble());
} else { } else {
chartPosition = new Point<double>( chartPosition = Point<double>(
isRtl ? bounds.left.toDouble() : bounds.right.toDouble(), isRtl ? bounds.left.toDouble() : bounds.right.toDouble(),
(bounds.top + (bounds.height / 2)).toDouble()); (bounds.top + (bounds.height / 2)).toDouble());
} }
return new DatumDetails.from(details, chartPosition: chartPosition); return DatumDetails.from(details, chartPosition: chartPosition);
} }
@override @override
BarRendererElement<D> getBaseDetails(dynamic datum, int index) { BarRendererElement<D> getBaseDetails(dynamic datum, int index) {
return new BarRendererElement<D>(); return BarRendererElement<D>();
} }
CornerStrategy get cornerStrategy { CornerStrategy get cornerStrategy {
@ -145,7 +145,7 @@ class BarRenderer<D>
int numBarGroups, int numBarGroups,
bool measureIsNull, bool measureIsNull,
bool measureIsNegative}) { bool measureIsNegative}) {
return new AnimatedBar<D>( return AnimatedBar<D>(
key: key, datum: datum, series: series, domainValue: domainValue) key: key, datum: datum, series: series, domainValue: domainValue)
..setNewTarget(makeBarRendererElement( ..setNewTarget(makeBarRendererElement(
color: color, color: color,
@ -192,7 +192,7 @@ class BarRenderer<D>
int numBarGroups, int numBarGroups,
bool measureIsNull, bool measureIsNull,
bool measureIsNegative}) { bool measureIsNegative}) {
return new BarRendererElement<D>() return BarRendererElement<D>()
..color = color ..color = color
..dashPattern = dashPattern ..dashPattern = dashPattern
..fillColor = fillColor ..fillColor = fillColor
@ -238,7 +238,7 @@ class BarRenderer<D>
if (bar != unmodifiedBar) { if (bar != unmodifiedBar) {
bounds = renderingVertically bounds = renderingVertically
? new Rectangle<int>( ? Rectangle<int>(
bar.bounds.left, bar.bounds.left,
max( max(
0, 0,
@ -247,7 +247,7 @@ class BarRenderer<D>
bar.bounds.width, bar.bounds.width,
max(0, bar.bounds.height - _stackedBarPadding), max(0, bar.bounds.height - _stackedBarPadding),
) )
: new Rectangle<int>( : Rectangle<int>(
max( max(
0, 0,
bar.bounds.left + bar.bounds.left +
@ -258,7 +258,7 @@ class BarRenderer<D>
); );
} }
bars.add(new CanvasRect(bounds, bars.add(CanvasRect(bounds,
dashPattern: bar.dashPattern, dashPattern: bar.dashPattern,
fill: bar.fillColor, fill: bar.fillColor,
pattern: bar.fillPattern, pattern: bar.fillPattern,
@ -292,7 +292,7 @@ class BarRenderer<D>
roundBottomRight = renderingVertically || isRtl ? false : true; roundBottomRight = renderingVertically || isRtl ? false : true;
} }
final barStack = new CanvasBarStack( final barStack = CanvasBarStack(
bars, bars,
radius: cornerStrategy.getRadius(maxBarWidth), radius: cornerStrategy.getRadius(maxBarWidth),
stackedBarPadding: _stackedBarPadding, stackedBarPadding: _stackedBarPadding,
@ -370,7 +370,7 @@ class BarRenderer<D>
final width = right - left; final width = right - left;
final height = bottom - top; final height = bottom - top;
return new Rectangle(left, top, width, height); return Rectangle(left, top, width, height);
} }
/// Generates a set of bounds that describe a bar. /// Generates a set of bounds that describe a bar.
@ -442,11 +442,11 @@ class BarRenderer<D>
Rectangle<int> bounds; Rectangle<int> bounds;
if (this.renderingVertically) { if (this.renderingVertically) {
// Rectangle clamps to zero width/height // Rectangle clamps to zero width/height
bounds = new Rectangle<int>(domainStart, measureEnd, bounds = Rectangle<int>(domainStart, measureEnd, domainEnd - domainStart,
domainEnd - domainStart, measureStart - measureEnd); measureStart - measureEnd);
} else { } else {
// Rectangle clamps to zero width/height // Rectangle clamps to zero width/height
bounds = new Rectangle<int>(min(measureStart, measureEnd), domainStart, bounds = Rectangle<int>(min(measureStart, measureEnd), domainStart,
(measureEnd - measureStart).abs(), domainEnd - domainStart); (measureEnd - measureStart).abs(), domainEnd - domainStart);
} }
return bounds; return bounds;
@ -511,8 +511,8 @@ class BarRendererElement<D> extends BaseBarRendererElement
var left = ((targetBounds.left - previousBounds.left) * animationPercent) + var left = ((targetBounds.left - previousBounds.left) * animationPercent) +
previousBounds.left; previousBounds.left;
bounds = new Rectangle<int>(left.round(), top.round(), bounds = Rectangle<int>(left.round(), top.round(), (right - left).round(),
(right - left).round(), (bottom - top).round()); (bottom - top).round());
roundPx = localTarget.roundPx; roundPx = localTarget.roundPx;
@ -533,7 +533,7 @@ class AnimatedBar<D> extends BaseAnimatedBar<D, BarRendererElement<D>> {
final BarRendererElement localTarget = target; final BarRendererElement localTarget = target;
// TODO: Animate out bars in the middle of a stack. // TODO: Animate out bars in the middle of a stack.
localTarget.bounds = new Rectangle<int>( localTarget.bounds = Rectangle<int>(
localTarget.bounds.left + (localTarget.bounds.width / 2).round(), localTarget.bounds.left + (localTarget.bounds.width / 2).round(),
localTarget.measureAxisPosition.round(), localTarget.measureAxisPosition.round(),
0, 0,
@ -552,5 +552,5 @@ class AnimatedBar<D> extends BaseAnimatedBar<D, BarRendererElement<D>> {
@override @override
BarRendererElement<D> clone(BarRendererElement bar) => BarRendererElement<D> clone(BarRendererElement bar) =>
new BarRendererElement<D>.clone(bar); BarRendererElement<D>.clone(bar);
} }

@ -56,7 +56,7 @@ class BarRendererConfig<D> extends BaseBarRendererConfig<D> {
@override @override
BarRenderer<D> build() { BarRenderer<D> build() {
return new BarRenderer<D>(config: this, rendererId: customRendererId); return BarRenderer<D>(config: this, rendererId: customRendererId);
} }
@override @override

@ -45,13 +45,13 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
final _barGroupInnerPadding = 2; final _barGroupInnerPadding = 2;
/// Standard color for all bar target lines. /// Standard color for all bar target lines.
final _color = new Color(r: 0, g: 0, b: 0, a: 153); final _color = Color(r: 0, g: 0, b: 0, a: 153);
factory BarTargetLineRenderer( factory BarTargetLineRenderer(
{BarTargetLineRendererConfig<D> config, {BarTargetLineRendererConfig<D> config,
String rendererId = 'barTargetLine'}) { String rendererId = 'barTargetLine'}) {
config ??= new BarTargetLineRendererConfig<D>(); config ??= BarTargetLineRendererConfig<D>();
return new BarTargetLineRenderer._internal( return BarTargetLineRenderer._internal(
config: config, rendererId: rendererId); config: config, rendererId: rendererId);
} }
@ -64,7 +64,7 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
@override @override
void configureSeries(List<MutableSeries<D>> seriesList) { void configureSeries(List<MutableSeries<D>> seriesList) {
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
series.colorFn ??= (_) => _color; series.colorFn ??= (_) => _color;
series.fillColorFn ??= (_) => _color; series.fillColorFn ??= (_) => _color;
}); });
@ -97,21 +97,21 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
Point<double> chartPosition; Point<double> chartPosition;
if (renderingVertically) { if (renderingVertically) {
chartPosition = new Point<double>( chartPosition = Point<double>(
(points[0].x + (points[1].x - points[0].x) / 2).toDouble(), (points[0].x + (points[1].x - points[0].x) / 2).toDouble(),
points[0].y.toDouble()); points[0].y.toDouble());
} else { } else {
chartPosition = new Point<double>(points[0].x.toDouble(), chartPosition = Point<double>(points[0].x.toDouble(),
(points[0].y + (points[1].y - points[0].y) / 2).toDouble()); (points[0].y + (points[1].y - points[0].y) / 2).toDouble());
} }
return new DatumDetails.from(details, chartPosition: chartPosition); return DatumDetails.from(details, chartPosition: chartPosition);
} }
@override @override
_BarTargetLineRendererElement getBaseDetails(dynamic datum, int index) { _BarTargetLineRendererElement getBaseDetails(dynamic datum, int index) {
final BarTargetLineRendererConfig<D> localConfig = config; final BarTargetLineRendererConfig<D> localConfig = config;
return new _BarTargetLineRendererElement() return _BarTargetLineRendererElement()
..roundEndCaps = localConfig.roundEndCaps; ..roundEndCaps = localConfig.roundEndCaps;
} }
@ -141,7 +141,7 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
double strokeWidthPx, double strokeWidthPx,
bool measureIsNull, bool measureIsNull,
bool measureIsNegative}) { bool measureIsNegative}) {
return new _AnimatedBarTargetLine( return _AnimatedBarTargetLine(
key: key, datum: datum, series: series, domainValue: domainValue) key: key, datum: datum, series: series, domainValue: domainValue)
..setNewTarget(makeBarRendererElement( ..setNewTarget(makeBarRendererElement(
color: color, color: color,
@ -188,7 +188,7 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
int numBarGroups, int numBarGroups,
bool measureIsNull, bool measureIsNull,
bool measureIsNegative}) { bool measureIsNegative}) {
return new _BarTargetLineRendererElement() return _BarTargetLineRendererElement()
..color = color ..color = color
..dashPattern = dashPattern ..dashPattern = dashPattern
..fillColor = fillColor ..fillColor = fillColor
@ -217,7 +217,7 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
double animationPercent, double animationPercent,
Iterable<_BarTargetLineRendererElement> barElements, Iterable<_BarTargetLineRendererElement> barElements,
) { ) {
barElements.forEach((_BarTargetLineRendererElement bar) { barElements.forEach((bar) {
// TODO: Combine common line attributes into // TODO: Combine common line attributes into
// GraphicsFactory.lineStyle or similar. // GraphicsFactory.lineStyle or similar.
canvas.drawLine( canvas.drawLine(
@ -299,13 +299,13 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
List<Point<int>> points; List<Point<int>> points;
if (renderingVertically) { if (renderingVertically) {
points = [ points = [
new Point<int>(domainStart, measureStart), Point<int>(domainStart, measureStart),
new Point<int>(domainEnd, measureStart) Point<int>(domainEnd, measureStart)
]; ];
} else { } else {
points = [ points = [
new Point<int>(measureStart, domainStart), Point<int>(measureStart, domainStart),
new Point<int>(measureStart, domainEnd) Point<int>(measureStart, domainEnd)
]; ];
} }
return points; return points;
@ -318,13 +318,13 @@ class BarTargetLineRenderer<D> extends BaseBarRenderer<D,
int bottom; int bottom;
int left; int left;
int right; int right;
points.forEach((Point<int> p) { points.forEach((p) {
top = top != null ? min(top, p.y) : p.y; top = top != null ? min(top, p.y) : p.y;
left = left != null ? min(left, p.x) : p.x; left = left != null ? min(left, p.x) : p.x;
bottom = bottom != null ? max(bottom, p.y) : p.y; bottom = bottom != null ? max(bottom, p.y) : p.y;
right = right != null ? max(right, p.x) : p.x; right = right != null ? max(right, p.x) : p.x;
}); });
return new Rectangle<int>(left, top, right - left, bottom - top); return Rectangle<int>(left, top, right - left, bottom - top);
} }
} }
@ -336,7 +336,7 @@ class _BarTargetLineRendererElement extends BaseBarRendererElement {
_BarTargetLineRendererElement.clone(_BarTargetLineRendererElement other) _BarTargetLineRendererElement.clone(_BarTargetLineRendererElement other)
: super.clone(other) { : super.clone(other) {
points = new List<Point<int>>.from(other.points); points = List<Point<int>>.from(other.points);
roundEndCaps = other.roundEndCaps; roundEndCaps = other.roundEndCaps;
} }
@ -362,7 +362,7 @@ class _BarTargetLineRendererElement extends BaseBarRendererElement {
previousPoint = previousPoints[pointIndex]; previousPoint = previousPoints[pointIndex];
lastPoint = previousPoint; lastPoint = previousPoint;
} else { } else {
previousPoint = new Point<int>(targetPoint.x, lastPoint.y); previousPoint = Point<int>(targetPoint.x, lastPoint.y);
} }
var x = ((targetPoint.x - previousPoint.x) * animationPercent) + var x = ((targetPoint.x - previousPoint.x) * animationPercent) +
@ -372,9 +372,9 @@ class _BarTargetLineRendererElement extends BaseBarRendererElement {
previousPoint.y; previousPoint.y;
if (points.length - 1 >= pointIndex) { if (points.length - 1 >= pointIndex) {
points[pointIndex] = new Point<int>(x.round(), y.round()); points[pointIndex] = Point<int>(x.round(), y.round());
} else { } else {
points.add(new Point<int>(x.round(), y.round())); points.add(Point<int>(x.round(), y.round()));
} }
} }
@ -410,13 +410,13 @@ class _AnimatedBarTargetLine<D>
for (var index = 0; index < localTarget.points.length; index++) { for (var index = 0; index < localTarget.points.length; index++) {
final targetPoint = localTarget.points[index]; final targetPoint = localTarget.points[index];
newPoints.add(new Point<int>( newPoints.add(
targetPoint.x, localTarget.measureAxisPosition.round())); Point<int>(targetPoint.x, localTarget.measureAxisPosition.round()));
} }
localTarget.points = newPoints; localTarget.points = newPoints;
} }
@override @override
_BarTargetLineRendererElement clone(_BarTargetLineRendererElement bar) => _BarTargetLineRendererElement clone(_BarTargetLineRendererElement bar) =>
new _BarTargetLineRendererElement.clone(bar); _BarTargetLineRendererElement.clone(bar);
} }

@ -57,14 +57,13 @@ class BarTargetLineRendererConfig<D> extends BaseBarRendererConfig<D> {
layoutPaintOrder: layoutPaintOrder, layoutPaintOrder: layoutPaintOrder,
minBarLengthPx: minBarLengthPx, minBarLengthPx: minBarLengthPx,
strokeWidthPx: strokeWidthPx, strokeWidthPx: strokeWidthPx,
symbolRenderer: symbolRenderer ?? new LineSymbolRenderer(), symbolRenderer: symbolRenderer ?? LineSymbolRenderer(),
weightPattern: weightPattern, weightPattern: weightPattern,
); );
@override @override
BarTargetLineRenderer<D> build() { BarTargetLineRenderer<D> build() {
return new BarTargetLineRenderer<D>( return BarTargetLineRenderer<D>(config: this, rendererId: customRendererId);
config: this, rendererId: customRendererId);
} }
@override @override

@ -34,20 +34,19 @@ import 'base_bar_renderer_config.dart' show BaseBarRendererConfig;
import 'base_bar_renderer_element.dart' import 'base_bar_renderer_element.dart'
show BaseAnimatedBar, BaseBarRendererElement; show BaseAnimatedBar, BaseBarRendererElement;
const barGroupIndexKey = const AttributeKey<int>('BarRenderer.barGroupIndex'); const barGroupIndexKey = AttributeKey<int>('BarRenderer.barGroupIndex');
const barGroupCountKey = const AttributeKey<int>('BarRenderer.barGroupCount'); const barGroupCountKey = AttributeKey<int>('BarRenderer.barGroupCount');
const barGroupWeightKey = const barGroupWeightKey = AttributeKey<double>('BarRenderer.barGroupWeight');
const AttributeKey<double>('BarRenderer.barGroupWeight');
const previousBarGroupWeightKey = const previousBarGroupWeightKey =
const AttributeKey<double>('BarRenderer.previousBarGroupWeight'); AttributeKey<double>('BarRenderer.previousBarGroupWeight');
const stackKeyKey = const AttributeKey<String>('BarRenderer.stackKey'); const stackKeyKey = AttributeKey<String>('BarRenderer.stackKey');
const barElementsKey = const barElementsKey =
const AttributeKey<List<BaseBarRendererElement>>('BarRenderer.elements'); AttributeKey<List<BaseBarRendererElement>>('BarRenderer.elements');
/// Base class for bar renderers that implements common stacking and grouping /// Base class for bar renderers that implements common stacking and grouping
/// logic. /// logic.
@ -85,7 +84,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
/// as the data was given to the chart. For the case where both grouping and /// as the data was given to the chart. For the case where both grouping and
/// stacking are disabled, this means that bars for data later in the series /// stacking are disabled, this means that bars for data later in the series
/// will be drawn "on top of" bars earlier in the series. /// will be drawn "on top of" bars earlier in the series.
final _barStackMap = new LinkedHashMap<String, List<B>>(); final _barStackMap = LinkedHashMap<String, List<B>>();
// Store a list of bar stacks that exist in the series data. // Store a list of bar stacks that exist in the series data.
// //
@ -95,7 +94,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
final _currentKeys = <String>[]; final _currentKeys = <String>[];
/// Stores a list of stack keys for each group key. /// Stores a list of stack keys for each group key.
final _currentGroupsStackKeys = new LinkedHashMap<D, Set<String>>(); final _currentGroupsStackKeys = LinkedHashMap<D, Set<String>>();
/// Optimization for getNearest to avoid scanning all data if possible. /// Optimization for getNearest to avoid scanning all data if possible.
ImmutableAxis<D> _prevDomainAxis; ImmutableAxis<D> _prevDomainAxis;
@ -105,8 +104,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
: super( : super(
rendererId: rendererId, rendererId: rendererId,
layoutPaintOrder: layoutPaintOrder, layoutPaintOrder: layoutPaintOrder,
symbolRenderer: symbolRenderer: config?.symbolRenderer ?? RoundedRectSymbolRenderer(),
config?.symbolRenderer ?? new RoundedRectSymbolRenderer(),
); );
@override @override
@ -126,7 +124,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
final orderedSeriesList = getOrderedSeriesList(seriesList); final orderedSeriesList = getOrderedSeriesList(seriesList);
orderedSeriesList.forEach((MutableSeries<D> series) { orderedSeriesList.forEach((series) {
var elements = <BaseBarRendererElement>[]; var elements = <BaseBarRendererElement>[];
var domainFn = series.domainFn; var domainFn = series.domainFn;
@ -255,7 +253,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
// Compute bar group weights. // Compute bar group weights.
final barWeights = _calculateBarWeights(numBarGroups); final barWeights = _calculateBarWeights(numBarGroups);
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
series.setAttr(barGroupCountKey, numBarGroups); series.setAttr(barGroupCountKey, numBarGroups);
if (barWeights.isNotEmpty) { if (barWeights.isNotEmpty) {
@ -290,7 +288,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
if (config.weightPattern != null) { if (config.weightPattern != null) {
if (numBarGroups > config.weightPattern.length) { if (numBarGroups > config.weightPattern.length) {
throw new ArgumentError('Number of series exceeds length of weight ' throw ArgumentError('Number of series exceeds length of weight '
'pattern ${config.weightPattern}'); 'pattern ${config.weightPattern}');
} }
@ -327,7 +325,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
// Given that charts can only have one domain axis, just grab it from the // Given that charts can only have one domain axis, just grab it from the
// first series. // first series.
final domainAxis = seriesList.first.getAttr(domainAxisKey); final domainAxis = seriesList.first.getAttr(domainAxisKey);
domainAxis.setRangeBandConfig(new RangeBandConfig.styleAssignedPercent()); domainAxis.setRangeBandConfig(RangeBandConfig.styleAssignedPercent());
} }
} }
@ -337,7 +335,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
final orderedSeriesList = getOrderedSeriesList(seriesList); final orderedSeriesList = getOrderedSeriesList(seriesList);
orderedSeriesList.forEach((final ImmutableSeries<D> series) { orderedSeriesList.forEach((final series) {
final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>; final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;
final domainFn = series.domainFn; final domainFn = series.domainFn;
final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>; final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;
@ -384,7 +382,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
var barStackList = _barStackMap.putIfAbsent(barStackMapKey, () => []); var barStackList = _barStackMap.putIfAbsent(barStackMapKey, () => []);
// If we already have an AnimatingBarfor that index, use it. // If we already have an AnimatingBarfor that index, use it.
var animatingBar = barStackList.firstWhere((B bar) => bar.key == barKey, var animatingBar = barStackList.firstWhere((bar) => bar.key == barKey,
orElse: () => null); orElse: () => null);
// If we don't have any existing bar element, create a new bar and have // If we don't have any existing bar element, create a new bar and have
@ -438,7 +436,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
// Store off stack keys for each bar group to help getNearest identify // Store off stack keys for each bar group to help getNearest identify
// groups of stacks. // groups of stacks.
_currentGroupsStackKeys _currentGroupsStackKeys
.putIfAbsent(domainValue, () => new Set<String>()) .putIfAbsent(domainValue, () => <String>{})
.add(barStackMapKey); .add(barStackMapKey);
// Get the barElement we are going to setup. // Get the barElement we are going to setup.
@ -469,7 +467,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
}); });
// Animate out bars that don't exist anymore. // Animate out bars that don't exist anymore.
_barStackMap.forEach((String key, List<B> barStackList) { _barStackMap.forEach((key, barStackList) {
for (var barIndex = 0; barIndex < barStackList.length; barIndex++) { for (var barIndex = 0; barIndex < barStackList.length; barIndex++) {
final bar = barStackList[barIndex]; final bar = barStackList[barIndex];
if (_currentKeys.contains(bar.key) != true) { if (_currentKeys.contains(bar.key) != true) {
@ -541,11 +539,11 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
void paint(ChartCanvas canvas, double animationPercent) { void paint(ChartCanvas canvas, double animationPercent) {
// Clean up the bars that no longer exist. // Clean up the bars that no longer exist.
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = new HashSet<String>(); final keysToRemove = HashSet<String>();
_barStackMap.forEach((String key, List<B> barStackList) { _barStackMap.forEach((key, barStackList) {
barStackList.retainWhere( barStackList.retainWhere(
(B bar) => !bar.animatingOut && !bar.targetBar.measureIsNull); (bar) => !bar.animatingOut && !bar.targetBar.measureIsNull);
if (barStackList.isEmpty) { if (barStackList.isEmpty) {
keysToRemove.add(key); keysToRemove.add(key);
@ -563,12 +561,12 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
}); });
} }
_barStackMap.forEach((String stackKey, List<B> barStack) { _barStackMap.forEach((stackKey, barStack) {
// Turn this into a list so that the getCurrentBar isn't called more than // Turn this into a list so that the getCurrentBar isn't called more than
// once for each animationPercent if the barElements are iterated more // once for each animationPercent if the barElements are iterated more
// than once. // than once.
final barElements = barStack final barElements = barStack
.map((B animatingBar) => animatingBar.getCurrentBar(animationPercent)) .map((animatingBar) => animatingBar.getCurrentBar(animationPercent))
.toList(); .toList();
if (barElements.isNotEmpty) { if (barElements.isNotEmpty) {
@ -663,7 +661,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
? _currentGroupsStackKeys[domainValue] ? _currentGroupsStackKeys[domainValue]
: _currentGroupsStackKeys.values : _currentGroupsStackKeys.values
.reduce((allKeys, keys) => allKeys..addAll(keys)); .reduce((allKeys, keys) => allKeys..addAll(keys));
stackKeys?.forEach((String stackKey) { stackKeys?.forEach((stackKey) {
if (where != null) { if (where != null) {
matchingSegments.addAll(_barStackMap[stackKey].where(where)); matchingSegments.addAll(_barStackMap[stackKey].where(where));
} else { } else {
@ -678,23 +676,21 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
// we can't use the optimized comparison for [OrdinalAxis]. // we can't use the optimized comparison for [OrdinalAxis].
List<DatumDetails<D>> _getVerticalDetailsForDomainValue( List<DatumDetails<D>> _getVerticalDetailsForDomainValue(
D domainValue, Point<double> chartPoint) { D domainValue, Point<double> chartPoint) {
return new List<DatumDetails<D>>.from(_getSegmentsForDomainValue( return List<DatumDetails<D>>.from(_getSegmentsForDomainValue(domainValue,
domainValue, where: (bar) => !bar.series.overlaySeries).map<DatumDetails<D>>((bar) {
where: (BaseAnimatedBar<D, R> bar) => !bar.series.overlaySeries)
.map<DatumDetails<D>>((BaseAnimatedBar<D, R> bar) {
final barBounds = getBoundsForBar(bar.currentBar); final barBounds = getBoundsForBar(bar.currentBar);
final segmentDomainDistance = final segmentDomainDistance =
_getDistance(chartPoint.x.round(), barBounds.left, barBounds.right); _getDistance(chartPoint.x.round(), barBounds.left, barBounds.right);
final segmentMeasureDistance = final segmentMeasureDistance =
_getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom); _getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom);
final nearestPoint = new Point<double>( final nearestPoint = Point<double>(
clamp(chartPoint.x, barBounds.left, barBounds.right).toDouble(), clamp(chartPoint.x, barBounds.left, barBounds.right).toDouble(),
clamp(chartPoint.y, barBounds.top, barBounds.bottom).toDouble()); clamp(chartPoint.y, barBounds.top, barBounds.bottom).toDouble());
final relativeDistance = chartPoint.distanceTo(nearestPoint); final relativeDistance = chartPoint.distanceTo(nearestPoint);
return new DatumDetails<D>( return DatumDetails<D>(
series: bar.series, series: bar.series,
datum: bar.datum, datum: bar.datum,
domain: bar.domainValue, domain: bar.domainValue,
@ -707,17 +703,15 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
List<DatumDetails<D>> _getHorizontalDetailsForDomainValue( List<DatumDetails<D>> _getHorizontalDetailsForDomainValue(
D domainValue, Point<double> chartPoint) { D domainValue, Point<double> chartPoint) {
return new List<DatumDetails<D>>.from(_getSegmentsForDomainValue( return List<DatumDetails<D>>.from(_getSegmentsForDomainValue(domainValue,
domainValue, where: (bar) => !bar.series.overlaySeries).map((bar) {
where: (BaseAnimatedBar<D, R> bar) => !bar.series.overlaySeries)
.map((BaseAnimatedBar<D, R> bar) {
final barBounds = getBoundsForBar(bar.currentBar); final barBounds = getBoundsForBar(bar.currentBar);
final segmentDomainDistance = final segmentDomainDistance =
_getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom); _getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom);
final segmentMeasureDistance = final segmentMeasureDistance =
_getDistance(chartPoint.x.round(), barBounds.left, barBounds.right); _getDistance(chartPoint.x.round(), barBounds.left, barBounds.right);
return new DatumDetails<D>( return DatumDetails<D>(
series: bar.series, series: bar.series,
datum: bar.datum, datum: bar.datum,
domain: bar.domainValue, domain: bar.domainValue,
@ -748,7 +742,7 @@ abstract class BaseBarRenderer<D, R extends BaseBarRendererElement,
List<S> seriesList) { List<S> seriesList) {
return (renderingVertically && config.stacked) return (renderingVertically && config.stacked)
? config.grouped ? config.grouped
? new _ReversedSeriesIterable(seriesList) ? _ReversedSeriesIterable(seriesList)
: seriesList.reversed : seriesList.reversed
: seriesList; : seriesList;
} }
@ -763,7 +757,7 @@ class _ReversedSeriesIterable<S extends ImmutableSeries> extends Iterable<S> {
_ReversedSeriesIterable(this.seriesList); _ReversedSeriesIterable(this.seriesList);
@override @override
Iterator<S> get iterator => new _ReversedSeriesIterator(seriesList); Iterator<S> get iterator => _ReversedSeriesIterator(seriesList);
} }
/// Iterator that keeps reverse series order but keeps category order. /// Iterator that keeps reverse series order but keeps category order.

@ -82,7 +82,7 @@ abstract class BaseBarRendererConfig<D> extends LayoutViewConfig
/// Not used for stacked bars. /// Not used for stacked bars.
final List<int> weightPattern; final List<int> weightPattern;
final rendererAttributes = new RendererAttributes(); final rendererAttributes = RendererAttributes();
BaseBarRendererConfig( BaseBarRendererConfig(
{this.customRendererId, {this.customRendererId,
@ -95,7 +95,7 @@ abstract class BaseBarRendererConfig<D> extends LayoutViewConfig
this.strokeWidthPx = 0.0, this.strokeWidthPx = 0.0,
SymbolRenderer symbolRenderer, SymbolRenderer symbolRenderer,
this.weightPattern}) this.weightPattern})
: this.symbolRenderer = symbolRenderer ?? new RoundedRectSymbolRenderer(); : this.symbolRenderer = symbolRenderer ?? RoundedRectSymbolRenderer();
/// Whether or not the bars should be organized into groups. /// Whether or not the bars should be organized into groups.
bool get grouped => bool get grouped =>
@ -112,10 +112,8 @@ abstract class BaseBarRendererConfig<D> extends LayoutViewConfig
if (identical(this, other)) { if (identical(this, other)) {
return true; return true;
} }
if (!(other is BaseBarRendererConfig)) { return other is BaseBarRendererConfig &&
return false; other.customRendererId == customRendererId &&
}
return other.customRendererId == customRendererId &&
other.dashPattern == dashPattern && other.dashPattern == dashPattern &&
other.fillPattern == fillPattern && other.fillPattern == fillPattern &&
other.groupingType == groupingType && other.groupingType == groupingType &&
@ -123,7 +121,7 @@ abstract class BaseBarRendererConfig<D> extends LayoutViewConfig
other.stackHorizontalSeparator == stackHorizontalSeparator && other.stackHorizontalSeparator == stackHorizontalSeparator &&
other.strokeWidthPx == strokeWidthPx && other.strokeWidthPx == strokeWidthPx &&
other.symbolRenderer == symbolRenderer && other.symbolRenderer == symbolRenderer &&
new ListEquality().equals(other.weightPattern, weightPattern); ListEquality().equals(other.weightPattern, weightPattern);
} }
int get hashcode { int get hashcode {

@ -35,12 +35,11 @@ abstract class BaseBarRendererElement {
BaseBarRendererElement.clone(BaseBarRendererElement other) { BaseBarRendererElement.clone(BaseBarRendererElement other) {
barStackIndex = other.barStackIndex; barStackIndex = other.barStackIndex;
color = color = other.color != null ? Color.fromOther(color: other.color) : null;
other.color != null ? new Color.fromOther(color: other.color) : null;
cumulativeTotal = other.cumulativeTotal; cumulativeTotal = other.cumulativeTotal;
dashPattern = other.dashPattern; dashPattern = other.dashPattern;
fillColor = other.fillColor != null fillColor = other.fillColor != null
? new Color.fromOther(color: other.fillColor) ? Color.fromOther(color: other.fillColor)
: null; : null;
fillPattern = other.fillPattern; fillPattern = other.fillPattern;
measureAxisPosition = other.measureAxisPosition; measureAxisPosition = other.measureAxisPosition;

@ -46,9 +46,9 @@ import 'tick_formatter.dart'
show TickFormatter, OrdinalTickFormatter, NumericTickFormatter; show TickFormatter, OrdinalTickFormatter, NumericTickFormatter;
import 'tick_provider.dart' show TickProvider; import 'tick_provider.dart' show TickProvider;
const measureAxisIdKey = const AttributeKey<String>('Axis.measureAxisId'); const measureAxisIdKey = AttributeKey<String>('Axis.measureAxisId');
const measureAxisKey = const AttributeKey<Axis>('Axis.measureAxis'); const measureAxisKey = AttributeKey<Axis>('Axis.measureAxis');
const domainAxisKey = const AttributeKey<Axis>('Axis.domainAxis'); const domainAxisKey = AttributeKey<Axis>('Axis.domainAxis');
/// Orientation of an Axis. /// Orientation of an Axis.
enum AxisOrientation { top, right, bottom, left } enum AxisOrientation { top, right, bottom, left }
@ -89,14 +89,8 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
/// Previous [Scale] of this axis, used to calculate tick animation. /// Previous [Scale] of this axis, used to calculate tick animation.
MutableScale<D> _previousScale; MutableScale<D> _previousScale;
TickProvider<D> _tickProvider;
/// [TickProvider] for this axis. /// [TickProvider] for this axis.
TickProvider<D> get tickProvider => _tickProvider; TickProvider<D> tickProvider;
set tickProvider(TickProvider<D> tickProvider) {
_tickProvider = tickProvider;
}
/// [TickFormatter] for this axis. /// [TickFormatter] for this axis.
TickFormatter<D> _tickFormatter; TickFormatter<D> _tickFormatter;
@ -122,9 +116,12 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
/// If the output range should be reversed. /// If the output range should be reversed.
bool reverseOutputRange = false; bool reverseOutputRange = false;
/// Whether or not the axis will configure the viewport to have "niced" ticks /// Configures whether the viewport should be reset back to default values
/// around the domain values. /// when the domain is reset.
bool _autoViewport = true; ///
/// This should generally be disabled when the viewport will be managed
/// externally, e.g. from pan and zoom behaviors.
bool autoViewport = true;
/// If the axis line should always be drawn. /// If the axis line should always be drawn.
bool forceDrawAxisLine; bool forceDrawAxisLine;
@ -143,7 +140,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
Rectangle<int> _componentBounds; Rectangle<int> _componentBounds;
Rectangle<int> _drawAreaBounds; Rectangle<int> _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
/// Order for chart layout painting. /// Order for chart layout painting.
/// ///
@ -156,7 +153,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
TickFormatter<D> tickFormatter, TickFormatter<D> tickFormatter,
MutableScale<D> scale}) MutableScale<D> scale})
: this._scale = scale, : this._scale = scale,
this._tickProvider = tickProvider, this.tickProvider = tickProvider,
this._tickFormatter = tickFormatter; this._tickFormatter = tickFormatter;
@protected @protected
@ -172,17 +169,6 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
@override @override
ScaleOutputExtent get range => _scale.range; ScaleOutputExtent get range => _scale.range;
/// Configures whether the viewport should be reset back to default values
/// when the domain is reset.
///
/// This should generally be disabled when the viewport will be managed
/// externally, e.g. from pan and zoom behaviors.
set autoViewport(bool autoViewport) {
_autoViewport = autoViewport;
}
bool get autoViewport => _autoViewport;
void setRangeBandConfig(RangeBandConfig rangeBandConfig) { void setRangeBandConfig(RangeBandConfig rangeBandConfig) {
mutableScale.rangeBandConfig = rangeBandConfig; mutableScale.rangeBandConfig = rangeBandConfig;
} }
@ -222,7 +208,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
_scale.resetDomain(); _scale.resetDomain();
reverseOutputRange = false; reverseOutputRange = false;
if (_autoViewport) { if (autoViewport) {
_scale.resetViewportSettings(); _scale.resetViewportSettings();
} }
@ -243,7 +229,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
} }
void setOutputRange(int start, int end) { void setOutputRange(int start, int end) {
_scale.range = new ScaleOutputExtent(start, end); _scale.range = ScaleOutputExtent(start, end);
} }
/// Request update ticks from tick provider and update the painted ticks. /// Request update ticks from tick provider and update the painted ticks.
@ -268,7 +254,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
formatterValueCache: _formatterValueCache, formatterValueCache: _formatterValueCache,
tickDrawStrategy: tickDrawStrategy, tickDrawStrategy: tickDrawStrategy,
orientation: axisOrientation, orientation: axisOrientation,
viewportExtensionEnabled: _autoViewport); viewportExtensionEnabled: autoViewport);
} }
/// Updates the ticks that are actually used for drawing. /// Updates the ticks that are actually used for drawing.
@ -277,7 +263,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
return; return;
} }
final providedTicks = new List.from(_providedTicks ?? []); final providedTicks = List.from(_providedTicks ?? []);
for (AxisTicks<D> animatedTick in _axisTicks) { for (AxisTicks<D> animatedTick in _axisTicks) {
final tick = providedTicks?.firstWhere( final tick = providedTicks?.firstWhere(
@ -302,7 +288,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
// Add new ticks // Add new ticks
providedTicks?.forEach((tick) { providedTicks?.forEach((tick) {
final animatedTick = new AxisTicks<D>(tick); final animatedTick = AxisTicks<D>(tick);
if (_previousScale != null) { if (_previousScale != null) {
animatedTick.animateInFrom(_previousScale[tick.value].toDouble()); animatedTick.animateInFrom(_previousScale[tick.value].toDouble());
} }
@ -378,15 +364,7 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
// //
@override @override
GraphicsFactory get graphicsFactory => _graphicsFactory; LayoutViewConfig get layoutConfig => LayoutViewConfig(
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override
LayoutViewConfig get layoutConfig => new LayoutViewConfig(
paintOrder: layoutPaintOrder, paintOrder: layoutPaintOrder,
position: _layoutPosition, position: _layoutPosition,
positionOrder: LayoutViewPositionOrder.axis); positionOrder: LayoutViewPositionOrder.axis);
@ -457,8 +435,8 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
isVertical ? _componentBounds.top : _componentBounds.right; isVertical ? _componentBounds.top : _componentBounds.right;
final outputRange = reverseOutputRange final outputRange = reverseOutputRange
? new ScaleOutputExtent(outputEnd, outputStart) ? ScaleOutputExtent(outputEnd, outputStart)
: new ScaleOutputExtent(outputStart, outputEnd); : ScaleOutputExtent(outputStart, outputEnd);
if (_scale.range != outputRange) { if (_scale.range != outputRange) {
_scale.range = outputRange; _scale.range = outputRange;
@ -510,9 +488,9 @@ abstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {
class NumericAxis extends Axis<num> { class NumericAxis extends Axis<num> {
NumericAxis({TickProvider<num> tickProvider}) NumericAxis({TickProvider<num> tickProvider})
: super( : super(
tickProvider: tickProvider ?? new NumericTickProvider(), tickProvider: tickProvider ?? NumericTickProvider(),
tickFormatter: new NumericTickFormatter(), tickFormatter: NumericTickFormatter(),
scale: new LinearScale(), scale: LinearScale(),
); );
void setScaleViewport(NumericExtents viewport) { void setScaleViewport(NumericExtents viewport) {
@ -529,7 +507,7 @@ class OrdinalAxis extends Axis<String> {
}) : super( }) : super(
tickProvider: tickProvider ?? const OrdinalTickProvider(), tickProvider: tickProvider ?? const OrdinalTickProvider(),
tickFormatter: tickFormatter ?? const OrdinalTickFormatter(), tickFormatter: tickFormatter ?? const OrdinalTickFormatter(),
scale: new SimpleOrdinalScale(), scale: SimpleOrdinalScale(),
); );
void setScaleViewport(OrdinalViewport viewport) { void setScaleViewport(OrdinalViewport viewport) {

@ -147,7 +147,7 @@ abstract class BaseTickDrawStrategy<D> implements TickDrawStrategy<D> {
CollisionReport collides(List<Tick<D>> ticks, AxisOrientation orientation) { CollisionReport collides(List<Tick<D>> ticks, AxisOrientation orientation) {
// If there are no ticks, they do not collide. // If there are no ticks, they do not collide.
if (ticks == null) { if (ticks == null) {
return new CollisionReport( return CollisionReport(
ticksCollide: false, ticks: ticks, alternateTicksUsed: false); ticksCollide: false, ticks: ticks, alternateTicksUsed: false);
} }
@ -228,12 +228,12 @@ abstract class BaseTickDrawStrategy<D> implements TickDrawStrategy<D> {
} }
if (collides) { if (collides) {
return new CollisionReport( return CollisionReport(
ticksCollide: true, ticks: ticks, alternateTicksUsed: false); ticksCollide: true, ticks: ticks, alternateTicksUsed: false);
} }
} }
return new CollisionReport( return CollisionReport(
ticksCollide: false, ticks: ticks, alternateTicksUsed: false); ticksCollide: false, ticks: ticks, alternateTicksUsed: false);
} }
@ -245,13 +245,13 @@ abstract class BaseTickDrawStrategy<D> implements TickDrawStrategy<D> {
final maxHorizontalSliceWidth = ticks final maxHorizontalSliceWidth = ticks
.fold( .fold(
0.0, 0.0,
(double prevMax, tick) => max( (prevMax, tick) => max<double>(
prevMax, prevMax,
tick.textElement.measurement.horizontalSliceWidth + tick.textElement.measurement.horizontalSliceWidth +
labelOffsetFromAxisPx)) labelOffsetFromAxisPx))
.round(); .round();
return new ViewMeasuredSizes( return ViewMeasuredSizes(
preferredWidth: maxHorizontalSliceWidth, preferredHeight: maxHeight); preferredWidth: maxHorizontalSliceWidth, preferredHeight: maxHeight);
} }
@ -261,11 +261,11 @@ abstract class BaseTickDrawStrategy<D> implements TickDrawStrategy<D> {
final maxVerticalSliceWidth = ticks final maxVerticalSliceWidth = ticks
.fold( .fold(
0.0, 0.0,
(double prevMax, tick) => (prevMax, tick) => max<double>(
max(prevMax, tick.textElement.measurement.verticalSliceWidth)) prevMax, tick.textElement.measurement.verticalSliceWidth))
.round(); .round();
return new ViewMeasuredSizes( return ViewMeasuredSizes(
preferredWidth: maxWidth, preferredWidth: maxWidth,
preferredHeight: maxVerticalSliceWidth + labelOffsetFromAxisPx); preferredHeight: maxVerticalSliceWidth + labelOffsetFromAxisPx);
} }

@ -56,7 +56,7 @@ class GridlineRendererSpec<D> extends SmallTickRendererSpec<D> {
@override @override
TickDrawStrategy<D> createDrawStrategy( TickDrawStrategy<D> createDrawStrategy(
ChartContext context, GraphicsFactory graphicsFactory) => ChartContext context, GraphicsFactory graphicsFactory) =>
new GridlineTickDrawStrategy<D>(context, graphicsFactory, GridlineTickDrawStrategy<D>(context, graphicsFactory,
tickLengthPx: tickLengthPx, tickLengthPx: tickLengthPx,
lineStyleSpec: lineStyle, lineStyleSpec: lineStyle,
labelStyleSpec: labelStyle, labelStyleSpec: labelStyle,
@ -125,34 +125,34 @@ class GridlineTickDrawStrategy<D> extends BaseTickDrawStrategy<D> {
switch (orientation) { switch (orientation) {
case AxisOrientation.top: case AxisOrientation.top:
final x = tick.locationPx; final x = tick.locationPx;
lineStart = new Point(x, axisBounds.bottom - tickLength); lineStart = Point(x, axisBounds.bottom - tickLength);
lineEnd = new Point(x, drawAreaBounds.bottom); lineEnd = Point(x, drawAreaBounds.bottom);
break; break;
case AxisOrientation.bottom: case AxisOrientation.bottom:
final x = tick.locationPx; final x = tick.locationPx;
lineStart = new Point(x, drawAreaBounds.top + tickLength); lineStart = Point(x, drawAreaBounds.top + tickLength);
lineEnd = new Point(x, axisBounds.top); lineEnd = Point(x, axisBounds.top);
break; break;
case AxisOrientation.right: case AxisOrientation.right:
final y = tick.locationPx; final y = tick.locationPx;
if (tickLabelAnchor == TickLabelAnchor.after || if (tickLabelAnchor == TickLabelAnchor.after ||
tickLabelAnchor == TickLabelAnchor.before) { tickLabelAnchor == TickLabelAnchor.before) {
lineStart = new Point(axisBounds.right, y); lineStart = Point(axisBounds.right, y);
} else { } else {
lineStart = new Point(axisBounds.left + tickLength, y); lineStart = Point(axisBounds.left + tickLength, y);
} }
lineEnd = new Point(drawAreaBounds.left, y); lineEnd = Point(drawAreaBounds.left, y);
break; break;
case AxisOrientation.left: case AxisOrientation.left:
final y = tick.locationPx; final y = tick.locationPx;
if (tickLabelAnchor == TickLabelAnchor.after || if (tickLabelAnchor == TickLabelAnchor.after ||
tickLabelAnchor == TickLabelAnchor.before) { tickLabelAnchor == TickLabelAnchor.before) {
lineStart = new Point(axisBounds.left, y); lineStart = Point(axisBounds.left, y);
} else { } else {
lineStart = new Point(axisBounds.right - tickLength, y); lineStart = Point(axisBounds.right - tickLength, y);
} }
lineEnd = new Point(drawAreaBounds.right, y); lineEnd = Point(drawAreaBounds.right, y);
break; break;
} }

@ -42,7 +42,7 @@ class NoneRenderSpec<D> extends RenderSpec<D> {
@override @override
TickDrawStrategy<D> createDrawStrategy( TickDrawStrategy<D> createDrawStrategy(
ChartContext context, GraphicsFactory graphicFactory) => ChartContext context, GraphicsFactory graphicFactory) =>
new NoneDrawStrategy<D>(context, graphicFactory, NoneDrawStrategy<D>(context, graphicFactory,
axisLineStyleSpec: axisLineStyle); axisLineStyleSpec: axisLineStyle);
@override @override
@ -68,7 +68,7 @@ class NoneDrawStrategy<D> implements TickDrawStrategy<D> {
@override @override
CollisionReport collides(List<Tick> ticks, AxisOrientation orientation) => CollisionReport collides(List<Tick> ticks, AxisOrientation orientation) =>
new CollisionReport(ticksCollide: false, ticks: ticks); CollisionReport(ticksCollide: false, ticks: ticks);
@override @override
void decorateTicks(List<Tick> ticks) { void decorateTicks(List<Tick> ticks) {
@ -125,12 +125,12 @@ class NoneDrawStrategy<D> implements TickDrawStrategy<D> {
@override @override
ViewMeasuredSizes measureHorizontallyDrawnTicks( ViewMeasuredSizes measureHorizontallyDrawnTicks(
List<Tick> ticks, int maxWidth, int maxHeight) { List<Tick> ticks, int maxWidth, int maxHeight) {
return new ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0); return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);
} }
@override @override
ViewMeasuredSizes measureVerticallyDrawnTicks( ViewMeasuredSizes measureVerticallyDrawnTicks(
List<Tick> ticks, int maxWidth, int maxHeight) { List<Tick> ticks, int maxWidth, int maxHeight) {
return new ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0); return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);
} }
} }

@ -57,7 +57,7 @@ class SmallTickRendererSpec<D> extends BaseRenderSpec<D> {
@override @override
TickDrawStrategy<D> createDrawStrategy( TickDrawStrategy<D> createDrawStrategy(
ChartContext context, GraphicsFactory graphicsFactory) => ChartContext context, GraphicsFactory graphicsFactory) =>
new SmallTickDrawStrategy<D>(context, graphicsFactory, SmallTickDrawStrategy<D>(context, graphicsFactory,
tickLengthPx: tickLengthPx, tickLengthPx: tickLengthPx,
lineStyleSpec: lineStyle, lineStyleSpec: lineStyle,
labelStyleSpec: labelStyle, labelStyleSpec: labelStyle,
@ -128,25 +128,25 @@ class SmallTickDrawStrategy<D> extends BaseTickDrawStrategy<D> {
switch (orientation) { switch (orientation) {
case AxisOrientation.top: case AxisOrientation.top:
double x = tick.locationPx; double x = tick.locationPx;
tickStart = new Point(x, axisBounds.bottom - tickLength); tickStart = Point(x, axisBounds.bottom - tickLength);
tickEnd = new Point(x, axisBounds.bottom); tickEnd = Point(x, axisBounds.bottom);
break; break;
case AxisOrientation.bottom: case AxisOrientation.bottom:
double x = tick.locationPx; double x = tick.locationPx;
tickStart = new Point(x, axisBounds.top); tickStart = Point(x, axisBounds.top);
tickEnd = new Point(x, axisBounds.top + tickLength); tickEnd = Point(x, axisBounds.top + tickLength);
break; break;
case AxisOrientation.right: case AxisOrientation.right:
double y = tick.locationPx; double y = tick.locationPx;
tickStart = new Point(axisBounds.left, y); tickStart = Point(axisBounds.left, y);
tickEnd = new Point(axisBounds.left + tickLength, y); tickEnd = Point(axisBounds.left + tickLength, y);
break; break;
case AxisOrientation.left: case AxisOrientation.left:
double y = tick.locationPx; double y = tick.locationPx;
tickStart = new Point(axisBounds.right - tickLength, y); tickStart = Point(axisBounds.right - tickLength, y);
tickEnd = new Point(axisBounds.right, y); tickEnd = Point(axisBounds.right, y);
break; break;
} }

@ -54,12 +54,12 @@ class EndPointsTickProvider<D> extends BaseTickProvider<D> {
final labels = formatter.format([start, end], formatterValueCache, final labels = formatter.format([start, end], formatterValueCache,
stepSize: scale.domainStepSize); stepSize: scale.domainStepSize);
ticks.add(new Tick( ticks.add(Tick(
value: start, value: start,
textElement: graphicsFactory.createTextElement(labels[0]), textElement: graphicsFactory.createTextElement(labels[0]),
locationPx: scale[start])); locationPx: scale[start]));
ticks.add(new Tick( ticks.add(Tick(
value: end, value: end,
textElement: graphicsFactory.createTextElement(labels[1]), textElement: graphicsFactory.createTextElement(labels[1]),
locationPx: scale[end])); locationPx: scale[end]));

@ -48,8 +48,7 @@ class BucketingNumericAxis extends NumericAxis {
/// [threshold] will be rendered at the baseline of the chart. The /// [threshold] will be rendered at the baseline of the chart. The
bool _showBucket; bool _showBucket;
BucketingNumericAxis() BucketingNumericAxis() : super(tickProvider: BucketingNumericTickProvider());
: super(tickProvider: new BucketingNumericTickProvider());
set threshold(num threshold) { set threshold(num threshold) {
_threshold = threshold; _threshold = threshold;

@ -83,7 +83,7 @@ class BucketingNumericTickProvider extends NumericTickProvider {
throw ('The showBucket flag must be set before getting ticks.'); throw ('The showBucket flag must be set before getting ticks.');
} }
final localFormatter = new _BucketingFormatter() final localFormatter = _BucketingFormatter()
..threshold = _threshold ..threshold = _threshold
..originalFormatter = formatter; ..originalFormatter = formatter;
@ -100,7 +100,7 @@ class BucketingNumericTickProvider extends NumericTickProvider {
assert(scale != null); assert(scale != null);
// Create a tick for the threshold. // Create a tick for the threshold.
final thresholdTick = new Tick<num>( final thresholdTick = Tick<num>(
value: _threshold, value: _threshold,
textElement: graphicsFactory textElement: graphicsFactory
.createTextElement(localFormatter.formatValue(_threshold)), .createTextElement(localFormatter.formatValue(_threshold)),
@ -110,8 +110,8 @@ class BucketingNumericTickProvider extends NumericTickProvider {
tickDrawStrategy.decorateTicks(<Tick<num>>[thresholdTick]); tickDrawStrategy.decorateTicks(<Tick<num>>[thresholdTick]);
// Filter out ticks that sit below the threshold. // Filter out ticks that sit below the threshold.
ticks.removeWhere((Tick<num> tick) => ticks.removeWhere(
tick.value <= thresholdTick.value && tick.value != 0.0); (tick) => tick.value <= thresholdTick.value && tick.value != 0.0);
// Finally, add our threshold tick to the list. // Finally, add our threshold tick to the list.
ticks.add(thresholdTick); ticks.add(thresholdTick);

@ -49,7 +49,7 @@ import 'linear_scale_viewport.dart' show LinearScaleViewportSettings;
class LinearScale implements NumericScale { class LinearScale implements NumericScale {
final LinearScaleDomainInfo _domainInfo; final LinearScaleDomainInfo _domainInfo;
final LinearScaleViewportSettings _viewportSettings; final LinearScaleViewportSettings _viewportSettings;
final LinearScaleFunction _scaleFunction = new LinearScaleFunction(); final LinearScaleFunction _scaleFunction = LinearScaleFunction();
RangeBandConfig rangeBandConfig = const RangeBandConfig.none(); RangeBandConfig rangeBandConfig = const RangeBandConfig.none();
StepSizeConfig stepSizeConfig = const StepSizeConfig.auto(); StepSizeConfig stepSizeConfig = const StepSizeConfig.auto();
@ -57,18 +57,18 @@ class LinearScale implements NumericScale {
bool _scaleReady = false; bool _scaleReady = false;
LinearScale() LinearScale()
: _domainInfo = new LinearScaleDomainInfo(), : _domainInfo = LinearScaleDomainInfo(),
_viewportSettings = new LinearScaleViewportSettings(); _viewportSettings = LinearScaleViewportSettings();
LinearScale._copy(LinearScale other) LinearScale._copy(LinearScale other)
: _domainInfo = new LinearScaleDomainInfo.copy(other._domainInfo), : _domainInfo = LinearScaleDomainInfo.copy(other._domainInfo),
_viewportSettings = _viewportSettings =
new LinearScaleViewportSettings.copy(other._viewportSettings), LinearScaleViewportSettings.copy(other._viewportSettings),
rangeBandConfig = other.rangeBandConfig, rangeBandConfig = other.rangeBandConfig,
stepSizeConfig = other.stepSizeConfig; stepSizeConfig = other.stepSizeConfig;
@override @override
LinearScale copy() => new LinearScale._copy(this); LinearScale copy() => LinearScale._copy(this);
// //
// Domain methods // Domain methods
@ -91,8 +91,8 @@ class LinearScale implements NumericScale {
} }
@override @override
NumericExtents get dataExtent => new NumericExtents( NumericExtents get dataExtent =>
_domainInfo.dataDomainStart, _domainInfo.dataDomainEnd); NumericExtents(_domainInfo.dataDomainStart, _domainInfo.dataDomainEnd);
@override @override
num get minimumDomainStep => _domainInfo.minimumDetectedDomainStep; num get minimumDomainStep => _domainInfo.minimumDetectedDomainStep;

@ -113,6 +113,6 @@ class LinearScaleDomainInfo {
tmpDomainEnd = _dataDomainEnd.isFinite ? _dataDomainEnd : 1.0; tmpDomainEnd = _dataDomainEnd.isFinite ? _dataDomainEnd : 1.0;
} }
return new NumericExtents(tmpDomainStart, tmpDomainEnd); return NumericExtents(tmpDomainStart, tmpDomainEnd);
} }
} }

@ -135,7 +135,7 @@ class LinearScaleViewportSettings {
double viewportStart = double viewportStart =
(-1.0 * translatePx / scaleScalingFactor) + domainInfo.extent.min; (-1.0 * translatePx / scaleScalingFactor) + domainInfo.extent.min;
_domainExtent = _domainExtent =
new NumericExtents(viewportStart, viewportStart + viewportDomainDiff); NumericExtents(viewportStart, viewportStart + viewportDomainDiff);
} }
} }
} }

@ -41,7 +41,7 @@ class NumericExtents implements Extents<num> {
max = value; max = value;
} }
} }
return new NumericExtents(min, max); return NumericExtents(min, max);
} }
/// Returns the union of this and other. /// Returns the union of this and other.
@ -50,13 +50,13 @@ class NumericExtents implements Extents<num> {
if (max >= other.max) { if (max >= other.max) {
return this; return this;
} else { } else {
return new NumericExtents(min, other.max); return NumericExtents(min, other.max);
} }
} else { } else {
if (other.max >= max) { if (other.max >= max) {
return other; return other;
} else { } else {
return new NumericExtents(other.min, max); return NumericExtents(other.min, max);
} }
} }
} }
@ -100,6 +100,6 @@ class NumericExtents implements Extents<num> {
String toString() => 'Extent($min, $max)'; String toString() => 'Extent($min, $max)';
static const NumericExtents unbounded = static const NumericExtents unbounded =
const NumericExtents(double.negativeInfinity, double.infinity); NumericExtents(double.negativeInfinity, double.infinity);
static const NumericExtents empty = const NumericExtents(0.0, 0.0); static const NumericExtents empty = NumericExtents(0.0, 0.0);
} }

@ -49,7 +49,7 @@ class NumericTickProvider extends BaseTickProvider<num> {
static const MIN_DIPS_BETWEEN_TICKS = 25; static const MIN_DIPS_BETWEEN_TICKS = 25;
/// Potential steps available to the baseTen value of the data. /// Potential steps available to the baseTen value of the data.
static const DEFAULT_STEPS = const [ static const DEFAULT_STEPS = [
0.01, 0.01,
0.02, 0.02,
0.025, 0.025,
@ -187,8 +187,8 @@ class NumericTickProvider extends BaseTickProvider<num> {
assert(steps != null && steps.isNotEmpty); assert(steps != null && steps.isNotEmpty);
steps.sort(); steps.sort();
final stepSet = new Set.from(steps); final stepSet = Set.from(steps);
_allowedSteps = new List<double>(stepSet.length * 3); _allowedSteps = List<double>(stepSet.length * 3);
int stepIndex = 0; int stepIndex = 0;
for (double step in stepSet) { for (double step in stepSet) {
assert(1.0 <= step && step < 10.0); assert(1.0 <= step && step < 10.0);
@ -220,7 +220,7 @@ class NumericTickProvider extends BaseTickProvider<num> {
: (tickHint.start / stepSize).ceil())); : (tickHint.start / stepSize).ceil()));
final tickStart = final tickStart =
(scale.viewportDomain.min / stepSize).ceil() * stepSize + tickZeroShift; (scale.viewportDomain.min / stepSize).ceil() * stepSize + tickZeroShift;
final stepInfo = new _TickStepInfo(stepSize.abs(), tickStart); final stepInfo = _TickStepInfo(stepSize.abs(), tickStart);
final tickValues = _getTickValues(stepInfo, tickHint.tickCount); final tickValues = _getTickValues(stepInfo, tickHint.tickCount);
// Create ticks from domain values. // Create ticks from domain values.
@ -299,8 +299,7 @@ class NumericTickProvider extends BaseTickProvider<num> {
final tickValues = _getTickValues(stepInfo, tickCount); final tickValues = _getTickValues(stepInfo, tickCount);
if (viewportExtensionEnabled) { if (viewportExtensionEnabled) {
mutableScale.viewportDomain = mutableScale.viewportDomain = NumericExtents(firstTick, lastTick);
new NumericExtents(firstTick, lastTick);
} }
// Create ticks from domain values. // Create ticks from domain values.
@ -434,7 +433,7 @@ class NumericTickProvider extends BaseTickProvider<num> {
!(low < 0 && !(low < 0 &&
high > 0 && high > 0 &&
(negativeRegionCount == 0 || positiveRegionCount == 0)), (negativeRegionCount == 0 || positiveRegionCount == 0)),
'Numeric tick provider cannot generate ${tickCount} ' 'Numeric tick provider cannot generate $tickCount '
'ticks when the axis range contains both positive and negative ' 'ticks when the axis range contains both positive and negative '
'values. A minimum of three ticks are required to include zero.'); 'values. A minimum of three ticks are required to include zero.');
@ -467,7 +466,7 @@ class NumericTickProvider extends BaseTickProvider<num> {
double stepStart = negativeRegionCount > 0 double stepStart = negativeRegionCount > 0
? (-1 * tmpStepSize * negativeRegionCount) ? (-1 * tmpStepSize * negativeRegionCount)
: 0.0; : 0.0;
return new _TickStepInfo(tmpStepSize, stepStart); return _TickStepInfo(tmpStepSize, stepStart);
} }
} }
} else { } else {
@ -487,16 +486,16 @@ class NumericTickProvider extends BaseTickProvider<num> {
// But wait until the last step to prevent the cost of the formatter. // But wait until the last step to prevent the cost of the formatter.
double tmpStepStart = _getStepLessThan(low, tmpStepSize); double tmpStepStart = _getStepLessThan(low, tmpStepSize);
if (tmpStepStart + (tmpStepSize * regionCount) >= high) { if (tmpStepStart + (tmpStepSize * regionCount) >= high) {
return new _TickStepInfo(tmpStepSize, tmpStepStart); return _TickStepInfo(tmpStepSize, tmpStepStart);
} }
} }
} }
return new _TickStepInfo(1.0, low.floorToDouble()); return _TickStepInfo(1.0, low.floorToDouble());
} }
List<double> _getTickValues(_TickStepInfo steps, int tickCount) { List<double> _getTickValues(_TickStepInfo steps, int tickCount) {
final tickValues = new List<double>(tickCount); final tickValues = List<double>(tickCount);
// We have our size and start, assign all the tick values to the given array. // We have our size and start, assign all the tick values to the given array.
for (int i = 0; i < tickCount; i++) { for (int i = 0; i < tickCount; i++) {
tickValues[i] = dataToAxisUnitConverter.invert( tickValues[i] = dataToAxisUnitConverter.invert(

@ -27,11 +27,11 @@ class OrdinalExtents extends Extents<String> {
/// [D] is the domain class type for the elements in the extents. /// [D] is the domain class type for the elements in the extents.
OrdinalExtents(List<String> range) : _range = range { OrdinalExtents(List<String> range) : _range = range {
// This asserts that all elements in [range] are unique. // This asserts that all elements in [range] are unique.
final uniqueValueCount = new HashSet.from(_range).length; final uniqueValueCount = HashSet.from(_range).length;
assert(uniqueValueCount == range.length); assert(uniqueValueCount == range.length);
} }
factory OrdinalExtents.all(List<String> range) => new OrdinalExtents(range); factory OrdinalExtents.all(List<String> range) => OrdinalExtents(range);
bool get isEmpty => _range.isEmpty; bool get isEmpty => _range.isEmpty;

@ -25,7 +25,7 @@ class OrdinalScaleDomainInfo {
int _index = 0; int _index = 0;
/// A map of domain value and the order it was added. /// A map of domain value and the order it was added.
final _domainsToOrder = new HashMap<String, int>(); final _domainsToOrder = HashMap<String, int>();
/// A list of domain values kept to support [getDomainAtIndex]. /// A list of domain values kept to support [getDomainAtIndex].
final _domainList = <String>[]; final _domainList = <String>[];
@ -33,7 +33,7 @@ class OrdinalScaleDomainInfo {
OrdinalScaleDomainInfo(); OrdinalScaleDomainInfo();
OrdinalScaleDomainInfo copy() { OrdinalScaleDomainInfo copy() {
return new OrdinalScaleDomainInfo() return OrdinalScaleDomainInfo()
.._domainsToOrder.addAll(_domainsToOrder) .._domainsToOrder.addAll(_domainsToOrder)
.._index = _index .._index = _index
.._domainList.addAll(_domainList); .._domainList.addAll(_domainList);
@ -64,7 +64,7 @@ class OrdinalScaleDomainInfo {
bool get isEmpty => (_index == 0); bool get isEmpty => (_index == 0);
bool get isNotEmpty => !isEmpty; bool get isNotEmpty => !isEmpty;
OrdinalExtents get extent => new OrdinalExtents.all(_domainList); OrdinalExtents get extent => OrdinalExtents.all(_domainList);
int get size => _index; int get size => _index;

@ -32,12 +32,12 @@ import 'scale.dart'
/// width of the bar is [rangeBand] and the position of the bar is retrieved /// width of the bar is [rangeBand] and the position of the bar is retrieved
/// by [[]]. /// by [[]].
class SimpleOrdinalScale implements OrdinalScale { class SimpleOrdinalScale implements OrdinalScale {
final _stepSizeConfig = new StepSizeConfig.auto(); final _stepSizeConfig = StepSizeConfig.auto();
OrdinalScaleDomainInfo _domain; OrdinalScaleDomainInfo _domain;
ScaleOutputExtent _range = new ScaleOutputExtent(0, 1); ScaleOutputExtent _range = ScaleOutputExtent(0, 1);
double _viewportScale = 1.0; double _viewportScale = 1.0;
double _viewportTranslatePx = 0.0; double _viewportTranslatePx = 0.0;
RangeBandConfig _rangeBandConfig = new RangeBandConfig.styleAssignedPercent(); RangeBandConfig _rangeBandConfig = RangeBandConfig.styleAssignedPercent();
bool _scaleChanged = true; bool _scaleChanged = true;
double _cachedStepSizePixels; double _cachedStepSizePixels;
@ -47,11 +47,11 @@ class SimpleOrdinalScale implements OrdinalScale {
int _viewportDataSize; int _viewportDataSize;
String _viewportStartingDomain; String _viewportStartingDomain;
SimpleOrdinalScale() : _domain = new OrdinalScaleDomainInfo(); SimpleOrdinalScale() : _domain = OrdinalScaleDomainInfo();
SimpleOrdinalScale._copy(SimpleOrdinalScale other) SimpleOrdinalScale._copy(SimpleOrdinalScale other)
: _domain = other._domain.copy(), : _domain = other._domain.copy(),
_range = new ScaleOutputExtent(other._range.start, other._range.end), _range = ScaleOutputExtent(other._range.start, other._range.end),
_viewportScale = other._viewportScale, _viewportScale = other._viewportScale,
_viewportTranslatePx = other._viewportTranslatePx, _viewportTranslatePx = other._viewportTranslatePx,
_rangeBandConfig = other._rangeBandConfig; _rangeBandConfig = other._rangeBandConfig;
@ -80,12 +80,12 @@ class SimpleOrdinalScale implements OrdinalScale {
@override @override
set rangeBandConfig(RangeBandConfig barGroupWidthConfig) { set rangeBandConfig(RangeBandConfig barGroupWidthConfig) {
if (barGroupWidthConfig == null) { if (barGroupWidthConfig == null) {
throw new ArgumentError.notNull('RangeBandConfig must not be null.'); throw ArgumentError.notNull('RangeBandConfig must not be null.');
} }
if (barGroupWidthConfig.type == RangeBandType.fixedDomain || if (barGroupWidthConfig.type == RangeBandType.fixedDomain ||
barGroupWidthConfig.type == RangeBandType.none) { barGroupWidthConfig.type == RangeBandType.none) {
throw new ArgumentError( throw ArgumentError(
'barGroupWidthConfig must not be NONE or FIXED_DOMAIN'); 'barGroupWidthConfig must not be NONE or FIXED_DOMAIN');
} }
@ -99,7 +99,7 @@ class SimpleOrdinalScale implements OrdinalScale {
@override @override
set stepSizeConfig(StepSizeConfig config) { set stepSizeConfig(StepSizeConfig config) {
if (config != null && config.type != StepSizeType.autoDetect) { if (config != null && config.type != StepSizeType.autoDetect) {
throw new ArgumentError( throw ArgumentError(
'Ordinal scales only support StepSizeConfig of type Auto'); 'Ordinal scales only support StepSizeConfig of type Auto');
} }
// Nothing is set because only auto is supported. // Nothing is set because only auto is supported.
@ -205,7 +205,7 @@ class SimpleOrdinalScale implements OrdinalScale {
if (startingDomain != null && if (startingDomain != null &&
viewportDataSize != null && viewportDataSize != null &&
viewportDataSize <= 0) { viewportDataSize <= 0) {
throw new ArgumentError('viewportDataSize can' 't be less than 1.'); throw ArgumentError('viewportDataSize can' 't be less than 1.');
} }
_scaleChanged = true; _scaleChanged = true;
@ -280,7 +280,7 @@ class SimpleOrdinalScale implements OrdinalScale {
} }
@override @override
SimpleOrdinalScale copy() => new SimpleOrdinalScale._copy(this); SimpleOrdinalScale copy() => SimpleOrdinalScale._copy(this);
void _updateCachedFields( void _updateCachedFields(
double stepSizePixels, double rangeBandPixels, double rangeBandShift) { double stepSizePixels, double rangeBandPixels, double rangeBandShift) {
@ -335,7 +335,7 @@ class SimpleOrdinalScale implements OrdinalScale {
case RangeBandType.fixedDomain: case RangeBandType.fixedDomain:
case RangeBandType.none: case RangeBandType.none:
default: default:
throw new StateError('RangeBandType must not be NONE or FIXED_DOMAIN'); throw StateError('RangeBandType must not be NONE or FIXED_DOMAIN');
break; break;
} }

@ -44,7 +44,7 @@ class AxisSpec<D> {
TickFormatterSpec<D> tickFormatterSpec, TickFormatterSpec<D> tickFormatterSpec,
bool showAxisLine, bool showAxisLine,
}) { }) {
return new AxisSpec( return AxisSpec(
renderSpec: renderSpec ?? other.renderSpec, renderSpec: renderSpec ?? other.renderSpec,
tickProviderSpec: tickProviderSpec ?? other.tickProviderSpec, tickProviderSpec: tickProviderSpec ?? other.tickProviderSpec,
tickFormatterSpec: tickFormatterSpec ?? other.tickFormatterSpec, tickFormatterSpec: tickFormatterSpec ?? other.tickFormatterSpec,

@ -80,8 +80,8 @@ class BucketingAxisSpec extends NumericAxisSpec {
tickProviderSpec: tickProviderSpec:
tickProviderSpec ?? const BucketingNumericTickProviderSpec(), tickProviderSpec ?? const BucketingNumericTickProviderSpec(),
tickFormatterSpec: tickFormatterSpec ?? tickFormatterSpec: tickFormatterSpec ??
new BasicNumericTickFormatterSpec.fromNumberFormat( BasicNumericTickFormatterSpec.fromNumberFormat(
new NumberFormat.percentPattern()), NumberFormat.percentPattern()),
showAxisLine: showAxisLine, showAxisLine: showAxisLine,
viewport: viewport ?? const NumericExtents(0.0, 1.0)); viewport: viewport ?? const NumericExtents(0.0, 1.0));
@ -104,7 +104,7 @@ class BucketingAxisSpec extends NumericAxisSpec {
} }
@override @override
BucketingNumericAxis createAxis() => new BucketingNumericAxis(); BucketingNumericAxis createAxis() => BucketingNumericAxis();
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -155,7 +155,7 @@ class BucketingNumericTickProviderSpec extends BasicNumericTickProviderSpec {
@override @override
BucketingNumericTickProvider createTickProvider(ChartContext context) { BucketingNumericTickProvider createTickProvider(ChartContext context) {
final provider = new BucketingNumericTickProvider() final provider = BucketingNumericTickProvider()
..zeroBound = zeroBound ..zeroBound = zeroBound
..dataIsInWholeNumbers = dataIsInWholeNumbers; ..dataIsInWholeNumbers = dataIsInWholeNumbers;

@ -85,7 +85,7 @@ class DateTimeAxisSpec extends AxisSpec<DateTime> {
/// Creates a [DateTimeAxis]. This should be called in place of createAxis. /// Creates a [DateTimeAxis]. This should be called in place of createAxis.
DateTimeAxis createDateTimeAxis(DateTimeFactory dateTimeFactory) => DateTimeAxis createDateTimeAxis(DateTimeFactory dateTimeFactory) =>
new DateTimeAxis(dateTimeFactory); DateTimeAxis(dateTimeFactory);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -121,10 +121,10 @@ class AutoDateTimeTickProviderSpec implements DateTimeTickProviderSpec {
@override @override
AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) { AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) {
if (includeTime) { if (includeTime) {
return new AutoAdjustingDateTimeTickProvider.createDefault( return AutoAdjustingDateTimeTickProvider.createDefault(
context.dateTimeFactory); context.dateTimeFactory);
} else { } else {
return new AutoAdjustingDateTimeTickProvider.createWithoutTime( return AutoAdjustingDateTimeTickProvider.createWithoutTime(
context.dateTimeFactory); context.dateTimeFactory);
} }
} }
@ -151,8 +151,8 @@ class DayTickProviderSpec implements DateTimeTickProviderSpec {
/// when searching for the appropriate tick intervals. /// when searching for the appropriate tick intervals.
@override @override
AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) { AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) {
return new AutoAdjustingDateTimeTickProvider.createWith([ return AutoAdjustingDateTimeTickProvider.createWith([
new TimeRangeTickProviderImpl(new DayTimeStepper(context.dateTimeFactory, TimeRangeTickProviderImpl(DayTimeStepper(context.dateTimeFactory,
allowedTickIncrements: increments)) allowedTickIncrements: increments))
]); ]);
} }
@ -175,7 +175,7 @@ class DateTimeEndPointsTickProviderSpec implements DateTimeTickProviderSpec {
/// two end points of the axis range /// two end points of the axis range
@override @override
EndPointsTickProvider<DateTime> createTickProvider(ChartContext context) { EndPointsTickProvider<DateTime> createTickProvider(ChartContext context) {
return new EndPointsTickProvider<DateTime>(); return EndPointsTickProvider<DateTime>();
} }
@override @override
@ -191,7 +191,7 @@ class StaticDateTimeTickProviderSpec implements DateTimeTickProviderSpec {
@override @override
StaticTickProvider<DateTime> createTickProvider(ChartContext context) => StaticTickProvider<DateTime> createTickProvider(ChartContext context) =>
new StaticTickProvider<DateTime>(tickSpecs); StaticTickProvider<DateTime>(tickSpecs);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -285,19 +285,19 @@ class AutoDateTimeTickFormatterSpec implements DateTimeTickFormatterSpec {
_makeFormatter(year, CalendarField.year, context); _makeFormatter(year, CalendarField.year, context);
} }
return new DateTimeTickFormatter(context.dateTimeFactory, overrides: map); return DateTimeTickFormatter(context.dateTimeFactory, overrides: map);
} }
TimeTickFormatterImpl _makeFormatter(TimeFormatterSpec spec, TimeTickFormatterImpl _makeFormatter(TimeFormatterSpec spec,
CalendarField transitionField, ChartContext context) { CalendarField transitionField, ChartContext context) {
if (spec.noonFormat != null) { if (spec.noonFormat != null) {
return new HourTickFormatter( return HourTickFormatter(
dateTimeFactory: context.dateTimeFactory, dateTimeFactory: context.dateTimeFactory,
simpleFormat: spec.format, simpleFormat: spec.format,
transitionFormat: spec.transitionFormat, transitionFormat: spec.transitionFormat,
noonFormat: spec.noonFormat); noonFormat: spec.noonFormat);
} else { } else {
return new TimeTickFormatterImpl( return TimeTickFormatterImpl(
dateTimeFactory: context.dateTimeFactory, dateTimeFactory: context.dateTimeFactory,
simpleFormat: spec.format, simpleFormat: spec.format,
transitionFormat: spec.transitionFormat, transitionFormat: spec.transitionFormat,

@ -68,7 +68,7 @@ class NumericAxisSpec extends AxisSpec<num> {
bool showAxisLine, bool showAxisLine,
NumericExtents viewport, NumericExtents viewport,
}) { }) {
return new NumericAxisSpec( return NumericAxisSpec(
renderSpec: renderSpec ?? other.renderSpec, renderSpec: renderSpec ?? other.renderSpec,
tickProviderSpec: tickProviderSpec ?? other.tickProviderSpec, tickProviderSpec: tickProviderSpec ?? other.tickProviderSpec,
tickFormatterSpec: tickFormatterSpec ?? other.tickFormatterSpec, tickFormatterSpec: tickFormatterSpec ?? other.tickFormatterSpec,
@ -88,7 +88,7 @@ class NumericAxisSpec extends AxisSpec<num> {
} }
@override @override
NumericAxis createAxis() => new NumericAxis(); NumericAxis createAxis() => NumericAxis();
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -141,7 +141,7 @@ class BasicNumericTickProviderSpec implements NumericTickProviderSpec {
@override @override
NumericTickProvider createTickProvider(ChartContext context) { NumericTickProvider createTickProvider(ChartContext context) {
final provider = new NumericTickProvider(); final provider = NumericTickProvider();
if (zeroBound != null) { if (zeroBound != null) {
provider.zeroBound = zeroBound; provider.zeroBound = zeroBound;
} }
@ -188,7 +188,7 @@ class NumericEndPointsTickProviderSpec implements NumericTickProviderSpec {
@override @override
EndPointsTickProvider<num> createTickProvider(ChartContext context) { EndPointsTickProvider<num> createTickProvider(ChartContext context) {
return new EndPointsTickProvider<num>(); return EndPointsTickProvider<num>();
} }
@override @override
@ -204,7 +204,7 @@ class StaticNumericTickProviderSpec implements NumericTickProviderSpec {
@override @override
StaticTickProvider<num> createTickProvider(ChartContext context) => StaticTickProvider<num> createTickProvider(ChartContext context) =>
new StaticTickProvider<num>(tickSpecs); StaticTickProvider<num>(tickSpecs);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -232,8 +232,8 @@ class BasicNumericTickFormatterSpec implements NumericTickFormatterSpec {
@override @override
NumericTickFormatter createTickFormatter(ChartContext context) { NumericTickFormatter createTickFormatter(ChartContext context) {
return numberFormat != null return numberFormat != null
? new NumericTickFormatter.fromNumberFormat(numberFormat) ? NumericTickFormatter.fromNumberFormat(numberFormat)
: new NumericTickFormatter(formatter: formatter); : NumericTickFormatter(formatter: formatter);
} }
@override @override

@ -66,7 +66,7 @@ class OrdinalAxisSpec extends AxisSpec<String> {
} }
@override @override
OrdinalAxis createAxis() => new OrdinalAxis(); OrdinalAxis createAxis() => OrdinalAxis();
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
@ -94,7 +94,7 @@ class BasicOrdinalTickProviderSpec implements OrdinalTickProviderSpec {
@override @override
OrdinalTickProvider createTickProvider(ChartContext context) => OrdinalTickProvider createTickProvider(ChartContext context) =>
new OrdinalTickProvider(); OrdinalTickProvider();
@override @override
bool operator ==(Object other) => other is BasicOrdinalTickProviderSpec; bool operator ==(Object other) => other is BasicOrdinalTickProviderSpec;
@ -112,7 +112,7 @@ class StaticOrdinalTickProviderSpec implements OrdinalTickProviderSpec {
@override @override
StaticTickProvider<String> createTickProvider(ChartContext context) => StaticTickProvider<String> createTickProvider(ChartContext context) =>
new StaticTickProvider<String>(tickSpecs); StaticTickProvider<String>(tickSpecs);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -129,7 +129,7 @@ class BasicOrdinalTickFormatterSpec implements OrdinalTickFormatterSpec {
@override @override
OrdinalTickFormatter createTickFormatter(ChartContext context) => OrdinalTickFormatter createTickFormatter(ChartContext context) =>
new OrdinalTickFormatter(); OrdinalTickFormatter();
@override @override
bool operator ==(Object other) => other is BasicOrdinalTickFormatterSpec; bool operator ==(Object other) => other is BasicOrdinalTickFormatterSpec;

@ -41,8 +41,8 @@ class PercentAxisSpec extends NumericAxisSpec {
tickProviderSpec: tickProviderSpec ?? tickProviderSpec: tickProviderSpec ??
const BasicNumericTickProviderSpec(dataIsInWholeNumbers: false), const BasicNumericTickProviderSpec(dataIsInWholeNumbers: false),
tickFormatterSpec: tickFormatterSpec ?? tickFormatterSpec: tickFormatterSpec ??
new BasicNumericTickFormatterSpec.fromNumberFormat( BasicNumericTickFormatterSpec.fromNumberFormat(
new NumberFormat.percentPattern()), NumberFormat.percentPattern()),
showAxisLine: showAxisLine, showAxisLine: showAxisLine,
viewport: viewport ?? const NumericExtents(0.0, 1.0)); viewport: viewport ?? const NumericExtents(0.0, 1.0));

@ -76,7 +76,7 @@ class StaticTickProvider<D> extends TickProvider<D> {
// We still check if the spec is within the viewport because we do not // We still check if the spec is within the viewport because we do not
// extend the axis for OrdinalScale. // extend the axis for OrdinalScale.
if (scale.compareDomainValueToViewport(spec.value) == 0) { if (scale.compareDomainValueToViewport(spec.value) == 0) {
final tick = new Tick<D>( final tick = Tick<D>(
value: spec.value, value: spec.value,
textElement: graphicsFactory textElement: graphicsFactory
.createTextElement(spec.label ?? formattedValues[i]), .createTextElement(spec.label ?? formattedValues[i]),

@ -34,7 +34,7 @@ abstract class SimpleTickFormatterBase<D> implements TickFormatter<D> {
@override @override
List<String> format(List<D> tickValues, Map<D, String> cache, List<String> format(List<D> tickValues, Map<D, String> cache,
{num stepSize}) => {num stepSize}) =>
tickValues.map((D value) { tickValues.map((value) {
// Try to use the cached formats first. // Try to use the cached formats first.
String formattedString = cache[value]; String formattedString = cache[value];
if (formattedString == null) { if (formattedString == null) {
@ -75,24 +75,24 @@ class NumericTickFormatter extends SimpleTickFormatterBase<num> {
/// [formatter] optionally specify a formatter to be used. Defaults to using /// [formatter] optionally specify a formatter to be used. Defaults to using
/// [NumberFormat.decimalPattern] if none is specified. /// [NumberFormat.decimalPattern] if none is specified.
factory NumericTickFormatter({MeasureFormatter formatter}) { factory NumericTickFormatter({MeasureFormatter formatter}) {
formatter ??= _getFormatter(new NumberFormat.decimalPattern()); formatter ??= _getFormatter(NumberFormat.decimalPattern());
return new NumericTickFormatter._internal(formatter); return NumericTickFormatter._internal(formatter);
} }
/// Constructs a new [NumericTickFormatter] that formats using [numberFormat]. /// Constructs a new [NumericTickFormatter] that formats using [numberFormat].
factory NumericTickFormatter.fromNumberFormat(NumberFormat numberFormat) { factory NumericTickFormatter.fromNumberFormat(NumberFormat numberFormat) {
return new NumericTickFormatter._internal(_getFormatter(numberFormat)); return NumericTickFormatter._internal(_getFormatter(numberFormat));
} }
/// Constructs a new formatter that uses [NumberFormat.compactCurrency]. /// Constructs a new formatter that uses [NumberFormat.compactCurrency].
factory NumericTickFormatter.compactSimpleCurrency() { factory NumericTickFormatter.compactSimpleCurrency() {
return new NumericTickFormatter._internal( return NumericTickFormatter._internal(
_getFormatter(new NumberFormat.compactCurrency())); _getFormatter(NumberFormat.compactCurrency()));
} }
/// Returns a [MeasureFormatter] that calls format on [numberFormat]. /// Returns a [MeasureFormatter] that calls format on [numberFormat].
static MeasureFormatter _getFormatter(NumberFormat numberFormat) { static MeasureFormatter _getFormatter(NumberFormat numberFormat) {
return (num value) => numberFormat.format(value); return (value) => numberFormat.format(value);
} }
@override @override

@ -73,7 +73,7 @@ abstract class BaseTickProvider<D> implements TickProvider<D> {
for (var i = 0; i < domainValues.length; i++) { for (var i = 0; i < domainValues.length; i++) {
final value = domainValues[i]; final value = domainValues[i];
final tick = new Tick( final tick = Tick(
value: value, value: value,
textElement: graphicsFactory.createTextElement(labels[i]), textElement: graphicsFactory.createTextElement(labels[i]),
locationPx: scale[value]); locationPx: scale[value]);

@ -54,7 +54,7 @@ class AutoAdjustingDateTimeTickProvider implements TickProvider<DateTime> {
/// Creates a default [AutoAdjustingDateTimeTickProvider] for day and time. /// Creates a default [AutoAdjustingDateTimeTickProvider] for day and time.
factory AutoAdjustingDateTimeTickProvider.createDefault( factory AutoAdjustingDateTimeTickProvider.createDefault(
DateTimeFactory dateTimeFactory) { DateTimeFactory dateTimeFactory) {
return new AutoAdjustingDateTimeTickProvider._internal([ return AutoAdjustingDateTimeTickProvider._internal([
createYearTickProvider(dateTimeFactory), createYearTickProvider(dateTimeFactory),
createMonthTickProvider(dateTimeFactory), createMonthTickProvider(dateTimeFactory),
createDayTickProvider(dateTimeFactory), createDayTickProvider(dateTimeFactory),
@ -66,7 +66,7 @@ class AutoAdjustingDateTimeTickProvider implements TickProvider<DateTime> {
/// Creates a default [AutoAdjustingDateTimeTickProvider] for day only. /// Creates a default [AutoAdjustingDateTimeTickProvider] for day only.
factory AutoAdjustingDateTimeTickProvider.createWithoutTime( factory AutoAdjustingDateTimeTickProvider.createWithoutTime(
DateTimeFactory dateTimeFactory) { DateTimeFactory dateTimeFactory) {
return new AutoAdjustingDateTimeTickProvider._internal([ return AutoAdjustingDateTimeTickProvider._internal([
createYearTickProvider(dateTimeFactory), createYearTickProvider(dateTimeFactory),
createMonthTickProvider(dateTimeFactory), createMonthTickProvider(dateTimeFactory),
createDayTickProvider(dateTimeFactory) createDayTickProvider(dateTimeFactory)
@ -80,11 +80,10 @@ class AutoAdjustingDateTimeTickProvider implements TickProvider<DateTime> {
factory AutoAdjustingDateTimeTickProvider.createWith( factory AutoAdjustingDateTimeTickProvider.createWith(
List<TimeRangeTickProvider> potentialTickProviders) { List<TimeRangeTickProvider> potentialTickProviders) {
if (potentialTickProviders == null || potentialTickProviders.isEmpty) { if (potentialTickProviders == null || potentialTickProviders.isEmpty) {
throw new ArgumentError('At least one TimeRangeTickProvider is required'); throw ArgumentError('At least one TimeRangeTickProvider is required');
} }
return new AutoAdjustingDateTimeTickProvider._internal( return AutoAdjustingDateTimeTickProvider._internal(potentialTickProviders);
potentialTickProviders);
} }
/// Generates a list of ticks for the given data which should not collide /// Generates a list of ticks for the given data which should not collide
@ -157,21 +156,21 @@ class AutoAdjustingDateTimeTickProvider implements TickProvider<DateTime> {
static TimeRangeTickProvider createYearTickProvider( static TimeRangeTickProvider createYearTickProvider(
DateTimeFactory dateTimeFactory) => DateTimeFactory dateTimeFactory) =>
new TimeRangeTickProviderImpl(new YearTimeStepper(dateTimeFactory)); TimeRangeTickProviderImpl(YearTimeStepper(dateTimeFactory));
static TimeRangeTickProvider createMonthTickProvider( static TimeRangeTickProvider createMonthTickProvider(
DateTimeFactory dateTimeFactory) => DateTimeFactory dateTimeFactory) =>
new TimeRangeTickProviderImpl(new MonthTimeStepper(dateTimeFactory)); TimeRangeTickProviderImpl(MonthTimeStepper(dateTimeFactory));
static TimeRangeTickProvider createDayTickProvider( static TimeRangeTickProvider createDayTickProvider(
DateTimeFactory dateTimeFactory) => DateTimeFactory dateTimeFactory) =>
new TimeRangeTickProviderImpl(new DayTimeStepper(dateTimeFactory)); TimeRangeTickProviderImpl(DayTimeStepper(dateTimeFactory));
static TimeRangeTickProvider createHourTickProvider( static TimeRangeTickProvider createHourTickProvider(
DateTimeFactory dateTimeFactory) => DateTimeFactory dateTimeFactory) =>
new TimeRangeTickProviderImpl(new HourTimeStepper(dateTimeFactory)); TimeRangeTickProviderImpl(HourTimeStepper(dateTimeFactory));
static TimeRangeTickProvider createMinuteTickProvider( static TimeRangeTickProvider createMinuteTickProvider(
DateTimeFactory dateTimeFactory) => DateTimeFactory dateTimeFactory) =>
new TimeRangeTickProviderImpl(new MinuteTimeStepper(dateTimeFactory)); TimeRangeTickProviderImpl(MinuteTimeStepper(dateTimeFactory));
} }

@ -57,7 +57,7 @@ abstract class BaseTimeStepper implements TimeStepper {
// Keep the steps iterable unless time extent changes, so the same iterator // Keep the steps iterable unless time extent changes, so the same iterator
// can be used and reset for different increments. // can be used and reset for different increments.
if (_stepsIterable == null || _stepsIterable.timeExtent != timeExtent) { if (_stepsIterable == null || _stepsIterable.timeExtent != timeExtent) {
_stepsIterable = new _TimeStepIteratorFactoryImpl(timeExtent, this); _stepsIterable = _TimeStepIteratorFactoryImpl(timeExtent, this);
} }
return _stepsIterable; return _stepsIterable;
} }
@ -67,7 +67,7 @@ abstract class BaseTimeStepper implements TimeStepper {
final stepBefore = getStepTimeBeforeInclusive(timeExtent.start, 1); final stepBefore = getStepTimeBeforeInclusive(timeExtent.start, 1);
final stepAfter = getStepTimeAfterInclusive(timeExtent.end, 1); final stepAfter = getStepTimeAfterInclusive(timeExtent.end, 1);
return new DateTimeExtents(start: stepBefore, end: stepAfter); return DateTimeExtents(start: stepBefore, end: stepAfter);
} }
DateTime getStepTimeAfterInclusive(DateTime time, int tickIncrement) { DateTime getStepTimeAfterInclusive(DateTime time, int tickIncrement) {
@ -127,8 +127,8 @@ class _TimeStepIteratorFactoryImpl extends TimeStepIteratorFactory {
DateTimeExtents timeExtent, BaseTimeStepper stepper) { DateTimeExtents timeExtent, BaseTimeStepper stepper) {
final startTime = timeExtent.start; final startTime = timeExtent.start;
final endTime = timeExtent.end; final endTime = timeExtent.end;
return new _TimeStepIteratorFactoryImpl._internal( return _TimeStepIteratorFactoryImpl._internal(
new _TimeStepIteratorImpl(startTime, endTime, stepper), timeExtent); _TimeStepIteratorImpl(startTime, endTime, stepper), timeExtent);
} }
@override @override

@ -28,11 +28,10 @@ class DateTimeAxis extends Axis<DateTime> {
{TickProvider tickProvider, TickFormatter tickFormatter}) {TickProvider tickProvider, TickFormatter tickFormatter})
: super( : super(
tickProvider: tickProvider ?? tickProvider: tickProvider ??
new AutoAdjustingDateTimeTickProvider.createDefault( AutoAdjustingDateTimeTickProvider.createDefault(dateTimeFactory),
dateTimeFactory),
tickFormatter: tickFormatter:
tickFormatter ?? new DateTimeTickFormatter(dateTimeFactory), tickFormatter ?? DateTimeTickFormatter(dateTimeFactory),
scale: new DateTimeScale(dateTimeFactory), scale: DateTimeScale(dateTimeFactory),
); );
void setScaleViewport(DateTimeExtents viewport) { void setScaleViewport(DateTimeExtents viewport) {

@ -27,7 +27,7 @@ class DateTimeScale extends MutableScale<DateTime> {
final DateTimeFactory dateTimeFactory; final DateTimeFactory dateTimeFactory;
final LinearScale _linearScale; final LinearScale _linearScale;
DateTimeScale(this.dateTimeFactory) : _linearScale = new LinearScale(); DateTimeScale(this.dateTimeFactory) : _linearScale = LinearScale();
DateTimeScale._copy(DateTimeScale other) DateTimeScale._copy(DateTimeScale other)
: dateTimeFactory = other.dateTimeFactory, : dateTimeFactory = other.dateTimeFactory,
@ -82,7 +82,7 @@ class DateTimeScale extends MutableScale<DateTime> {
DateTimeExtents get viewportDomain { DateTimeExtents get viewportDomain {
final extents = _linearScale.viewportDomain; final extents = _linearScale.viewportDomain;
return new DateTimeExtents( return DateTimeExtents(
start: dateTimeFactory start: dateTimeFactory
.createDateTimeFromMilliSecondsSinceEpoch(extents.min.toInt()), .createDateTimeFromMilliSecondsSinceEpoch(extents.min.toInt()),
end: dateTimeFactory end: dateTimeFactory
@ -90,13 +90,13 @@ class DateTimeScale extends MutableScale<DateTime> {
} }
set viewportDomain(DateTimeExtents extents) { set viewportDomain(DateTimeExtents extents) {
_linearScale.viewportDomain = new NumericExtents( _linearScale.viewportDomain = NumericExtents(
extents.start.millisecondsSinceEpoch, extents.start.millisecondsSinceEpoch,
extents.end.millisecondsSinceEpoch); extents.end.millisecondsSinceEpoch);
} }
@override @override
DateTimeScale copy() => new DateTimeScale._copy(this); DateTimeScale copy() => DateTimeScale._copy(this);
@override @override
double get viewportTranslatePx => _linearScale.viewportTranslatePx; double get viewportTranslatePx => _linearScale.viewportTranslatePx;

@ -56,27 +56,27 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
factory DateTimeTickFormatter(DateTimeFactory dateTimeFactory, factory DateTimeTickFormatter(DateTimeFactory dateTimeFactory,
{Map<int, TimeTickFormatter> overrides}) { {Map<int, TimeTickFormatter> overrides}) {
final Map<int, TimeTickFormatter> map = { final Map<int, TimeTickFormatter> map = {
MINUTE: new TimeTickFormatterImpl( MINUTE: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'mm', simpleFormat: 'mm',
transitionFormat: 'h mm', transitionFormat: 'h mm',
transitionField: CalendarField.hourOfDay), transitionField: CalendarField.hourOfDay),
HOUR: new HourTickFormatter( HOUR: HourTickFormatter(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'h', simpleFormat: 'h',
transitionFormat: 'MMM d ha', transitionFormat: 'MMM d ha',
noonFormat: 'ha'), noonFormat: 'ha'),
23 * HOUR: new TimeTickFormatterImpl( 23 * HOUR: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'd', simpleFormat: 'd',
transitionFormat: 'MMM d', transitionFormat: 'MMM d',
transitionField: CalendarField.month), transitionField: CalendarField.month),
28 * DAY: new TimeTickFormatterImpl( 28 * DAY: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'MMM', simpleFormat: 'MMM',
transitionFormat: 'MMM yyyy', transitionFormat: 'MMM yyyy',
transitionField: CalendarField.year), transitionField: CalendarField.year),
364 * DAY: new TimeTickFormatterImpl( 364 * DAY: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'yyyy', simpleFormat: 'yyyy',
transitionFormat: 'yyyy', transitionFormat: 'yyyy',
@ -88,23 +88,23 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
map.addAll(overrides); map.addAll(overrides);
} }
return new DateTimeTickFormatter._internal(map); return DateTimeTickFormatter._internal(map);
} }
/// Creates a [DateTimeTickFormatter] without the time component. /// Creates a [DateTimeTickFormatter] without the time component.
factory DateTimeTickFormatter.withoutTime(DateTimeFactory dateTimeFactory) { factory DateTimeTickFormatter.withoutTime(DateTimeFactory dateTimeFactory) {
return new DateTimeTickFormatter._internal({ return DateTimeTickFormatter._internal({
23 * HOUR: new TimeTickFormatterImpl( 23 * HOUR: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'd', simpleFormat: 'd',
transitionFormat: 'MMM d', transitionFormat: 'MMM d',
transitionField: CalendarField.month), transitionField: CalendarField.month),
28 * DAY: new TimeTickFormatterImpl( 28 * DAY: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'MMM', simpleFormat: 'MMM',
transitionFormat: 'MMM yyyy', transitionFormat: 'MMM yyyy',
transitionField: CalendarField.year), transitionField: CalendarField.year),
365 * DAY: new TimeTickFormatterImpl( 365 * DAY: TimeTickFormatterImpl(
dateTimeFactory: dateTimeFactory, dateTimeFactory: dateTimeFactory,
simpleFormat: 'yyyy', simpleFormat: 'yyyy',
transitionFormat: 'yyyy', transitionFormat: 'yyyy',
@ -119,7 +119,7 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
/// ///
/// [formatter] The format for all ticks. /// [formatter] The format for all ticks.
factory DateTimeTickFormatter.uniform(TimeTickFormatter formatter) { factory DateTimeTickFormatter.uniform(TimeTickFormatter formatter) {
return new DateTimeTickFormatter._internal({ANY: formatter}); return DateTimeTickFormatter._internal({ANY: formatter});
} }
/// Creates a [DateTimeTickFormatter] that formats ticks with [formatters]. /// Creates a [DateTimeTickFormatter] that formats ticks with [formatters].
@ -129,10 +129,10 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
Map<int, TimeTickFormatter> formatters) { Map<int, TimeTickFormatter> formatters) {
// Formatters must be non empty. // Formatters must be non empty.
if (formatters == null || formatters.isEmpty) { if (formatters == null || formatters.isEmpty) {
throw new ArgumentError('At least one TimeTickFormatter is required.'); throw ArgumentError('At least one TimeTickFormatter is required.');
} }
return new DateTimeTickFormatter._internal(formatters); return DateTimeTickFormatter._internal(formatters);
} }
DateTimeTickFormatter._internal(this._timeFormatters) { DateTimeTickFormatter._internal(this._timeFormatters) {
@ -202,7 +202,7 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
// Only need to check the first value, because the values after are expected // Only need to check the first value, because the values after are expected
// to be greater. // to be greater.
if (prev <= 0) { if (prev <= 0) {
throw new ArgumentError('Formatter keys must be positive'); throw ArgumentError('Formatter keys must be positive');
} }
while (valuesIterator.moveNext() && isSorted) { while (valuesIterator.moveNext() && isSorted) {
@ -211,7 +211,7 @@ class DateTimeTickFormatter implements TickFormatter<DateTime> {
} }
if (!isSorted) { if (!isSorted) {
throw new ArgumentError( throw ArgumentError(
'Formatters must be sorted with keys in increasing order'); 'Formatters must be sorted with keys in increasing order');
} }
} }

@ -19,7 +19,7 @@ import 'base_time_stepper.dart' show BaseTimeStepper;
/// Day stepper. /// Day stepper.
class DayTimeStepper extends BaseTimeStepper { class DayTimeStepper extends BaseTimeStepper {
// TODO: Remove the 14 day increment if we add week stepper. // TODO: Remove the 14 day increment if we add week stepper.
static const _defaultIncrements = const [1, 2, 3, 7, 14]; static const _defaultIncrements = [1, 2, 3, 7, 14];
static const _hoursInDay = 24; static const _hoursInDay = 24;
final List<int> _allowedTickIncrements; final List<int> _allowedTickIncrements;
@ -39,7 +39,7 @@ class DayTimeStepper extends BaseTimeStepper {
// All increments must be > 0. // All increments must be > 0.
assert(allowedTickIncrements.any((increment) => increment <= 0) == false); assert(allowedTickIncrements.any((increment) => increment <= 0) == false);
return new DayTimeStepper._internal(dateTimeFactory, allowedTickIncrements); return DayTimeStepper._internal(dateTimeFactory, allowedTickIncrements);
} }
@override @override
@ -60,7 +60,7 @@ class DayTimeStepper extends BaseTimeStepper {
final dayRemainder = (time.day - 1) % tickIncrement; final dayRemainder = (time.day - 1) % tickIncrement;
// Subtract an extra hour in case stepping through a daylight saving change. // Subtract an extra hour in case stepping through a daylight saving change.
final dayBefore = dayRemainder > 0 final dayBefore = dayRemainder > 0
? time.subtract(new Duration(hours: (_hoursInDay * dayRemainder) - 1)) ? time.subtract(Duration(hours: (_hoursInDay * dayRemainder) - 1))
: time; : time;
// Explicitly leaving off hours and beyond to truncate to start of day. // Explicitly leaving off hours and beyond to truncate to start of day.
final stepBefore = dateTimeFactory.createDateTime( final stepBefore = dateTimeFactory.createDateTime(
@ -73,7 +73,7 @@ class DayTimeStepper extends BaseTimeStepper {
DateTime getNextStepTime(DateTime time, int tickIncrement) { DateTime getNextStepTime(DateTime time, int tickIncrement) {
// Add an extra hour in case stepping through a daylight saving change. // Add an extra hour in case stepping through a daylight saving change.
final stepAfter = final stepAfter =
time.add(new Duration(hours: (_hoursInDay * tickIncrement) + 1)); time.add(Duration(hours: (_hoursInDay * tickIncrement) + 1));
// Explicitly leaving off hours and beyond to truncate to start of day. // Explicitly leaving off hours and beyond to truncate to start of day.
return dateTimeFactory.createDateTime( return dateTimeFactory.createDateTime(
stepAfter.year, stepAfter.month, stepAfter.day); stepAfter.year, stepAfter.month, stepAfter.day);

@ -18,7 +18,7 @@ import 'base_time_stepper.dart' show BaseTimeStepper;
/// Hour stepper. /// Hour stepper.
class HourTimeStepper extends BaseTimeStepper { class HourTimeStepper extends BaseTimeStepper {
static const _defaultIncrements = const [1, 2, 3, 4, 6, 12, 24]; static const _defaultIncrements = [1, 2, 3, 4, 6, 12, 24];
static const _hoursInDay = 24; static const _hoursInDay = 24;
static const _millisecondsInHour = 3600 * 1000; static const _millisecondsInHour = 3600 * 1000;
@ -41,8 +41,7 @@ class HourTimeStepper extends BaseTimeStepper {
.any((increment) => increment <= 0 || increment > 24) == .any((increment) => increment <= 0 || increment > 24) ==
false); false);
return new HourTimeStepper._internal( return HourTimeStepper._internal(dateTimeFactory, allowedTickIncrements);
dateTimeFactory, allowedTickIncrements);
} }
@override @override
@ -60,7 +59,7 @@ class HourTimeStepper extends BaseTimeStepper {
DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) { DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {
final nextDay = dateTimeFactory final nextDay = dateTimeFactory
.createDateTime(time.year, time.month, time.day) .createDateTime(time.year, time.month, time.day)
.add(new Duration(hours: _hoursInDay + 1)); .add(Duration(hours: _hoursInDay + 1));
final nextDayStart = dateTimeFactory.createDateTime( final nextDayStart = dateTimeFactory.createDateTime(
nextDay.year, nextDay.month, nextDay.day); nextDay.year, nextDay.month, nextDay.day);
@ -83,6 +82,6 @@ class HourTimeStepper extends BaseTimeStepper {
/// [time] is expected to be a [DateTime] with the hour at start of the hour. /// [time] is expected to be a [DateTime] with the hour at start of the hour.
@override @override
DateTime getNextStepTime(DateTime time, int tickIncrement) { DateTime getNextStepTime(DateTime time, int tickIncrement) {
return time.add(new Duration(hours: tickIncrement)); return time.add(Duration(hours: tickIncrement));
} }
} }

@ -18,7 +18,7 @@ import 'base_time_stepper.dart';
/// Minute stepper where ticks generated aligns with the hour. /// Minute stepper where ticks generated aligns with the hour.
class MinuteTimeStepper extends BaseTimeStepper { class MinuteTimeStepper extends BaseTimeStepper {
static const _defaultIncrements = const [5, 10, 15, 20, 30]; static const _defaultIncrements = [5, 10, 15, 20, 30];
static const _millisecondsInMinute = 60 * 1000; static const _millisecondsInMinute = 60 * 1000;
final List<int> _allowedTickIncrements; final List<int> _allowedTickIncrements;
@ -40,8 +40,7 @@ class MinuteTimeStepper extends BaseTimeStepper {
.any((increment) => increment <= 0 || increment > 60) == .any((increment) => increment <= 0 || increment > 60) ==
false); false);
return new MinuteTimeStepper._internal( return MinuteTimeStepper._internal(dateTimeFactory, allowedTickIncrements);
dateTimeFactory, allowedTickIncrements);
} }
@override @override
@ -73,6 +72,6 @@ class MinuteTimeStepper extends BaseTimeStepper {
@override @override
DateTime getNextStepTime(DateTime time, int tickIncrement) { DateTime getNextStepTime(DateTime time, int tickIncrement) {
return time.add(new Duration(minutes: tickIncrement)); return time.add(Duration(minutes: tickIncrement));
} }
} }

@ -18,7 +18,7 @@ import 'base_time_stepper.dart' show BaseTimeStepper;
/// Month stepper. /// Month stepper.
class MonthTimeStepper extends BaseTimeStepper { class MonthTimeStepper extends BaseTimeStepper {
static const _defaultIncrements = const [1, 2, 3, 4, 6, 12]; static const _defaultIncrements = [1, 2, 3, 4, 6, 12];
final List<int> _allowedTickIncrements; final List<int> _allowedTickIncrements;
@ -37,8 +37,7 @@ class MonthTimeStepper extends BaseTimeStepper {
// All increments must be > 0. // All increments must be > 0.
assert(allowedTickIncrements.any((increment) => increment <= 0) == false); assert(allowedTickIncrements.any((increment) => increment <= 0) == false);
return new MonthTimeStepper._internal( return MonthTimeStepper._internal(dateTimeFactory, allowedTickIncrements);
dateTimeFactory, allowedTickIncrements);
} }
@override @override

@ -18,7 +18,7 @@ import 'base_time_stepper.dart' show BaseTimeStepper;
/// Year stepper. /// Year stepper.
class YearTimeStepper extends BaseTimeStepper { class YearTimeStepper extends BaseTimeStepper {
static const _defaultIncrements = const [1, 2, 5, 10, 50, 100, 500, 1000]; static const _defaultIncrements = [1, 2, 5, 10, 50, 100, 500, 1000];
final List<int> _allowedTickIncrements; final List<int> _allowedTickIncrements;
@ -37,8 +37,7 @@ class YearTimeStepper extends BaseTimeStepper {
// All increments must be > 0. // All increments must be > 0.
assert(allowedTickIncrements.any((increment) => increment <= 0) == false); assert(allowedTickIncrements.any((increment) => increment <= 0) == false);
return new YearTimeStepper._internal( return YearTimeStepper._internal(dateTimeFactory, allowedTickIncrements);
dateTimeFactory, allowedTickIncrements);
} }
@override @override

@ -55,14 +55,14 @@ class NumericCartesianChart extends CartesianChart<num> {
: super( : super(
vertical: vertical, vertical: vertical,
layoutConfig: layoutConfig, layoutConfig: layoutConfig,
domainAxis: new NumericAxis(), domainAxis: NumericAxis(),
primaryMeasureAxis: primaryMeasureAxis, primaryMeasureAxis: primaryMeasureAxis,
secondaryMeasureAxis: secondaryMeasureAxis, secondaryMeasureAxis: secondaryMeasureAxis,
disjointMeasureAxes: disjointMeasureAxes); disjointMeasureAxes: disjointMeasureAxes);
@protected @protected
void initDomainAxis() { void initDomainAxis() {
_domainAxis.tickDrawStrategy = new SmallTickRendererSpec<num>() _domainAxis.tickDrawStrategy = SmallTickRendererSpec<num>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
} }
} }
@ -77,7 +77,7 @@ class OrdinalCartesianChart extends CartesianChart<String> {
: super( : super(
vertical: vertical, vertical: vertical,
layoutConfig: layoutConfig, layoutConfig: layoutConfig,
domainAxis: new OrdinalAxis(), domainAxis: OrdinalAxis(),
primaryMeasureAxis: primaryMeasureAxis, primaryMeasureAxis: primaryMeasureAxis,
secondaryMeasureAxis: secondaryMeasureAxis, secondaryMeasureAxis: secondaryMeasureAxis,
disjointMeasureAxes: disjointMeasureAxes); disjointMeasureAxes: disjointMeasureAxes);
@ -85,17 +85,17 @@ class OrdinalCartesianChart extends CartesianChart<String> {
@protected @protected
void initDomainAxis() { void initDomainAxis() {
_domainAxis _domainAxis
..tickDrawStrategy = new SmallTickRendererSpec<String>() ..tickDrawStrategy = SmallTickRendererSpec<String>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
} }
} }
abstract class CartesianChart<D> extends BaseChart<D> { abstract class CartesianChart<D> extends BaseChart<D> {
static final _defaultLayoutConfig = new LayoutConfig( static final _defaultLayoutConfig = LayoutConfig(
topSpec: new MarginSpec.fromPixel(minPixel: 20), topSpec: MarginSpec.fromPixel(minPixel: 20),
bottomSpec: new MarginSpec.fromPixel(minPixel: 20), bottomSpec: MarginSpec.fromPixel(minPixel: 20),
leftSpec: new MarginSpec.fromPixel(minPixel: 20), leftSpec: MarginSpec.fromPixel(minPixel: 20),
rightSpec: new MarginSpec.fromPixel(minPixel: 20), rightSpec: MarginSpec.fromPixel(minPixel: 20),
); );
bool vertical; bool vertical;
@ -148,8 +148,8 @@ abstract class CartesianChart<D> extends BaseChart<D> {
: vertical = vertical ?? true, : vertical = vertical ?? true,
// [domainAxis] will be set to the new axis in [configurationChanged]. // [domainAxis] will be set to the new axis in [configurationChanged].
_newDomainAxis = domainAxis, _newDomainAxis = domainAxis,
_primaryMeasureAxis = primaryMeasureAxis ?? new NumericAxis(), _primaryMeasureAxis = primaryMeasureAxis ?? NumericAxis(),
_secondaryMeasureAxis = secondaryMeasureAxis ?? new NumericAxis(), _secondaryMeasureAxis = secondaryMeasureAxis ?? NumericAxis(),
_disjointMeasureAxes = disjointMeasureAxes ?? <String, NumericAxis>{}, _disjointMeasureAxes = disjointMeasureAxes ?? <String, NumericAxis>{},
super(layoutConfig: layoutConfig ?? _defaultLayoutConfig) { super(layoutConfig: layoutConfig ?? _defaultLayoutConfig) {
// As a convenience for chart configuration, set the paint order on any axis // As a convenience for chart configuration, set the paint order on any axis
@ -157,7 +157,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
_primaryMeasureAxis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis; _primaryMeasureAxis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis;
_secondaryMeasureAxis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis; _secondaryMeasureAxis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis;
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis; axis.layoutPaintOrder ??= LayoutViewPaintOrder.measureAxis;
}); });
} }
@ -166,17 +166,16 @@ abstract class CartesianChart<D> extends BaseChart<D> {
super.init(context, graphicsFactory); super.init(context, graphicsFactory);
_primaryMeasureAxis.context = context; _primaryMeasureAxis.context = context;
_primaryMeasureAxis.tickDrawStrategy = new GridlineRendererSpec<num>() _primaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
_secondaryMeasureAxis.context = context; _secondaryMeasureAxis.context = context;
_secondaryMeasureAxis.tickDrawStrategy = new GridlineRendererSpec<num>() _secondaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis.context = context; axis.context = context;
axis.tickDrawStrategy = axis.tickDrawStrategy = NoneDrawStrategy<num>(context, graphicsFactory);
new NoneDrawStrategy<num>(context, graphicsFactory);
}); });
} }
@ -277,7 +276,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
/// A [LinkedHashMap] is used to ensure consistent ordering when painting the /// A [LinkedHashMap] is used to ensure consistent ordering when painting the
/// axes. /// axes.
set disjointMeasureAxisSpecs(LinkedHashMap<String, AxisSpec> axisSpecs) { set disjointMeasureAxisSpecs(LinkedHashMap<String, AxisSpec> axisSpecs) {
axisSpecs.forEach((String axisId, AxisSpec axisSpec) { axisSpecs.forEach((axisId, axisSpec) {
axisSpec.configure( axisSpec.configure(
_disjointMeasureAxes[axisId], context, graphicsFactory); _disjointMeasureAxes[axisId], context, graphicsFactory);
}); });
@ -299,7 +298,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
@override @override
SeriesRenderer<D> makeDefaultRenderer() { SeriesRenderer<D> makeDefaultRenderer() {
return new BarRenderer()..rendererId = SeriesRenderer.defaultRendererId; return BarRenderer()..rendererId = SeriesRenderer.defaultRendererId;
} }
@override @override
@ -331,7 +330,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
} }
// Add all disjoint axis views so that their range will be configured. // Add all disjoint axis views so that their range will be configured.
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
addView(axis); addView(axis);
}); });
@ -340,7 +339,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
_primaryMeasureAxis.resetDomains(); _primaryMeasureAxis.resetDomains();
_secondaryMeasureAxis.resetDomains(); _secondaryMeasureAxis.resetDomains();
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis.resetDomains(); axis.resetDomains();
}); });
@ -363,7 +362,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
: AxisOrientation.right) : AxisOrientation.right)
..reverseOutputRange = flipVerticalAxisOutput; ..reverseOutputRange = flipVerticalAxisOutput;
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis axis
..axisOrientation = (reverseAxisDirection ..axisOrientation = (reverseAxisDirection
? AxisOrientation.left ? AxisOrientation.left
@ -385,7 +384,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
..axisOrientation = AxisOrientation.top ..axisOrientation = AxisOrientation.top
..reverseOutputRange = reverseAxisDirection; ..reverseOutputRange = reverseAxisDirection;
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis axis
..axisOrientation = AxisOrientation.top ..axisOrientation = AxisOrientation.top
..reverseOutputRange = reverseAxisDirection; ..reverseOutputRange = reverseAxisDirection;
@ -394,8 +393,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
// Have each renderer configure the axes with their domain and measure // Have each renderer configure the axes with their domain and measure
// values. // values.
rendererToSeriesList rendererToSeriesList.forEach((rendererId, seriesList) {
.forEach((String rendererId, List<MutableSeries<D>> seriesList) {
getSeriesRenderer(rendererId).configureDomainAxes(seriesList); getSeriesRenderer(rendererId).configureDomainAxes(seriesList);
getSeriesRenderer(rendererId).configureMeasureAxes(seriesList); getSeriesRenderer(rendererId).configureMeasureAxes(seriesList);
}); });
@ -416,7 +414,7 @@ abstract class CartesianChart<D> extends BaseChart<D> {
_secondaryMeasureAxis.updateTicks(); _secondaryMeasureAxis.updateTicks();
} }
_disjointMeasureAxes.forEach((String axisId, NumericAxis axis) { _disjointMeasureAxes.forEach((axisId, axis) {
axis.updateTicks(); axis.updateTicks();
}); });
@ -449,11 +447,11 @@ abstract class CartesianChart<D> extends BaseChart<D> {
final measurePosition = final measurePosition =
series.getAttr(measureAxisKey).getLocation(measure); series.getAttr(measureAxisKey).getLocation(measure);
final chartPosition = new Point<double>( final chartPosition = Point<double>(
vertical ? domainPosition : measurePosition, vertical ? domainPosition : measurePosition,
vertical ? measurePosition : domainPosition); vertical ? measurePosition : domainPosition);
entries.add(new DatumDetails( entries.add(DatumDetails(
datum: datum, datum: datum,
domain: domain, domain: domain,
measure: measure, measure: measure,

@ -52,7 +52,7 @@ abstract class BaseCartesianRenderer<D> extends BaseSeriesRenderer<D>
@override @override
void configureDomainAxes(List<MutableSeries<D>> seriesList) { void configureDomainAxes(List<MutableSeries<D>> seriesList) {
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
if (series.data.isEmpty) { if (series.data.isEmpty) {
return; return;
} }
@ -100,7 +100,7 @@ abstract class BaseCartesianRenderer<D> extends BaseSeriesRenderer<D>
@override @override
void configureMeasureAxes(List<MutableSeries<D>> seriesList) { void configureMeasureAxes(List<MutableSeries<D>> seriesList) {
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
if (series.data.isEmpty) { if (series.data.isEmpty) {
return; return;
} }

@ -66,7 +66,7 @@ abstract class BaseChart<D> {
/// initial draw cycle (e.g. a [Legend] may hide some series). /// initial draw cycle (e.g. a [Legend] may hide some series).
List<MutableSeries<D>> _currentSeriesList; List<MutableSeries<D>> _currentSeriesList;
Set<String> _usingRenderers = new Set<String>(); Set<String> _usingRenderers = Set<String>();
Map<String, List<MutableSeries<D>>> _rendererToSeriesList; Map<String, List<MutableSeries<D>>> _rendererToSeriesList;
final _seriesRenderers = <String, SeriesRenderer<D>>{}; final _seriesRenderers = <String, SeriesRenderer<D>>{};
@ -83,7 +83,7 @@ abstract class BaseChart<D> {
/// that does something with tap events, such as "click to select data." /// that does something with tap events, such as "click to select data."
bool get isTappable => _behaviorTappableMap.isNotEmpty; bool get isTappable => _behaviorTappableMap.isNotEmpty;
final _gestureProxy = new ProxyGestureListener(); final _gestureProxy = ProxyGestureListener();
final _selectionModels = <SelectionModelType, MutableSelectionModel<D>>{}; final _selectionModels = <SelectionModelType, MutableSelectionModel<D>>{};
@ -99,7 +99,7 @@ abstract class BaseChart<D> {
final _lifecycleListeners = <LifecycleListener<D>>[]; final _lifecycleListeners = <LifecycleListener<D>>[];
BaseChart({LayoutConfig layoutConfig}) { BaseChart({LayoutConfig layoutConfig}) {
_layoutManager = new LayoutManagerImpl(config: layoutConfig); _layoutManager = LayoutManagerImpl(config: layoutConfig);
} }
void init(ChartContext context, GraphicsFactory graphicsFactory) { void init(ChartContext context, GraphicsFactory graphicsFactory) {
@ -109,8 +109,8 @@ abstract class BaseChart<D> {
if (this.graphicsFactory != graphicsFactory) { if (this.graphicsFactory != graphicsFactory) {
this.graphicsFactory = graphicsFactory; this.graphicsFactory = graphicsFactory;
_layoutManager.applyToViews( _layoutManager
(LayoutView view) => view.graphicsFactory = graphicsFactory); .applyToViews((view) => view.graphicsFactory = graphicsFactory);
} }
configurationChanged(); configurationChanged();
@ -154,8 +154,7 @@ abstract class BaseChart<D> {
/// Returns MutableSelectionModel for the given type. Lazy creates one upon first /// Returns MutableSelectionModel for the given type. Lazy creates one upon first
/// request. /// request.
MutableSelectionModel<D> getSelectionModel(SelectionModelType type) { MutableSelectionModel<D> getSelectionModel(SelectionModelType type) {
return _selectionModels.putIfAbsent( return _selectionModels.putIfAbsent(type, () => MutableSelectionModel<D>());
type, () => new MutableSelectionModel<D>());
} }
/// Returns a list of datum details from selection model of [type]. /// Returns a list of datum details from selection model of [type].
@ -206,10 +205,9 @@ abstract class BaseChart<D> {
SeriesRenderer<D> makeDefaultRenderer(); SeriesRenderer<D> makeDefaultRenderer();
bool pointWithinRenderer(Point<double> chartPosition) { bool pointWithinRenderer(Point<double> chartPosition) {
return _usingRenderers.any((String rendererId) => return _usingRenderers.any((rendererId) => getSeriesRenderer(rendererId)
getSeriesRenderer(rendererId) .componentBounds
.componentBounds .containsPoint(chartPosition));
.containsPoint(chartPosition));
} }
/// Retrieves the datum details that are nearest to the given [drawAreaPoint]. /// Retrieves the datum details that are nearest to the given [drawAreaPoint].
@ -229,13 +227,13 @@ abstract class BaseChart<D> {
selectAcrossAllDrawAreaComponents ? drawableLayoutAreaBounds : null; selectAcrossAllDrawAreaComponents ? drawableLayoutAreaBounds : null;
final details = <DatumDetails<D>>[]; final details = <DatumDetails<D>>[];
_usingRenderers.forEach((String rendererId) { _usingRenderers.forEach((rendererId) {
details.addAll(getSeriesRenderer(rendererId) details.addAll(getSeriesRenderer(rendererId)
.getNearestDatumDetailPerSeries( .getNearestDatumDetailPerSeries(
drawAreaPoint, selectNearestByDomain, boundsOverride)); drawAreaPoint, selectNearestByDomain, boundsOverride));
}); });
details.sort((DatumDetails<D> a, DatumDetails<D> b) { details.sort((a, b) {
// Sort so that the nearest one is first. // Sort so that the nearest one is first.
// Special sort, sort by domain distance first, then by measure distance. // Special sort, sort by domain distance first, then by measure distance.
if (selectNearestByDomain) { if (selectNearestByDomain) {
@ -356,7 +354,7 @@ abstract class BaseChart<D> {
} }
/// Returns a list of behaviors that have been added. /// Returns a list of behaviors that have been added.
List<ChartBehavior<D>> get behaviors => new List.unmodifiable(_behaviorStack); List<ChartBehavior<D>> get behaviors => List.unmodifiable(_behaviorStack);
// //
// Layout methods // Layout methods
@ -423,7 +421,7 @@ abstract class BaseChart<D> {
} }
var processedSeriesList = var processedSeriesList =
new List<MutableSeries<D>>.from(seriesList.map(makeSeries)); List<MutableSeries<D>>.from(seriesList.map(makeSeries));
// Allow listeners to manipulate the seriesList. // Allow listeners to manipulate the seriesList.
fireOnDraw(processedSeriesList); fireOnDraw(processedSeriesList);
@ -464,9 +462,8 @@ abstract class BaseChart<D> {
void drawInternal(List<MutableSeries<D>> seriesList, void drawInternal(List<MutableSeries<D>> seriesList,
{bool skipAnimation, bool skipLayout}) { {bool skipAnimation, bool skipLayout}) {
seriesList = seriesList seriesList =
.map((MutableSeries<D> series) => new MutableSeries<D>.clone(series)) seriesList.map((series) => MutableSeries<D>.clone(series)).toList();
.toList();
// TODO: Handle exiting renderers. // TODO: Handle exiting renderers.
_animationsTemporarilyDisabled = skipAnimation; _animationsTemporarilyDisabled = skipAnimation;
@ -487,7 +484,7 @@ abstract class BaseChart<D> {
List<MutableSeries<D>> get currentSeriesList => _currentSeriesList; List<MutableSeries<D>> get currentSeriesList => _currentSeriesList;
MutableSeries<D> makeSeries(Series<dynamic, D> series) { MutableSeries<D> makeSeries(Series<dynamic, D> series) {
final s = new MutableSeries<D>(series); final s = MutableSeries<D>(series);
// Setup the Renderer // Setup the Renderer
final rendererId = final rendererId =
@ -505,14 +502,13 @@ abstract class BaseChart<D> {
// Build map of rendererIds to SeriesLists. This map can't be re-used later // Build map of rendererIds to SeriesLists. This map can't be re-used later
// in the preprocessSeries call because some behaviors might alter the // in the preprocessSeries call because some behaviors might alter the
// seriesList. // seriesList.
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
String rendererId = series.getAttr(rendererIdKey); String rendererId = series.getAttr(rendererIdKey);
rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series); rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series);
}); });
// Have each renderer add missing color functions to their seriesLists. // Have each renderer add missing color functions to their seriesLists.
rendererToSeriesList rendererToSeriesList.forEach((rendererId, seriesList) {
.forEach((String rendererId, List<MutableSeries<D>> seriesList) {
getSeriesRenderer(rendererId).configureSeries(seriesList); getSeriesRenderer(rendererId).configureSeries(seriesList);
}); });
} }
@ -525,10 +521,10 @@ abstract class BaseChart<D> {
Map<String, List<MutableSeries<D>>> rendererToSeriesList = {}; Map<String, List<MutableSeries<D>>> rendererToSeriesList = {};
var unusedRenderers = _usingRenderers; var unusedRenderers = _usingRenderers;
_usingRenderers = new Set<String>(); _usingRenderers = Set<String>();
// Build map of rendererIds to SeriesLists. // Build map of rendererIds to SeriesLists.
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
String rendererId = series.getAttr(rendererIdKey); String rendererId = series.getAttr(rendererIdKey);
rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series); rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series);
@ -538,11 +534,10 @@ abstract class BaseChart<D> {
// Allow unused renderers to render out content. // Allow unused renderers to render out content.
unusedRenderers unusedRenderers
.forEach((String rendererId) => rendererToSeriesList[rendererId] = []); .forEach((rendererId) => rendererToSeriesList[rendererId] = []);
// Have each renderer preprocess their seriesLists. // Have each renderer preprocess their seriesLists.
rendererToSeriesList rendererToSeriesList.forEach((rendererId, seriesList) {
.forEach((String rendererId, List<MutableSeries<D>> seriesList) {
getSeriesRenderer(rendererId).preprocessSeries(seriesList); getSeriesRenderer(rendererId).preprocessSeries(seriesList);
}); });
@ -555,8 +550,7 @@ abstract class BaseChart<D> {
void onPostLayout(Map<String, List<MutableSeries<D>>> rendererToSeriesList) { void onPostLayout(Map<String, List<MutableSeries<D>>> rendererToSeriesList) {
// Update each renderer with // Update each renderer with
rendererToSeriesList rendererToSeriesList.forEach((rendererId, seriesList) {
.forEach((String rendererId, List<MutableSeries<D>> seriesList) {
getSeriesRenderer(rendererId).update(seriesList, animatingThisDraw); getSeriesRenderer(rendererId).update(seriesList, animatingThisDraw);
}); });
@ -574,7 +568,7 @@ abstract class BaseChart<D> {
void paint(ChartCanvas canvas) { void paint(ChartCanvas canvas) {
canvas.drawingView = 'BaseView'; canvas.drawingView = 'BaseView';
_layoutManager.paintOrderedViews.forEach((LayoutView view) { _layoutManager.paintOrderedViews.forEach((view) {
canvas.drawingView = view.runtimeType.toString(); canvas.drawingView = view.runtimeType.toString();
view.paint(canvas, animatingThisDraw ? animationPercent : 1.0); view.paint(canvas, animatingThisDraw ? animationPercent : 1.0);
}); });
@ -594,7 +588,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnDraw(List<MutableSeries<D>> seriesList) { fireOnDraw(List<MutableSeries<D>> seriesList) {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onData != null) { if (listener.onData != null) {
listener.onData(seriesList); listener.onData(seriesList);
} }
@ -603,7 +597,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnPreprocess(List<MutableSeries<D>> seriesList) { fireOnPreprocess(List<MutableSeries<D>> seriesList) {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onPreprocess != null) { if (listener.onPreprocess != null) {
listener.onPreprocess(seriesList); listener.onPreprocess(seriesList);
} }
@ -612,7 +606,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnPostprocess(List<MutableSeries<D>> seriesList) { fireOnPostprocess(List<MutableSeries<D>> seriesList) {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onPostprocess != null) { if (listener.onPostprocess != null) {
listener.onPostprocess(seriesList); listener.onPostprocess(seriesList);
} }
@ -621,7 +615,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnAxisConfigured() { fireOnAxisConfigured() {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onAxisConfigured != null) { if (listener.onAxisConfigured != null) {
listener.onAxisConfigured(); listener.onAxisConfigured();
} }
@ -630,7 +624,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnPostrender(ChartCanvas canvas) { fireOnPostrender(ChartCanvas canvas) {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onPostrender != null) { if (listener.onPostrender != null) {
listener.onPostrender(canvas); listener.onPostrender(canvas);
} }
@ -639,7 +633,7 @@ abstract class BaseChart<D> {
@protected @protected
fireOnAnimationComplete() { fireOnAnimationComplete() {
_lifecycleListeners.forEach((LifecycleListener<D> listener) { _lifecycleListeners.forEach((listener) {
if (listener.onAnimationComplete != null) { if (listener.onAnimationComplete != null) {
listener.onAnimationComplete(); listener.onAnimationComplete();
} }
@ -654,8 +648,8 @@ abstract class BaseChart<D> {
} }
_behaviorStack.clear(); _behaviorStack.clear();
_behaviorRoleMap.clear(); _behaviorRoleMap.clear();
_selectionModels.values.forEach((MutableSelectionModel selectionModel) => _selectionModels.values
selectionModel.clearAllListeners()); .forEach((selectionModel) => selectionModel.clearAllListeners());
} }
} }
@ -707,6 +701,7 @@ class LifecycleListener<D> {
this.onAnimationComplete}); this.onAnimationComplete});
} }
typedef LifecycleSeriesListCallback<D>(List<MutableSeries<D>> seriesList); typedef LifecycleSeriesListCallback<D> = Function(
typedef LifecycleCanvasCallback(ChartCanvas canvas); List<MutableSeries<D>> seriesList);
typedef LifecycleEmptyCallback(); typedef LifecycleCanvasCallback = Function(ChartCanvas canvas);
typedef LifecycleEmptyCallback = Function();

@ -57,10 +57,10 @@ abstract class A11yExploreBehavior<D> implements ChartBehavior<D> {
switch (exploreModeTrigger) { switch (exploreModeTrigger) {
case ExploreModeTrigger.pressHold: case ExploreModeTrigger.pressHold:
_listener = new GestureListener(onLongPress: _toggleExploreMode); _listener = GestureListener(onLongPress: _toggleExploreMode);
break; break;
case ExploreModeTrigger.tap: case ExploreModeTrigger.tap:
_listener = new GestureListener(onTap: _toggleExploreMode); _listener = GestureListener(onTap: _toggleExploreMode);
break; break;
} }
} }

@ -15,7 +15,7 @@
import 'dart:math' show Rectangle; import 'dart:math' show Rectangle;
typedef void OnFocus(); typedef OnFocus = void Function();
/// Container for accessibility data. /// Container for accessibility data.
class A11yNode { class A11yNode {

@ -28,7 +28,8 @@ import 'a11y_explore_behavior.dart'
import 'a11y_node.dart' show A11yNode, OnFocus; import 'a11y_node.dart' show A11yNode, OnFocus;
/// Returns a string for a11y vocalization from a list of series datum. /// Returns a string for a11y vocalization from a list of series datum.
typedef String VocalizationCallback<D>(List<SeriesDatum<D>> seriesDatums); typedef VocalizationCallback<D> = String Function(
List<SeriesDatum<D>> seriesDatums);
/// A simple vocalization that returns the domain value to string. /// A simple vocalization that returns the domain value to string.
String domainVocalization<D>(List<SeriesDatum<D>> seriesDatums) { String domainVocalization<D>(List<SeriesDatum<D>> seriesDatums) {
@ -58,8 +59,7 @@ class DomainA11yExploreBehavior<D> extends A11yExploreBehavior<D> {
minimumWidth: minimumWidth, minimumWidth: minimumWidth,
exploreModeEnabledAnnouncement: exploreModeEnabledAnnouncement, exploreModeEnabledAnnouncement: exploreModeEnabledAnnouncement,
exploreModeDisabledAnnouncement: exploreModeDisabledAnnouncement) { exploreModeDisabledAnnouncement: exploreModeDisabledAnnouncement) {
_lifecycleListener = _lifecycleListener = LifecycleListener<D>(onPostprocess: _updateSeriesList);
new LifecycleListener<D>(onPostprocess: _updateSeriesList);
} }
@override @override
@ -77,11 +77,11 @@ class DomainA11yExploreBehavior<D> extends A11yExploreBehavior<D> {
D domain = series.domainFn(index); D domain = series.domainFn(index);
domainSeriesDatum[domain] ??= <SeriesDatum<D>>[]; domainSeriesDatum[domain] ??= <SeriesDatum<D>>[];
domainSeriesDatum[domain].add(new SeriesDatum<D>(series, datum)); domainSeriesDatum[domain].add(SeriesDatum<D>(series, datum));
} }
} }
domainSeriesDatum.forEach((D domain, List<SeriesDatum<D>> seriesDatums) { domainSeriesDatum.forEach((domain, seriesDatums) {
final a11yDescription = _vocalizationCallback(seriesDatums); final a11yDescription = _vocalizationCallback(seriesDatums);
final firstSeries = seriesDatums.first.series; final firstSeries = seriesDatums.first.series;
@ -93,7 +93,7 @@ class DomainA11yExploreBehavior<D> extends A11yExploreBehavior<D> {
? domainAxis.stepSize ? domainAxis.stepSize
: minimumWidth; : minimumWidth;
nodes.add(new _DomainA11yNode(a11yDescription, nodes.add(_DomainA11yNode(a11yDescription,
location: location, location: location,
stepSize: stepSize, stepSize: stepSize,
chartDrawBounds: _chart.drawAreaBounds, chartDrawBounds: _chart.drawAreaBounds,
@ -134,7 +134,7 @@ class DomainA11yExploreBehavior<D> extends A11yExploreBehavior<D> {
} }
@override @override
String get role => 'DomainA11yExplore-${exploreModeTrigger}'; String get role => 'DomainA11yExplore-$exploreModeTrigger';
} }
/// A11yNode with domain specific information. /// A11yNode with domain specific information.
@ -157,16 +157,16 @@ class _DomainA11yNode extends A11yNode implements Comparable<_DomainA11yNode> {
var top = chartDrawBounds.top; var top = chartDrawBounds.top;
var width = stepSize.round(); var width = stepSize.round();
var height = chartDrawBounds.height; var height = chartDrawBounds.height;
boundingBox = new Rectangle(left, top, width, height); boundingBox = Rectangle(left, top, width, height);
} else { } else {
var left = chartDrawBounds.left; var left = chartDrawBounds.left;
var top = (location - stepSize / 2).round(); var top = (location - stepSize / 2).round();
var width = chartDrawBounds.width; var width = chartDrawBounds.width;
var height = stepSize.round(); var height = stepSize.round();
boundingBox = new Rectangle(left, top, width, height); boundingBox = Rectangle(left, top, width, height);
} }
return new _DomainA11yNode._internal(label, boundingBox, return _DomainA11yNode._internal(label, boundingBox,
location: location, location: location,
isRtl: isRtl, isRtl: isRtl,
renderVertically: renderVertically, renderVertically: renderVertically,

@ -19,7 +19,7 @@ import '../../behavior/chart_behavior.dart' show ChartBehavior;
import '../../processed_series.dart' show MutableSeries; import '../../processed_series.dart' show MutableSeries;
const percentInjectedKey = const percentInjectedKey =
const AttributeKey<bool>('PercentInjector.percentInjected'); AttributeKey<bool>('PercentInjector.percentInjected');
/// Chart behavior that can inject series or domain percentages into each datum. /// Chart behavior that can inject series or domain percentages into each datum.
/// ///
@ -49,7 +49,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
PercentInjector({this.totalType = PercentInjectorTotalType.domain}) { PercentInjector({this.totalType = PercentInjectorTotalType.domain}) {
// Set up chart draw cycle listeners. // Set up chart draw cycle listeners.
_lifecycleListener = _lifecycleListener =
new LifecycleListener<D>(onPreprocess: _preProcess, onData: _onData); LifecycleListener<D>(onPreprocess: _preProcess, onData: _onData);
} }
@override @override
@ -65,7 +65,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
/// Resets the state of the behavior when new data is drawn on the chart. /// Resets the state of the behavior when new data is drawn on the chart.
void _onData(List<MutableSeries<D>> seriesList) { void _onData(List<MutableSeries<D>> seriesList) {
// Reset tracking of percentage injection for new data. // Reset tracking of percentage injection for new data.
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
series.setAttr(percentInjectedKey, false); series.setAttr(percentInjectedKey, false);
}); });
} }
@ -77,7 +77,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
/// the [seriesList] between chart redraws. /// the [seriesList] between chart redraws.
void _preProcess(List<MutableSeries<D>> seriesList) { void _preProcess(List<MutableSeries<D>> seriesList) {
var percentInjected = true; var percentInjected = true;
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
percentInjected = percentInjected && series.getAttr(percentInjectedKey); percentInjected = percentInjected && series.getAttr(percentInjectedKey);
}); });
@ -95,7 +95,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
// Walk the series and compute the domain total. Series total is // Walk the series and compute the domain total. Series total is
// automatically computed by [MutableSeries]. // automatically computed by [MutableSeries].
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
final seriesCategory = series.seriesCategory; final seriesCategory = series.seriesCategory;
final rawMeasureFn = series.rawMeasureFn; final rawMeasureFn = series.rawMeasureFn;
final domainFn = series.domainFn; final domainFn = series.domainFn;
@ -118,10 +118,10 @@ class PercentInjector<D> implements ChartBehavior<D> {
}); });
// Add percent of domain and series accessor functions. // Add percent of domain and series accessor functions.
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
// Replace the default measure accessor with one that computes the // Replace the default measure accessor with one that computes the
// percentage. // percentage.
series.measureFn = (int index) { series.measureFn = (index) {
final measure = series.rawMeasureFn(index); final measure = series.rawMeasureFn(index);
if (measure == null || measure == 0.0) { if (measure == null || measure == 0.0) {
@ -140,7 +140,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
// Replace the default measure lower bound accessor with one that // Replace the default measure lower bound accessor with one that
// computes the percentage. // computes the percentage.
if (series.measureLowerBoundFn != null) { if (series.measureLowerBoundFn != null) {
series.measureLowerBoundFn = (int index) { series.measureLowerBoundFn = (index) {
final measureLowerBound = series.rawMeasureLowerBoundFn(index); final measureLowerBound = series.rawMeasureLowerBoundFn(index);
if (measureLowerBound == null || measureLowerBound == 0.0) { if (measureLowerBound == null || measureLowerBound == 0.0) {
@ -160,7 +160,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
// Replace the default measure upper bound accessor with one that // Replace the default measure upper bound accessor with one that
// computes the percentage. // computes the percentage.
if (series.measureUpperBoundFn != null) { if (series.measureUpperBoundFn != null) {
series.measureUpperBoundFn = (int index) { series.measureUpperBoundFn = (index) {
final measureUpperBound = series.rawMeasureUpperBoundFn(index); final measureUpperBound = series.rawMeasureUpperBoundFn(index);
if (measureUpperBound == null || measureUpperBound == 0.0) { if (measureUpperBound == null || measureUpperBound == 0.0) {
@ -183,16 +183,16 @@ class PercentInjector<D> implements ChartBehavior<D> {
break; break;
case PercentInjectorTotalType.series: case PercentInjectorTotalType.series:
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
// Replace the default measure accessor with one that computes the // Replace the default measure accessor with one that computes the
// percentage. // percentage.
series.measureFn = (int index) => series.measureFn =
series.rawMeasureFn(index) / series.seriesMeasureTotal; (index) => series.rawMeasureFn(index) / series.seriesMeasureTotal;
// Replace the default measure lower bound accessor with one that // Replace the default measure lower bound accessor with one that
// computes the percentage. // computes the percentage.
if (series.measureLowerBoundFn != null) { if (series.measureLowerBoundFn != null) {
series.measureLowerBoundFn = (int index) => series.measureLowerBoundFn = (index) =>
series.rawMeasureLowerBoundFn(index) / series.rawMeasureLowerBoundFn(index) /
series.seriesMeasureTotal; series.seriesMeasureTotal;
} }
@ -200,7 +200,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
// Replace the default measure upper bound accessor with one that // Replace the default measure upper bound accessor with one that
// computes the percentage. // computes the percentage.
if (series.measureUpperBoundFn != null) { if (series.measureUpperBoundFn != null) {
series.measureUpperBoundFn = (int index) => series.measureUpperBoundFn = (index) =>
series.rawMeasureUpperBoundFn(index) / series.rawMeasureUpperBoundFn(index) /
series.seriesMeasureTotal; series.seriesMeasureTotal;
} }
@ -211,7 +211,7 @@ class PercentInjector<D> implements ChartBehavior<D> {
break; break;
default: default:
throw new ArgumentError('Unsupported totalType: ${totalType}'); throw ArgumentError('Unsupported totalType: $totalType');
} }
} }

@ -47,9 +47,9 @@ class ChartTitle<D> implements ChartBehavior<D> {
static const _defaultTitleDirection = ChartTitleDirection.auto; static const _defaultTitleDirection = ChartTitleDirection.auto;
static const _defaultTitleOutsideJustification = OutsideJustification.middle; static const _defaultTitleOutsideJustification = OutsideJustification.middle;
static final _defaultTitleStyle = static final _defaultTitleStyle =
new TextStyleSpec(fontSize: 18, color: StyleFactory.style.tickColor); TextStyleSpec(fontSize: 18, color: StyleFactory.style.tickColor);
static final _defaultSubTitleStyle = static final _defaultSubTitleStyle =
new TextStyleSpec(fontSize: 14, color: StyleFactory.style.tickColor); TextStyleSpec(fontSize: 14, color: StyleFactory.style.tickColor);
static const _defaultInnerPadding = 10; static const _defaultInnerPadding = 10;
static const _defaultTitlePadding = 18; static const _defaultTitlePadding = 18;
static const _defaultOuterPadding = 10; static const _defaultOuterPadding = 10;
@ -79,7 +79,7 @@ class ChartTitle<D> implements ChartBehavior<D> {
TextStyleSpec titleStyleSpec, TextStyleSpec titleStyleSpec,
String subTitle, String subTitle,
TextStyleSpec subTitleStyleSpec}) { TextStyleSpec subTitleStyleSpec}) {
_config = new _ChartTitleConfig() _config = _ChartTitleConfig()
..behaviorPosition = behaviorPosition ?? _defaultBehaviorPosition ..behaviorPosition = behaviorPosition ?? _defaultBehaviorPosition
..innerPadding = innerPadding ?? _defaultInnerPadding ..innerPadding = innerPadding ?? _defaultInnerPadding
..layoutMinSize = layoutMinSize ..layoutMinSize = layoutMinSize
@ -96,7 +96,7 @@ class ChartTitle<D> implements ChartBehavior<D> {
..subTitleStyleSpec = subTitleStyleSpec ?? _defaultSubTitleStyle; ..subTitleStyleSpec = subTitleStyleSpec ?? _defaultSubTitleStyle;
_lifecycleListener = _lifecycleListener =
new LifecycleListener<D>(onAxisConfigured: _updateViewData); LifecycleListener<D>(onAxisConfigured: _updateViewData);
} }
/// Layout position for the title. /// Layout position for the title.
@ -228,7 +228,7 @@ class ChartTitle<D> implements ChartBehavior<D> {
void attachTo(BaseChart<D> chart) { void attachTo(BaseChart<D> chart) {
_chart = chart; _chart = chart;
_view = new _ChartTitleLayoutView<D>( _view = _ChartTitleLayoutView<D>(
layoutPaintOrder: LayoutViewPaintOrder.chartTitle, layoutPaintOrder: LayoutViewPaintOrder.chartTitle,
config: _config, config: _config,
chart: _chart); chart: _chart);
@ -270,7 +270,7 @@ class _ChartTitleLayoutView<D> extends LayoutView {
Rectangle<int> _componentBounds; Rectangle<int> _componentBounds;
Rectangle<int> _drawAreaBounds; Rectangle<int> _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
/// Cached layout element for the title text. /// Cached layout element for the title text.
/// ///
@ -292,20 +292,12 @@ class _ChartTitleLayoutView<D> extends LayoutView {
@required this.chart}) @required this.chart})
: this._config = config { : this._config = config {
// Set inside body to resolve [_layoutPosition]. // Set inside body to resolve [_layoutPosition].
_layoutConfig = new LayoutViewConfig( _layoutConfig = LayoutViewConfig(
paintOrder: layoutPaintOrder, paintOrder: layoutPaintOrder,
position: _layoutPosition, position: _layoutPosition,
positionOrder: LayoutViewPositionOrder.chartTitle); positionOrder: LayoutViewPositionOrder.chartTitle);
} }
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
/// Sets the configuration for the title behavior. /// Sets the configuration for the title behavior.
set config(_ChartTitleConfig config) { set config(_ChartTitleConfig config) {
_config = config; _config = config;
@ -415,7 +407,7 @@ class _ChartTitleLayoutView<D> extends LayoutView {
// Reset the cached text elements used during the paint step. // Reset the cached text elements used during the paint step.
_resetTextElementCache(); _resetTextElementCache();
return new ViewMeasuredSizes( return ViewMeasuredSizes(
minWidth: minWidth, minWidth: minWidth,
minHeight: minHeight, minHeight: minHeight,
preferredWidth: preferredWidth, preferredWidth: preferredWidth,
@ -707,7 +699,7 @@ class _ChartTitleLayoutView<D> extends LayoutView {
labelY = (bounds.bottom - padding).round(); labelY = (bounds.bottom - padding).round();
} }
return new Point<int>(labelX, labelY); return Point<int>(labelX, labelY);
} }
/// Gets the resolved location for a title in the left or right margin. /// Gets the resolved location for a title in the left or right margin.
@ -780,7 +772,7 @@ class _ChartTitleLayoutView<D> extends LayoutView {
labelX = (bounds.right - padding).round(); labelX = (bounds.right - padding).round();
} }
return new Point<int>(labelX, labelY); return Point<int>(labelX, labelY);
} }
// Helper function that converts [TextStyleSpec] to [TextStyle]. // Helper function that converts [TextStyleSpec] to [TextStyle].

@ -35,7 +35,7 @@ class DomainHighlighter<D> implements ChartBehavior<D> {
DomainHighlighter([this.selectionModelType = SelectionModelType.info]) { DomainHighlighter([this.selectionModelType = SelectionModelType.info]) {
_lifecycleListener = _lifecycleListener =
new LifecycleListener<D>(onPostprocess: _updateColorFunctions); LifecycleListener<D>(onPostprocess: _updateColorFunctions);
} }
void _selectionChanged(SelectionModel selectionModel) { void _selectionChanged(SelectionModel selectionModel) {
@ -45,11 +45,11 @@ class DomainHighlighter<D> implements ChartBehavior<D> {
void _updateColorFunctions(List<MutableSeries<D>> seriesList) { void _updateColorFunctions(List<MutableSeries<D>> seriesList) {
SelectionModel selectionModel = SelectionModel selectionModel =
_chart.getSelectionModel(selectionModelType); _chart.getSelectionModel(selectionModelType);
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
final origColorFn = series.colorFn; final origColorFn = series.colorFn;
if (origColorFn != null) { if (origColorFn != null) {
series.colorFn = (int index) { series.colorFn = (index) {
final origColor = origColorFn(index); final origColor = origColorFn(index);
if (selectionModel.isDatumSelected(series, index)) { if (selectionModel.isDatumSelected(series, index)) {
return origColor.darker; return origColor.darker;

@ -40,7 +40,7 @@ class InitialSelection<D> implements ChartBehavior<D> {
{this.selectionModelType = SelectionModelType.info, {this.selectionModelType = SelectionModelType.info,
this.selectedDataConfig, this.selectedDataConfig,
this.selectedSeriesConfig}) { this.selectedSeriesConfig}) {
_lifecycleListener = new LifecycleListener<D>(onData: _setInitialSelection); _lifecycleListener = LifecycleListener<D>(onData: _setInitialSelection);
} }
void _setInitialSelection(List<MutableSeries<D>> seriesList) { void _setInitialSelection(List<MutableSeries<D>> seriesList) {
@ -49,7 +49,7 @@ class InitialSelection<D> implements ChartBehavior<D> {
} }
_firstDraw = false; _firstDraw = false;
final immutableModel = new SelectionModel<D>.fromConfig( final immutableModel = SelectionModel<D>.fromConfig(
selectedDataConfig, selectedSeriesConfig, seriesList); selectedDataConfig, selectedSeriesConfig, seriesList);
_chart.getSelectionModel(selectionModelType).updateSelection( _chart.getSelectionModel(selectionModelType).updateSelection(

@ -44,7 +44,7 @@ class DatumLegend<D> extends Legend<D> {
}) : super( }) : super(
selectionModelType: selectionModelType ?? SelectionModelType.info, selectionModelType: selectionModelType ?? SelectionModelType.info,
legendEntryGenerator: legendEntryGenerator:
legendEntryGenerator ?? new PerDatumLegendEntryGenerator(), legendEntryGenerator ?? PerDatumLegendEntryGenerator(),
entryTextStyle: entryTextStyle) { entryTextStyle: entryTextStyle) {
// Call the setters that include the setting for default. // Call the setters that include the setting for default.
this.showMeasures = showMeasures; this.showMeasures = showMeasures;

@ -51,28 +51,37 @@ import 'legend_entry_generator.dart';
/// Flutter, using widgets). /// Flutter, using widgets).
abstract class Legend<D> implements ChartBehavior<D>, LayoutView { abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
final SelectionModelType selectionModelType; final SelectionModelType selectionModelType;
final legendState = new LegendState<D>(); final legendState = LegendState<D>();
final LegendEntryGenerator<D> legendEntryGenerator; final LegendEntryGenerator<D> legendEntryGenerator;
String _title; /// Sets title text to display before legend entries.
String title;
BaseChart _chart; BaseChart _chart;
LifecycleListener<D> _lifecycleListener; LifecycleListener<D> _lifecycleListener;
Rectangle<int> _componentBounds; Rectangle<int> _componentBounds;
Rectangle<int> _drawAreaBounds; Rectangle<int> _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
BehaviorPosition _behaviorPosition = BehaviorPosition.end; BehaviorPosition behaviorPosition = BehaviorPosition.end;
OutsideJustification _outsideJustification = OutsideJustification outsideJustification =
OutsideJustification.startDrawArea; OutsideJustification.startDrawArea;
InsideJustification _insideJustification = InsideJustification.topStart; InsideJustification insideJustification = InsideJustification.topStart;
LegendCellPadding _cellPadding; LegendCellPadding cellPadding;
LegendCellPadding _legendPadding; LegendCellPadding legendPadding;
TextStyleSpec _titleTextStyle; /// Text style of the legend title text.
TextStyleSpec titleTextStyle;
LegendTapHandling _legendTapHandling = LegendTapHandling.hide; /// Configures the behavior of the legend when the user taps/clicks on an
/// entry. Defaults to no behavior.
///
/// Tapping on a legend entry will update the data visible on the chart. For
/// example, when [LegendTapHandling.hide] is configured, the series or datum
/// associated with that entry will be removed from the chart. Tapping on that
/// entry a second time will make the data visible again.
LegendTapHandling legendTapHandling = LegendTapHandling.hide;
List<MutableSeries<D>> _currentSeriesList; List<MutableSeries<D>> _currentSeriesList;
@ -80,7 +89,7 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
/// the legend entries. /// the legend entries.
List<MutableSeries<D>> _postProcessSeriesList; List<MutableSeries<D>> _postProcessSeriesList;
static final _decimalPattern = new NumberFormat.decimalPattern(); static final _decimalPattern = NumberFormat.decimalPattern();
/// Default measure formatter for legends. /// Default measure formatter for legends.
@protected @protected
@ -89,50 +98,11 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
} }
Legend({this.selectionModelType, this.legendEntryGenerator, entryTextStyle}) { Legend({this.selectionModelType, this.legendEntryGenerator, entryTextStyle}) {
_lifecycleListener = new LifecycleListener( _lifecycleListener = LifecycleListener(
onPostprocess: _postProcess, onPreprocess: _preProcess, onData: onData); onPostprocess: _postProcess, onPreprocess: _preProcess, onData: onData);
legendEntryGenerator.entryTextStyle = entryTextStyle; legendEntryGenerator.entryTextStyle = entryTextStyle;
} }
String get title => _title;
/// Sets title text to display before legend entries.
set title(String title) {
_title = title;
}
BehaviorPosition get behaviorPosition => _behaviorPosition;
set behaviorPosition(BehaviorPosition behaviorPosition) {
_behaviorPosition = behaviorPosition;
}
OutsideJustification get outsideJustification => _outsideJustification;
set outsideJustification(OutsideJustification outsideJustification) {
_outsideJustification = outsideJustification;
}
InsideJustification get insideJustification => _insideJustification;
set insideJustification(InsideJustification insideJustification) {
_insideJustification = insideJustification;
}
LegendCellPadding get cellPadding => _cellPadding;
set cellPadding(LegendCellPadding cellPadding) {
_cellPadding = cellPadding;
}
LegendCellPadding get legendPadding => _legendPadding;
set legendPadding(LegendCellPadding legendPadding) {
_legendPadding = legendPadding;
}
LegendTapHandling get legendTapHandling => _legendTapHandling;
/// Text style of the legend entry text. /// Text style of the legend entry text.
TextStyleSpec get entryTextStyle => legendEntryGenerator.entryTextStyle; TextStyleSpec get entryTextStyle => legendEntryGenerator.entryTextStyle;
@ -140,31 +110,13 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
legendEntryGenerator.entryTextStyle = entryTextStyle; legendEntryGenerator.entryTextStyle = entryTextStyle;
} }
/// Text style of the legend title text.
TextStyleSpec get titleTextStyle => _titleTextStyle;
set titleTextStyle(TextStyleSpec titleTextStyle) {
_titleTextStyle = titleTextStyle;
}
/// Configures the behavior of the legend when the user taps/clicks on an
/// entry. Defaults to no behavior.
///
/// Tapping on a legend entry will update the data visible on the chart. For
/// example, when [LegendTapHandling.hide] is configured, the series or datum
/// associated with that entry will be removed from the chart. Tapping on that
/// entry a second time will make the data visible again.
set legendTapHandling(LegendTapHandling legendTapHandling) {
_legendTapHandling = legendTapHandling;
}
/// Resets any hidden series data when new data is drawn on the chart. /// Resets any hidden series data when new data is drawn on the chart.
@protected @protected
void onData(List<MutableSeries<D>> seriesList) {} void onData(List<MutableSeries<D>> seriesList) {}
/// Store off a copy of the series list for use when we render the legend. /// Store off a copy of the series list for use when we render the legend.
void _preProcess(List<MutableSeries<D>> seriesList) { void _preProcess(List<MutableSeries<D>> seriesList) {
_currentSeriesList = new List.from(seriesList); _currentSeriesList = List.from(seriesList);
preProcessSeriesList(seriesList); preProcessSeriesList(seriesList);
} }
@ -251,17 +203,9 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
bool get isRtl => _chart.context.isRtl; bool get isRtl => _chart.context.isRtl;
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override @override
LayoutViewConfig get layoutConfig { LayoutViewConfig get layoutConfig {
return new LayoutViewConfig( return LayoutViewConfig(
position: _layoutPosition, position: _layoutPosition,
positionOrder: LayoutViewPositionOrder.legend, positionOrder: LayoutViewPositionOrder.legend,
paintOrder: LayoutViewPaintOrder.legend); paintOrder: LayoutViewPaintOrder.legend);
@ -270,7 +214,7 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
/// Get layout position from legend position. /// Get layout position from legend position.
LayoutPosition get _layoutPosition { LayoutPosition get _layoutPosition {
LayoutPosition position; LayoutPosition position;
switch (_behaviorPosition) { switch (behaviorPosition) {
case BehaviorPosition.bottom: case BehaviorPosition.bottom:
position = LayoutPosition.Bottom; position = LayoutPosition.Bottom;
break; break;
@ -296,7 +240,7 @@ abstract class Legend<D> implements ChartBehavior<D>, LayoutView {
ViewMeasuredSizes measure(int maxWidth, int maxHeight) { ViewMeasuredSizes measure(int maxWidth, int maxHeight) {
// Native child classes should override this method to return real // Native child classes should override this method to return real
// measurements. // measurements.
return new ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0); return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);
} }
@override @override

@ -39,8 +39,7 @@ class PerDatumLegendEntryGenerator<D> implements LegendEntryGenerator<D> {
final series = seriesList[0]; final series = seriesList[0];
for (var i = 0; i < series.data.length; i++) { for (var i = 0; i < series.data.length; i++) {
legendEntries.add(new LegendEntry<D>( legendEntries.add(LegendEntry<D>(series, series.domainFn(i).toString(),
series, series.domainFn(i).toString(),
color: series.colorFn(i), color: series.colorFn(i),
datum: series.data[i], datum: series.data[i],
datumIndex: i, datumIndex: i,

@ -38,7 +38,7 @@ class PerSeriesLegendEntryGenerator<D> implements LegendEntryGenerator<D> {
@override @override
List<LegendEntry<D>> getLegendEntries(List<MutableSeries<D>> seriesList) { List<LegendEntry<D>> getLegendEntries(List<MutableSeries<D>> seriesList) {
final legendEntries = seriesList final legendEntries = seriesList
.map((series) => new LegendEntry<D>(series, series.displayName, .map((series) => LegendEntry<D>(series, series.displayName,
color: series.colorFn(0), textStyle: entryTextStyle)) color: series.colorFn(0), textStyle: entryTextStyle))
.toList(); .toList();
@ -72,7 +72,7 @@ class PerSeriesLegendEntryGenerator<D> implements LegendEntryGenerator<D> {
final seriesAndMeasure = <String, num>{}; final seriesAndMeasure = <String, num>{};
// Hash set of series ID's that use the secondary measure axis // Hash set of series ID's that use the secondary measure axis
final secondaryAxisSeriesIDs = new HashSet<String>(); final secondaryAxisSeriesIDs = HashSet<String>();
for (SeriesDatum<D> selectedDatum in selectionModel.selectedDatum) { for (SeriesDatum<D> selectedDatum in selectionModel.selectedDatum) {
final series = selectedDatum.series; final series = selectedDatum.series;

@ -31,7 +31,7 @@ import 'per_series_legend_entry_generator.dart';
/// By default this behavior creates a legend entry per series. /// By default this behavior creates a legend entry per series.
class SeriesLegend<D> extends Legend<D> { class SeriesLegend<D> extends Legend<D> {
/// List of currently hidden series, by ID. /// List of currently hidden series, by ID.
final _hiddenSeriesList = new Set<String>(); final _hiddenSeriesList = Set<String>();
/// List of series IDs that should be hidden by default. /// List of series IDs that should be hidden by default.
List<String> _defaultHiddenSeries; List<String> _defaultHiddenSeries;
@ -50,7 +50,7 @@ class SeriesLegend<D> extends Legend<D> {
}) : super( }) : super(
selectionModelType: selectionModelType ?? SelectionModelType.info, selectionModelType: selectionModelType ?? SelectionModelType.info,
legendEntryGenerator: legendEntryGenerator:
legendEntryGenerator ?? new PerSeriesLegendEntryGenerator(), legendEntryGenerator ?? PerSeriesLegendEntryGenerator(),
entryTextStyle: entryTextStyle) { entryTextStyle: entryTextStyle) {
// Call the setters that include the setting for default. // Call the setters that include the setting for default.
this.showMeasures = showMeasures; this.showMeasures = showMeasures;
@ -134,14 +134,14 @@ class SeriesLegend<D> extends Legend<D> {
void onData(List<MutableSeries<D>> seriesList) { void onData(List<MutableSeries<D>> seriesList) {
// If a series was removed from the chart, remove it from our current list // If a series was removed from the chart, remove it from our current list
// of hidden series. // of hidden series.
final seriesIds = seriesList.map((MutableSeries<D> series) => series.id); final seriesIds = seriesList.map((series) => series.id);
_hiddenSeriesList.removeWhere((String id) => !seriesIds.contains(id)); _hiddenSeriesList.removeWhere((id) => !seriesIds.contains(id));
} }
@override @override
void preProcessSeriesList(List<MutableSeries<D>> seriesList) { void preProcessSeriesList(List<MutableSeries<D>> seriesList) {
seriesList.removeWhere((MutableSeries<D> series) { seriesList.removeWhere((series) {
return _hiddenSeriesList.contains(series.id); return _hiddenSeriesList.contains(series.id);
}); });
} }
@ -161,7 +161,7 @@ class SeriesLegend<D> extends Legend<D> {
/// color if it was previously hidden. /// color if it was previously hidden.
@protected @protected
void showSeries(String seriesId) { void showSeries(String seriesId) {
_hiddenSeriesList.removeWhere((String id) => id == seriesId); _hiddenSeriesList.removeWhere((id) => id == seriesId);
} }
/// Returns whether or not a given series [seriesId] is currently hidden. /// Returns whether or not a given series [seriesId] is currently hidden.

@ -133,16 +133,16 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
LinePointHighlighterFollowLineType.nearest, LinePointHighlighterFollowLineType.nearest,
dashPattern = dashPattern ?? [1, 3], dashPattern = dashPattern ?? [1, 3],
drawFollowLinesAcrossChart = drawFollowLinesAcrossChart ?? true, drawFollowLinesAcrossChart = drawFollowLinesAcrossChart ?? true,
symbolRenderer = symbolRenderer ?? new CircleSymbolRenderer() { symbolRenderer = symbolRenderer ?? CircleSymbolRenderer() {
_lifecycleListener = _lifecycleListener =
new LifecycleListener<D>(onAxisConfigured: _updateViewData); LifecycleListener<D>(onAxisConfigured: _updateViewData);
} }
@override @override
void attachTo(BaseChart<D> chart) { void attachTo(BaseChart<D> chart) {
_chart = chart; _chart = chart;
_view = new _LinePointLayoutView<D>( _view = _LinePointLayoutView<D>(
chart: chart, chart: chart,
layoutPaintOrder: LayoutViewPaintOrder.linePointHighlighter, layoutPaintOrder: LayoutViewPaintOrder.linePointHighlighter,
showHorizontalFollowLine: showHorizontalFollowLine, showHorizontalFollowLine: showHorizontalFollowLine,
@ -205,7 +205,7 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
? detail.radiusPx.toDouble() + radiusPaddingPx ? detail.radiusPx.toDouble() + radiusPaddingPx
: defaultRadiusPx; : defaultRadiusPx;
final pointKey = '${lineKey}::${detail.domain}'; final pointKey = '$lineKey::${detail.domain}';
// If we already have a point for that key, use it. // If we already have a point for that key, use it.
_AnimatedPoint<D> animatingPoint; _AnimatedPoint<D> animatingPoint;
@ -213,16 +213,16 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
animatingPoint = _seriesPointMap[pointKey]; animatingPoint = _seriesPointMap[pointKey];
} else { } else {
// Create a new point and have it animate in from axis. // Create a new point and have it animate in from axis.
final point = new _DatumPoint<D>( final point = _DatumPoint<D>(
datum: datum, datum: datum,
domain: detail.domain, domain: detail.domain,
series: series, series: series,
x: domainAxis.getLocation(detail.domain), x: domainAxis.getLocation(detail.domain),
y: measureAxis.getLocation(0.0)); y: measureAxis.getLocation(0.0));
animatingPoint = new _AnimatedPoint<D>( animatingPoint = _AnimatedPoint<D>(
key: pointKey, overlaySeries: series.overlaySeries) key: pointKey, overlaySeries: series.overlaySeries)
..setNewTarget(new _PointRendererElement<D>() ..setNewTarget(_PointRendererElement<D>()
..point = point ..point = point
..color = detail.color ..color = detail.color
..fillColor = detail.fillColor ..fillColor = detail.fillColor
@ -235,7 +235,7 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
newSeriesMap[pointKey] = animatingPoint; newSeriesMap[pointKey] = animatingPoint;
// Create a new line using the final point locations. // Create a new line using the final point locations.
final point = new _DatumPoint<D>( final point = _DatumPoint<D>(
datum: datum, datum: datum,
domain: detail.domain, domain: detail.domain,
series: series, series: series,
@ -246,7 +246,7 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
_currentKeys.add(pointKey); _currentKeys.add(pointKey);
// Get the point element we are going to setup. // Get the point element we are going to setup.
final pointElement = new _PointRendererElement<D>() final pointElement = _PointRendererElement<D>()
..point = point ..point = point
..color = detail.color ..color = detail.color
..fillColor = detail.fillColor ..fillColor = detail.fillColor
@ -259,7 +259,7 @@ class LinePointHighlighter<D> implements ChartBehavior<D> {
} }
// Animate out points that don't exist anymore. // Animate out points that don't exist anymore.
_seriesPointMap.forEach((String key, _AnimatedPoint<D> point) { _seriesPointMap.forEach((key, point) {
if (_currentKeys.contains(point.key) != true) { if (_currentKeys.contains(point.key) != true) {
point.animateOut(); point.animateOut();
newSeriesMap[point.key] = point; newSeriesMap[point.key] = point;
@ -293,7 +293,7 @@ class _LinePointLayoutView<D> extends LayoutView {
final SymbolRenderer symbolRenderer; final SymbolRenderer symbolRenderer;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
/// Store a map of series drawn on the chart, mapped by series name. /// Store a map of series drawn on the chart, mapped by series name.
/// ///
@ -309,7 +309,7 @@ class _LinePointLayoutView<D> extends LayoutView {
@required this.symbolRenderer, @required this.symbolRenderer,
this.dashPattern, this.dashPattern,
this.drawFollowLinesAcrossChart, this.drawFollowLinesAcrossChart,
}) : this.layoutConfig = new LayoutViewConfig( }) : this.layoutConfig = LayoutViewConfig(
paintOrder: LayoutViewPaintOrder.linePointHighlighter, paintOrder: LayoutViewPaintOrder.linePointHighlighter,
position: LayoutPosition.DrawArea, position: LayoutPosition.DrawArea,
positionOrder: layoutPaintOrder); positionOrder: layoutPaintOrder);
@ -318,14 +318,6 @@ class _LinePointLayoutView<D> extends LayoutView {
_seriesPointMap = value; _seriesPointMap = value;
} }
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override @override
ViewMeasuredSizes measure(int maxWidth, int maxHeight) { ViewMeasuredSizes measure(int maxWidth, int maxHeight) {
return null; return null;
@ -346,17 +338,17 @@ class _LinePointLayoutView<D> extends LayoutView {
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = <String>[]; final keysToRemove = <String>[];
_seriesPointMap.forEach((String key, _AnimatedPoint<D> point) { _seriesPointMap.forEach((key, point) {
if (point.animatingOut) { if (point.animatingOut) {
keysToRemove.add(key); keysToRemove.add(key);
} }
}); });
keysToRemove.forEach((String key) => _seriesPointMap.remove(key)); keysToRemove.forEach((key) => _seriesPointMap.remove(key));
} }
final points = <_PointRendererElement<D>>[]; final points = <_PointRendererElement<D>>[];
_seriesPointMap.forEach((String key, _AnimatedPoint<D> point) { _seriesPointMap.forEach((key, point) {
points.add(point.getCurrentPoint(animationPercent)); points.add(point.getCurrentPoint(animationPercent));
}); });
@ -449,8 +441,8 @@ class _LinePointLayoutView<D> extends LayoutView {
canvas.drawLine( canvas.drawLine(
points: [ points: [
new Point<num>(leftBound, pointElement.point.y), Point<num>(leftBound, pointElement.point.y),
new Point<num>(rightBound, pointElement.point.y), Point<num>(rightBound, pointElement.point.y),
], ],
stroke: StyleFactory.style.linePointHighlighterColor, stroke: StyleFactory.style.linePointHighlighterColor,
strokeWidthPx: 1.0, strokeWidthPx: 1.0,
@ -473,8 +465,8 @@ class _LinePointLayoutView<D> extends LayoutView {
canvas.drawLine( canvas.drawLine(
points: [ points: [
new Point<num>(pointElement.point.x, topBound), Point<num>(pointElement.point.x, topBound),
new Point<num>( Point<num>(
pointElement.point.x, drawBounds.top + drawBounds.height), pointElement.point.x, drawBounds.top + drawBounds.height),
], ],
stroke: StyleFactory.style.linePointHighlighterColor, stroke: StyleFactory.style.linePointHighlighterColor,
@ -500,7 +492,7 @@ class _LinePointLayoutView<D> extends LayoutView {
continue; continue;
} }
final bounds = new Rectangle<double>( final bounds = Rectangle<double>(
pointElement.point.x - pointElement.radiusPx, pointElement.point.x - pointElement.radiusPx,
pointElement.point.y - pointElement.radiusPx, pointElement.point.y - pointElement.radiusPx,
pointElement.radiusPx * 2, pointElement.radiusPx * 2,
@ -531,7 +523,7 @@ class _DatumPoint<D> extends Point<double> {
: super(x, y); : super(x, y);
factory _DatumPoint.from(_DatumPoint<D> other, [double x, double y]) { factory _DatumPoint.from(_DatumPoint<D> other, [double x, double y]) {
return new _DatumPoint<D>( return _DatumPoint<D>(
datum: other.datum, datum: other.datum,
domain: other.domain, domain: other.domain,
series: other.series, series: other.series,
@ -550,7 +542,7 @@ class _PointRendererElement<D> {
SymbolRenderer symbolRenderer; SymbolRenderer symbolRenderer;
_PointRendererElement<D> clone() { _PointRendererElement<D> clone() {
return new _PointRendererElement<D>() return _PointRendererElement<D>()
..point = this.point ..point = this.point
..color = this.color ..color = this.color
..fillColor = this.fillColor ..fillColor = this.fillColor
@ -569,7 +561,7 @@ class _PointRendererElement<D> {
final y = _lerpDouble(previousPoint.y, targetPoint.y, animationPercent); final y = _lerpDouble(previousPoint.y, targetPoint.y, animationPercent);
point = new _DatumPoint<D>.from(targetPoint, x, y); point = _DatumPoint<D>.from(targetPoint, x, y);
color = getAnimatedColor(previous.color, target.color, animationPercent); color = getAnimatedColor(previous.color, target.color, animationPercent);
@ -625,7 +617,7 @@ class _AnimatedPoint<D> {
// Set the target measure value to the axis position for all points. // Set the target measure value to the axis position for all points.
final targetPoint = newTarget.point; final targetPoint = newTarget.point;
final newPoint = new _DatumPoint<D>.from(targetPoint, targetPoint.x, final newPoint = _DatumPoint<D>.from(targetPoint, targetPoint.x,
newTarget.measureAxisPosition.roundToDouble()); newTarget.measureAxisPosition.roundToDouble());
newTarget.point = newPoint; newTarget.point = newPoint;
@ -685,7 +677,7 @@ class LinePointHighlighterTester<D> {
bool isDatumSelected(D datum) { bool isDatumSelected(D datum) {
var contains = false; var contains = false;
behavior._seriesPointMap.forEach((String key, _AnimatedPoint<D> point) { behavior._seriesPointMap.forEach((key, point) {
if (point._currentPoint.point.datum == datum) { if (point._currentPoint.point.datum == datum) {
contains = true; contains = true;
return; return;

@ -54,7 +54,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
static const _defaultLabelPosition = AnnotationLabelPosition.auto; static const _defaultLabelPosition = AnnotationLabelPosition.auto;
static const _defaultLabelPadding = 5; static const _defaultLabelPadding = 5;
static final _defaultLabelStyle = static final _defaultLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.black); TextStyleSpec(fontSize: 12, color: Color.black);
static const _defaultStrokeWidthPx = 2.0; static const _defaultStrokeWidthPx = 2.0;
/// List of annotations to render on the chart. /// List of annotations to render on the chart.
@ -121,20 +121,20 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
extendAxis = extendAxis ?? true, extendAxis = extendAxis ?? true,
labelPadding = labelPadding ?? _defaultLabelPadding, labelPadding = labelPadding ?? _defaultLabelPadding,
defaultStrokeWidthPx = defaultStrokeWidthPx ?? _defaultStrokeWidthPx { defaultStrokeWidthPx = defaultStrokeWidthPx ?? _defaultStrokeWidthPx {
_lifecycleListener = new LifecycleListener<D>( _lifecycleListener = LifecycleListener<D>(
onPostprocess: _updateAxisRange, onAxisConfigured: _updateViewData); onPostprocess: _updateAxisRange, onAxisConfigured: _updateViewData);
} }
@override @override
void attachTo(BaseChart<D> chart) { void attachTo(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'RangeAnnotation can only be attached to a CartesianChart'); 'RangeAnnotation can only be attached to a CartesianChart');
} }
_chart = chart; _chart = chart;
_view = new _RangeAnnotationLayoutView<D>( _view = _RangeAnnotationLayoutView<D>(
defaultColor: defaultColor, labelPadding: labelPadding, chart: chart); defaultColor: defaultColor, labelPadding: labelPadding, chart: chart);
chart.addView(_view); chart.addView(_view);
@ -155,7 +155,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
if (extendAxis) { if (extendAxis) {
final domainAxis = _chart.domainAxis; final domainAxis = _chart.domainAxis;
annotations.forEach((AnnotationSegment annotation) { annotations.forEach((annotation) {
Axis axis; Axis axis;
switch (annotation.axisType) { switch (annotation.axisType) {
@ -182,7 +182,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
void _updateViewData() { void _updateViewData() {
_currentKeys.clear(); _currentKeys.clear();
annotations.forEach((AnnotationSegment annotation) { annotations.forEach((annotation) {
Axis axis; Axis axis;
switch (annotation.axisType) { switch (annotation.axisType) {
@ -251,8 +251,8 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
animatingAnnotation = _annotationMap[key]; animatingAnnotation = _annotationMap[key];
} else { } else {
// Create a new annotation, positioned at the start and end values. // Create a new annotation, positioned at the start and end values.
animatingAnnotation = new _AnimatedAnnotation<D>(key: key) animatingAnnotation = _AnimatedAnnotation<D>(key: key)
..setNewTarget(new _AnnotationElement<D>() ..setNewTarget(_AnnotationElement<D>()
..annotation = annotationDatum ..annotation = annotationDatum
..color = color ..color = color
..dashPattern = dashPattern ..dashPattern = dashPattern
@ -272,7 +272,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
_currentKeys.add(key); _currentKeys.add(key);
// Get the annotation element we are going to setup. // Get the annotation element we are going to setup.
final annotationElement = new _AnnotationElement<D>() final annotationElement = _AnnotationElement<D>()
..annotation = annotationDatum ..annotation = annotationDatum
..color = color ..color = color
..dashPattern = dashPattern ..dashPattern = dashPattern
@ -289,7 +289,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
}); });
// Animate out annotations that don't exist anymore. // Animate out annotations that don't exist anymore.
_annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) { _annotationMap.forEach((key, annotation) {
if (_currentKeys.contains(annotation.key) != true) { if (_currentKeys.contains(annotation.key) != true) {
annotation.animateOut(); annotation.animateOut();
} }
@ -310,7 +310,7 @@ class RangeAnnotation<D> implements ChartBehavior<D> {
final startPosition = (axis.getLocation(startValue) * 100).round() / 100; final startPosition = (axis.getLocation(startValue) * 100).round() / 100;
final endPosition = (axis.getLocation(endValue) * 100).round() / 100; final endPosition = (axis.getLocation(endValue) * 100).round() / 100;
return new _DatumAnnotation( return _DatumAnnotation(
startPosition: startPosition, startPosition: startPosition,
endPosition: endPosition, endPosition: endPosition,
axisType: axisType); axisType: axisType);
@ -335,7 +335,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
Rectangle<int> get drawBounds => _drawAreaBounds; Rectangle<int> get drawBounds => _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
/// Store a map of series drawn on the chart, mapped by series name. /// Store a map of series drawn on the chart, mapped by series name.
/// ///
@ -347,7 +347,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
@required this.defaultColor, @required this.defaultColor,
@required this.labelPadding, @required this.labelPadding,
@required this.chart, @required this.chart,
}) : this.layoutConfig = new LayoutViewConfig( }) : this.layoutConfig = LayoutViewConfig(
paintOrder: LayoutViewPaintOrder.rangeAnnotation, paintOrder: LayoutViewPaintOrder.rangeAnnotation,
position: LayoutPosition.DrawArea, position: LayoutPosition.DrawArea,
positionOrder: LayoutViewPositionOrder.drawArea); positionOrder: LayoutViewPositionOrder.drawArea);
@ -356,14 +356,6 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
_annotationMap = value; _annotationMap = value;
} }
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override @override
ViewMeasuredSizes measure(int maxWidth, int maxHeight) { ViewMeasuredSizes measure(int maxWidth, int maxHeight) {
return null; return null;
@ -384,16 +376,16 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = <String>[]; final keysToRemove = <String>[];
_annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) { _annotationMap.forEach((key, annotation) {
if (annotation.animatingOut) { if (annotation.animatingOut) {
keysToRemove.add(key); keysToRemove.add(key);
} }
}); });
keysToRemove.forEach((String key) => _annotationMap.remove(key)); keysToRemove.forEach((key) => _annotationMap.remove(key));
} }
_annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) { _annotationMap.forEach((key, annotation) {
final annotationElement = final annotationElement =
annotation.getCurrentAnnotation(animationPercent); annotation.getCurrentAnnotation(animationPercent);
@ -477,7 +469,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (annotationElement.annotation.axisType) { switch (annotationElement.annotation.axisType) {
case RangeAnnotationAxisType.domain: case RangeAnnotationAxisType.domain:
bounds = new Rectangle<num>( bounds = Rectangle<num>(
annotationElement.annotation.startPosition, annotationElement.annotation.startPosition,
_drawAreaBounds.top, _drawAreaBounds.top,
annotationElement.annotation.endPosition - annotationElement.annotation.endPosition -
@ -486,7 +478,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
break; break;
case RangeAnnotationAxisType.measure: case RangeAnnotationAxisType.measure:
bounds = new Rectangle<num>( bounds = Rectangle<num>(
_drawAreaBounds.left, _drawAreaBounds.left,
annotationElement.annotation.endPosition, annotationElement.annotation.endPosition,
_drawAreaBounds.width, _drawAreaBounds.width,
@ -505,16 +497,16 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (annotationElement.annotation.axisType) { switch (annotationElement.annotation.axisType) {
case RangeAnnotationAxisType.domain: case RangeAnnotationAxisType.domain:
points.add(new Point<num>( points.add(Point<num>(
annotationElement.annotation.startPosition, _drawAreaBounds.top)); annotationElement.annotation.startPosition, _drawAreaBounds.top));
points.add(new Point<num>( points.add(Point<num>(
annotationElement.annotation.endPosition, _drawAreaBounds.bottom)); annotationElement.annotation.endPosition, _drawAreaBounds.bottom));
break; break;
case RangeAnnotationAxisType.measure: case RangeAnnotationAxisType.measure:
points.add(new Point<num>( points.add(Point<num>(
_drawAreaBounds.left, annotationElement.annotation.startPosition)); _drawAreaBounds.left, annotationElement.annotation.startPosition));
points.add(new Point<num>( points.add(Point<num>(
_drawAreaBounds.right, annotationElement.annotation.endPosition)); _drawAreaBounds.right, annotationElement.annotation.endPosition));
break; break;
} }
@ -655,7 +647,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (calculatedLabelPosition) { switch (calculatedLabelPosition) {
case AnnotationLabelPosition.margin: case AnnotationLabelPosition.margin:
case AnnotationLabelPosition.auto: case AnnotationLabelPosition.auto:
throw new ArgumentError(_unresolvedAutoMessage); throw ArgumentError(_unresolvedAutoMessage);
break; break;
case AnnotationLabelPosition.outside: case AnnotationLabelPosition.outside:
@ -685,7 +677,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
break; break;
} }
return new Point<int>(labelX.round(), labelY.round()); return Point<int>(labelX.round(), labelY.round());
} }
/// Gets the resolved location for a vertical domain annotation label element. /// Gets the resolved location for a vertical domain annotation label element.
@ -734,7 +726,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (calculatedLabelPosition) { switch (calculatedLabelPosition) {
case AnnotationLabelPosition.margin: case AnnotationLabelPosition.margin:
case AnnotationLabelPosition.auto: case AnnotationLabelPosition.auto:
throw new ArgumentError(_unresolvedAutoMessage); throw ArgumentError(_unresolvedAutoMessage);
break; break;
case AnnotationLabelPosition.outside: case AnnotationLabelPosition.outside:
@ -764,7 +756,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
break; break;
} }
return new Point<int>(labelX.round(), labelY.round()); return Point<int>(labelX.round(), labelY.round());
} }
/// Gets the resolved location for a measure annotation label element. /// Gets the resolved location for a measure annotation label element.
@ -834,7 +826,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (calculatedLabelPosition) { switch (calculatedLabelPosition) {
case AnnotationLabelPosition.margin: case AnnotationLabelPosition.margin:
case AnnotationLabelPosition.auto: case AnnotationLabelPosition.auto:
throw new ArgumentError(_unresolvedAutoMessage); throw ArgumentError(_unresolvedAutoMessage);
break; break;
case AnnotationLabelPosition.outside: case AnnotationLabelPosition.outside:
@ -858,7 +850,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
break; break;
} }
return new Point<int>(labelX.round(), labelY.round()); return Point<int>(labelX.round(), labelY.round());
} }
/// Gets the resolved location for a vertical measure annotation label /// Gets the resolved location for a vertical measure annotation label
@ -920,7 +912,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
switch (calculatedLabelPosition) { switch (calculatedLabelPosition) {
case AnnotationLabelPosition.margin: case AnnotationLabelPosition.margin:
case AnnotationLabelPosition.auto: case AnnotationLabelPosition.auto:
throw new ArgumentError(_unresolvedAutoMessage); throw ArgumentError(_unresolvedAutoMessage);
break; break;
case AnnotationLabelPosition.outside: case AnnotationLabelPosition.outside:
@ -944,7 +936,7 @@ class _RangeAnnotationLayoutView<D> extends LayoutView {
break; break;
} }
return new Point<int>(labelX.round(), labelY.round()); return Point<int>(labelX.round(), labelY.round());
} }
/// Resolves [AnnotationLabelPosition.auto] configuration for an annotation /// Resolves [AnnotationLabelPosition.auto] configuration for an annotation
@ -1014,7 +1006,7 @@ class _DatumAnnotation {
factory _DatumAnnotation.from(_DatumAnnotation other, factory _DatumAnnotation.from(_DatumAnnotation other,
[double startPosition, double endPosition]) { [double startPosition, double endPosition]) {
return new _DatumAnnotation( return _DatumAnnotation(
startPosition: startPosition ?? other.startPosition, startPosition: startPosition ?? other.startPosition,
endPosition: endPosition ?? other.endPosition, endPosition: endPosition ?? other.endPosition,
axisType: other.axisType); axisType: other.axisType);
@ -1035,9 +1027,9 @@ class _AnnotationElement<D> {
double strokeWidthPx; double strokeWidthPx;
_AnnotationElement<D> clone() { _AnnotationElement<D> clone() {
return new _AnnotationElement<D>() return _AnnotationElement<D>()
..annotation = new _DatumAnnotation.from(annotation) ..annotation = _DatumAnnotation.from(annotation)
..color = color != null ? new Color.fromOther(color: color) : null ..color = color != null ? Color.fromOther(color: color) : null
..startLabel = this.startLabel ..startLabel = this.startLabel
..endLabel = this.endLabel ..endLabel = this.endLabel
..isRange = this.isRange ..isRange = this.isRange
@ -1065,7 +1057,7 @@ class _AnnotationElement<D> {
previousAnnotation.endPosition; previousAnnotation.endPosition;
annotation = annotation =
new _DatumAnnotation.from(targetAnnotation, startPosition, endPosition); _DatumAnnotation.from(targetAnnotation, startPosition, endPosition);
color = getAnimatedColor(previous.color, target.color, animationPercent); color = getAnimatedColor(previous.color, target.color, animationPercent);
@ -1128,7 +1120,7 @@ class RangeAnnotationTester<D> {
RangeAnnotationTester(this.behavior); RangeAnnotationTester(this.behavior);
set graphicsFactory(GraphicsFactory value) { set graphicsFactory(GraphicsFactory value) {
behavior._view._graphicsFactory = value; behavior._view.graphicsFactory = value;
} }
mockLayout(Rectangle<int> bounds) { mockLayout(Rectangle<int> bounds) {
@ -1148,7 +1140,7 @@ class RangeAnnotationTester<D> {
AnnotationLabelPosition labelPosition}) { AnnotationLabelPosition labelPosition}) {
var exists = false; var exists = false;
behavior._annotationMap.forEach((String key, _AnimatedAnnotation<D> a) { behavior._annotationMap.forEach((key, a) {
final currentAnnotation = a._currentAnnotation; final currentAnnotation = a._currentAnnotation;
final annotation = currentAnnotation.annotation; final annotation = currentAnnotation.annotation;
@ -1222,7 +1214,7 @@ class RangeAnnotationSegment<D> extends AnnotationSegment<D> {
labelStyleSpec: labelStyleSpec); labelStyleSpec: labelStyleSpec);
@override @override
String get key => 'r::${axisType}::${axisId}::${startValue}::${endValue}'; String get key => 'r::$axisType::$axisId::$startValue::$endValue';
} }
/// Data for a chart line annotation. /// Data for a chart line annotation.
@ -1253,7 +1245,7 @@ class LineAnnotationSegment<D> extends AnnotationSegment<D> {
labelStyleSpec: labelStyleSpec); labelStyleSpec: labelStyleSpec);
@override @override
String get key => 'l::${axisType}::${axisId}::${value}'; String get key => 'l::$axisType::$axisId::$value';
} }
/// Axis type for an annotation. /// Axis type for an annotation.

@ -47,11 +47,10 @@ class LockSelection<D> implements ChartBehavior<D> {
// Setup the appropriate gesture listening. // Setup the appropriate gesture listening.
switch (this.eventTrigger) { switch (this.eventTrigger) {
case SelectionTrigger.tap: case SelectionTrigger.tap:
_listener = _listener = GestureListener(onTapTest: _onTapTest, onTap: _onSelect);
new GestureListener(onTapTest: _onTapTest, onTap: _onSelect);
break; break;
default: default:
throw new ArgumentError('LockSelection does not support the event ' throw ArgumentError('LockSelection does not support the event '
'trigger "${this.eventTrigger}"'); 'trigger "${this.eventTrigger}"');
break; break;
} }

@ -107,11 +107,10 @@ class SelectNearest<D> implements ChartBehavior<D> {
// Setup the appropriate gesture listening. // Setup the appropriate gesture listening.
switch (this.eventTrigger) { switch (this.eventTrigger) {
case SelectionTrigger.tap: case SelectionTrigger.tap:
_listener = _listener = GestureListener(onTapTest: _onTapTest, onTap: _onSelect);
new GestureListener(onTapTest: _onTapTest, onTap: _onSelect);
break; break;
case SelectionTrigger.tapAndDrag: case SelectionTrigger.tapAndDrag:
_listener = new GestureListener( _listener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onTap: _onSelect, onTap: _onSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -119,7 +118,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
); );
break; break;
case SelectionTrigger.pressHold: case SelectionTrigger.pressHold:
_listener = new GestureListener( _listener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onLongPress: _onSelect, onLongPress: _onSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -127,7 +126,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
onDragEnd: _onDeselectAll); onDragEnd: _onDeselectAll);
break; break;
case SelectionTrigger.longPressHold: case SelectionTrigger.longPressHold:
_listener = new GestureListener( _listener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onLongPress: _onLongPressSelect, onLongPress: _onLongPressSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -136,7 +135,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
break; break;
case SelectionTrigger.hover: case SelectionTrigger.hover:
default: default:
_listener = new GestureListener(onHover: _onSelect); _listener = GestureListener(onHover: _onSelect);
break; break;
} }
} }
@ -171,11 +170,10 @@ class SelectNearest<D> implements ChartBehavior<D> {
details[0].domainDistance <= maximumDomainDistancePx) { details[0].domainDistance <= maximumDomainDistancePx) {
seriesDatumList = expandToDomain seriesDatumList = expandToDomain
? _expandToDomain(details.first) ? _expandToDomain(details.first)
: [new SeriesDatum<D>(details.first.series, details.first.datum)]; : [SeriesDatum<D>(details.first.series, details.first.datum)];
// Filter out points from overlay series. // Filter out points from overlay series.
seriesDatumList seriesDatumList.removeWhere((datum) => datum.series.overlaySeries);
.removeWhere((SeriesDatum<D> datum) => datum.series.overlaySeries);
if (selectClosestSeries && seriesList.isEmpty) { if (selectClosestSeries && seriesList.isEmpty) {
if (details.first.series.overlaySeries) { if (details.first.series.overlaySeries) {
@ -184,7 +182,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
// copy of the list by domain distance because we do not want to // copy of the list by domain distance because we do not want to
// re-order the actual return values here. // re-order the actual return values here.
final sortedSeriesDatumList = final sortedSeriesDatumList =
new List<SeriesDatum<D>>.from(seriesDatumList); List<SeriesDatum<D>>.from(seriesDatumList);
sortedSeriesDatumList.sort((a, b) => sortedSeriesDatumList.sort((a, b) =>
a.datum.domainDistance.compareTo(b.datum.domainDistance)); a.datum.domainDistance.compareTo(b.datum.domainDistance));
seriesList.add(sortedSeriesDatumList.first.series); seriesList.add(sortedSeriesDatumList.first.series);
@ -215,7 +213,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
List<SeriesDatum<D>> _expandToDomain(DatumDetails<D> nearestDetails) { List<SeriesDatum<D>> _expandToDomain(DatumDetails<D> nearestDetails) {
// Make sure that the "nearest" datum is at the top of the list. // Make sure that the "nearest" datum is at the top of the list.
final data = <SeriesDatum<D>>[ final data = <SeriesDatum<D>>[
new SeriesDatum(nearestDetails.series, nearestDetails.datum) SeriesDatum(nearestDetails.series, nearestDetails.datum)
]; ];
final nearestDomain = nearestDetails.domain; final nearestDomain = nearestDetails.domain;
@ -236,7 +234,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
} }
if (domain == nearestDomain) { if (domain == nearestDomain) {
data.add(new SeriesDatum(series, datum)); data.add(SeriesDatum(series, datum));
} else if (testBounds) { } else if (testBounds) {
final domainLowerBound = domainLowerBoundFn(i); final domainLowerBound = domainLowerBoundFn(i);
final domainUpperBound = domainUpperBoundFn(i); final domainUpperBound = domainUpperBoundFn(i);
@ -261,7 +259,7 @@ class SelectNearest<D> implements ChartBehavior<D> {
} }
if (addDatum) { if (addDatum) {
data.add(new SeriesDatum(series, datum)); data.add(SeriesDatum(series, datum));
} }
} }
} }

@ -153,9 +153,9 @@ class Slider<D> implements ChartBehavior<D> {
this.snapToDatum = false, this.snapToDatum = false,
SliderStyle style, SliderStyle style,
this.layoutPaintOrder = LayoutViewPaintOrder.slider}) { this.layoutPaintOrder = LayoutViewPaintOrder.slider}) {
_handleRenderer = handleRenderer ?? new RectSymbolRenderer(); _handleRenderer = handleRenderer ?? RectSymbolRenderer();
_roleId = roleId ?? ''; _roleId = roleId ?? '';
_style = style ?? new SliderStyle(); _style = style ?? SliderStyle();
_domainValue = initialDomainValue; _domainValue = initialDomainValue;
if (_domainValue != null) { if (_domainValue != null) {
@ -165,7 +165,7 @@ class Slider<D> implements ChartBehavior<D> {
// Setup the appropriate gesture listening. // Setup the appropriate gesture listening.
switch (this.eventTrigger) { switch (this.eventTrigger) {
case SelectionTrigger.tapAndDrag: case SelectionTrigger.tapAndDrag:
_gestureListener = new GestureListener( _gestureListener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onTap: _onSelect, onTap: _onSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -173,7 +173,7 @@ class Slider<D> implements ChartBehavior<D> {
onDragEnd: _onDragEnd); onDragEnd: _onDragEnd);
break; break;
case SelectionTrigger.pressHold: case SelectionTrigger.pressHold:
_gestureListener = new GestureListener( _gestureListener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onLongPress: _onSelect, onLongPress: _onSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -181,7 +181,7 @@ class Slider<D> implements ChartBehavior<D> {
onDragEnd: _onDragEnd); onDragEnd: _onDragEnd);
break; break;
case SelectionTrigger.longPressHold: case SelectionTrigger.longPressHold:
_gestureListener = new GestureListener( _gestureListener = GestureListener(
onTapTest: _onTapTest, onTapTest: _onTapTest,
onLongPress: _onLongPressSelect, onLongPress: _onLongPressSelect,
onDragStart: _onSelect, onDragStart: _onSelect,
@ -189,21 +189,20 @@ class Slider<D> implements ChartBehavior<D> {
onDragEnd: _onDragEnd); onDragEnd: _onDragEnd);
break; break;
default: default:
throw new ArgumentError('Slider does not support the event trigger ' throw ArgumentError('Slider does not support the event trigger '
'"${this.eventTrigger}"'); '"${this.eventTrigger}"');
break; break;
} }
// Set up chart draw cycle listeners. // Set up chart draw cycle listeners.
_lifecycleListener = new LifecycleListener<D>( _lifecycleListener = LifecycleListener<D>(
onData: _setInitialDragState, onData: _setInitialDragState,
onAxisConfigured: _updateViewData, onAxisConfigured: _updateViewData,
onPostrender: _fireChangeEvent, onPostrender: _fireChangeEvent,
); );
// Set up slider event listeners. // Set up slider event listeners.
_sliderEventListener = _sliderEventListener = SliderEventListener<D>(onChange: onChangeCallback);
new SliderEventListener<D>(onChange: onChangeCallback);
} }
bool _onTapTest(Point<double> chartPoint) { bool _onTapTest(Point<double> chartPoint) {
@ -286,7 +285,7 @@ class Slider<D> implements ChartBehavior<D> {
} }
void _updateViewData() { void _updateViewData() {
_sliderHandle ??= new _AnimatedSlider(); _sliderHandle ??= _AnimatedSlider();
// If not set in the constructor, initial position for the handle is the // If not set in the constructor, initial position for the handle is the
// center of the draw area. // center of the draw area.
@ -299,10 +298,10 @@ class Slider<D> implements ChartBehavior<D> {
_moveSliderToDomain(_domainValue); _moveSliderToDomain(_domainValue);
// Move the handle to the current event position. // Move the handle to the current event position.
final element = new _SliderElement() final element = _SliderElement()
..domainCenterPoint = ..domainCenterPoint =
new Point<int>(_domainCenterPoint.x, _domainCenterPoint.y) Point<int>(_domainCenterPoint.x, _domainCenterPoint.y)
..buttonBounds = new Rectangle<int>(_handleBounds.left, _handleBounds.top, ..buttonBounds = Rectangle<int>(_handleBounds.left, _handleBounds.top,
_handleBounds.width, _handleBounds.height) _handleBounds.width, _handleBounds.height)
..fill = _style.fillColor ..fill = _style.fillColor
..stroke = _style.strokeColor ..stroke = _style.strokeColor
@ -342,7 +341,7 @@ class Slider<D> implements ChartBehavior<D> {
// Fire the event. // Fire the event.
_sliderEventListener.onChange( _sliderEventListener.onChange(
new Point<int>(_domainCenterPoint.x, _domainCenterPoint.y), Point<int>(_domainCenterPoint.x, _domainCenterPoint.y),
_domainValue, _domainValue,
_roleId, _roleId,
dragState); dragState);
@ -378,10 +377,9 @@ class Slider<D> implements ChartBehavior<D> {
_domainValue = _chart.domainAxis.getDomain(position.toDouble()); _domainValue = _chart.domainAxis.getDomain(position.toDouble());
if (_domainCenterPoint != null) { if (_domainCenterPoint != null) {
_domainCenterPoint = _domainCenterPoint = Point<int>(position.round(), _domainCenterPoint.y);
new Point<int>(position.round(), _domainCenterPoint.y);
} else { } else {
_domainCenterPoint = new Point<int>( _domainCenterPoint = Point<int>(
position.round(), (viewBounds.top + viewBounds.height / 2).round()); position.round(), (viewBounds.top + viewBounds.height / 2).round());
} }
@ -394,12 +392,12 @@ class Slider<D> implements ChartBehavior<D> {
handleReferenceY = viewBounds.top; handleReferenceY = viewBounds.top;
break; break;
default: default:
throw new ArgumentError('Slider does not support the handle position ' throw ArgumentError('Slider does not support the handle position '
'"${_style.handlePosition}"'); '"${_style.handlePosition}"');
} }
// Move the slider handle along the domain axis. // Move the slider handle along the domain axis.
_handleBounds = new Rectangle<int>( _handleBounds = Rectangle<int>(
(_domainCenterPoint.x - (_domainCenterPoint.x -
_style.handleSize.width / 2 + _style.handleSize.width / 2 +
_style.handleOffset.x) _style.handleOffset.x)
@ -432,7 +430,7 @@ class Slider<D> implements ChartBehavior<D> {
bool _moveSliderToDomain(D domain) { bool _moveSliderToDomain(D domain) {
final x = _chart.domainAxis.getLocation(domain); final x = _chart.domainAxis.getLocation(domain);
return _moveSliderToPoint(new Point<double>(x, 0.0)); return _moveSliderToPoint(Point<double>(x, 0.0));
} }
/// Programmatically moves the slider to the location of [domain] on the /// Programmatically moves the slider to the location of [domain] on the
@ -470,8 +468,7 @@ class Slider<D> implements ChartBehavior<D> {
@override @override
void attachTo(BaseChart<D> chart) { void attachTo(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError('Slider can only be attached to a cartesian chart.');
'Slider can only be attached to a cartesian chart.');
} }
_chart = chart as CartesianChart; _chart = chart as CartesianChart;
@ -479,7 +476,7 @@ class Slider<D> implements ChartBehavior<D> {
// Only vertical rendering is supported by this behavior. // Only vertical rendering is supported by this behavior.
assert(_chart.vertical); assert(_chart.vertical);
_view = new _SliderLayoutView<D>( _view = _SliderLayoutView<D>(
layoutPaintOrder: layoutPaintOrder, handleRenderer: _handleRenderer); layoutPaintOrder: layoutPaintOrder, handleRenderer: _handleRenderer);
chart.addView(_view); chart.addView(_view);
@ -496,7 +493,7 @@ class Slider<D> implements ChartBehavior<D> {
} }
@override @override
String get role => 'Slider-${eventTrigger.toString()}-${_roleId}'; String get role => 'Slider-${eventTrigger.toString()}-$_roleId';
} }
/// Style configuration for a [Slider] behavior. /// Style configuration for a [Slider] behavior.
@ -572,7 +569,7 @@ class _SliderLayoutView<D> extends LayoutView {
Rectangle<int> get drawBounds => _drawAreaBounds; Rectangle<int> get drawBounds => _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
/// Renderer for the handle. Defaults to a rectangle. /// Renderer for the handle. Defaults to a rectangle.
SymbolRenderer _handleRenderer; SymbolRenderer _handleRenderer;
@ -582,7 +579,7 @@ class _SliderLayoutView<D> extends LayoutView {
_SliderLayoutView( _SliderLayoutView(
{@required int layoutPaintOrder, @required SymbolRenderer handleRenderer}) {@required int layoutPaintOrder, @required SymbolRenderer handleRenderer})
: this.layoutConfig = new LayoutViewConfig( : this.layoutConfig = LayoutViewConfig(
paintOrder: layoutPaintOrder, paintOrder: layoutPaintOrder,
position: LayoutPosition.DrawArea, position: LayoutPosition.DrawArea,
positionOrder: LayoutViewPositionOrder.drawArea), positionOrder: LayoutViewPositionOrder.drawArea),
@ -592,14 +589,6 @@ class _SliderLayoutView<D> extends LayoutView {
_sliderHandle = value; _sliderHandle = value;
} }
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override @override
ViewMeasuredSizes measure(int maxWidth, int maxHeight) { ViewMeasuredSizes measure(int maxWidth, int maxHeight) {
return null; return null;
@ -616,10 +605,8 @@ class _SliderLayoutView<D> extends LayoutView {
canvas.drawLine( canvas.drawLine(
points: [ points: [
new Point<num>( Point<num>(sliderElement.domainCenterPoint.x, _drawAreaBounds.top),
sliderElement.domainCenterPoint.x, _drawAreaBounds.top), Point<num>(sliderElement.domainCenterPoint.x, _drawAreaBounds.bottom),
new Point<num>(
sliderElement.domainCenterPoint.x, _drawAreaBounds.bottom),
], ],
stroke: sliderElement.stroke, stroke: sliderElement.stroke,
strokeWidthPx: sliderElement.strokeWidthPx); strokeWidthPx: sliderElement.strokeWidthPx);
@ -646,7 +633,7 @@ class _SliderElement<D> {
double strokeWidthPx; double strokeWidthPx;
_SliderElement<D> clone() { _SliderElement<D> clone() {
return new _SliderElement<D>() return _SliderElement<D>()
..domainCenterPoint = this.domainCenterPoint ..domainCenterPoint = this.domainCenterPoint
..buttonBounds = this.buttonBounds ..buttonBounds = this.buttonBounds
..fill = this.fill ..fill = this.fill
@ -668,7 +655,7 @@ class _SliderElement<D> {
final y = ((targetPoint.y - previousPoint.y) * animationPercent) + final y = ((targetPoint.y - previousPoint.y) * animationPercent) +
previousPoint.y; previousPoint.y;
domainCenterPoint = new Point<int>(x.round(), y.round()); domainCenterPoint = Point<int>(x.round(), y.round());
final previousBounds = localPrevious.buttonBounds; final previousBounds = localPrevious.buttonBounds;
final targetBounds = localTarget.buttonBounds; final targetBounds = localTarget.buttonBounds;
@ -685,7 +672,7 @@ class _SliderElement<D> {
((targetBounds.left - previousBounds.left) * animationPercent) + ((targetBounds.left - previousBounds.left) * animationPercent) +
previousBounds.left; previousBounds.left;
buttonBounds = new Rectangle<int>(left.round(), top.round(), buttonBounds = Rectangle<int>(left.round(), top.round(),
(right - left).round(), (bottom - top).round()); (right - left).round(), (bottom - top).round());
fill = getAnimatedColor(previous.fill, target.fill, animationPercent); fill = getAnimatedColor(previous.fill, target.fill, animationPercent);
@ -726,7 +713,7 @@ class _AnimatedSlider<D> {
final bottom = targetBounds.bottom; final bottom = targetBounds.bottom;
final left = right; final left = right;
newTarget.buttonBounds = new Rectangle<int>(left.round(), top.round(), newTarget.buttonBounds = Rectangle<int>(left.round(), top.round(),
(right - left).round(), (bottom - top).round()); (right - left).round(), (bottom - top).round());
// Animate the stroke width to 0 so that we don't get a lingering line after // Animate the stroke width to 0 so that we don't get a lingering line after
@ -775,8 +762,8 @@ class SliderEventListener<D> {
/// [domain] is the domain value at the slider position. /// [domain] is the domain value at the slider position.
/// ///
/// [dragState] indicates the current state of a drag event. /// [dragState] indicates the current state of a drag event.
typedef SliderListenerCallback<D>(Point<int> point, D domain, String roleId, typedef SliderListenerCallback<D> = Function(Point<int> point, D domain,
SliderListenerDragState dragState); String roleId, SliderListenerDragState dragState);
/// Describes the current state of a slider change as a result of a drag event. /// Describes the current state of a slider change as a result of a drag event.
/// ///

@ -43,7 +43,7 @@ abstract class InitialHintBehavior<D> implements ChartBehavior<D> {
@protected @protected
CartesianChart<D> get chart => _chart; CartesianChart<D> get chart => _chart;
Duration _hintDuration = new Duration(milliseconds: 3000); Duration _hintDuration = Duration(milliseconds: 3000);
/// The amount of time to animate to the desired viewport. /// The amount of time to animate to the desired viewport.
/// ///
@ -104,9 +104,9 @@ abstract class InitialHintBehavior<D> implements ChartBehavior<D> {
double _targetViewportScalingFactor; double _targetViewportScalingFactor;
InitialHintBehavior() { InitialHintBehavior() {
_listener = new GestureListener(onTapTest: onTapTest); _listener = GestureListener(onTapTest: onTapTest);
_lifecycleListener = new LifecycleListener<D>( _lifecycleListener = LifecycleListener<D>(
onAxisConfigured: _onAxisConfigured, onAxisConfigured: _onAxisConfigured,
onAnimationComplete: _onAnimationComplete); onAnimationComplete: _onAnimationComplete);
} }
@ -114,7 +114,7 @@ abstract class InitialHintBehavior<D> implements ChartBehavior<D> {
@override @override
attachTo(BaseChart<D> chart) { attachTo(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'InitialHintBehavior can only be attached to a CartesianChart'); 'InitialHintBehavior can only be attached to a CartesianChart');
} }
@ -127,7 +127,7 @@ abstract class InitialHintBehavior<D> implements ChartBehavior<D> {
@override @override
removeFrom(BaseChart<D> chart) { removeFrom(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'InitialHintBehavior can only be removed from a CartesianChart'); 'InitialHintBehavior can only be removed from a CartesianChart');
} }

@ -68,7 +68,7 @@ class PanBehavior<D> implements ChartBehavior<D> {
} }
PanBehavior() { PanBehavior() {
_listener = new GestureListener( _listener = GestureListener(
onTapTest: onTapTest, onTapTest: onTapTest,
onDragStart: onDragStart, onDragStart: onDragStart,
onDragUpdate: onDragUpdate, onDragUpdate: onDragUpdate,
@ -79,7 +79,7 @@ class PanBehavior<D> implements ChartBehavior<D> {
@override @override
attachTo(BaseChart<D> chart) { attachTo(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'PanBehavior can only be attached to a CartesianChart'); 'PanBehavior can only be attached to a CartesianChart');
} }
@ -91,7 +91,7 @@ class PanBehavior<D> implements ChartBehavior<D> {
// Wrap domain axis tick provider with the panning behavior one. // Wrap domain axis tick provider with the panning behavior one.
_domainAxisTickProvider = _domainAxisTickProvider =
new PanningTickProvider<D>(_chart.domainAxis.tickProvider); PanningTickProvider<D>(_chart.domainAxis.tickProvider);
_chart.domainAxis.tickProvider = _domainAxisTickProvider; _chart.domainAxis.tickProvider = _domainAxisTickProvider;
} }
@ -99,7 +99,7 @@ class PanBehavior<D> implements ChartBehavior<D> {
@override @override
removeFrom(BaseChart<D> chart) { removeFrom(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'PanBehavior can only be attached to a CartesianChart'); 'PanBehavior can only be attached to a CartesianChart');
} }
@ -218,4 +218,4 @@ class PanBehavior<D> implements ChartBehavior<D> {
} }
/// Callback for when panning is completed. /// Callback for when panning is completed.
typedef void PanningCompletedCallback(); typedef PanningCompletedCallback = void Function();

@ -64,7 +64,7 @@ class PanningTickProvider<D> implements TickProvider<D> {
TickHint<D> tickHint, TickHint<D> tickHint,
}) { }) {
if (_mode == PanningTickProviderMode.stepSizeLocked) { if (_mode == PanningTickProviderMode.stepSizeLocked) {
tickHint = new TickHint( tickHint = TickHint(
_ticks.first.value, _ticks.first.value,
_ticks.last.value, _ticks.last.value,
tickCount: _ticks.length, tickCount: _ticks.length,

@ -72,9 +72,9 @@ class CanvasBarStack {
final width = right - left; final width = right - left;
final height = bottom - top; final height = bottom - top;
final fullStackRect = new Rectangle(left, top, width, height); final fullStackRect = Rectangle(left, top, width, height);
return new CanvasBarStack._internal( return CanvasBarStack._internal(
segments, segments,
radius: radius, radius: radius,
stackedBarPadding: stackedBarPadding, stackedBarPadding: stackedBarPadding,

@ -151,7 +151,7 @@ Color getAnimatedColor(Color previous, Color target, double animationPercent) {
var b = (((target.b - previous.b) * animationPercent) + previous.b).round(); var b = (((target.b - previous.b) * animationPercent) + previous.b).round();
var a = (((target.a - previous.a) * animationPercent) + previous.a).round(); var a = (((target.a - previous.a) * animationPercent) + previous.a).round();
return new Color(a: a, r: r, g: g, b: b); return Color(a: a, r: r, g: g, b: b);
} }
/// Defines the pattern for a color fill. /// Defines the pattern for a color fill.

@ -19,8 +19,8 @@ import '../../common/color.dart' show Color;
import '../../common/symbol_renderer.dart' show SymbolRenderer; import '../../common/symbol_renderer.dart' show SymbolRenderer;
import 'processed_series.dart' show ImmutableSeries; import 'processed_series.dart' show ImmutableSeries;
typedef String DomainFormatter<D>(D domain); typedef DomainFormatter<D> = String Function(D domain);
typedef String MeasureFormatter(num measure); typedef MeasureFormatter = String Function(num measure);
/// Represents processed rendering details for a data point from a series. /// Represents processed rendering details for a data point from a series.
class DatumDetails<D> { class DatumDetails<D> {
@ -183,7 +183,7 @@ class DatumDetails<D> {
double radiusPx, double radiusPx,
SymbolRenderer symbolRenderer, SymbolRenderer symbolRenderer,
double strokeWidthPx}) { double strokeWidthPx}) {
return new DatumDetails<D>( return DatumDetails<D>(
datum: datum ?? other.datum, datum: datum ?? other.datum,
index: index ?? other.index, index: index ?? other.index,
domain: domain ?? other.domain, domain: domain ?? other.domain,

@ -56,7 +56,7 @@ class MutableSeries<D> extends ImmutableSeries<D> {
AccessorFn<TextStyleSpec> insideLabelStyleAccessorFn; AccessorFn<TextStyleSpec> insideLabelStyleAccessorFn;
AccessorFn<TextStyleSpec> outsideLabelStyleAccessorFn; AccessorFn<TextStyleSpec> outsideLabelStyleAccessorFn;
final _attrs = new SeriesAttributes(); final _attrs = SeriesAttributes();
Axis measureAxis; Axis measureAxis;
Axis domainAxis; Axis domainAxis;

@ -48,8 +48,8 @@ class SelectionModel<D> {
/// Create a deep copy of the selection model. /// Create a deep copy of the selection model.
SelectionModel.fromOther(SelectionModel<D> other) { SelectionModel.fromOther(SelectionModel<D> other) {
_selectedDatum = new List.from(other._selectedDatum); _selectedDatum = List.from(other._selectedDatum);
_selectedSeries = new List.from(other._selectedSeries); _selectedSeries = List.from(other._selectedSeries);
} }
/// Create selection model from configuration. /// Create selection model from configuration.
@ -64,8 +64,8 @@ class SelectionModel<D> {
} }
// Add to list of selected series. // Add to list of selected series.
_selectedSeries.addAll(seriesList.where((ImmutableSeries<D> series) => _selectedSeries.addAll(seriesList
selectedDataMap.keys.contains(series.id))); .where((series) => selectedDataMap.keys.contains(series.id)));
// Add to list of selected data. // Add to list of selected data.
for (ImmutableSeries<D> series in seriesList) { for (ImmutableSeries<D> series in seriesList) {
@ -76,7 +76,7 @@ class SelectionModel<D> {
final datum = series.data[i]; final datum = series.data[i];
if (selectedDataMap[series.id].contains(domainFn(i))) { if (selectedDataMap[series.id].contains(domainFn(i))) {
_selectedDatum.add(new SeriesDatum(series, datum)); _selectedDatum.add(SeriesDatum(series, datum));
} }
} }
} }
@ -86,11 +86,11 @@ class SelectionModel<D> {
// Add to list of selected series, if it does not already exist. // Add to list of selected series, if it does not already exist.
if (selectedSeriesConfig != null) { if (selectedSeriesConfig != null) {
final remainingSeriesToAdd = selectedSeriesConfig final remainingSeriesToAdd = selectedSeriesConfig
.where((String seriesId) => !selectedSeries.contains(seriesId)) .where((seriesId) => !selectedSeries.contains(seriesId))
.toList(); .toList();
_selectedSeries.addAll(seriesList.where((ImmutableSeries<D> series) => _selectedSeries.addAll(seriesList
remainingSeriesToAdd.contains(series.id))); .where((series) => remainingSeriesToAdd.contains(series.id)));
} }
} }
@ -99,14 +99,13 @@ class SelectionModel<D> {
bool isDatumSelected(ImmutableSeries<D> series, int index) { bool isDatumSelected(ImmutableSeries<D> series, int index) {
final datum = index == null ? null : series.data[index]; final datum = index == null ? null : series.data[index];
return _selectedDatum.contains(new SeriesDatum(series, datum)); return _selectedDatum.contains(SeriesDatum(series, datum));
} }
/// Returns the selected [SeriesDatum] for this [SelectionModel]. /// Returns the selected [SeriesDatum] for this [SelectionModel].
/// ///
/// This is empty by default. /// This is empty by default.
List<SeriesDatum<D>> get selectedDatum => List<SeriesDatum<D>> get selectedDatum => List.unmodifiable(_selectedDatum);
new List.unmodifiable(_selectedDatum);
/// Returns true if this [SelectionModel] has a selected series. /// Returns true if this [SelectionModel] has a selected series.
bool get hasSeriesSelection => _selectedSeries.isNotEmpty; bool get hasSeriesSelection => _selectedSeries.isNotEmpty;
@ -115,7 +114,7 @@ class SelectionModel<D> {
/// ///
/// This is empty by default. /// This is empty by default.
List<ImmutableSeries<D>> get selectedSeries => List<ImmutableSeries<D>> get selectedSeries =>
new List.unmodifiable(_selectedSeries); List.unmodifiable(_selectedSeries);
/// Returns true if this [SelectionModel] has a selected datum or series. /// Returns true if this [SelectionModel] has a selected datum or series.
bool get hasAnySelection => bool get hasAnySelection =>
@ -124,14 +123,14 @@ class SelectionModel<D> {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is SelectionModel && return other is SelectionModel &&
new ListEquality().equals(_selectedDatum, other.selectedDatum) && ListEquality().equals(_selectedDatum, other.selectedDatum) &&
new ListEquality().equals(_selectedSeries, other.selectedSeries); ListEquality().equals(_selectedSeries, other.selectedSeries);
} }
@override @override
int get hashCode { int get hashCode {
int hashcode = new ListEquality().hash(_selectedDatum); int hashcode = ListEquality().hash(_selectedDatum);
hashcode = hashcode * 37 + new ListEquality().hash(_selectedSeries); hashcode = hashcode * 37 + ListEquality().hash(_selectedSeries);
return hashcode; return hashcode;
} }
} }
@ -168,12 +167,11 @@ class MutableSelectionModel<D> extends SelectionModel<D> {
_selectedSeries = seriesList; _selectedSeries = seriesList;
// Provide a copy, so listeners get an immutable model. // Provide a copy, so listeners get an immutable model.
final copyOfSelectionModel = new SelectionModel.fromOther(this); final copyOfSelectionModel = SelectionModel.fromOther(this);
_updatedListeners.forEach((listener) => listener(copyOfSelectionModel)); _updatedListeners.forEach((listener) => listener(copyOfSelectionModel));
final changed = final changed = !ListEquality().equals(origSelectedDatum, _selectedDatum) ||
!new ListEquality().equals(origSelectedDatum, _selectedDatum) || !ListEquality().equals(origSelectedSeries, _selectedSeries);
!new ListEquality().equals(origSelectedSeries, _selectedSeries);
if (notifyListeners && changed) { if (notifyListeners && changed) {
_changedListeners.forEach((listener) => listener(copyOfSelectionModel)); _changedListeners.forEach((listener) => listener(copyOfSelectionModel));
} }
@ -220,7 +218,7 @@ class MutableSelectionModel<D> extends SelectionModel<D> {
/// Callback for SelectionModel. It is triggered when the selection state /// Callback for SelectionModel. It is triggered when the selection state
/// changes. /// changes.
typedef SelectionModelListener<D>(SelectionModel<D> model); typedef SelectionModelListener<D> = Function(SelectionModel<D> model);
enum SelectionModelType { enum SelectionModelType {
/// Typical Hover or Details event for viewing the details of the selected /// Typical Hover or Details event for viewing the details of the selected

@ -41,10 +41,10 @@ import 'series_datum.dart' show SeriesDatum;
/// [rendererIdKey] can be added as an attribute to user-defined [Series] /// [rendererIdKey] can be added as an attribute to user-defined [Series]
/// objects. /// objects.
const AttributeKey<String> rendererIdKey = const AttributeKey<String> rendererIdKey =
const AttributeKey<String>('SeriesRenderer.rendererId'); AttributeKey<String>('SeriesRenderer.rendererId');
const AttributeKey<SeriesRenderer> rendererKey = const AttributeKey<SeriesRenderer> rendererKey =
const AttributeKey<SeriesRenderer>('SeriesRenderer.renderer'); AttributeKey<SeriesRenderer>('SeriesRenderer.renderer');
/// A series renderer draws one or more series of data onto a chart canvas. /// A series renderer draws one or more series of data onto a chart canvas.
abstract class SeriesRenderer<D> extends LayoutView { abstract class SeriesRenderer<D> extends LayoutView {
@ -142,25 +142,17 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
Rectangle<int> get drawBounds => _drawAreaBounds; Rectangle<int> get drawBounds => _drawAreaBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
BaseSeriesRenderer({ BaseSeriesRenderer({
@required this.rendererId, @required this.rendererId,
@required int layoutPaintOrder, @required int layoutPaintOrder,
this.symbolRenderer, this.symbolRenderer,
}) : this.layoutConfig = new LayoutViewConfig( }) : this.layoutConfig = LayoutViewConfig(
paintOrder: layoutPaintOrder, paintOrder: layoutPaintOrder,
position: LayoutPosition.DrawArea, position: LayoutPosition.DrawArea,
positionOrder: LayoutViewPositionOrder.drawArea); positionOrder: LayoutViewPositionOrder.drawArea);
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
@override @override
void onAttach(BaseChart<D> chart) {} void onAttach(BaseChart<D> chart) {}
@ -185,7 +177,7 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
int maxMissing = 0; int maxMissing = 0;
bool hasSpecifiedCategory = false; bool hasSpecifiedCategory = false;
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
if (series.colorFn == null) { if (series.colorFn == null) {
// If there is no category, give it a default category to match logic. // If there is no category, give it a default category to match logic.
String category = series.seriesCategory; String category = series.seriesCategory;
@ -208,7 +200,7 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
if (!emptyCategoryUsesSinglePalette && !hasSpecifiedCategory) { if (!emptyCategoryUsesSinglePalette && !hasSpecifiedCategory) {
final palettes = StyleFactory.style.getOrderedPalettes(maxMissing); final palettes = StyleFactory.style.getOrderedPalettes(maxMissing);
int index = 0; int index = 0;
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
if (series.colorFn == null) { if (series.colorFn == null) {
final color = palettes[index % palettes.length].shadeDefault; final color = palettes[index % palettes.length].shadeDefault;
index++; index++;
@ -227,7 +219,7 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
// the max for any category to ensure that the gradients look appropriate. // the max for any category to ensure that the gradients look appropriate.
final colorsByCategory = <String, List<Color>>{}; final colorsByCategory = <String, List<Color>>{};
int index = 0; int index = 0;
missingColorCountPerCategory.keys.forEach((String category) { missingColorCountPerCategory.keys.forEach((category) {
colorsByCategory[category] = colorsByCategory[category] =
colorPalettes[index % colorPalettes.length].makeShades(maxMissing); colorPalettes[index % colorPalettes.length].makeShades(maxMissing);
index++; index++;
@ -236,7 +228,7 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
missingColorCountPerCategory[category] = 0; missingColorCountPerCategory[category] = 0;
}); });
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
if (series.colorFn == null) { if (series.colorFn == null) {
final category = series.seriesCategory ?? defaultCategory; final category = series.seriesCategory ?? defaultCategory;
@ -249,12 +241,12 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
} }
// Fill color defaults to the series color if no accessor is provided. // Fill color defaults to the series color if no accessor is provided.
series.fillColorFn ??= (int index) => series.colorFn(index); series.fillColorFn ??= (index) => series.colorFn(index);
}); });
} else { } else {
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
// Fill color defaults to the series color if no accessor is provided. // Fill color defaults to the series color if no accessor is provided.
series.fillColorFn ??= (int index) => series.colorFn(index); series.fillColorFn ??= (index) => series.colorFn(index);
}); });
} }
} }
@ -346,7 +338,7 @@ abstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {
var strokeWidthPx = strokeWidthPxFn != null ? strokeWidthPxFn(index) : null; var strokeWidthPx = strokeWidthPxFn != null ? strokeWidthPxFn(index) : null;
strokeWidthPx = strokeWidthPx?.toDouble(); strokeWidthPx = strokeWidthPx?.toDouble();
final details = new DatumDetails<D>( final details = DatumDetails<D>(
datum: seriesDatum.datum, datum: seriesDatum.datum,
index: seriesDatum.index, index: seriesDatum.index,
domain: domainValue, domain: domainValue,

@ -35,7 +35,7 @@ class LayoutConfig {
/// Specs that applies to one margin. /// Specs that applies to one margin.
class MarginSpec { class MarginSpec {
/// [MarginSpec] that has max of 50 percent. /// [MarginSpec] that has max of 50 percent.
static const defaultSpec = const MarginSpec._internal(null, null, null, 50); static const defaultSpec = MarginSpec._internal(null, null, null, 50);
final int _minPixel; final int _minPixel;
final int _maxPixel; final int _maxPixel;
@ -64,7 +64,7 @@ class MarginSpec {
assert(minPixel <= maxPixel); assert(minPixel <= maxPixel);
} }
return new MarginSpec._internal(minPixel, maxPixel, null, null); return MarginSpec._internal(minPixel, maxPixel, null, null);
} }
/// Create [MarginSpec] with a fixed pixel size [pixels]. /// Create [MarginSpec] with a fixed pixel size [pixels].
@ -74,7 +74,7 @@ class MarginSpec {
// Require require or higher setting if set // Require require or higher setting if set
assert(pixels == null || pixels >= 0); assert(pixels == null || pixels >= 0);
return new MarginSpec._internal(pixels, pixels, null, null); return MarginSpec._internal(pixels, pixels, null, null);
} }
/// Create [MarginSpec] that specifies min/max percentage. /// Create [MarginSpec] that specifies min/max percentage.
@ -92,7 +92,7 @@ class MarginSpec {
assert(minPercent <= maxPercent); assert(minPercent <= maxPercent);
} }
return new MarginSpec._internal(null, null, minPercent, maxPercent); return MarginSpec._internal(null, null, minPercent, maxPercent);
} }
/// Get the min pixels, given the [totalPixels]. /// Get the min pixels, given the [totalPixels].

@ -53,7 +53,7 @@ class LayoutManagerImpl implements LayoutManager {
/// Create a new [LayoutManager]. /// Create a new [LayoutManager].
LayoutManagerImpl({LayoutConfig config}) LayoutManagerImpl({LayoutConfig config})
: this.config = config ?? new LayoutConfig(); : this.config = config ?? LayoutConfig();
/// Add one [LayoutView]. /// Add one [LayoutView].
void addView(LayoutView view) { void addView(LayoutView view) {
@ -79,9 +79,9 @@ class LayoutManagerImpl implements LayoutManager {
@override @override
List<LayoutView> get paintOrderedViews { List<LayoutView> get paintOrderedViews {
if (_viewsNeedPaintSort) { if (_viewsNeedPaintSort) {
_paintOrderedViews = new List<LayoutView>.from(_views); _paintOrderedViews = List<LayoutView>.from(_views);
_paintOrderedViews.sort((LayoutView v1, LayoutView v2) => _paintOrderedViews.sort((v1, v2) =>
v1.layoutConfig.paintOrder.compareTo(v2.layoutConfig.paintOrder)); v1.layoutConfig.paintOrder.compareTo(v2.layoutConfig.paintOrder));
_viewsNeedPaintSort = false; _viewsNeedPaintSort = false;
@ -93,10 +93,9 @@ class LayoutManagerImpl implements LayoutManager {
@override @override
List<LayoutView> get positionOrderedViews { List<LayoutView> get positionOrderedViews {
if (_viewsNeedPositionSort) { if (_viewsNeedPositionSort) {
_positionOrderedViews = new List<LayoutView>.from(_views); _positionOrderedViews = List<LayoutView>.from(_views);
_positionOrderedViews.sort((LayoutView v1, LayoutView v2) => v1 _positionOrderedViews.sort((v1, v2) => v1.layoutConfig.positionOrder
.layoutConfig.positionOrder
.compareTo(v2.layoutConfig.positionOrder)); .compareTo(v2.layoutConfig.positionOrder));
_viewsNeedPositionSort = false; _viewsNeedPositionSort = false;
@ -114,8 +113,7 @@ class LayoutManagerImpl implements LayoutManager {
Rectangle<int> get drawableLayoutAreaBounds { Rectangle<int> get drawableLayoutAreaBounds {
assert(_drawAreaBoundsOutdated == false); assert(_drawAreaBoundsOutdated == false);
final drawableViews = final drawableViews = _views.where((view) => view.isSeriesRenderer);
_views.where((LayoutView view) => view.isSeriesRenderer);
var componentBounds = drawableViews?.first?.componentBounds; var componentBounds = drawableViews?.first?.componentBounds;
@ -126,7 +124,7 @@ class LayoutManagerImpl implements LayoutManager {
} }
} }
} else { } else {
componentBounds = new Rectangle(0, 0, 0, 0); componentBounds = Rectangle(0, 0, 0, 0);
} }
return componentBounds; return componentBounds;
@ -226,8 +224,8 @@ class LayoutManagerImpl implements LayoutManager {
); );
// Bounds for the draw area. // Bounds for the draw area.
_drawAreaBounds = new Rectangle(measurements.leftWidth, _drawAreaBounds = Rectangle(measurements.leftWidth, measurements.topHeight,
measurements.topHeight, drawAreaWidth, drawAreaHeight); drawAreaWidth, drawAreaHeight);
_drawAreaBoundsOutdated = false; _drawAreaBoundsOutdated = false;
} }
@ -243,26 +241,26 @@ class LayoutManagerImpl implements LayoutManager {
_viewsForPositions(LayoutPosition.Left, LayoutPosition.FullLeft); _viewsForPositions(LayoutPosition.Left, LayoutPosition.FullLeft);
var drawAreaViews = _viewsForPositions(LayoutPosition.DrawArea); var drawAreaViews = _viewsForPositions(LayoutPosition.DrawArea);
final fullBounds = new Rectangle(0, 0, width, height); final fullBounds = Rectangle(0, 0, width, height);
// Layout the margins. // Layout the margins.
new LeftMarginLayoutStrategy() LeftMarginLayoutStrategy()
.layout(leftViews, _measurements.leftSizes, fullBounds, drawAreaBounds); .layout(leftViews, _measurements.leftSizes, fullBounds, drawAreaBounds);
new RightMarginLayoutStrategy().layout( RightMarginLayoutStrategy().layout(
rightViews, _measurements.rightSizes, fullBounds, drawAreaBounds); rightViews, _measurements.rightSizes, fullBounds, drawAreaBounds);
new BottomMarginLayoutStrategy().layout( BottomMarginLayoutStrategy().layout(
bottomViews, _measurements.bottomSizes, fullBounds, drawAreaBounds); bottomViews, _measurements.bottomSizes, fullBounds, drawAreaBounds);
new TopMarginLayoutStrategy() TopMarginLayoutStrategy()
.layout(topViews, _measurements.topSizes, fullBounds, drawAreaBounds); .layout(topViews, _measurements.topSizes, fullBounds, drawAreaBounds);
// Layout the drawArea. // Layout the drawArea.
drawAreaViews.forEach( drawAreaViews
(LayoutView view) => view.layout(_drawAreaBounds, _drawAreaBounds)); .forEach((view) => view.layout(_drawAreaBounds, _drawAreaBounds));
} }
Iterable<LayoutView> _viewsForPositions(LayoutPosition p1, Iterable<LayoutView> _viewsForPositions(LayoutPosition p1,
[LayoutPosition p2]) { [LayoutPosition p2]) {
return positionOrderedViews.where((LayoutView view) => return positionOrderedViews.where((view) =>
(view.layoutConfig.position == p1 || (view.layoutConfig.position == p1 ||
(p2 != null && view.layoutConfig.position == p2))); (p2 != null && view.layoutConfig.position == p2)));
} }
@ -297,14 +295,14 @@ class LayoutManagerImpl implements LayoutManager {
? height - bottomHeight - topHeight ? height - bottomHeight - topHeight
: height; : height;
var leftSizes = new LeftMarginLayoutStrategy().measure(leftViews, var leftSizes = LeftMarginLayoutStrategy().measure(leftViews,
maxWidth: useMax ? maxLeftWidth : leftWidth, maxWidth: useMax ? maxLeftWidth : leftWidth,
height: adjustedHeight, height: adjustedHeight,
fullHeight: height); fullHeight: height);
leftWidth = max(leftSizes.total, config.leftSpec.getMinPixels(width)); leftWidth = max(leftSizes.total, config.leftSpec.getMinPixels(width));
var rightSizes = new RightMarginLayoutStrategy().measure(rightViews, var rightSizes = RightMarginLayoutStrategy().measure(rightViews,
maxWidth: useMax ? maxRightWidth : rightWidth, maxWidth: useMax ? maxRightWidth : rightWidth,
height: adjustedHeight, height: adjustedHeight,
fullHeight: height); fullHeight: height);
@ -312,20 +310,20 @@ class LayoutManagerImpl implements LayoutManager {
final adjustedWidth = width - leftWidth - rightWidth; final adjustedWidth = width - leftWidth - rightWidth;
var bottomSizes = new BottomMarginLayoutStrategy().measure(bottomViews, var bottomSizes = BottomMarginLayoutStrategy().measure(bottomViews,
maxHeight: useMax ? maxBottomHeight : bottomHeight, maxHeight: useMax ? maxBottomHeight : bottomHeight,
width: adjustedWidth, width: adjustedWidth,
fullWidth: width); fullWidth: width);
bottomHeight = bottomHeight =
max(bottomSizes.total, config.bottomSpec.getMinPixels(height)); max(bottomSizes.total, config.bottomSpec.getMinPixels(height));
var topSizes = new TopMarginLayoutStrategy().measure(topViews, var topSizes = TopMarginLayoutStrategy().measure(topViews,
maxHeight: useMax ? maxTopHeight : topHeight, maxHeight: useMax ? maxTopHeight : topHeight,
width: adjustedWidth, width: adjustedWidth,
fullWidth: width); fullWidth: width);
topHeight = max(topSizes.total, config.topSpec.getMinPixels(height)); topHeight = max(topSizes.total, config.topSpec.getMinPixels(height));
return new _MeasuredSizes( return _MeasuredSizes(
leftWidth: leftWidth, leftWidth: leftWidth,
leftSizes: leftSizes, leftSizes: leftSizes,
rightWidth: rightWidth, rightWidth: rightWidth,

@ -39,8 +39,8 @@ class SizeList {
} }
class _DesiredViewSizes { class _DesiredViewSizes {
final preferredSizes = new SizeList(); final preferredSizes = SizeList();
final minimumSizes = new SizeList(); final minimumSizes = SizeList();
void add(int preferred, int minimum) { void add(int preferred, int minimum) {
preferredSizes.add(preferred); preferredSizes.add(preferred);
@ -74,10 +74,10 @@ abstract class VerticalMarginStrategy {
{@required int maxWidth, {@required int maxWidth,
@required int height, @required int height,
@required int fullHeight}) { @required int fullHeight}) {
final measuredWidths = new _DesiredViewSizes(); final measuredWidths = _DesiredViewSizes();
int remainingWidth = maxWidth; int remainingWidth = maxWidth;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final viewMargin = params.viewMargin; final viewMargin = params.viewMargin;
@ -118,7 +118,7 @@ class LeftMarginLayoutStrategy extends VerticalMarginStrategy {
var prevBoundsRight = drawAreaBounds.left; var prevBoundsRight = drawAreaBounds.left;
int i = 0; int i = 0;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final width = measuredSizes[i]; final width = measuredSizes[i];
@ -133,7 +133,7 @@ class LeftMarginLayoutStrategy extends VerticalMarginStrategy {
prevBoundsRight = left - params.viewMargin.leftPx; prevBoundsRight = left - params.viewMargin.leftPx;
// Layout this component. // Layout this component.
view.layout(new Rectangle(left, top, width, height), drawAreaBounds); view.layout(Rectangle(left, top, width, height), drawAreaBounds);
i++; i++;
}); });
@ -148,7 +148,7 @@ class RightMarginLayoutStrategy extends VerticalMarginStrategy {
var prevBoundsLeft = drawAreaBounds.right; var prevBoundsLeft = drawAreaBounds.right;
int i = 0; int i = 0;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final width = measuredSizes[i]; final width = measuredSizes[i];
@ -163,7 +163,7 @@ class RightMarginLayoutStrategy extends VerticalMarginStrategy {
prevBoundsLeft = left + width + params.viewMargin.rightPx; prevBoundsLeft = left + width + params.viewMargin.rightPx;
// Layout this component. // Layout this component.
view.layout(new Rectangle(left, top, width, height), drawAreaBounds); view.layout(Rectangle(left, top, width, height), drawAreaBounds);
i++; i++;
}); });
@ -174,10 +174,10 @@ class RightMarginLayoutStrategy extends VerticalMarginStrategy {
abstract class HorizontalMarginStrategy { abstract class HorizontalMarginStrategy {
SizeList measure(Iterable<LayoutView> views, SizeList measure(Iterable<LayoutView> views,
{@required int maxHeight, @required int width, @required int fullWidth}) { {@required int maxHeight, @required int width, @required int fullWidth}) {
final measuredHeights = new _DesiredViewSizes(); final measuredHeights = _DesiredViewSizes();
int remainingHeight = maxHeight; int remainingHeight = maxHeight;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final viewMargin = params.viewMargin; final viewMargin = params.viewMargin;
@ -218,7 +218,7 @@ class TopMarginLayoutStrategy extends HorizontalMarginStrategy {
var prevBoundsBottom = drawAreaBounds.top; var prevBoundsBottom = drawAreaBounds.top;
int i = 0; int i = 0;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final height = measuredSizes[i]; final height = measuredSizes[i];
@ -234,7 +234,7 @@ class TopMarginLayoutStrategy extends HorizontalMarginStrategy {
prevBoundsBottom = top - params.viewMargin.topPx; prevBoundsBottom = top - params.viewMargin.topPx;
// Layout this component. // Layout this component.
view.layout(new Rectangle(left, top, width, height), drawAreaBounds); view.layout(Rectangle(left, top, width, height), drawAreaBounds);
i++; i++;
}); });
@ -249,7 +249,7 @@ class BottomMarginLayoutStrategy extends HorizontalMarginStrategy {
var prevBoundsTop = drawAreaBounds.bottom; var prevBoundsTop = drawAreaBounds.bottom;
int i = 0; int i = 0;
views.forEach((LayoutView view) { views.forEach((view) {
final params = view.layoutConfig; final params = view.layoutConfig;
final height = measuredSizes[i]; final height = measuredSizes[i];
@ -265,7 +265,7 @@ class BottomMarginLayoutStrategy extends HorizontalMarginStrategy {
prevBoundsTop = top + height + params.viewMargin.bottomPx; prevBoundsTop = top + height + params.viewMargin.bottomPx;
// Layout this component. // Layout this component.
view.layout(new Rectangle(left, top, width, height), drawAreaBounds); view.layout(Rectangle(left, top, width, height), drawAreaBounds);
i++; i++;
}); });

@ -80,8 +80,7 @@ class LayoutViewPositionOrder {
/// A configuration for margin (empty space) around a layout child view. /// A configuration for margin (empty space) around a layout child view.
class ViewMargin { class ViewMargin {
/// A [ViewMargin] with all zero px. /// A [ViewMargin] with all zero px.
static const empty = static const empty = ViewMargin(topPx: 0, bottomPx: 0, rightPx: 0, leftPx: 0);
const ViewMargin(topPx: 0, bottomPx: 0, rightPx: 0, leftPx: 0);
final int topPx; final int topPx;
final int bottomPx; final int bottomPx;
@ -152,7 +151,7 @@ class LayoutViewConfig {
/// The measurement is tight to the component, without adding [ComponentBuffer]. /// The measurement is tight to the component, without adding [ComponentBuffer].
class ViewMeasuredSizes { class ViewMeasuredSizes {
/// All zeroes component size. /// All zeroes component size.
static const zero = const ViewMeasuredSizes( static const zero = ViewMeasuredSizes(
preferredWidth: 0, preferredHeight: 0, minWidth: 0, minHeight: 0); preferredWidth: 0, preferredHeight: 0, minWidth: 0, minHeight: 0);
final int preferredWidth; final int preferredWidth;

@ -37,7 +37,6 @@ class LineChart extends NumericCartesianChart {
@override @override
SeriesRenderer<num> makeDefaultRenderer() { SeriesRenderer<num> makeDefaultRenderer() {
return new LineRenderer<num>() return LineRenderer<num>()..rendererId = SeriesRenderer.defaultRendererId;
..rendererId = SeriesRenderer.defaultRendererId;
} }
} }

@ -33,11 +33,10 @@ import '../scatter_plot/point_renderer.dart' show PointRenderer;
import '../scatter_plot/point_renderer_config.dart' show PointRendererConfig; import '../scatter_plot/point_renderer_config.dart' show PointRendererConfig;
import 'line_renderer_config.dart' show LineRendererConfig; import 'line_renderer_config.dart' show LineRendererConfig;
const styleSegmentsKey = const AttributeKey<List<_LineRendererElement>>( const styleSegmentsKey =
'LineRenderer.styleSegments'); AttributeKey<List<_LineRendererElement>>('LineRenderer.styleSegments');
const lineStackIndexKey = const lineStackIndexKey = AttributeKey<int>('LineRenderer.lineStackIndex');
const AttributeKey<int>('LineRenderer.lineStackIndex');
class LineRenderer<D> extends BaseCartesianRenderer<D> { class LineRenderer<D> extends BaseCartesianRenderer<D> {
// Configuration used to extend the clipping area to extend the draw bounds. // Configuration used to extend the clipping area to extend the draw bounds.
@ -69,9 +68,9 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final _currentKeys = <String>[]; final _currentKeys = <String>[];
factory LineRenderer({String rendererId, LineRendererConfig config}) { factory LineRenderer({String rendererId, LineRendererConfig config}) {
return new LineRenderer._internal( return LineRenderer._internal(
rendererId: rendererId ?? 'line', rendererId: rendererId ?? 'line',
config: config ?? new LineRendererConfig()); config: config ?? LineRendererConfig());
} }
LineRenderer._internal({String rendererId, this.config}) LineRenderer._internal({String rendererId, this.config})
@ -79,8 +78,8 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
rendererId: rendererId, rendererId: rendererId,
layoutPaintOrder: config.layoutPaintOrder, layoutPaintOrder: config.layoutPaintOrder,
symbolRenderer: config.symbolRenderer) { symbolRenderer: config.symbolRenderer) {
_pointRenderer = new PointRenderer<D>( _pointRenderer = PointRenderer<D>(
config: new PointRendererConfig<D>(radiusPx: this.config.radiusPx)); config: PointRendererConfig<D>(radiusPx: this.config.radiusPx));
} }
@override @override
@ -96,13 +95,13 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
void configureSeries(List<MutableSeries<D>> seriesList) { void configureSeries(List<MutableSeries<D>> seriesList) {
assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: false); assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: false);
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
// Add a default area color function which applies the configured // Add a default area color function which applies the configured
// areaOpacity value to the datum's current color. // areaOpacity value to the datum's current color.
series.areaColorFn ??= (int index) { series.areaColorFn ??= (index) {
final color = series.colorFn(index); final color = series.colorFn(index);
return new Color( return Color(
r: color.r, r: color.r,
g: color.g, g: color.g,
b: color.b, b: color.b,
@ -123,7 +122,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
series.measureUpperBoundFn != null && series.measureUpperBoundFn != null &&
series.measureLowerBoundFn != null); series.measureLowerBoundFn != null);
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
final colorFn = series.colorFn; final colorFn = series.colorFn;
final areaColorFn = series.areaColorFn; final areaColorFn = series.areaColorFn;
final domainFn = series.domainFn; final domainFn = series.domainFn;
@ -136,7 +135,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final styleSegments = <_LineRendererElement<D>>[]; final styleSegments = <_LineRendererElement<D>>[];
var styleSegmentsIndex = 0; var styleSegmentsIndex = 0;
final usedKeys = new Set<String>(); final usedKeys = Set<String>();
// Configure style segments for each series. // Configure style segments for each series.
String previousSegmentKey; String previousSegmentKey;
@ -163,8 +162,8 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// Compare strokeWidthPx to 2 decimals of precision. Any less and you // Compare strokeWidthPx to 2 decimals of precision. Any less and you
// can't see any difference in the canvas anyways. // can't see any difference in the canvas anyways.
final strokeWidthPxRounded = (strokeWidthPx * 100).round() / 100; final strokeWidthPxRounded = (strokeWidthPx * 100).round() / 100;
var styleKey = '${series.id}__${styleSegmentsIndex}__${color}' var styleKey = '${series.id}__${styleSegmentsIndex}__$color'
'__${dashPattern}__${strokeWidthPxRounded}'; '__${dashPattern}__$strokeWidthPxRounded';
if (styleKey != previousSegmentKey) { if (styleKey != previousSegmentKey) {
// If we have a repeated style segment, update the repeat index and // If we have a repeated style segment, update the repeat index and
@ -173,8 +172,8 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
if (usedKeys.isNotEmpty && usedKeys.contains(styleKey)) { if (usedKeys.isNotEmpty && usedKeys.contains(styleKey)) {
styleSegmentsIndex++; styleSegmentsIndex++;
styleKey = '${series.id}__${styleSegmentsIndex}__${color}' styleKey = '${series.id}__${styleSegmentsIndex}__$color'
'__${dashPattern}__${strokeWidthPxRounded}'; '__${dashPattern}__$strokeWidthPxRounded';
} }
// Make sure that the previous style segment extends to the current // Make sure that the previous style segment extends to the current
@ -185,11 +184,11 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
} }
// Create a new style segment. // Create a new style segment.
currentDetails = new _LineRendererElement<D>() currentDetails = _LineRendererElement<D>()
..color = color ..color = color
..areaColor = areaColor ..areaColor = areaColor
..dashPattern = dashPattern ..dashPattern = dashPattern
..domainExtent = new _Range<D>(domain, domain) ..domainExtent = _Range<D>(domain, domain)
..strokeWidthPx = strokeWidthPx ..strokeWidthPx = strokeWidthPx
..styleKey = styleKey ..styleKey = styleKey
..roundEndCaps = config.roundEndCaps; ..roundEndCaps = config.roundEndCaps;
@ -273,7 +272,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
} }
} }
return (int i) => curOffsets[domainFn(i)]; return (i) => curOffsets[domainFn(i)];
} }
/// Merge the line map and the new series so that the new elements are mixed /// Merge the line map and the new series so that the new elements are mixed
@ -285,7 +284,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
void _mergeIntoSeriesMap(List<ImmutableSeries<D>> seriesList) { void _mergeIntoSeriesMap(List<ImmutableSeries<D>> seriesList) {
List<MapEntry<String, List<_AnimatedElements<D>>>> newLineMap = []; List<MapEntry<String, List<_AnimatedElements<D>>>> newLineMap = [];
seriesList.forEach((ImmutableSeries<D> series) { seriesList.forEach((series) {
final key = series.id; final key = series.id;
// First, add all the series from the old map that have been removed from // First, add all the series from the old map that have been removed from
@ -332,7 +331,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
_mergeIntoSeriesMap(seriesList); _mergeIntoSeriesMap(seriesList);
seriesList.forEach((ImmutableSeries<D> series) { seriesList.forEach((series) {
final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>; final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;
final lineKey = series.id; final lineKey = series.id;
final stackIndex = series.getAttr(lineStackIndexKey); final stackIndex = series.getAttr(lineStackIndexKey);
@ -372,12 +371,12 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// later to display only the relevant parts of data. This ensures that // later to display only the relevant parts of data. This ensures that
// styles that visually depend on the start location, such as dash // styles that visually depend on the start location, such as dash
// patterns, are not disrupted by other changes in style. // patterns, are not disrupted by other changes in style.
styleSegments.forEach((_LineRendererElement styleSegment) { styleSegments.forEach((styleSegment) {
final styleKey = styleSegment.styleKey; final styleKey = styleSegment.styleKey;
// If we already have an AnimatingPoint for that index, use it. // If we already have an AnimatingPoint for that index, use it.
var animatingElements = elementsList.firstWhere( var animatingElements = elementsList.firstWhere(
(_AnimatedElements elements) => elements.styleKey == styleKey, (elements) => elements.styleKey == styleKey,
orElse: () => null); orElse: () => null);
if (animatingElements != null) { if (animatingElements != null) {
@ -398,7 +397,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final animatingLines = <_AnimatedLine<D>>[]; final animatingLines = <_AnimatedLine<D>>[];
for (var index = 0; index < lineElementList.length; index++) { for (var index = 0; index < lineElementList.length; index++) {
animatingLines.add(new _AnimatedLine<D>( animatingLines.add(_AnimatedLine<D>(
key: lineElementList[index].styleKey, key: lineElementList[index].styleKey,
overlaySeries: series.overlaySeries) overlaySeries: series.overlaySeries)
..setNewTarget(lineElementList[index])); ..setNewTarget(lineElementList[index]));
@ -410,7 +409,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
animatingAreas = <_AnimatedArea<D>>[]; animatingAreas = <_AnimatedArea<D>>[];
for (var index = 0; index < areaElementList.length; index++) { for (var index = 0; index < areaElementList.length; index++) {
animatingAreas.add(new _AnimatedArea<D>( animatingAreas.add(_AnimatedArea<D>(
key: areaElementList[index].styleKey, key: areaElementList[index].styleKey,
overlaySeries: series.overlaySeries) overlaySeries: series.overlaySeries)
..setNewTarget(areaElementList[index])); ..setNewTarget(areaElementList[index]));
@ -424,14 +423,14 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
animatingBounds ??= <_AnimatedArea<D>>[]; animatingBounds ??= <_AnimatedArea<D>>[];
for (var index = 0; index < boundsElementList.length; index++) { for (var index = 0; index < boundsElementList.length; index++) {
animatingBounds.add(new _AnimatedArea<D>( animatingBounds.add(_AnimatedArea<D>(
key: boundsElementList[index].styleKey, key: boundsElementList[index].styleKey,
overlaySeries: series.overlaySeries) overlaySeries: series.overlaySeries)
..setNewTarget(boundsElementList[index])); ..setNewTarget(boundsElementList[index]));
} }
} }
animatingElements = new _AnimatedElements<D>() animatingElements = _AnimatedElements<D>()
..styleKey = styleSegment.styleKey ..styleKey = styleSegment.styleKey
..allPoints = allPointList ..allPoints = allPointList
..lines = animatingLines ..lines = animatingLines
@ -458,7 +457,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// than we did in the previous chart draw cycle. // than we did in the previous chart draw cycle.
// TODO: Nicer animations for incoming segments. // TODO: Nicer animations for incoming segments.
if (index >= animatingElements.lines.length) { if (index >= animatingElements.lines.length) {
animatingElements.lines.add(new _AnimatedLine<D>( animatingElements.lines.add(_AnimatedLine<D>(
key: lineElement.styleKey, key: lineElement.styleKey,
overlaySeries: series.overlaySeries)); overlaySeries: series.overlaySeries));
} }
@ -473,7 +472,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// cycle than we did in the previous chart draw cycle. // cycle than we did in the previous chart draw cycle.
// TODO: Nicer animations for incoming segments. // TODO: Nicer animations for incoming segments.
if (index >= animatingElements.areas.length) { if (index >= animatingElements.areas.length) {
animatingElements.areas.add(new _AnimatedArea<D>( animatingElements.areas.add(_AnimatedArea<D>(
key: areaElement.styleKey, key: areaElement.styleKey,
overlaySeries: series.overlaySeries)); overlaySeries: series.overlaySeries));
} }
@ -489,7 +488,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// cycle than we did in the previous chart draw cycle. // cycle than we did in the previous chart draw cycle.
// TODO: Nicer animations for incoming segments. // TODO: Nicer animations for incoming segments.
if (index >= animatingElements.bounds.length) { if (index >= animatingElements.bounds.length) {
animatingElements.bounds.add(new _AnimatedArea<D>( animatingElements.bounds.add(_AnimatedArea<D>(
key: boundElement.styleKey, key: boundElement.styleKey,
overlaySeries: series.overlaySeries)); overlaySeries: series.overlaySeries));
} }
@ -506,7 +505,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
}); });
// Animate out lines that don't exist anymore. // Animate out lines that don't exist anymore.
_seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) { _seriesLineMap.forEach((key, elements) {
for (var element in elements) { for (var element in elements) {
if (element.lines != null) { if (element.lines != null) {
for (var line in element.lines) { for (var line in element.lines) {
@ -599,10 +598,10 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final linePointList = lineSegments[index]; final linePointList = lineSegments[index];
// Update the set of areas that still exist in the series data. // Update the set of areas that still exist in the series data.
final lineStyleKey = '${styleKey}__line__${index}'; final lineStyleKey = '${styleKey}__line__$index';
_currentKeys.add(lineStyleKey); _currentKeys.add(lineStyleKey);
lineElements.add(new _LineRendererElement<D>() lineElements.add(_LineRendererElement<D>()
..points = linePointList ..points = linePointList
..color = color ..color = color
..areaColor = areaColor ..areaColor = areaColor
@ -622,10 +621,10 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final areaPointList = areaSegments[index]; final areaPointList = areaSegments[index];
// Update the set of areas that still exist in the series data. // Update the set of areas that still exist in the series data.
final areaStyleKey = '${styleKey}__area_${index}'; final areaStyleKey = '${styleKey}__area_$index';
_currentKeys.add(areaStyleKey); _currentKeys.add(areaStyleKey);
areaElements.add(new _AreaRendererElement<D>() areaElements.add(_AreaRendererElement<D>()
..points = areaPointList ..points = areaPointList
..color = color ..color = color
..areaColor = areaColor ..areaColor = areaColor
@ -643,10 +642,10 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
for (var index = 0; index < boundsSegment.length; index++) { for (var index = 0; index < boundsSegment.length; index++) {
final boundsPointList = boundsSegment[index]; final boundsPointList = boundsSegment[index];
final boundsStyleKey = '${styleKey}__bounds_${index}'; final boundsStyleKey = '${styleKey}__bounds_$index';
_currentKeys.add(boundsStyleKey); _currentKeys.add(boundsStyleKey);
boundsElements.add(new _AreaRendererElement<D>() boundsElements.add(_AreaRendererElement<D>()
..points = boundsPointList ..points = boundsPointList
..color = color ..color = color
..areaColor = areaColor ..areaColor = areaColor
@ -858,7 +857,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final areaPointList = <_DatumPoint<D>>[]; final areaPointList = <_DatumPoint<D>>[];
// Add all points for upper bounds. // Add all points for upper bounds.
areaPointList.addAll(pointList.map((datumPoint) => new _DatumPoint.from( areaPointList.addAll(pointList.map((datumPoint) => _DatumPoint.from(
datumPoint, datumPoint,
datumPoint.x, datumPoint.x,
initializeFromZero initializeFromZero
@ -869,7 +868,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// Add all points for lower bounds, in reverse order. // Add all points for lower bounds, in reverse order.
areaPointList.addAll(pointList.reversed.map((datumPoint) => areaPointList.addAll(pointList.reversed.map((datumPoint) =>
new _DatumPoint.from( _DatumPoint.from(
datumPoint, datumPoint,
datumPoint.x, datumPoint.x,
initializeFromZero initializeFromZero
@ -902,7 +901,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final endPosition = domainAxis.getLocation(details.domainExtent.end) ?? final endPosition = domainAxis.getLocation(details.domainExtent.end) ??
drawBounds.right.toDouble(); drawBounds.right.toDouble();
return new _Range<num>(startPosition, endPosition); return _Range<num>(startPosition, endPosition);
} }
@override @override
@ -919,9 +918,8 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = <String>[]; final keysToRemove = <String>[];
_seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) { _seriesLineMap.forEach((key, elements) {
elements.removeWhere( elements.removeWhere((element) => element.animatingOut);
(_AnimatedElements<D> element) => element.animatingOut);
if (elements.isEmpty) { if (elements.isEmpty) {
keysToRemove.add(key); keysToRemove.add(key);
@ -931,16 +929,15 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
keysToRemove.forEach(_seriesLineMap.remove); keysToRemove.forEach(_seriesLineMap.remove);
} }
_seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) { _seriesLineMap.forEach((key, elements) {
if (config.includeArea) { if (config.includeArea) {
elements elements
.map<List<_AnimatedArea<D>>>( .map<List<_AnimatedArea<D>>>(
(_AnimatedElements<D> animatingElement) => (animatingElement) => animatingElement.areas)
animatingElement.areas) .expand<_AnimatedArea<D>>((areas) => areas)
.expand<_AnimatedArea<D>>((List<_AnimatedArea<D>> areas) => areas) .map<_AreaRendererElement<D>>((animatingArea) =>
.map<_AreaRendererElement<D>>((_AnimatedArea<D> animatingArea) =>
animatingArea?.getCurrentArea(animationPercent)) animatingArea?.getCurrentArea(animationPercent))
.forEach((_AreaRendererElement area) { .forEach((area) {
if (area != null) { if (area != null) {
canvas.drawPolygon( canvas.drawPolygon(
clipBounds: _getClipBoundsForExtent(area.positionExtent), clipBounds: _getClipBoundsForExtent(area.positionExtent),
@ -953,12 +950,11 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
if (_hasMeasureBounds) { if (_hasMeasureBounds) {
elements elements
.map<List<_AnimatedArea<D>>>( .map<List<_AnimatedArea<D>>>(
(_AnimatedElements<D> animatingElement) => (animatingElement) => animatingElement.bounds)
animatingElement.bounds) .expand<_AnimatedArea<D>>((bounds) => bounds)
.expand<_AnimatedArea<D>>((List<_AnimatedArea<D>> bounds) => bounds) .map<_AreaRendererElement<D>>((animatingBounds) =>
.map<_AreaRendererElement<D>>((_AnimatedArea<D> animatingBounds) =>
animatingBounds?.getCurrentArea(animationPercent)) animatingBounds?.getCurrentArea(animationPercent))
.forEach((_AreaRendererElement bound) { .forEach((bound) {
if (bound != null) { if (bound != null) {
canvas.drawPolygon( canvas.drawPolygon(
clipBounds: _getClipBoundsForExtent(bound.positionExtent), clipBounds: _getClipBoundsForExtent(bound.positionExtent),
@ -971,12 +967,11 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
if (config.includeLine) { if (config.includeLine) {
elements elements
.map<List<_AnimatedLine<D>>>( .map<List<_AnimatedLine<D>>>(
(_AnimatedElements<D> animatingElement) => (animatingElement) => animatingElement.lines)
animatingElement.lines) .expand<_AnimatedLine<D>>((lines) => lines)
.expand<_AnimatedLine<D>>((List<_AnimatedLine<D>> lines) => lines) .map<_LineRendererElement<D>>((animatingLine) =>
.map<_LineRendererElement<D>>((_AnimatedLine<D> animatingLine) =>
animatingLine?.getCurrentLine(animationPercent)) animatingLine?.getCurrentLine(animationPercent))
.forEach((_LineRendererElement line) { .forEach((line) {
if (line != null) { if (line != null) {
canvas.drawLine( canvas.drawLine(
clipBounds: _getClipBoundsForExtent(line.positionExtent), clipBounds: _getClipBoundsForExtent(line.positionExtent),
@ -1009,7 +1004,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
? clamp((extent.start), drawBounds.left, drawBounds.right) ? clamp((extent.start), drawBounds.left, drawBounds.right)
: clamp((extent.end), drawBounds.left, drawBounds.right); : clamp((extent.end), drawBounds.left, drawBounds.right);
return new Rectangle<num>( return Rectangle<num>(
left, left,
drawBounds.top - drawBoundTopExtensionPx, drawBounds.top - drawBoundTopExtensionPx,
right - left, right - left,
@ -1035,7 +1030,7 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
? measureAxis.getLocation(measureValue + measureOffsetValue) ? measureAxis.getLocation(measureValue + measureOffsetValue)
: null; : null;
return new _DatumPoint<D>( return _DatumPoint<D>(
datum: datum, datum: datum,
domain: domainValue, domain: domainValue,
series: series, series: series,
@ -1054,18 +1049,18 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
return nearest; return nearest;
} }
_seriesLineMap.values.forEach((List<_AnimatedElements<D>> seriesSegments) { _seriesLineMap.values.forEach((seriesSegments) {
_DatumPoint<D> nearestPoint; _DatumPoint<D> nearestPoint;
double nearestDomainDistance = 10000.0; double nearestDomainDistance = 10000.0;
double nearestMeasureDistance = 10000.0; double nearestMeasureDistance = 10000.0;
double nearestRelativeDistance = 10000.0; double nearestRelativeDistance = 10000.0;
seriesSegments.forEach((_AnimatedElements<D> segment) { seriesSegments.forEach((segment) {
if (segment.overlaySeries) { if (segment.overlaySeries) {
return; return;
} }
segment.allPoints.forEach((Point p) { segment.allPoints.forEach((p) {
// Don't look at points not in the drawArea. // Don't look at points not in the drawArea.
if (p.x < componentBounds.left || p.x > componentBounds.right) { if (p.x < componentBounds.left || p.x > componentBounds.right) {
return; return;
@ -1108,8 +1103,8 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
// Found a point, add it to the list. // Found a point, add it to the list.
if (nearestPoint != null) { if (nearestPoint != null) {
nearest.add(new DatumDetails<D>( nearest.add(DatumDetails<D>(
chartPosition: new Point<double>(nearestPoint.x, nearestPoint.y), chartPosition: Point<double>(nearestPoint.x, nearestPoint.y),
datum: nearestPoint.datum, datum: nearestPoint.datum,
domain: nearestPoint.domain, domain: nearestPoint.domain,
series: nearestPoint.series, series: nearestPoint.series,
@ -1134,9 +1129,9 @@ class LineRenderer<D> extends BaseCartesianRenderer<D> {
final point = _getPoint(seriesDatum.datum, details.domain, series, final point = _getPoint(seriesDatum.datum, details.domain, series,
domainAxis, details.measure, details.measureOffset, measureAxis); domainAxis, details.measure, details.measureOffset, measureAxis);
final chartPosition = new Point<double>(point.x, point.y); final chartPosition = Point<double>(point.x, point.y);
return new DatumDetails.from(details, chartPosition: chartPosition); return DatumDetails.from(details, chartPosition: chartPosition);
} }
} }
@ -1151,7 +1146,7 @@ class _DatumPoint<D> extends Point<double> {
: super(x, y); : super(x, y);
factory _DatumPoint.from(_DatumPoint<D> other, [double x, double y]) { factory _DatumPoint.from(_DatumPoint<D> other, [double x, double y]) {
return new _DatumPoint<D>( return _DatumPoint<D>(
datum: other.datum, datum: other.datum,
domain: other.domain, domain: other.domain,
series: other.series, series: other.series,
@ -1175,13 +1170,11 @@ class _LineRendererElement<D> {
bool roundEndCaps; bool roundEndCaps;
_LineRendererElement<D> clone() { _LineRendererElement<D> clone() {
return new _LineRendererElement<D>() return _LineRendererElement<D>()
..points = new List<_DatumPoint<D>>.from(points) ..points = List<_DatumPoint<D>>.from(points)
..color = color != null ? new Color.fromOther(color: color) : null ..color = color != null ? Color.fromOther(color: color) : null
..areaColor = ..areaColor = areaColor != null ? Color.fromOther(color: areaColor) : null
areaColor != null ? new Color.fromOther(color: areaColor) : null ..dashPattern = dashPattern != null ? List<int>.from(dashPattern) : null
..dashPattern =
dashPattern != null ? new List<int>.from(dashPattern) : null
..domainExtent = domainExtent ..domainExtent = domainExtent
..measureAxisPosition = measureAxisPosition ..measureAxisPosition = measureAxisPosition
..positionExtent = positionExtent ..positionExtent = positionExtent
@ -1207,7 +1200,7 @@ class _LineRendererElement<D> {
lastPoint = previousPoint; lastPoint = previousPoint;
} else { } else {
previousPoint = previousPoint =
new _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y); _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y);
} }
final x = ((targetPoint.x - previousPoint.x) * animationPercent) + final x = ((targetPoint.x - previousPoint.x) * animationPercent) +
@ -1224,9 +1217,9 @@ class _LineRendererElement<D> {
} }
if (points.length - 1 >= pointIndex) { if (points.length - 1 >= pointIndex) {
points[pointIndex] = new _DatumPoint<D>.from(targetPoint, x, y); points[pointIndex] = _DatumPoint<D>.from(targetPoint, x, y);
} else { } else {
points.add(new _DatumPoint<D>.from(targetPoint, x, y)); points.add(_DatumPoint<D>.from(targetPoint, x, y));
} }
} }
@ -1278,7 +1271,7 @@ class _AnimatedLine<D> {
for (var index = 0; index < newTarget.points.length; index++) { for (var index = 0; index < newTarget.points.length; index++) {
var targetPoint = newTarget.points[index]; var targetPoint = newTarget.points[index];
newPoints.add(new _DatumPoint<D>.from(targetPoint, targetPoint.x, newPoints.add(_DatumPoint<D>.from(targetPoint, targetPoint.x,
newTarget.measureAxisPosition.roundToDouble())); newTarget.measureAxisPosition.roundToDouble()));
} }
@ -1328,11 +1321,10 @@ class _AreaRendererElement<D> {
String styleKey; String styleKey;
_AreaRendererElement<D> clone() { _AreaRendererElement<D> clone() {
return new _AreaRendererElement<D>() return _AreaRendererElement<D>()
..points = new List<_DatumPoint<D>>.from(points) ..points = List<_DatumPoint<D>>.from(points)
..color = color != null ? new Color.fromOther(color: color) : null ..color = color != null ? Color.fromOther(color: color) : null
..areaColor = ..areaColor = areaColor != null ? Color.fromOther(color: areaColor) : null
areaColor != null ? new Color.fromOther(color: areaColor) : null
..domainExtent = domainExtent ..domainExtent = domainExtent
..measureAxisPosition = measureAxisPosition ..measureAxisPosition = measureAxisPosition
..positionExtent = positionExtent ..positionExtent = positionExtent
@ -1356,7 +1348,7 @@ class _AreaRendererElement<D> {
lastPoint = previousPoint; lastPoint = previousPoint;
} else { } else {
previousPoint = previousPoint =
new _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y); _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y);
} }
final x = ((targetPoint.x - previousPoint.x) * animationPercent) + final x = ((targetPoint.x - previousPoint.x) * animationPercent) +
@ -1373,9 +1365,9 @@ class _AreaRendererElement<D> {
} }
if (points.length - 1 >= pointIndex) { if (points.length - 1 >= pointIndex) {
points[pointIndex] = new _DatumPoint<D>.from(targetPoint, x, y); points[pointIndex] = _DatumPoint<D>.from(targetPoint, x, y);
} else { } else {
points.add(new _DatumPoint<D>.from(targetPoint, x, y)); points.add(_DatumPoint<D>.from(targetPoint, x, y));
} }
} }
@ -1423,7 +1415,7 @@ class _AnimatedArea<D> {
for (var index = 0; index < newTarget.points.length; index++) { for (var index = 0; index < newTarget.points.length; index++) {
var targetPoint = newTarget.points[index]; var targetPoint = newTarget.points[index];
newPoints.add(new _DatumPoint<D>.from(targetPoint, targetPoint.x, newPoints.add(_DatumPoint<D>.from(targetPoint, targetPoint.x,
newTarget.measureAxisPosition.roundToDouble())); newTarget.measureAxisPosition.roundToDouble()));
} }

@ -26,7 +26,7 @@ class LineRendererConfig<D> extends LayoutViewConfig
final SymbolRenderer symbolRenderer; final SymbolRenderer symbolRenderer;
final rendererAttributes = new RendererAttributes(); final rendererAttributes = RendererAttributes();
/// Radius of points on the line, if [includePoints] is enabled. /// Radius of points on the line, if [includePoints] is enabled.
final double radiusPx; final double radiusPx;
@ -83,10 +83,10 @@ class LineRendererConfig<D> extends LayoutViewConfig
this.areaOpacity = 0.1, this.areaOpacity = 0.1,
this.roundEndCaps = false, this.roundEndCaps = false,
SymbolRenderer symbolRenderer}) SymbolRenderer symbolRenderer})
: this.symbolRenderer = symbolRenderer ?? new LineSymbolRenderer(); : this.symbolRenderer = symbolRenderer ?? LineSymbolRenderer();
@override @override
LineRenderer<D> build() { LineRenderer<D> build() {
return new LineRenderer<D>(config: this, rendererId: customRendererId); return LineRenderer<D>(config: this, rendererId: customRendererId);
} }
} }

@ -39,10 +39,10 @@ class ArcLabelDecorator<D> extends ArcRendererDecorator<D> {
static const _defaultLabelPosition = ArcLabelPosition.auto; static const _defaultLabelPosition = ArcLabelPosition.auto;
static const _defaultLabelPadding = 5; static const _defaultLabelPadding = 5;
static final _defaultInsideLabelStyle = static final _defaultInsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.white); TextStyleSpec(fontSize: 12, color: Color.white);
static final _defaultOutsideLabelStyle = static final _defaultOutsideLabelStyle =
new TextStyleSpec(fontSize: 12, color: Color.black); TextStyleSpec(fontSize: 12, color: Color.black);
static final _defaultLeaderLineStyle = new ArcLabelLeaderLineStyleSpec( static final _defaultLeaderLineStyle = ArcLabelLeaderLineStyleSpec(
length: 20.0, length: 20.0,
thickness: 1.0, thickness: 1.0,
color: StyleFactory.style.arcLabelOutsideLeaderLine); color: StyleFactory.style.arcLabelOutsideLeaderLine);
@ -136,16 +136,16 @@ class ArcLabelDecorator<D> extends ArcRendererDecorator<D> {
final centerRadius = arcElements.innerRadius + final centerRadius = arcElements.innerRadius +
((arcElements.radius - arcElements.innerRadius) / 2); ((arcElements.radius - arcElements.innerRadius) / 2);
final innerPoint = new Point<double>( final innerPoint = Point<double>(
arcElements.center.x + arcElements.innerRadius * cos(centerAngle), arcElements.center.x + arcElements.innerRadius * cos(centerAngle),
arcElements.center.y + arcElements.innerRadius * sin(centerAngle)); arcElements.center.y + arcElements.innerRadius * sin(centerAngle));
final outerPoint = new Point<double>( final outerPoint = Point<double>(
arcElements.center.x + arcElements.radius * cos(centerAngle), arcElements.center.x + arcElements.radius * cos(centerAngle),
arcElements.center.y + arcElements.radius * sin(centerAngle)); arcElements.center.y + arcElements.radius * sin(centerAngle));
//final bounds = element.bounds; //final bounds = element.bounds;
final bounds = new Rectangle<double>.fromPoints(innerPoint, outerPoint); final bounds = Rectangle<double>.fromPoints(innerPoint, outerPoint);
// Get space available inside and outside the arc. // Get space available inside and outside the arc.
final totalPadding = labelPadding * 2; final totalPadding = labelPadding * 2;
@ -268,7 +268,7 @@ class ArcLabelDecorator<D> extends ArcRendererDecorator<D> {
bool previousLabelLeftOfChart) { bool previousLabelLeftOfChart) {
final labelRadius = arcElements.radius + leaderLineStyleSpec.length / 2; final labelRadius = arcElements.radius + leaderLineStyleSpec.length / 2;
final labelPoint = new Point<double>( final labelPoint = Point<double>(
arcElements.center.x + labelRadius * cos(centerAngle), arcElements.center.x + labelRadius * cos(centerAngle),
arcElements.center.y + labelRadius * sin(centerAngle)); arcElements.center.y + labelRadius * sin(centerAngle));
@ -347,10 +347,10 @@ class ArcLabelDecorator<D> extends ArcRendererDecorator<D> {
final tailX = (labelLeftOfChart ? -1 : 1) * leaderLineStyleSpec.length; final tailX = (labelLeftOfChart ? -1 : 1) * leaderLineStyleSpec.length;
final leaderLineTailPoint = final leaderLineTailPoint =
new Point<double>(labelPoint.x + tailX, labelPoint.y); Point<double>(labelPoint.x + tailX, labelPoint.y);
final centerRadius = radius - leaderLineStyleSpec.length / 2; final centerRadius = radius - leaderLineStyleSpec.length / 2;
final leaderLineStartPoint = new Point<double>( final leaderLineStartPoint = Point<double>(
arcCenterPoint.x + centerRadius * cos(centerAngle), arcCenterPoint.x + centerRadius * cos(centerAngle),
arcCenterPoint.y + centerRadius * sin(centerAngle)); arcCenterPoint.y + centerRadius * sin(centerAngle));

@ -32,7 +32,7 @@ import 'arc_renderer_config.dart' show ArcRendererConfig;
import 'arc_renderer_decorator.dart' show ArcRendererDecorator; import 'arc_renderer_decorator.dart' show ArcRendererDecorator;
const arcElementsKey = const arcElementsKey =
const AttributeKey<List<ArcRendererElement>>('ArcRenderer.elements'); AttributeKey<List<ArcRendererElement>>('ArcRenderer.elements');
class ArcRenderer<D> extends BaseSeriesRenderer<D> { class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// Constant used in the calculation of [centerContentBounds], calculated once // Constant used in the calculation of [centerContentBounds], calculated once
@ -49,7 +49,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
/// ///
/// [LinkedHashMap] is used to render the series on the canvas in the same /// [LinkedHashMap] is used to render the series on the canvas in the same
/// order as the data was given to the chart. /// order as the data was given to the chart.
final _seriesArcMap = new LinkedHashMap<String, _AnimatedArcList<D>>(); final _seriesArcMap = LinkedHashMap<String, _AnimatedArcList<D>>();
// Store a list of arcs that exist in the series data. // Store a list of arcs that exist in the series data.
// //
@ -59,9 +59,9 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final _currentKeys = <String>[]; final _currentKeys = <String>[];
factory ArcRenderer({String rendererId, ArcRendererConfig config}) { factory ArcRenderer({String rendererId, ArcRendererConfig config}) {
return new ArcRenderer._internal( return ArcRenderer._internal(
rendererId: rendererId ?? 'line', rendererId: rendererId ?? 'line',
config: config ?? new ArcRendererConfig()); config: config ?? ArcRendererConfig());
} }
ArcRenderer._internal({String rendererId, this.config}) ArcRenderer._internal({String rendererId, this.config})
@ -84,7 +84,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
@override @override
void preprocessSeries(List<MutableSeries<D>> seriesList) { void preprocessSeries(List<MutableSeries<D>> seriesList) {
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
var elements = <ArcRendererElement<D>>[]; var elements = <ArcRendererElement<D>>[];
var domainFn = series.domainFn; var domainFn = series.domainFn;
@ -110,7 +110,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
var angle = arcLength == 2 * pi ? arcLength * .999999 : arcLength; var angle = arcLength == 2 * pi ? arcLength * .999999 : arcLength;
var endAngle = startAngle + angle; var endAngle = startAngle + angle;
var details = new ArcRendererElement<D>(); var details = ArcRendererElement<D>();
details.startAngle = startAngle; details.startAngle = startAngle;
details.endAngle = endAngle; details.endAngle = endAngle;
details.index = 0; details.index = 0;
@ -132,7 +132,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
var angle = arcLength * percentOfSeries; var angle = arcLength * percentOfSeries;
var endAngle = startAngle + angle; var endAngle = startAngle + angle;
var details = new ArcRendererElement<D>(); var details = ArcRendererElement<D>();
details.startAngle = startAngle; details.startAngle = startAngle;
details.endAngle = endAngle; details.endAngle = endAngle;
details.index = arcIndex; details.index = arcIndex;
@ -158,8 +158,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final bounds = _chart.drawAreaBounds; final bounds = _chart.drawAreaBounds;
final center = new Point<double>( final center = Point<double>((bounds.left + bounds.width / 2).toDouble(),
(bounds.left + bounds.width / 2).toDouble(),
(bounds.top + bounds.height / 2).toDouble()); (bounds.top + bounds.height / 2).toDouble());
final radius = bounds.height < bounds.width final radius = bounds.height < bounds.width
@ -168,18 +167,18 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
if (config.arcRatio != null) { if (config.arcRatio != null) {
if (0 < config.arcRatio || config.arcRatio > 1) { if (0 < config.arcRatio || config.arcRatio > 1) {
throw new ArgumentError('arcRatio must be between 0 and 1'); throw ArgumentError('arcRatio must be between 0 and 1');
} }
} }
final innerRadius = _calculateInnerRadius(radius); final innerRadius = _calculateInnerRadius(radius);
seriesList.forEach((ImmutableSeries<D> series) { seriesList.forEach((series) {
var colorFn = series.colorFn; var colorFn = series.colorFn;
var arcListKey = series.id; var arcListKey = series.id;
var arcList = var arcList =
_seriesArcMap.putIfAbsent(arcListKey, () => new _AnimatedArcList()); _seriesArcMap.putIfAbsent(arcListKey, () => _AnimatedArcList());
var elementsList = series.getAttr(arcElementsKey); var elementsList = series.getAttr(arcElementsKey);
@ -191,9 +190,8 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
var arcKey = '__no_data__'; var arcKey = '__no_data__';
// If we already have an AnimatingArc for that index, use it. // If we already have an AnimatingArc for that index, use it.
var animatingArc = arcList.arcs.firstWhere( var animatingArc = arcList.arcs
(_AnimatedArc arc) => arc.key == arcKey, .firstWhere((arc) => arc.key == arcKey, orElse: () => null);
orElse: () => null);
arcList.center = center; arcList.center = center;
arcList.radius = radius; arcList.radius = radius;
@ -205,7 +203,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// If we don't have any existing arc element, create a new arc. Unlike // If we don't have any existing arc element, create a new arc. Unlike
// real arcs, we should not animate the no data state in from 0. // real arcs, we should not animate the no data state in from 0.
if (animatingArc == null) { if (animatingArc == null) {
animatingArc = new _AnimatedArc<D>(arcKey, null, null); animatingArc = _AnimatedArc<D>(arcKey, null, null);
arcList.arcs.add(animatingArc); arcList.arcs.add(animatingArc);
} else { } else {
animatingArc.datum = null; animatingArc.datum = null;
@ -217,7 +215,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// Get the arcElement we are going to setup. // Get the arcElement we are going to setup.
// Optimization to prevent allocation in non-animating case. // Optimization to prevent allocation in non-animating case.
final arcElement = new ArcRendererElement<D>() final arcElement = ArcRendererElement<D>()
..color = config.noDataColor ..color = config.noDataColor
..startAngle = details.startAngle ..startAngle = details.startAngle
..endAngle = details.endAngle ..endAngle = details.endAngle
@ -235,9 +233,8 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
var arcKey = domainValue.toString(); var arcKey = domainValue.toString();
// If we already have an AnimatingArc for that index, use it. // If we already have an AnimatingArc for that index, use it.
var animatingArc = arcList.arcs.firstWhere( var animatingArc = arcList.arcs
(_AnimatedArc arc) => arc.key == arcKey, .firstWhere((arc) => arc.key == arcKey, orElse: () => null);
orElse: () => null);
arcList.center = center; arcList.center = center;
arcList.radius = radius; arcList.radius = radius;
@ -251,8 +248,8 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// angle. If there were no previous arcs, then animate everything in // angle. If there were no previous arcs, then animate everything in
// from 0. // from 0.
if (animatingArc == null) { if (animatingArc == null) {
animatingArc = new _AnimatedArc<D>(arcKey, datum, domainValue) animatingArc = _AnimatedArc<D>(arcKey, datum, domainValue)
..setNewTarget(new ArcRendererElement<D>() ..setNewTarget(ArcRendererElement<D>()
..color = colorFn(arcIndex) ..color = colorFn(arcIndex)
..startAngle = previousEndAngle ..startAngle = previousEndAngle
..endAngle = previousEndAngle ..endAngle = previousEndAngle
@ -273,7 +270,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// Get the arcElement we are going to setup. // Get the arcElement we are going to setup.
// Optimization to prevent allocation in non-animating case. // Optimization to prevent allocation in non-animating case.
final arcElement = new ArcRendererElement<D>() final arcElement = ArcRendererElement<D>()
..color = colorFn(arcIndex) ..color = colorFn(arcIndex)
..startAngle = details.startAngle ..startAngle = details.startAngle
..endAngle = details.endAngle ..endAngle = details.endAngle
@ -286,7 +283,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
}); });
// Animate out arcs that don't exist anymore. // Animate out arcs that don't exist anymore.
_seriesArcMap.forEach((String key, _AnimatedArcList<D> arcList) { _seriesArcMap.forEach((key, arcList) {
for (var arcIndex = 0; arcIndex < arcList.arcs.length; arcIndex++) { for (var arcIndex = 0; arcIndex < arcList.arcs.length; arcIndex++) {
final arc = arcList.arcs[arcIndex]; final arc = arcList.arcs[arcIndex];
final arcStartAngle = arc.previousArcStartAngle; final arcStartAngle = arc.previousArcStartAngle;
@ -319,8 +316,8 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = <String>[]; final keysToRemove = <String>[];
_seriesArcMap.forEach((String key, _AnimatedArcList<D> arcList) { _seriesArcMap.forEach((key, arcList) {
arcList.arcs.removeWhere((_AnimatedArc<D> arc) => arc.animatingOut); arcList.arcs.removeWhere((arc) => arc.animatingOut);
if (arcList.arcs.isEmpty) { if (arcList.arcs.isEmpty) {
keysToRemove.add(key); keysToRemove.add(key);
@ -330,9 +327,9 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
keysToRemove.forEach(_seriesArcMap.remove); keysToRemove.forEach(_seriesArcMap.remove);
} }
_seriesArcMap.forEach((String key, _AnimatedArcList<D> arcList) { _seriesArcMap.forEach((key, arcList) {
final circleSectors = <CanvasPieSlice>[]; final circleSectors = <CanvasPieSlice>[];
final arcElementsList = new ArcRendererElementList<D>() final arcElementsList = ArcRendererElementList<D>()
..arcs = <ArcRendererElement<D>>[] ..arcs = <ArcRendererElement<D>>[]
..center = arcList.center ..center = arcList.center
..innerRadius = arcList.innerRadius ..innerRadius = arcList.innerRadius
@ -342,11 +339,11 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
..strokeWidthPx = arcList.strokeWidthPx; ..strokeWidthPx = arcList.strokeWidthPx;
arcList.arcs arcList.arcs
.map<ArcRendererElement<D>>((_AnimatedArc<D> animatingArc) => .map<ArcRendererElement<D>>(
animatingArc.getCurrentArc(animationPercent)) (animatingArc) => animatingArc.getCurrentArc(animationPercent))
.forEach((ArcRendererElement arc) { .forEach((arc) {
circleSectors.add( circleSectors
new CanvasPieSlice(arc.startAngle, arc.endAngle, fill: arc.color)); .add(CanvasPieSlice(arc.startAngle, arc.endAngle, fill: arc.color));
arcElementsList.arcs.add(arc); arcElementsList.arcs.add(arc);
}); });
@ -354,8 +351,8 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// Decorate the arcs with decorators that should appear below the main // Decorate the arcs with decorators that should appear below the main
// series data. // series data.
arcRendererDecorators arcRendererDecorators
.where((ArcRendererDecorator decorator) => !decorator.renderAbove) .where((decorator) => !decorator.renderAbove)
.forEach((ArcRendererDecorator decorator) { .forEach((decorator) {
decorator.decorate(arcElementsList, canvas, graphicsFactory, decorator.decorate(arcElementsList, canvas, graphicsFactory,
drawBounds: drawBounds, drawBounds: drawBounds,
animationPercent: animationPercent, animationPercent: animationPercent,
@ -363,15 +360,15 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
}); });
// Draw the arcs. // Draw the arcs.
canvas.drawPie(new CanvasPie( canvas.drawPie(CanvasPie(
circleSectors, arcList.center, arcList.radius, arcList.innerRadius, circleSectors, arcList.center, arcList.radius, arcList.innerRadius,
stroke: arcList.stroke, strokeWidthPx: arcList.strokeWidthPx)); stroke: arcList.stroke, strokeWidthPx: arcList.strokeWidthPx));
// Decorate the arcs with decorators that should appear above the main // Decorate the arcs with decorators that should appear above the main
// series data. This is the typical place for labels. // series data. This is the typical place for labels.
arcRendererDecorators arcRendererDecorators
.where((ArcRendererDecorator decorator) => decorator.renderAbove) .where((decorator) => decorator.renderAbove)
.forEach((ArcRendererDecorator decorator) { .forEach((decorator) {
decorator.decorate(arcElementsList, canvas, graphicsFactory, decorator.decorate(arcElementsList, canvas, graphicsFactory,
drawBounds: drawBounds, drawBounds: drawBounds,
animationPercent: animationPercent, animationPercent: animationPercent,
@ -398,7 +395,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
arcList.innerRadius < config.minHoleWidthForCenterContent) { arcList.innerRadius < config.minHoleWidthForCenterContent) {
// Return default bounds of 0 size. // Return default bounds of 0 size.
final bounds = _chart.drawAreaBounds; final bounds = _chart.drawAreaBounds;
return new Rectangle<int>((bounds.left + bounds.width / 2).round(), return Rectangle<int>((bounds.left + bounds.width / 2).round(),
(bounds.top + bounds.height / 2).round(), 0, 0); (bounds.top + bounds.height / 2).round(), 0, 0);
} }
@ -406,7 +403,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
// size that will fit within the pie's inner radius. // size that will fit within the pie's inner radius.
final width = (_cosPIOver4 * arcList.innerRadius).floor(); final width = (_cosPIOver4 * arcList.innerRadius).floor();
return new Rectangle<int>((arcList.center.x - width).round(), return Rectangle<int>((arcList.center.x - width).round(),
(arcList.center.y - width).round(), width * 2, width * 2); (arcList.center.y - width).round(), width * 2, width * 2);
} }
@ -422,7 +419,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final chartPosition = _getChartPosition(series.id, domain.toString()); final chartPosition = _getChartPosition(series.id, domain.toString());
return new DatumDetails( return DatumDetails(
datum: datum, datum: datum,
domain: domain, domain: domain,
measure: measure, measure: measure,
@ -457,7 +454,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final centerPointRadius = final centerPointRadius =
arcList.innerRadius + (arcList.radius - arcList.innerRadius) / 2; arcList.innerRadius + (arcList.radius - arcList.innerRadius) / 2;
chartPosition = new Point<double>( chartPosition = Point<double>(
centerPointRadius * cos(centerAngle) + arcList.center.x, centerPointRadius * cos(centerAngle) + arcList.center.x,
centerPointRadius * sin(centerAngle) + arcList.center.y); centerPointRadius * sin(centerAngle) + arcList.center.y);
@ -478,7 +475,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
return nearest; return nearest;
} }
_seriesArcMap.forEach((String key, _AnimatedArcList<D> arcList) { _seriesArcMap.forEach((key, arcList) {
if (arcList.series.overlaySeries) { if (arcList.series.overlaySeries) {
return; return;
} }
@ -506,11 +503,11 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
chartPointAngle = 2 * pi + chartPointAngle; chartPointAngle = 2 * pi + chartPointAngle;
} }
arcList.arcs.forEach((_AnimatedArc<D> arc) { arcList.arcs.forEach((arc) {
if (innerRadius <= distance && distance <= radius) { if (innerRadius <= distance && distance <= radius) {
if (arc.currentArcStartAngle <= chartPointAngle && if (arc.currentArcStartAngle <= chartPointAngle &&
chartPointAngle <= arc.currentArcEndAngle) { chartPointAngle <= arc.currentArcEndAngle) {
nearest.add(new DatumDetails<D>( nearest.add(DatumDetails<D>(
series: arcList.series, series: arcList.series,
datum: arc.datum, datum: arc.datum,
domain: arc.domain, domain: arc.domain,
@ -531,7 +528,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final chartPosition = final chartPosition =
_getChartPosition(details.series.id, details.domain.toString()); _getChartPosition(details.series.id, details.domain.toString());
return new DatumDetails.from(details, chartPosition: chartPosition); return DatumDetails.from(details, chartPosition: chartPosition);
} }
/// Assigns colors to series that are missing their colorFn. /// Assigns colors to series that are missing their colorFn.
@ -540,7 +537,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
{@required bool emptyCategoryUsesSinglePalette}) { {@required bool emptyCategoryUsesSinglePalette}) {
int maxMissing = 0; int maxMissing = 0;
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
if (series.colorFn == null) { if (series.colorFn == null) {
maxMissing = max(maxMissing, series.data.length); maxMissing = max(maxMissing, series.data.length);
} }
@ -550,7 +547,7 @@ class ArcRenderer<D> extends BaseSeriesRenderer<D> {
final colorPalettes = StyleFactory.style.getOrderedPalettes(1); final colorPalettes = StyleFactory.style.getOrderedPalettes(1);
final colorPalette = colorPalettes[0].makeShades(maxMissing); final colorPalette = colorPalettes[0].makeShades(maxMissing);
seriesList.forEach((MutableSeries series) { seriesList.forEach((series) {
series.colorFn ??= (index) => colorPalette[index]; series.colorFn ??= (index) => colorPalette[index];
}); });
} }
@ -593,10 +590,10 @@ class ArcRendererElement<D> {
ImmutableSeries<D> series; ImmutableSeries<D> series;
ArcRendererElement<D> clone() { ArcRendererElement<D> clone() {
return new ArcRendererElement<D>() return ArcRendererElement<D>()
..startAngle = startAngle ..startAngle = startAngle
..endAngle = endAngle ..endAngle = endAngle
..color = new Color.fromOther(color: color) ..color = Color.fromOther(color: color)
..index = index ..index = index
..key = key ..key = key
..series = series; ..series = series;

@ -34,7 +34,7 @@ class ArcRendererConfig<D> extends LayoutViewConfig
final SymbolRenderer symbolRenderer; final SymbolRenderer symbolRenderer;
final rendererAttributes = new RendererAttributes(); final rendererAttributes = RendererAttributes();
/// Total arc length, in radians. /// Total arc length, in radians.
/// ///
@ -85,10 +85,10 @@ class ArcRendererConfig<D> extends LayoutViewConfig
SymbolRenderer symbolRenderer}) SymbolRenderer symbolRenderer})
: this.noDataColor = StyleFactory.style.noDataColor, : this.noDataColor = StyleFactory.style.noDataColor,
this.stroke = StyleFactory.style.white, this.stroke = StyleFactory.style.white,
this.symbolRenderer = symbolRenderer ?? new CircleSymbolRenderer(); this.symbolRenderer = symbolRenderer ?? CircleSymbolRenderer();
@override @override
ArcRenderer<D> build() { ArcRenderer<D> build() {
return new ArcRenderer<D>(config: this, rendererId: customRendererId); return ArcRenderer<D>(config: this, rendererId: customRendererId);
} }
} }

@ -24,11 +24,11 @@ import '../layout/layout_config.dart' show LayoutConfig, MarginSpec;
import 'arc_renderer.dart' show ArcRenderer; import 'arc_renderer.dart' show ArcRenderer;
class PieChart<D> extends BaseChart<D> { class PieChart<D> extends BaseChart<D> {
static final _defaultLayoutConfig = new LayoutConfig( static final _defaultLayoutConfig = LayoutConfig(
topSpec: new MarginSpec.fromPixel(minPixel: 20), topSpec: MarginSpec.fromPixel(minPixel: 20),
bottomSpec: new MarginSpec.fromPixel(minPixel: 20), bottomSpec: MarginSpec.fromPixel(minPixel: 20),
leftSpec: new MarginSpec.fromPixel(minPixel: 20), leftSpec: MarginSpec.fromPixel(minPixel: 20),
rightSpec: new MarginSpec.fromPixel(minPixel: 20), rightSpec: MarginSpec.fromPixel(minPixel: 20),
); );
PieChart({LayoutConfig layoutConfig}) PieChart({LayoutConfig layoutConfig})
@ -38,7 +38,7 @@ class PieChart<D> extends BaseChart<D> {
void drawInternal(List<MutableSeries<D>> seriesList, void drawInternal(List<MutableSeries<D>> seriesList,
{bool skipAnimation, bool skipLayout}) { {bool skipAnimation, bool skipLayout}) {
if (seriesList.length > 1) { if (seriesList.length > 1) {
throw new ArgumentError('PieChart can only render a single series'); throw ArgumentError('PieChart can only render a single series');
} }
super.drawInternal(seriesList, super.drawInternal(seriesList,
skipAnimation: skipAnimation, skipLayout: skipLayout); skipAnimation: skipAnimation, skipLayout: skipLayout);
@ -46,7 +46,7 @@ class PieChart<D> extends BaseChart<D> {
@override @override
SeriesRenderer<D> makeDefaultRenderer() { SeriesRenderer<D> makeDefaultRenderer() {
return new ArcRenderer<D>()..rendererId = SeriesRenderer.defaultRendererId; return ArcRenderer<D>()..rendererId = SeriesRenderer.defaultRendererId;
} }
/// Returns a list of datum details from selection model of [type]. /// Returns a list of datum details from selection model of [type].

@ -37,7 +37,7 @@ class ComparisonPointsDecorator<D> extends PointRendererDecorator<D> {
final bool renderAbove = false; final bool renderAbove = false;
ComparisonPointsDecorator({PointSymbolRenderer symbolRenderer}) ComparisonPointsDecorator({PointSymbolRenderer symbolRenderer})
: this.symbolRenderer = symbolRenderer ?? new CylinderSymbolRenderer(); : this.symbolRenderer = symbolRenderer ?? CylinderSymbolRenderer();
@override @override
void decorate(PointRendererElement<D> pointElement, ChartCanvas canvas, void decorate(PointRendererElement<D> pointElement, ChartCanvas canvas,
@ -79,19 +79,19 @@ class ComparisonPointsDecorator<D> extends PointRendererDecorator<D> {
// Construct the points that describe our line p1p2. // Construct the points that describe our line p1p2.
var p1 = var p1 =
new Point<double>(pointElement.point.xLower, pointElement.point.yLower); Point<double>(pointElement.point.xLower, pointElement.point.yLower);
var p2 = var p2 =
new Point<double>(pointElement.point.xUpper, pointElement.point.yUpper); Point<double>(pointElement.point.xUpper, pointElement.point.yUpper);
// First check to see if there is no intersection at all between the line // First check to see if there is no intersection at all between the line
// p1p2 and [drawBounds]. // p1p2 and [drawBounds].
final dataBoundsRect = new Rectangle<num>.fromPoints(p1, p2); final dataBoundsRect = Rectangle<num>.fromPoints(p1, p2);
if (!drawBounds.intersects(dataBoundsRect)) { if (!drawBounds.intersects(dataBoundsRect)) {
return null; return null;
} }
// Line with end points [p1] and [p2]. // Line with end points [p1] and [p2].
final p1p2 = new _Line.fromPoints(p1, p2); final p1p2 = _Line.fromPoints(p1, p2);
// Next, slide p1 along the line p1p2 towards the edge of the draw area if // Next, slide p1 along the line p1p2 towards the edge of the draw area if
// the point is located outside of it. // the point is located outside of it.
@ -125,14 +125,14 @@ class ComparisonPointsDecorator<D> extends PointRendererDecorator<D> {
// with equations y = bounds.top and y = bounds.bottom. We can pass these // with equations y = bounds.top and y = bounds.bottom. We can pass these
// into a standard line interception method to find our point. // into a standard line interception method to find our point.
if (p1.y < bounds.top) { if (p1.y < bounds.top) {
final p = line.intersection(new _Line(0.0, bounds.top.toDouble())); final p = line.intersection(_Line(0.0, bounds.top.toDouble()));
if (p != null && bounds.containsPoint(p)) { if (p != null && bounds.containsPoint(p)) {
return p; return p;
} }
} }
if (p1.y > bounds.bottom) { if (p1.y > bounds.bottom) {
final p = line.intersection(new _Line(0.0, bounds.bottom.toDouble())); final p = line.intersection(_Line(0.0, bounds.bottom.toDouble()));
if (p != null && bounds.containsPoint(p)) { if (p != null && bounds.containsPoint(p)) {
return p; return p;
} }
@ -145,16 +145,14 @@ class ComparisonPointsDecorator<D> extends PointRendererDecorator<D> {
// //
// y = slope * x + yIntercept // y = slope * x + yIntercept
if (p1.x < bounds.left) { if (p1.x < bounds.left) {
final p = final p = line.intersection(_Line.fromVertical(bounds.left.toDouble()));
line.intersection(new _Line.fromVertical(bounds.left.toDouble()));
if (p != null && bounds.containsPoint(p)) { if (p != null && bounds.containsPoint(p)) {
return p; return p;
} }
} }
if (p1.x > bounds.right) { if (p1.x > bounds.right) {
final p = final p = line.intersection(_Line.fromVertical(bounds.right.toDouble()));
line.intersection(new _Line.fromVertical(bounds.right.toDouble()));
if (p != null && bounds.containsPoint(p)) { if (p != null && bounds.containsPoint(p)) {
return p; return p;
} }
@ -187,7 +185,7 @@ class _Line {
factory _Line.fromPoints(Point<num> p1, Point<num> p2) { factory _Line.fromPoints(Point<num> p1, Point<num> p2) {
// Handle vertical lines. // Handle vertical lines.
if (p1.x == p2.x) { if (p1.x == p2.x) {
return new _Line.fromVertical(p1.x); return _Line.fromVertical(p1.x);
} }
// Slope of the line p1p2. // Slope of the line p1p2.
@ -196,12 +194,12 @@ class _Line {
// y-intercept of the line p1p2. // y-intercept of the line p1p2.
double b = (p1.y - (m * p1.x)).toDouble(); double b = (p1.y - (m * p1.x)).toDouble();
return new _Line(m, b); return _Line(m, b);
} }
/// Creates a vertical line, with the question x = [xIntercept]. /// Creates a vertical line, with the question x = [xIntercept].
factory _Line.fromVertical(num xIntercept) { factory _Line.fromVertical(num xIntercept) {
return new _Line(null, null, xIntercept.toDouble()); return _Line(null, null, xIntercept.toDouble());
} }
/// Computes the intersection of `this` and [other]. /// Computes the intersection of `this` and [other].
@ -218,14 +216,14 @@ class _Line {
// just plug its xIntercept value into the line equation as x and solve for // just plug its xIntercept value into the line equation as x and solve for
// y. // y.
if (other.vertical) { if (other.vertical) {
return new Point<double>( return Point<double>(
other.xIntercept, slope * other.xIntercept + yIntercept); other.xIntercept, slope * other.xIntercept + yIntercept);
} }
// If this line is a vertical line (has undefined slope), then we can just // If this line is a vertical line (has undefined slope), then we can just
// plug its xIntercept value into the line equation as x and solve for y. // plug its xIntercept value into the line equation as x and solve for y.
if (vertical) { if (vertical) {
return new Point<double>( return Point<double>(
xIntercept, other.slope * xIntercept + other.yIntercept); xIntercept, other.slope * xIntercept + other.yIntercept);
} }
@ -236,6 +234,6 @@ class _Line {
final y = slope * (other.yIntercept - yIntercept) / (slope - other.slope) + final y = slope * (other.yIntercept - yIntercept) / (slope - other.slope) +
yIntercept; yIntercept;
return new Point<double>(x, y); return Point<double>(x, y);
} }
} }

@ -38,22 +38,22 @@ import 'point_renderer_config.dart' show PointRendererConfig;
import 'point_renderer_decorator.dart' show PointRendererDecorator; import 'point_renderer_decorator.dart' show PointRendererDecorator;
const pointElementsKey = const pointElementsKey =
const AttributeKey<List<PointRendererElement>>('PointRenderer.elements'); AttributeKey<List<PointRendererElement>>('PointRenderer.elements');
const pointSymbolRendererFnKey = const pointSymbolRendererFnKey =
const AttributeKey<AccessorFn<String>>('PointRenderer.symbolRendererFn'); AttributeKey<AccessorFn<String>>('PointRenderer.symbolRendererFn');
const pointSymbolRendererIdKey = const pointSymbolRendererIdKey =
const AttributeKey<String>('PointRenderer.symbolRendererId'); AttributeKey<String>('PointRenderer.symbolRendererId');
/// Defines a fixed radius for data bounds lines (typically drawn by attaching a /// Defines a fixed radius for data bounds lines (typically drawn by attaching a
/// [ComparisonPointsDecorator] to the renderer. /// [ComparisonPointsDecorator] to the renderer.
const boundsLineRadiusPxKey = const boundsLineRadiusPxKey =
const AttributeKey<double>('SymbolAnnotationRenderer.boundsLineRadiusPx'); AttributeKey<double>('SymbolAnnotationRenderer.boundsLineRadiusPx');
/// Defines an [AccessorFn] for the radius for data bounds lines (typically /// Defines an [AccessorFn] for the radius for data bounds lines (typically
/// drawn by attaching a [ComparisonPointsDecorator] to the renderer. /// drawn by attaching a [ComparisonPointsDecorator] to the renderer.
const boundsLineRadiusPxFnKey = const AttributeKey<AccessorFn<double>>( const boundsLineRadiusPxFnKey = AttributeKey<AccessorFn<double>>(
'SymbolAnnotationRenderer.boundsLineRadiusPxFn'); 'SymbolAnnotationRenderer.boundsLineRadiusPxFn');
const defaultSymbolRendererId = '__default__'; const defaultSymbolRendererId = '__default__';
@ -75,7 +75,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
/// [LinkedHashMap] is used to render the series on the canvas in the same /// [LinkedHashMap] is used to render the series on the canvas in the same
/// order as the data was given to the chart. /// order as the data was given to the chart.
@protected @protected
var seriesPointMap = new LinkedHashMap<String, List<AnimatedPoint<D>>>(); var seriesPointMap = LinkedHashMap<String, List<AnimatedPoint<D>>>();
// Store a list of lines that exist in the series data. // Store a list of lines that exist in the series data.
// //
@ -85,14 +85,13 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
final _currentKeys = <String>[]; final _currentKeys = <String>[];
PointRenderer({String rendererId, PointRendererConfig config}) PointRenderer({String rendererId, PointRendererConfig config})
: this.config = config ?? new PointRendererConfig(), : this.config = config ?? PointRendererConfig(),
pointRendererDecorators = config?.pointRendererDecorators ?? [], pointRendererDecorators = config?.pointRendererDecorators ?? [],
super( super(
rendererId: rendererId ?? 'point', rendererId: rendererId ?? 'point',
layoutPaintOrder: layoutPaintOrder:
config?.layoutPaintOrder ?? LayoutViewPaintOrder.point, config?.layoutPaintOrder ?? LayoutViewPaintOrder.point,
symbolRenderer: symbolRenderer: config?.symbolRenderer ?? CircleSymbolRenderer());
config?.symbolRenderer ?? new CircleSymbolRenderer());
@override @override
void configureSeries(List<MutableSeries<D>> seriesList) { void configureSeries(List<MutableSeries<D>> seriesList) {
@ -101,7 +100,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
@override @override
void preprocessSeries(List<MutableSeries<D>> seriesList) { void preprocessSeries(List<MutableSeries<D>> seriesList) {
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
final elements = <PointRendererElement<D>>[]; final elements = <PointRendererElement<D>>[];
// Default to the configured radius if none was defined by the series. // Default to the configured radius if none was defined by the series.
@ -132,9 +131,8 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// series data between chart draw cycles. Ideally we should require the // series data between chart draw cycles. Ideally we should require the
// user to provide a key function, but this at least provides some // user to provide a key function, but this at least provides some
// smoothing when adding/removing data. // smoothing when adding/removing data.
series.keyFn ??= series.keyFn ??= (index) => '${series.id}__${series.domainFn(index)}__'
(int index) => '${series.id}__${series.domainFn(index)}__' '${series.measureFn(index)}';
'${series.measureFn(index)}';
for (var index = 0; index < series.data.length; index++) { for (var index = 0; index < series.data.length; index++) {
// Default to the configured radius if none was returned by the // Default to the configured radius if none was returned by the
@ -181,7 +179,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
var fillColor = fillColorFn(index); var fillColor = fillColorFn(index);
fillColor ??= color; fillColor ??= color;
final details = new PointRendererElement<D>() final details = PointRendererElement<D>()
..color = color ..color = color
..fillColor = fillColor ..fillColor = fillColor
..radiusPx = radiusPx.toDouble() ..radiusPx = radiusPx.toDouble()
@ -203,7 +201,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// later for sorting. // later for sorting.
final sortedSeriesIds = []; final sortedSeriesIds = [];
seriesList.forEach((ImmutableSeries<D> series) { seriesList.forEach((series) {
sortedSeriesIds.add(series.id); sortedSeriesIds.add(series.id);
final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>; final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;
@ -256,9 +254,8 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
final pointKey = keyFn(index); final pointKey = keyFn(index);
// If we already have an AnimatingPoint for that index, use it. // If we already have an AnimatingPoint for that index, use it.
var animatingPoint = pointList.firstWhere( var animatingPoint = pointList
(AnimatedPoint point) => point.key == pointKey, .firstWhere((point) => point.key == pointKey, orElse: () => null);
orElse: () => null);
// If we don't have any existing arc element, create a new arc and // If we don't have any existing arc element, create a new arc and
// have it animate in from the position of the previous arc's end // have it animate in from the position of the previous arc's end
@ -279,9 +276,9 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
0.0, 0.0,
measureAxis); measureAxis);
animatingPoint = new AnimatedPoint<D>( animatingPoint = AnimatedPoint<D>(
key: pointKey, overlaySeries: series.overlaySeries) key: pointKey, overlaySeries: series.overlaySeries)
..setNewTarget(new PointRendererElement<D>() ..setNewTarget(PointRendererElement<D>()
..color = details.color ..color = details.color
..fillColor = details.fillColor ..fillColor = details.fillColor
..measureAxisPosition = measureAxis.getLocation(0.0) ..measureAxisPosition = measureAxis.getLocation(0.0)
@ -298,7 +295,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
_currentKeys.add(pointKey); _currentKeys.add(pointKey);
// Get the pointElement we are going to setup. // Get the pointElement we are going to setup.
final pointElement = new PointRendererElement<D>() final pointElement = PointRendererElement<D>()
..color = details.color ..color = details.color
..fillColor = details.fillColor ..fillColor = details.fillColor
..measureAxisPosition = measureAxis.getLocation(0.0) ..measureAxisPosition = measureAxis.getLocation(0.0)
@ -315,11 +312,11 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// Sort the renderer elements to be in the same order as the series list. // Sort the renderer elements to be in the same order as the series list.
// They may get disordered between chart draw cycles if a behavior adds or // They may get disordered between chart draw cycles if a behavior adds or
// removes series from the list (e.g. click to hide on legends). // removes series from the list (e.g. click to hide on legends).
seriesPointMap = new LinkedHashMap.fromIterable(sortedSeriesIds, seriesPointMap = LinkedHashMap.fromIterable(sortedSeriesIds,
key: (k) => k, value: (k) => seriesPointMap[k]); key: (k) => k, value: (k) => seriesPointMap[k]);
// Animate out points that don't exist anymore. // Animate out points that don't exist anymore.
seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) { seriesPointMap.forEach((key, points) {
for (var point in points) { for (var point in points) {
if (_currentKeys.contains(point.key) != true) { if (_currentKeys.contains(point.key) != true) {
point.animateOut(); point.animateOut();
@ -342,27 +339,27 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
if (animationPercent == 1.0) { if (animationPercent == 1.0) {
final keysToRemove = <String>[]; final keysToRemove = <String>[];
seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) { seriesPointMap.forEach((key, points) {
points.removeWhere((AnimatedPoint<D> point) => point.animatingOut); points.removeWhere((point) => point.animatingOut);
if (points.isEmpty) { if (points.isEmpty) {
keysToRemove.add(key); keysToRemove.add(key);
} }
}); });
keysToRemove.forEach((String key) => seriesPointMap.remove(key)); keysToRemove.forEach((key) => seriesPointMap.remove(key));
} }
seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) { seriesPointMap.forEach((key, points) {
points points
.map<PointRendererElement<D>>((AnimatedPoint<D> animatingPoint) => .map<PointRendererElement<D>>((animatingPoint) =>
animatingPoint.getCurrentPoint(animationPercent)) animatingPoint.getCurrentPoint(animationPercent))
.forEach((PointRendererElement point) { .forEach((point) {
// Decorate the points with decorators that should appear below the main // Decorate the points with decorators that should appear below the main
// series data. // series data.
pointRendererDecorators pointRendererDecorators
.where((PointRendererDecorator decorator) => !decorator.renderAbove) .where((decorator) => !decorator.renderAbove)
.forEach((PointRendererDecorator decorator) { .forEach((decorator) {
decorator.decorate(point, canvas, graphicsFactory, decorator.decorate(point, canvas, graphicsFactory,
drawBounds: componentBounds, drawBounds: componentBounds,
animationPercent: animationPercent, animationPercent: animationPercent,
@ -374,7 +371,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// prevents harshly clipping off half of the shape. // prevents harshly clipping off half of the shape.
if (point.point.y != null && if (point.point.y != null &&
componentBounds.containsPoint(point.point)) { componentBounds.containsPoint(point.point)) {
final bounds = new Rectangle<double>( final bounds = Rectangle<double>(
point.point.x - point.radiusPx, point.point.x - point.radiusPx,
point.point.y - point.radiusPx, point.point.y - point.radiusPx,
point.radiusPx * 2, point.radiusPx * 2,
@ -388,8 +385,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
} else { } else {
final id = point.symbolRendererId; final id = point.symbolRendererId;
if (!config.customSymbolRenderers.containsKey(id)) { if (!config.customSymbolRenderers.containsKey(id)) {
throw new ArgumentError( throw ArgumentError('Invalid custom symbol renderer id "$id"');
'Invalid custom symbol renderer id "${id}"');
} }
final customRenderer = config.customSymbolRenderers[id]; final customRenderer = config.customSymbolRenderers[id];
@ -403,8 +399,8 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// Decorate the points with decorators that should appear above the main // Decorate the points with decorators that should appear above the main
// series data. This is the typical place for labels. // series data. This is the typical place for labels.
pointRendererDecorators pointRendererDecorators
.where((PointRendererDecorator decorator) => decorator.renderAbove) .where((decorator) => decorator.renderAbove)
.forEach((PointRendererDecorator decorator) { .forEach((decorator) {
decorator.decorate(point, canvas, graphicsFactory, decorator.decorate(point, canvas, graphicsFactory,
drawBounds: componentBounds, drawBounds: componentBounds,
animationPercent: animationPercent, animationPercent: animationPercent,
@ -450,7 +446,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
? measureAxis.getLocation(measureUpperBoundValue + measureOffsetValue) ? measureAxis.getLocation(measureUpperBoundValue + measureOffsetValue)
: null; : null;
return new DatumPoint<D>( return DatumPoint<D>(
datum: datum, datum: datum,
domain: domainValue, domain: domainValue,
series: series, series: series,
@ -472,13 +468,13 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
return nearest; return nearest;
} }
seriesPointMap.values.forEach((List<AnimatedPoint<D>> points) { seriesPointMap.values.forEach((points) {
PointRendererElement<D> nearestPoint; PointRendererElement<D> nearestPoint;
double nearestDomainDistance = _maxInitialDistance; double nearestDomainDistance = _maxInitialDistance;
double nearestMeasureDistance = _maxInitialDistance; double nearestMeasureDistance = _maxInitialDistance;
double nearestRelativeDistance = _maxInitialDistance; double nearestRelativeDistance = _maxInitialDistance;
points.forEach((AnimatedPoint<D> point) { points.forEach((point) {
if (point.overlaySeries) { if (point.overlaySeries) {
return; return;
} }
@ -519,14 +515,13 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
} else { } else {
final id = nearestPoint.symbolRendererId; final id = nearestPoint.symbolRendererId;
if (!config.customSymbolRenderers.containsKey(id)) { if (!config.customSymbolRenderers.containsKey(id)) {
throw new ArgumentError( throw ArgumentError('Invalid custom symbol renderer id "$id"');
'Invalid custom symbol renderer id "${id}"');
} }
nearestSymbolRenderer = config.customSymbolRenderers[id]; nearestSymbolRenderer = config.customSymbolRenderers[id];
} }
nearest.add(new DatumDetails<D>( nearest.add(DatumDetails<D>(
datum: nearestPoint.point.datum, datum: nearestPoint.point.datum,
domain: nearestPoint.point.domain, domain: nearestPoint.point.domain,
series: nearestPoint.point.series, series: nearestPoint.point.series,
@ -573,9 +568,9 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
// use the smaller of this distance and the distance from the primary // use the smaller of this distance and the distance from the primary
// point as the relativeDistance from this datum. // point as the relativeDistance from this datum.
final num relativeDistanceBounds = distanceBetweenPointAndLineSegment( final num relativeDistanceBounds = distanceBetweenPointAndLineSegment(
new Vector2(chartPoint.x, chartPoint.y), Vector2(chartPoint.x, chartPoint.y),
new Vector2(datumPoint.xLower, datumPoint.yLower), Vector2(datumPoint.xLower, datumPoint.yLower),
new Vector2(datumPoint.xUpper, datumPoint.yUpper)); Vector2(datumPoint.xUpper, datumPoint.yUpper));
insidePoint = (relativeDistance < radiusPx) || insidePoint = (relativeDistance < radiusPx) ||
(boundsLineRadiusPx != null && (boundsLineRadiusPx != null &&
@ -589,7 +584,7 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
insidePoint = (relativeDistance < radiusPx); insidePoint = (relativeDistance < radiusPx);
} }
return new _Distances( return _Distances(
domainDistance: domainDistance, domainDistance: domainDistance,
measureDistance: measureDistance, measureDistance: measureDistance,
relativeDistance: relativeDistance, relativeDistance: relativeDistance,
@ -636,16 +631,16 @@ class PointRenderer<D> extends BaseCartesianRenderer<D> {
} else { } else {
final id = symbolRendererId; final id = symbolRendererId;
if (!config.customSymbolRenderers.containsKey(id)) { if (!config.customSymbolRenderers.containsKey(id)) {
throw new ArgumentError('Invalid custom symbol renderer id "${id}"'); throw ArgumentError('Invalid custom symbol renderer id "$id"');
} }
nearestSymbolRenderer = config.customSymbolRenderers[id]; nearestSymbolRenderer = config.customSymbolRenderers[id];
} }
return new DatumDetails.from(details, return DatumDetails.from(details,
chartPosition: new Point<double>(point.x, point.y), chartPosition: Point<double>(point.x, point.y),
chartPositionLower: new Point<double>(point.xLower, point.yLower), chartPositionLower: Point<double>(point.xLower, point.yLower),
chartPositionUpper: new Point<double>(point.xUpper, point.yUpper), chartPositionUpper: Point<double>(point.xUpper, point.yUpper),
symbolRenderer: nearestSymbolRenderer); symbolRenderer: nearestSymbolRenderer);
} }
} }
@ -682,7 +677,7 @@ class DatumPoint<D> extends Point<double> {
double y, double y,
double yLower, double yLower,
double yUpper}) { double yUpper}) {
return new DatumPoint<D>( return DatumPoint<D>(
datum: other.datum, datum: other.datum,
domain: other.domain, domain: other.domain,
series: other.series, series: other.series,
@ -706,11 +701,10 @@ class PointRendererElement<D> {
String symbolRendererId; String symbolRendererId;
PointRendererElement<D> clone() { PointRendererElement<D> clone() {
return new PointRendererElement<D>() return PointRendererElement<D>()
..point = new DatumPoint<D>.from(point) ..point = DatumPoint<D>.from(point)
..color = color != null ? new Color.fromOther(color: color) : null ..color = color != null ? Color.fromOther(color: color) : null
..fillColor = ..fillColor = fillColor != null ? Color.fromOther(color: fillColor) : null
fillColor != null ? new Color.fromOther(color: fillColor) : null
..measureAxisPosition = measureAxisPosition ..measureAxisPosition = measureAxisPosition
..radiusPx = radiusPx ..radiusPx = radiusPx
..boundsLineRadiusPx = boundsLineRadiusPx ..boundsLineRadiusPx = boundsLineRadiusPx
@ -756,7 +750,7 @@ class PointRendererElement<D> {
previousPoint.yUpper previousPoint.yUpper
: null; : null;
point = new DatumPoint<D>.from(targetPoint, point = DatumPoint<D>.from(targetPoint,
x: x, x: x,
xLower: xLower, xLower: xLower,
xUpper: xUpper, xUpper: xUpper,
@ -808,7 +802,7 @@ class AnimatedPoint<D> {
// Set the target measure value to the axis position. // Set the target measure value to the axis position.
var targetPoint = newTarget.point; var targetPoint = newTarget.point;
newTarget.point = new DatumPoint<D>.from(targetPoint, newTarget.point = DatumPoint<D>.from(targetPoint,
x: targetPoint.x, x: targetPoint.x,
y: newTarget.measureAxisPosition.roundToDouble(), y: newTarget.measureAxisPosition.roundToDouble(),
yLower: newTarget.measureAxisPosition.roundToDouble(), yLower: newTarget.measureAxisPosition.roundToDouble(),

@ -42,7 +42,7 @@ class PointRendererConfig<D> extends LayoutViewConfig
/// [symbolRenderer]. /// [symbolRenderer].
final Map<String, SymbolRenderer> customSymbolRenderers; final Map<String, SymbolRenderer> customSymbolRenderers;
final rendererAttributes = new RendererAttributes(); final rendererAttributes = RendererAttributes();
/// Default radius of the points, used if a series does not define a radiusPx /// Default radius of the points, used if a series does not define a radiusPx
/// accessor function. /// accessor function.
@ -75,6 +75,6 @@ class PointRendererConfig<D> extends LayoutViewConfig
@override @override
PointRenderer<D> build() { PointRenderer<D> build() {
return new PointRenderer<D>(config: this, rendererId: customRendererId); return PointRenderer<D>(config: this, rendererId: customRendererId);
} }
} }

@ -55,13 +55,12 @@ class ScatterPlotChart extends NumericCartesianChart {
@override @override
SeriesRenderer<num> makeDefaultRenderer() { SeriesRenderer<num> makeDefaultRenderer() {
return new PointRenderer<num>() return PointRenderer<num>()..rendererId = SeriesRenderer.defaultRendererId;
..rendererId = SeriesRenderer.defaultRendererId;
} }
@override @override
void initDomainAxis() { void initDomainAxis() {
domainAxis.tickDrawStrategy = new GridlineRendererSpec<num>() domainAxis.tickDrawStrategy = GridlineRendererSpec<num>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
} }
} }

@ -32,7 +32,7 @@ import '../layout/layout_view.dart'
LayoutViewPaintOrder, LayoutViewPaintOrder,
LayoutViewPositionOrder, LayoutViewPositionOrder,
ViewMeasuredSizes; ViewMeasuredSizes;
import 'point_renderer.dart' show AnimatedPoint, DatumPoint, PointRenderer; import 'point_renderer.dart' show DatumPoint, PointRenderer;
import 'symbol_annotation_renderer_config.dart' import 'symbol_annotation_renderer_config.dart'
show SymbolAnnotationRendererConfig; show SymbolAnnotationRendererConfig;
@ -51,13 +51,13 @@ import 'symbol_annotation_renderer_config.dart'
class SymbolAnnotationRenderer<D> extends PointRenderer<D> class SymbolAnnotationRenderer<D> extends PointRenderer<D>
implements LayoutView { implements LayoutView {
Rectangle<int> _componentBounds; Rectangle<int> _componentBounds;
GraphicsFactory _graphicsFactory; GraphicsFactory graphicsFactory;
CartesianChart<D> _chart; CartesianChart<D> _chart;
var _currentHeight = 0; var _currentHeight = 0;
final _seriesInfo = new LinkedHashMap<String, _SeriesInfo<D>>(); final _seriesInfo = LinkedHashMap<String, _SeriesInfo<D>>();
SymbolAnnotationRenderer( SymbolAnnotationRenderer(
{String rendererId, SymbolAnnotationRendererConfig config}) {String rendererId, SymbolAnnotationRendererConfig config})
@ -79,7 +79,7 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
double offset = 0.0; double offset = 0.0;
seriesList.forEach((MutableSeries<D> series) { seriesList.forEach((series) {
final seriesKey = series.id; final seriesKey = series.id;
// Default to the configured radius if none was defined by the series. // Default to the configured radius if none was defined by the series.
@ -105,19 +105,18 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
localConfig.verticalSymbolTopPaddingPx + localConfig.verticalSymbolTopPaddingPx +
(rowInnerHeight / 2); (rowInnerHeight / 2);
series.measureFn = (int index) => 0; series.measureFn = (index) => 0;
series.measureOffsetFn = (int index) => 0; series.measureOffsetFn = (index) => 0;
// Override the key function to allow for range annotations that start at // Override the key function to allow for range annotations that start at
// the same point. This is a necessary hack because every annotation has a // the same point. This is a necessary hack because every annotation has a
// measure value of 0, so the key generated in [PointRenderer] is not // measure value of 0, so the key generated in [PointRenderer] is not
// unique enough. // unique enough.
series.keyFn ??= series.keyFn ??= (index) => '${series.id}__${series.domainFn(index)}__'
(int index) => '${series.id}__${series.domainFn(index)}__' '${series.domainLowerBoundFn(index)}__'
'${series.domainLowerBoundFn(index)}__' '${series.domainUpperBoundFn(index)}';
'${series.domainUpperBoundFn(index)}';
_seriesInfo[seriesKey] = new _SeriesInfo<D>( _seriesInfo[seriesKey] = _SeriesInfo<D>(
rowHeight: rowHeight, rowHeight: rowHeight,
rowStart: offset, rowStart: offset,
symbolCenter: symbolCenter, symbolCenter: symbolCenter,
@ -165,7 +164,7 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
final measureUpperBoundPosition = final measureUpperBoundPosition =
domainUpperBoundPosition != null ? measurePosition : null; domainUpperBoundPosition != null ? measurePosition : null;
return new DatumPoint<D>( return DatumPoint<D>(
datum: datum, datum: datum,
domain: domainValue, domain: domainValue,
series: series, series: series,
@ -180,7 +179,7 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
@override @override
void onAttach(BaseChart<D> chart) { void onAttach(BaseChart<D> chart) {
if (!(chart is CartesianChart)) { if (!(chart is CartesianChart)) {
throw new ArgumentError( throw ArgumentError(
'SymbolAnnotationRenderer can only be attached to a CartesianChart'); 'SymbolAnnotationRenderer can only be attached to a CartesianChart');
} }
@ -205,13 +204,13 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
// Use the domain axis of the attached chart to render the separator lines // Use the domain axis of the attached chart to render the separator lines
// to keep the same overall style. // to keep the same overall style.
if ((config as SymbolAnnotationRendererConfig).showSeparatorLines) { if ((config as SymbolAnnotationRendererConfig).showSeparatorLines) {
seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) { seriesPointMap.forEach((key, points) {
final seriesInfo = _seriesInfo[key]; final seriesInfo = _seriesInfo[key];
final y = componentBounds.top + seriesInfo.rowStart; final y = componentBounds.top + seriesInfo.rowStart;
final domainAxis = _chart.domainAxis; final domainAxis = _chart.domainAxis;
final bounds = new Rectangle<int>( final bounds = Rectangle<int>(
componentBounds.left, y.round(), componentBounds.width, 0); componentBounds.left, y.round(), componentBounds.width, 0);
domainAxis.tickDrawStrategy domainAxis.tickDrawStrategy
.drawAxisLine(canvas, domainAxis.axisOrientation, bounds); .drawAxisLine(canvas, domainAxis.axisOrientation, bounds);
@ -219,21 +218,13 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
} }
} }
@override
GraphicsFactory get graphicsFactory => _graphicsFactory;
@override
set graphicsFactory(GraphicsFactory value) {
_graphicsFactory = value;
}
// //
// Layout methods // Layout methods
// //
@override @override
LayoutViewConfig get layoutConfig { LayoutViewConfig get layoutConfig {
return new LayoutViewConfig( return LayoutViewConfig(
paintOrder: LayoutViewPaintOrder.point, paintOrder: LayoutViewPaintOrder.point,
position: LayoutPosition.Bottom, position: LayoutPosition.Bottom,
positionOrder: LayoutViewPositionOrder.symbolAnnotation); positionOrder: LayoutViewPositionOrder.symbolAnnotation);
@ -244,7 +235,7 @@ class SymbolAnnotationRenderer<D> extends PointRenderer<D>
// The sizing of component is not flexible. It's height is always a multiple // The sizing of component is not flexible. It's height is always a multiple
// of the number of series rendered, even if that ends up taking all of the // of the number of series rendered, even if that ends up taking all of the
// available margin space. // available margin space.
return new ViewMeasuredSizes( return ViewMeasuredSizes(
preferredWidth: maxWidth, preferredHeight: _currentHeight); preferredWidth: maxWidth, preferredHeight: _currentHeight);
} }

@ -57,8 +57,8 @@ class SymbolAnnotationRendererConfig<D> extends PointRendererConfig<D> {
customRendererId: customRendererId, customRendererId: customRendererId,
pointRendererDecorators: pointRendererDecorators ?? pointRendererDecorators: pointRendererDecorators ??
[ [
new ComparisonPointsDecorator( ComparisonPointsDecorator(
symbolRenderer: new RectangleRangeSymbolRenderer()) symbolRenderer: RectangleRangeSymbolRenderer())
], ],
radiusPx: radiusPx, radiusPx: radiusPx,
symbolRenderer: symbolRenderer, symbolRenderer: symbolRenderer,
@ -66,7 +66,7 @@ class SymbolAnnotationRendererConfig<D> extends PointRendererConfig<D> {
@override @override
SymbolAnnotationRenderer<D> build() { SymbolAnnotationRenderer<D> build() {
return new SymbolAnnotationRenderer<D>( return SymbolAnnotationRenderer<D>(
config: this, rendererId: customRendererId); config: this, rendererId: customRendererId);
} }
} }

@ -41,20 +41,20 @@ class TimeSeriesChart extends CartesianChart<DateTime> {
: super( : super(
vertical: vertical, vertical: vertical,
layoutConfig: layoutConfig, layoutConfig: layoutConfig,
domainAxis: new DateTimeAxis(dateTimeFactory), domainAxis: DateTimeAxis(dateTimeFactory),
primaryMeasureAxis: primaryMeasureAxis, primaryMeasureAxis: primaryMeasureAxis,
secondaryMeasureAxis: secondaryMeasureAxis, secondaryMeasureAxis: secondaryMeasureAxis,
disjointMeasureAxes: disjointMeasureAxes); disjointMeasureAxes: disjointMeasureAxes);
@override @override
void initDomainAxis() { void initDomainAxis() {
domainAxis.tickDrawStrategy = new SmallTickRendererSpec<DateTime>() domainAxis.tickDrawStrategy = SmallTickRendererSpec<DateTime>()
.createDrawStrategy(context, graphicsFactory); .createDrawStrategy(context, graphicsFactory);
} }
@override @override
SeriesRenderer<DateTime> makeDefaultRenderer() { SeriesRenderer<DateTime> makeDefaultRenderer() {
return new LineRenderer<DateTime>() return LineRenderer<DateTime>()
..rendererId = SeriesRenderer.defaultRendererId; ..rendererId = SeriesRenderer.defaultRendererId;
} }

@ -17,9 +17,9 @@ import 'package:meta/meta.dart' show immutable;
@immutable @immutable
class Color { class Color {
static const black = const Color(r: 0, g: 0, b: 0); static const black = Color(r: 0, g: 0, b: 0);
static const white = const Color(r: 255, g: 255, b: 255); static const white = Color(r: 255, g: 255, b: 255);
static const transparent = const Color(r: 0, g: 0, b: 0, a: 0); static const transparent = Color(r: 0, g: 0, b: 0, a: 0);
static const _darkerPercentOfOrig = 0.7; static const _darkerPercentOfOrig = 0.7;
static const _lighterPercentOfOrig = 0.1; static const _lighterPercentOfOrig = 0.1;
@ -53,12 +53,12 @@ class Color {
final g = (bigint >> 8) & 255; final g = (bigint >> 8) & 255;
final b = bigint & 255; final b = bigint & 255;
final a = 255; final a = 255;
return new Color(r: r, g: g, b: b, a: a); return Color(r: r, g: g, b: b, a: a);
} }
Color get darker => Color get darker =>
_darker ?? _darker ??
new Color( Color(
r: (r * _darkerPercentOfOrig).round(), r: (r * _darkerPercentOfOrig).round(),
g: (g * _darkerPercentOfOrig).round(), g: (g * _darkerPercentOfOrig).round(),
b: (b * _darkerPercentOfOrig).round(), b: (b * _darkerPercentOfOrig).round(),
@ -66,7 +66,7 @@ class Color {
Color get lighter => Color get lighter =>
_lighter ?? _lighter ??
new Color( Color(
r: r + ((255 - r) * _lighterPercentOfOrig).round(), r: r + ((255 - r) * _lighterPercentOfOrig).round(),
g: g + ((255 - g) * _lighterPercentOfOrig).round(), g: g + ((255 - g) * _lighterPercentOfOrig).round(),
b: b + ((255 - b) * _lighterPercentOfOrig).round(), b: b + ((255 - b) * _lighterPercentOfOrig).round(),

@ -48,7 +48,7 @@ class LocalDateTimeFactory implements DateTimeFactory {
DateTime createDateTimeFromMilliSecondsSinceEpoch( DateTime createDateTimeFromMilliSecondsSinceEpoch(
int millisecondsSinceEpoch) { int millisecondsSinceEpoch) {
return new DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch); return DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch);
} }
DateTime createDateTime(int year, DateTime createDateTime(int year,
@ -59,13 +59,13 @@ class LocalDateTimeFactory implements DateTimeFactory {
int second = 0, int second = 0,
int millisecond = 0, int millisecond = 0,
int microsecond = 0]) { int microsecond = 0]) {
return new DateTime( return DateTime(
year, month, day, hour, minute, second, millisecond, microsecond); year, month, day, hour, minute, second, millisecond, microsecond);
} }
/// Returns a [DateFormat]. /// Returns a [DateFormat].
DateFormat createDateFormat(String pattern) { DateFormat createDateFormat(String pattern) {
return new DateFormat(pattern); return DateFormat(pattern);
} }
} }
@ -75,7 +75,7 @@ class UTCDateTimeFactory implements DateTimeFactory {
DateTime createDateTimeFromMilliSecondsSinceEpoch( DateTime createDateTimeFromMilliSecondsSinceEpoch(
int millisecondsSinceEpoch) { int millisecondsSinceEpoch) {
return new DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, return DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch,
isUtc: true); isUtc: true);
} }
@ -87,12 +87,12 @@ class UTCDateTimeFactory implements DateTimeFactory {
int second = 0, int second = 0,
int millisecond = 0, int millisecond = 0,
int microsecond = 0]) { int microsecond = 0]) {
return new DateTime.utc( return DateTime.utc(
year, month, day, hour, minute, second, millisecond, microsecond); year, month, day, hour, minute, second, millisecond, microsecond);
} }
/// Returns a [DateFormat]. /// Returns a [DateFormat].
DateFormat createDateFormat(String pattern) { DateFormat createDateFormat(String pattern) {
return new DateFormat(pattern); return DateFormat(pattern);
} }
} }

@ -95,10 +95,11 @@ class GestureListener {
this.onTapCancel = onTapCancel ?? defaultTapCancel; this.onTapCancel = onTapCancel ?? defaultTapCancel;
} }
typedef GestureCancelCallback(); typedef GestureCancelCallback = Function();
typedef bool GestureSinglePointCallback(Point<double> localPosition); typedef GestureSinglePointCallback = bool Function(Point<double> localPosition);
typedef bool GestureDragStartCallback(Point<double> localPosition); typedef GestureDragStartCallback = bool Function(Point<double> localPosition);
typedef GestureDragUpdateCallback(Point<double> localPosition, double scale); typedef GestureDragUpdateCallback = Function(
typedef GestureDragEndCallback( Point<double> localPosition, double scale);
typedef GestureDragEndCallback = Function(
Point<double> localPosition, double scale, double pixelsPerSec); Point<double> localPosition, double scale, double pixelsPerSec);

@ -20,9 +20,9 @@ import 'palette.dart' show Palette;
/// ///
/// @link https://material.io/guidelines/style/color.html#color-color-palette /// @link https://material.io/guidelines/style/color.html#color-color-palette
class MaterialPalette { class MaterialPalette {
static const black = const Color(r: 0, g: 0, b: 0); static const black = Color(r: 0, g: 0, b: 0);
static const transparent = const Color(r: 0, g: 0, b: 0, a: 0); static const transparent = Color(r: 0, g: 0, b: 0, a: 0);
static const white = const Color(r: 255, g: 255, b: 255); static const white = Color(r: 255, g: 255, b: 255);
static Palette get blue => const MaterialBlue(); static Palette get blue => const MaterialBlue();
static Palette get red => const MaterialRed(); static Palette get red => const MaterialRed();
@ -77,10 +77,10 @@ class MaterialPalette {
} }
class MaterialBlue extends Palette { class MaterialBlue extends Palette {
static const _shade200 = const Color(r: 0x90, g: 0xCA, b: 0xF9); //#90CAF9 static const _shade200 = Color(r: 0x90, g: 0xCA, b: 0xF9); //#90CAF9
static const _shade500 = const Color( static const _shade500 =
r: 0x21, g: 0x96, b: 0xF3, darker: _shade700, lighter: _shade200); Color(r: 0x21, g: 0x96, b: 0xF3, darker: _shade700, lighter: _shade200);
static const _shade700 = const Color(r: 0x19, g: 0x76, b: 0xD2); //#1976D2 static const _shade700 = Color(r: 0x19, g: 0x76, b: 0xD2); //#1976D2
const MaterialBlue(); const MaterialBlue();
@ -89,10 +89,10 @@ class MaterialBlue extends Palette {
} }
class MaterialRed extends Palette { class MaterialRed extends Palette {
static const _shade200 = const Color(r: 0xEF, g: 0x9A, b: 0x9A); //#EF9A9A static const _shade200 = Color(r: 0xEF, g: 0x9A, b: 0x9A); //#EF9A9A
static const _shade700 = const Color(r: 0xD3, g: 0x2F, b: 0x2F); //#D32F2F static const _shade700 = Color(r: 0xD3, g: 0x2F, b: 0x2F); //#D32F2F
static const _shade500 = const Color( static const _shade500 =
r: 0xF4, g: 0x43, b: 0x36, darker: _shade700, lighter: _shade200); Color(r: 0xF4, g: 0x43, b: 0x36, darker: _shade700, lighter: _shade200);
const MaterialRed(); const MaterialRed();
@ -101,10 +101,10 @@ class MaterialRed extends Palette {
} }
class MaterialYellow extends Palette { class MaterialYellow extends Palette {
static const _shade200 = const Color(r: 0xFF, g: 0xF5, b: 0x9D); //#FFF59D static const _shade200 = Color(r: 0xFF, g: 0xF5, b: 0x9D); //#FFF59D
static const _shade700 = const Color(r: 0xFB, g: 0xC0, b: 0x2D); //#FBC02D static const _shade700 = Color(r: 0xFB, g: 0xC0, b: 0x2D); //#FBC02D
static const _shade500 = const Color( static const _shade500 =
r: 0xFF, g: 0xEB, b: 0x3B, darker: _shade700, lighter: _shade200); Color(r: 0xFF, g: 0xEB, b: 0x3B, darker: _shade700, lighter: _shade200);
const MaterialYellow(); const MaterialYellow();
@ -113,10 +113,10 @@ class MaterialYellow extends Palette {
} }
class MaterialGreen extends Palette { class MaterialGreen extends Palette {
static const _shade200 = const Color(r: 0xA5, g: 0xD6, b: 0xA7); //#A5D6A7 static const _shade200 = Color(r: 0xA5, g: 0xD6, b: 0xA7); //#A5D6A7
static const _shade700 = const Color(r: 0x38, g: 0x8E, b: 0x3C); //#388E3C; static const _shade700 = Color(r: 0x38, g: 0x8E, b: 0x3C); //#388E3C;
static const _shade500 = const Color( static const _shade500 =
r: 0x4C, g: 0xAF, b: 0x50, darker: _shade700, lighter: _shade200); Color(r: 0x4C, g: 0xAF, b: 0x50, darker: _shade700, lighter: _shade200);
const MaterialGreen(); const MaterialGreen();
@ -125,10 +125,10 @@ class MaterialGreen extends Palette {
} }
class MaterialPurple extends Palette { class MaterialPurple extends Palette {
static const _shade200 = const Color(r: 0xCE, g: 0x93, b: 0xD8); //#CE93D8 static const _shade200 = Color(r: 0xCE, g: 0x93, b: 0xD8); //#CE93D8
static const _shade700 = const Color(r: 0x7B, g: 0x1F, b: 0xA2); //#7B1FA2 static const _shade700 = Color(r: 0x7B, g: 0x1F, b: 0xA2); //#7B1FA2
static const _shade500 = const Color( static const _shade500 =
r: 0x9C, g: 0x27, b: 0xB0, darker: _shade700, lighter: _shade200); Color(r: 0x9C, g: 0x27, b: 0xB0, darker: _shade700, lighter: _shade200);
const MaterialPurple(); const MaterialPurple();
@ -137,10 +137,10 @@ class MaterialPurple extends Palette {
} }
class MaterialCyan extends Palette { class MaterialCyan extends Palette {
static const _shade200 = const Color(r: 0x80, g: 0xDE, b: 0xEA); //#80DEEA static const _shade200 = Color(r: 0x80, g: 0xDE, b: 0xEA); //#80DEEA
static const _shade700 = const Color(r: 0x00, g: 0x97, b: 0xA7); //#0097A7 static const _shade700 = Color(r: 0x00, g: 0x97, b: 0xA7); //#0097A7
static const _shade500 = const Color( static const _shade500 =
r: 0x00, g: 0xBC, b: 0xD4, darker: _shade700, lighter: _shade200); Color(r: 0x00, g: 0xBC, b: 0xD4, darker: _shade700, lighter: _shade200);
const MaterialCyan(); const MaterialCyan();
@ -149,10 +149,10 @@ class MaterialCyan extends Palette {
} }
class MaterialDeepOrange extends Palette { class MaterialDeepOrange extends Palette {
static const _shade200 = const Color(r: 0xFF, g: 0xAB, b: 0x91); //#FFAB91 static const _shade200 = Color(r: 0xFF, g: 0xAB, b: 0x91); //#FFAB91
static const _shade700 = const Color(r: 0xE6, g: 0x4A, b: 0x19); //#E64A19 static const _shade700 = Color(r: 0xE6, g: 0x4A, b: 0x19); //#E64A19
static const _shade500 = const Color( static const _shade500 =
r: 0xFF, g: 0x57, b: 0x22, darker: _shade700, lighter: _shade200); Color(r: 0xFF, g: 0x57, b: 0x22, darker: _shade700, lighter: _shade200);
const MaterialDeepOrange(); const MaterialDeepOrange();
@ -161,10 +161,10 @@ class MaterialDeepOrange extends Palette {
} }
class MaterialLime extends Palette { class MaterialLime extends Palette {
static const _shade200 = const Color(r: 0xE6, g: 0xEE, b: 0x9C); //#E6EE9C static const _shade200 = Color(r: 0xE6, g: 0xEE, b: 0x9C); //#E6EE9C
static const _shade700 = const Color(r: 0xAF, g: 0xB4, b: 0x2B); //#AFB42B static const _shade700 = Color(r: 0xAF, g: 0xB4, b: 0x2B); //#AFB42B
static const _shade500 = const Color( static const _shade500 =
r: 0xCD, g: 0xDC, b: 0x39, darker: _shade700, lighter: _shade200); Color(r: 0xCD, g: 0xDC, b: 0x39, darker: _shade700, lighter: _shade200);
const MaterialLime(); const MaterialLime();
@ -173,10 +173,10 @@ class MaterialLime extends Palette {
} }
class MaterialIndigo extends Palette { class MaterialIndigo extends Palette {
static const _shade200 = const Color(r: 0x9F, g: 0xA8, b: 0xDA); //#9FA8DA static const _shade200 = Color(r: 0x9F, g: 0xA8, b: 0xDA); //#9FA8DA
static const _shade700 = const Color(r: 0x30, g: 0x3F, b: 0x9F); //#303F9F static const _shade700 = Color(r: 0x30, g: 0x3F, b: 0x9F); //#303F9F
static const _shade500 = const Color( static const _shade500 =
r: 0x3F, g: 0x51, b: 0xB5, darker: _shade700, lighter: _shade200); Color(r: 0x3F, g: 0x51, b: 0xB5, darker: _shade700, lighter: _shade200);
const MaterialIndigo(); const MaterialIndigo();
@ -185,10 +185,10 @@ class MaterialIndigo extends Palette {
} }
class MaterialPink extends Palette { class MaterialPink extends Palette {
static const _shade200 = const Color(r: 0xF4, g: 0x8F, b: 0xB1); //#F48FB1 static const _shade200 = Color(r: 0xF4, g: 0x8F, b: 0xB1); //#F48FB1
static const _shade700 = const Color(r: 0xC2, g: 0x18, b: 0x5B); //#C2185B static const _shade700 = Color(r: 0xC2, g: 0x18, b: 0x5B); //#C2185B
static const _shade500 = const Color( static const _shade500 =
r: 0xE9, g: 0x1E, b: 0x63, darker: _shade700, lighter: _shade200); Color(r: 0xE9, g: 0x1E, b: 0x63, darker: _shade700, lighter: _shade200);
const MaterialPink(); const MaterialPink();
@ -197,10 +197,10 @@ class MaterialPink extends Palette {
} }
class MaterialTeal extends Palette { class MaterialTeal extends Palette {
static const _shade200 = const Color(r: 0x80, g: 0xCB, b: 0xC4); //#80CBC4 static const _shade200 = Color(r: 0x80, g: 0xCB, b: 0xC4); //#80CBC4
static const _shade700 = const Color(r: 0x00, g: 0x79, b: 0x6B); //#00796B static const _shade700 = Color(r: 0x00, g: 0x79, b: 0x6B); //#00796B
static const _shade500 = const Color( static const _shade500 =
r: 0x00, g: 0x96, b: 0x88, darker: _shade700, lighter: _shade200); Color(r: 0x00, g: 0x96, b: 0x88, darker: _shade700, lighter: _shade200);
const MaterialTeal(); const MaterialTeal();
@ -209,10 +209,10 @@ class MaterialTeal extends Palette {
} }
class MaterialGray extends Palette { class MaterialGray extends Palette {
static const _shade200 = const Color(r: 0xEE, g: 0xEE, b: 0xEE); //#EEEEEE static const _shade200 = Color(r: 0xEE, g: 0xEE, b: 0xEE); //#EEEEEE
static const _shade700 = const Color(r: 0x61, g: 0x61, b: 0x61); //#616161 static const _shade700 = Color(r: 0x61, g: 0x61, b: 0x61); //#616161
static const _shade500 = const Color( static const _shade500 =
r: 0x9E, g: 0x9E, b: 0x9E, darker: _shade700, lighter: _shade200); Color(r: 0x9E, g: 0x9E, b: 0x9E, darker: _shade700, lighter: _shade200);
const MaterialGray(); const MaterialGray();

@ -39,14 +39,14 @@ abstract class Palette {
darker: shadeDefault.darker, lighter: lighterColor)); darker: shadeDefault.darker, lighter: lighterColor));
} }
colors.add(new Color.fromOther(color: shadeDefault, lighter: lighterColor)); colors.add(Color.fromOther(color: shadeDefault, lighter: lighterColor));
return colors; return colors;
} }
Color _getSteppedColor(Color color, int index, int steps, Color _getSteppedColor(Color color, int index, int steps,
{Color darker, Color lighter}) { {Color darker, Color lighter}) {
final fraction = index / steps; final fraction = index / steps;
return new Color( return Color(
r: color.r + ((255 - color.r) * fraction).round(), r: color.r + ((255 - color.r) * fraction).round(),
g: color.g + ((255 - color.g) * fraction).round(), g: color.g + ((255 - color.g) * fraction).round(),
b: color.b + ((255 - color.b) * fraction).round(), b: color.b + ((255 - color.b) * fraction).round(),

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save