/*
* Copyright (C) 2015 Brent Marriott
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hookedonplay.decoviewlib.charts;
import android.graphics.Color;
import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.animation.Interpolator;
import java.util.ArrayList;
/**
* ArcItem holds the attributes required to represent an animated arc
* <p/>
* Construction example:
* <p/>
* ArcItem arcItem = new ArcItem.Builder(getResources().getColor(R.color.orb1_series2))
* .setRange(0,100,0)
* .setLineWidth(10)
* .setSpinDuration(8000)
* .setShowPointWhenEmpty(false)
* .build();
*/
@SuppressWarnings("unused")
public class SeriesItem {
/**
* Main color of the arc
*/
private int mColor;
/**
* Secondary Color of the arc used to create gradient for arc. This is only used if the
* alpha component is > 0
*/
private int mColorSecondary;
/**
* The width of the line used to draw the arc
*/
private float mLineWidth;
/**
* Duration taken to animate a 360 degree animation of an arc
*/
private final long mSpinDuration;
/**
* Minimum value the represents the start of the arc. For example the view may represent
* a distance where it starts at 0km and ends at 100km
*/
private final float mMinValue;
/**
* Value to represent the end of the arc
*/
private final float mMaxValue;
/**
* Initial value for this arc. When drawing a background track this should be set to the
* maximum value
*/
private final float mInitialValue;
/**
* Initial value for visibility of this arc.
*/
private final boolean mInitialVisibility;
/**
* Determines if the arc animate in a clockwise or anticlockwise direction
*/
private final boolean mSpinClockwise;
/**
* Set the cap of the arc to be rounded rather than square
*/
private final boolean mRoundCap;
/**
* Draw this series as a point rather than an arc
*/
private final boolean mDrawAsPoint;
/**
* Style to draw the data
* {@link ChartStyle}
*/
private final ChartStyle mChartStyle;
/**
* Interpolator used to perform the animation as the current
* value is moved
*/
private final Interpolator mInterpolator;
/**
* Draw the arc even when it is empty
*/
private final boolean mShowPointWhenEmpty;
/**
* Draw the arc at an amount inset from the outside of the view
*/
private PointF mInset;
/**
* Draw shadow on edge for effect. Any number of edge effects can be applied
*/
private ArrayList<EdgeDetail> mEdgeDetail;
/**
* Label for the data series
*/
private SeriesLabel mSeriesLabel;
/**
* Set the shadow size for the series. This is drawn as a fade around the series that goes from
* the color set mShadowColor and fades for mShadowSize pixels until it is transparent
*
* IMPORTANT: If you set this you need to call DecoView.disableHardwareAccelerationForDecoView()
* as drawing of this shadow cannot be done with hardware acceleration enabled
*/
private float mShadowSize;
/**
* Set the color of the shadow surrounding the series
*/
private int mShadowColor;
/**
* Provides optional callback functionality on progress update of animation
*/
private ArrayList<SeriesItemListener> mListeners;
private SeriesItem(Builder builder) {
mColor = builder.mColor;
mColorSecondary = builder.mColorSecondary;
mLineWidth = builder.mLineWidth;
mSpinDuration = builder.mSpinDuration;
mMinValue = builder.mMinValue;
mMaxValue = builder.mMaxValue;
mInitialValue = builder.mInitialValue;
mInitialVisibility = builder.mInitialVisibility;
mSpinClockwise = builder.mSpinClockwise;
mRoundCap = builder.mRoundCap;
mDrawAsPoint = builder.mDrawAsPoint;
mChartStyle = builder.mChartStyle;
mInterpolator = builder.mInterpolator;
mShowPointWhenEmpty = builder.mShowPointWhenEmpty;
mInset = builder.mInset;
mEdgeDetail = builder.mEdgeDetail;
mSeriesLabel = builder.mSeriesLabel;
mShadowSize = builder.mShadowSize;
mShadowColor = builder.mShadowColor;
}
public int getColor() {
return mColor;
}
public void setColor(int color) {
mColor = color;
}
public int getSecondaryColor() {
return mColorSecondary;
}
public void setSecondaryColor(int color) {
mColorSecondary = color;
}
public float getLineWidth() {
return mLineWidth;
}
public void setLineWidth(float lineWidth) {
mLineWidth = lineWidth;
}
public long getSpinDuration() {
return mSpinDuration;
}
public float getMinValue() {
return mMinValue;
}
public float getMaxValue() {
return mMaxValue;
}
public float getInitialValue() {
return mInitialValue;
}
public boolean getInitialVisibility() {
return mInitialVisibility;
}
public boolean getSpinClockwise() {
return mSpinClockwise;
}
public boolean getRoundCap() {
return mRoundCap;
}
public boolean getDrawAsPoint() {
return mDrawAsPoint;
}
public ChartStyle getChartStyle() {
return mChartStyle;
}
public Interpolator getInterpolator() {
return mInterpolator;
}
public boolean showPointWhenEmpty() {
return mShowPointWhenEmpty;
}
public PointF getInset() {
if (mInset == null) {
mInset = new PointF(0, 0);
}
return mInset;
}
public ArrayList<EdgeDetail> getEdgeDetail() {
return mEdgeDetail;
}
public void addEdgeDetail(@Nullable EdgeDetail edgeDetail) {
if (edgeDetail == null) {
mEdgeDetail = null;
return;
}
if (mEdgeDetail == null) {
mEdgeDetail = new ArrayList<>();
}
mEdgeDetail.add(new EdgeDetail(edgeDetail));
}
public void setSeriesLabel(SeriesLabel label) {
mSeriesLabel = label;
}
public SeriesLabel getSeriesLabel() {
return mSeriesLabel;
}
public void setShadowSize(float shadowSize) {
mShadowSize = shadowSize;
}
public float getShadowSize() {
return mShadowSize;
}
public void setShadowColor(int shadowColor) {
mShadowColor = shadowColor;
}
public int getShadowColor() {
return mShadowColor;
}
/**
* Set a listener to get notification of completion of animation
*
* @param listener OrbSeriesItemListener to be used for callbacks
*/
public void addArcSeriesItemListener(@NonNull SeriesItemListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<>();
}
mListeners.add(listener);
}
ArrayList<SeriesItemListener> getListeners() {
return mListeners;
}
public enum ChartStyle {
STYLE_DONUT, /* Default: Hole in middle */
STYLE_PIE, /* Drawn from center point to outer limit */
STYLE_LINE_HORIZONTAL, /* Drawn as a horizontal straight line */
STYLE_LINE_VERTICAL /* Drawn as a horizontal straight line */
}
/**
* Callback interface for notification of animation end
*/
public interface SeriesItemListener {
void onSeriesItemAnimationProgress(float percentComplete, float currentPosition);
void onSeriesItemDisplayProgress(float percentComplete);
}
public static class Builder {
private int mColor = Color.argb(255, 32, 32, 32);
private int mColorSecondary = Color.argb(0, 0, 0, 0);
private float mLineWidth = -1;
private long mSpinDuration = 5000;
private float mMinValue;
private float mMaxValue = 100f;
private float mInitialValue;
private boolean mInitialVisibility = true;
private boolean mSpinClockwise = true;
private boolean mRoundCap = true;
private boolean mDrawAsPoint;
private ChartStyle mChartStyle = ChartStyle.STYLE_DONUT;
private Interpolator mInterpolator;
private boolean mShowPointWhenEmpty = true;
private PointF mInset;
private ArrayList<EdgeDetail> mEdgeDetail;
private SeriesLabel mSeriesLabel;
private float mShadowSize = 0f;
private int mShadowColor = Color.BLACK;
public Builder(int color) {
mColor = color;
}
public Builder(int color, int colorSecondary) {
mColor = color;
mColorSecondary = colorSecondary;
}
public Builder setLineWidth(final float lineWidth) {
mLineWidth = lineWidth;
return this;
}
public Builder setSpinDuration(final long spinDuration) {
if (spinDuration <= 100) {
throw new IllegalArgumentException("SpinDuration must be > 100 (value is in ms)");
}
mSpinDuration = spinDuration;
return this;
}
public Builder setInitialVisibility(final boolean visibility) {
mInitialVisibility = visibility;
return this;
}
public Builder setSpinClockwise(final boolean spinClockwise) {
mSpinClockwise = spinClockwise;
return this;
}
public Builder setCapRounded(final boolean roundCap) {
mRoundCap = roundCap;
return this;
}
public Builder setDrawAsPoint(final boolean drawAsPoint) {
mDrawAsPoint = drawAsPoint;
return this;
}
public Builder setChartStyle(@NonNull final ChartStyle chartStyle) {
mChartStyle = chartStyle;
return this;
}
public Builder setRange(final float minValue, final float maxValue, final float initialValue) {
if (minValue >= maxValue) {
throw new IllegalArgumentException("minimum value must be less that maximum value");
}
if (minValue > initialValue || maxValue < initialValue) {
throw new IllegalArgumentException("Initial value must be in the range of min .. max");
}
mMinValue = minValue;
mMaxValue = maxValue;
mInitialValue = initialValue;
return this;
}
/**
* Set the interpolator to be used with the animation
*
* @param interpolator Optional interpolator to set
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setInterpolator(@Nullable Interpolator interpolator) {
mInterpolator = interpolator;
return this;
}
public Builder setShowPointWhenEmpty(boolean showPointWhenEmpty) {
mShowPointWhenEmpty = showPointWhenEmpty;
return this;
}
public Builder setInset(@Nullable PointF inset) {
mInset = inset;
return this;
}
public Builder addEdgeDetail(@Nullable EdgeDetail edgeDetail) {
if (edgeDetail == null) {
mEdgeDetail = null;
return this;
}
if (mEdgeDetail == null) {
mEdgeDetail = new ArrayList<>();
}
mEdgeDetail.add(new EdgeDetail(edgeDetail));
return this;
}
public Builder setSeriesLabel(@Nullable SeriesLabel seriesLabel) {
mSeriesLabel = seriesLabel;
return this;
}
public Builder setShadowSize(float shadowSize) {
mShadowSize = shadowSize;
return this;
}
public Builder setShadowColor(int shadowColor) {
mShadowColor = shadowColor;
return this;
}
/**
* Creates a {@link SeriesItem} with the arguments supplied to this builder.
*/
public SeriesItem build() {
return new SeriesItem(this);
}
}
}