正在查看: 爱心e站 v1.0.0 应用的 LineChartRenderer.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: 爱心e站 v1.0.0 应用的 LineChartRenderer.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package lecho.lib.hellocharts.renderer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import lecho.lib.hellocharts.model.ColumnChartData;
import lecho.lib.hellocharts.model.Line;
import lecho.lib.hellocharts.model.LineChartData;
import lecho.lib.hellocharts.model.PointValue;
import lecho.lib.hellocharts.model.SelectedValue;
import lecho.lib.hellocharts.model.ValueShape;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.provider.LineChartDataProvider;
import lecho.lib.hellocharts.util.ChartUtils;
import lecho.lib.hellocharts.view.Chart;
public class LineChartRenderer extends AbstractChartRenderer {
private static final int DEFAULT_LINE_STROKE_WIDTH_DP = 3;
private static final int DEFAULT_TOUCH_TOLERANCE_MARGIN_DP = 4;
private static final float LINE_SMOOTHNESS = 0.16f;
private static final int MODE_DRAW = 0;
private static final int MODE_HIGHLIGHT = 1;
private float baseValue;
private int checkPrecision;
private LineChartDataProvider dataProvider;
private Paint linePaint;
private Path path;
private Paint pointPaint;
private Bitmap softwareBitmap;
private Canvas softwareCanvas;
private Viewport tempMaximumViewport;
private int touchToleranceMargin;
public LineChartRenderer(Context context, Chart chart, LineChartDataProvider dataProvider) {
super(context, chart);
this.path = new Path();
this.linePaint = new Paint();
this.pointPaint = new Paint();
this.softwareCanvas = new Canvas();
this.tempMaximumViewport = new Viewport();
this.dataProvider = dataProvider;
this.touchToleranceMargin = ChartUtils.dp2px(this.density, 4);
this.linePaint.setAntiAlias(true);
this.linePaint.setStyle(Paint.Style.STROKE);
this.linePaint.setStrokeCap(Paint.Cap.ROUND);
this.linePaint.setStrokeWidth(ChartUtils.dp2px(this.density, 3));
this.pointPaint.setAntiAlias(true);
this.pointPaint.setStyle(Paint.Style.FILL);
this.checkPrecision = ChartUtils.dp2px(this.density, 2);
}
@Override
public void onChartSizeChanged() {
int internalMargin = calculateContentRectInternalMargin();
this.computator.insetContentRectByInternalMargins(internalMargin, internalMargin, internalMargin, internalMargin);
if (this.computator.getChartWidth() > 0 && this.computator.getChartHeight() > 0) {
this.softwareBitmap = Bitmap.createBitmap(this.computator.getChartWidth(), this.computator.getChartHeight(), Bitmap.Config.ARGB_8888);
this.softwareCanvas.setBitmap(this.softwareBitmap);
}
}
@Override
public void onChartDataChanged() {
super.onChartDataChanged();
int internalMargin = calculateContentRectInternalMargin();
this.computator.insetContentRectByInternalMargins(internalMargin, internalMargin, internalMargin, internalMargin);
this.baseValue = this.dataProvider.getLineChartData().getBaseValue();
onChartViewportChanged();
}
@Override
public void onChartViewportChanged() {
if (this.isViewportCalculationEnabled) {
calculateMaxViewport();
this.computator.setMaxViewport(this.tempMaximumViewport);
this.computator.setCurrentViewport(this.computator.getMaximumViewport());
}
}
@Override
public void draw(Canvas canvas) {
Canvas drawCanvas;
LineChartData data = this.dataProvider.getLineChartData();
if (this.softwareBitmap != null) {
drawCanvas = this.softwareCanvas;
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
} else {
drawCanvas = canvas;
}
for (Line line : data.getLines()) {
if (line.hasLines()) {
if (line.isCubic()) {
drawSmoothPath(drawCanvas, line);
} else if (line.isSquare()) {
drawSquarePath(drawCanvas, line);
} else {
drawPath(drawCanvas, line);
}
}
}
if (this.softwareBitmap != null) {
canvas.drawBitmap(this.softwareBitmap, ColumnChartData.DEFAULT_BASE_VALUE, ColumnChartData.DEFAULT_BASE_VALUE, (Paint) null);
}
}
@Override
public void drawUnclipped(Canvas canvas) {
LineChartData data = this.dataProvider.getLineChartData();
int lineIndex = 0;
for (Line line : data.getLines()) {
if (checkIfShouldDrawPoints(line)) {
drawPoints(canvas, line, lineIndex, 0);
}
lineIndex++;
}
if (isTouched()) {
highlightPoints(canvas);
}
}
private boolean checkIfShouldDrawPoints(Line line) {
return line.hasPoints() || line.getValues().size() == 1;
}
@Override
public boolean checkTouch(float touchX, float touchY) {
this.selectedValue.clear();
LineChartData data = this.dataProvider.getLineChartData();
int lineIndex = 0;
for (Line line : data.getLines()) {
if (checkIfShouldDrawPoints(line)) {
int pointRadius = ChartUtils.dp2px(this.density, line.getPointRadius());
int valueIndex = 0;
for (PointValue pointValue : line.getValues()) {
float rawValueX = this.computator.computeRawX(pointValue.getX());
float rawValueY = this.computator.computeRawY(pointValue.getY());
if (isInArea(rawValueX, rawValueY, touchX, touchY, this.touchToleranceMargin + pointRadius)) {
this.selectedValue.set(lineIndex, valueIndex, SelectedValue.SelectedValueType.LINE);
}
valueIndex++;
}
}
lineIndex++;
}
return isTouched();
}
private void calculateMaxViewport() {
this.tempMaximumViewport.set(Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MAX_VALUE);
LineChartData data = this.dataProvider.getLineChartData();
for (Line line : data.getLines()) {
for (PointValue pointValue : line.getValues()) {
if (pointValue.getX() < this.tempMaximumViewport.left) {
this.tempMaximumViewport.left = pointValue.getX();
}
if (pointValue.getX() > this.tempMaximumViewport.right) {
this.tempMaximumViewport.right = pointValue.getX();
}
if (pointValue.getY() < this.tempMaximumViewport.bottom) {
this.tempMaximumViewport.bottom = pointValue.getY();
}
if (pointValue.getY() > this.tempMaximumViewport.top) {
this.tempMaximumViewport.top = pointValue.getY();
}
}
}
}
private int calculateContentRectInternalMargin() {
int margin;
int contentAreaMargin = 0;
LineChartData data = this.dataProvider.getLineChartData();
for (Line line : data.getLines()) {
if (checkIfShouldDrawPoints(line) && (margin = line.getPointRadius() + 4) > contentAreaMargin) {
contentAreaMargin = margin;
}
}
return ChartUtils.dp2px(this.density, contentAreaMargin);
}
private void drawPath(Canvas canvas, Line line) {
prepareLinePaint(line);
int valueIndex = 0;
for (PointValue pointValue : line.getValues()) {
float rawX = this.computator.computeRawX(pointValue.getX());
float rawY = this.computator.computeRawY(pointValue.getY());
if (valueIndex == 0) {
this.path.moveTo(rawX, rawY);
} else {
this.path.lineTo(rawX, rawY);
}
valueIndex++;
}
canvas.drawPath(this.path, this.linePaint);
if (line.isFilled()) {
drawArea(canvas, line);
}
this.path.reset();
}
private void drawSquarePath(Canvas canvas, Line line) {
prepareLinePaint(line);
int valueIndex = 0;
float previousRawY = ColumnChartData.DEFAULT_BASE_VALUE;
for (PointValue pointValue : line.getValues()) {
float rawX = this.computator.computeRawX(pointValue.getX());
float rawY = this.computator.computeRawY(pointValue.getY());
if (valueIndex == 0) {
this.path.moveTo(rawX, rawY);
} else {
this.path.lineTo(rawX, previousRawY);
this.path.lineTo(rawX, rawY);
}
previousRawY = rawY;
valueIndex++;
}
canvas.drawPath(this.path, this.linePaint);
if (line.isFilled()) {
drawArea(canvas, line);
}
this.path.reset();
}
private void drawSmoothPath(Canvas canvas, Line line) {
float nextPointX;
float nextPointY;
prepareLinePaint(line);
int lineSize = line.getValues().size();
float prePreviousPointX = Float.NaN;
float prePreviousPointY = Float.NaN;
float previousPointX = Float.NaN;
float previousPointY = Float.NaN;
float currentPointX = Float.NaN;
float currentPointY = Float.NaN;
for (int valueIndex = 0; valueIndex < lineSize; valueIndex++) {
if (Float.isNaN(currentPointX)) {
PointValue linePoint = line.getValues().get(valueIndex);
currentPointX = this.computator.computeRawX(linePoint.getX());
currentPointY = this.computator.computeRawY(linePoint.getY());
}
if (Float.isNaN(previousPointX)) {
if (valueIndex > 0) {
PointValue linePoint2 = line.getValues().get(valueIndex - 1);
previousPointX = this.computator.computeRawX(linePoint2.getX());
previousPointY = this.computator.computeRawY(linePoint2.getY());
} else {
previousPointX = currentPointX;
previousPointY = currentPointY;
}
}
if (Float.isNaN(prePreviousPointX)) {
if (valueIndex > 1) {
PointValue linePoint3 = line.getValues().get(valueIndex - 2);
prePreviousPointX = this.computator.computeRawX(linePoint3.getX());
prePreviousPointY = this.computator.computeRawY(linePoint3.getY());
} else {
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
}
}
if (valueIndex < lineSize - 1) {
PointValue linePoint4 = line.getValues().get(valueIndex + 1);
nextPointX = this.computator.computeRawX(linePoint4.getX());
nextPointY = this.computator.computeRawY(linePoint4.getY());
} else {
nextPointX = currentPointX;
nextPointY = currentPointY;
}
if (valueIndex == 0) {
this.path.moveTo(currentPointX, currentPointY);
} else {
float firstDiffX = currentPointX - prePreviousPointX;
float firstDiffY = currentPointY - prePreviousPointY;
float secondDiffX = nextPointX - previousPointX;
float secondDiffY = nextPointY - previousPointY;
float firstControlPointX = previousPointX + (LINE_SMOOTHNESS * firstDiffX);
float firstControlPointY = previousPointY + (LINE_SMOOTHNESS * firstDiffY);
float secondControlPointX = currentPointX - (LINE_SMOOTHNESS * secondDiffX);
float secondControlPointY = currentPointY - (LINE_SMOOTHNESS * secondDiffY);
this.path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY, currentPointX, currentPointY);
}
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
previousPointX = currentPointX;
previousPointY = currentPointY;
currentPointX = nextPointX;
currentPointY = nextPointY;
}
canvas.drawPath(this.path, this.linePaint);
if (line.isFilled()) {
drawArea(canvas, line);
}
this.path.reset();
}
private void prepareLinePaint(Line line) {
this.linePaint.setStrokeWidth(ChartUtils.dp2px(this.density, line.getStrokeWidth()));
this.linePaint.setColor(line.getColor());
this.linePaint.setPathEffect(line.getPathEffect());
}
private void drawPoints(Canvas canvas, Line line, int lineIndex, int mode) {
this.pointPaint.setColor(line.getPointColor());
int valueIndex = 0;
for (PointValue pointValue : line.getValues()) {
int pointRadius = ChartUtils.dp2px(this.density, line.getPointRadius());
float rawX = this.computator.computeRawX(pointValue.getX());
float rawY = this.computator.computeRawY(pointValue.getY());
if (this.computator.isWithinContentRect(rawX, rawY, this.checkPrecision)) {
if (mode == 0) {
drawPoint(canvas, line, pointValue, rawX, rawY, pointRadius);
if (line.hasLabels()) {
drawLabel(canvas, line, pointValue, rawX, rawY, this.labelOffset + pointRadius);
}
} else if (1 == mode) {
highlightPoint(canvas, line, pointValue, rawX, rawY, lineIndex, valueIndex);
} else {
throw new IllegalStateException("Cannot process points in mode: " + mode);
}
}
valueIndex++;
}
}
private void drawPoint(Canvas canvas, Line line, PointValue pointValue, float rawX, float rawY, float pointRadius) {
if (ValueShape.SQUARE.equals(line.getShape())) {
canvas.drawRect(rawX - pointRadius, rawY - pointRadius, rawX + pointRadius, rawY + pointRadius, this.pointPaint);
return;
}
if (ValueShape.CIRCLE.equals(line.getShape())) {
canvas.drawCircle(rawX, rawY, pointRadius, this.pointPaint);
} else {
if (ValueShape.DIAMOND.equals(line.getShape())) {
canvas.save();
canvas.rotate(45.0f, rawX, rawY);
canvas.drawRect(rawX - pointRadius, rawY - pointRadius, rawX + pointRadius, rawY + pointRadius, this.pointPaint);
canvas.restore();
return;
}
throw new IllegalArgumentException("Invalid point shape: " + line.getShape());
}
}
private void highlightPoints(Canvas canvas) {
int lineIndex = this.selectedValue.getFirstIndex();
Line line = this.dataProvider.getLineChartData().getLines().get(lineIndex);
drawPoints(canvas, line, lineIndex, 1);
}
private void highlightPoint(Canvas canvas, Line line, PointValue pointValue, float rawX, float rawY, int lineIndex, int valueIndex) {
if (this.selectedValue.getFirstIndex() == lineIndex && this.selectedValue.getSecondIndex() == valueIndex) {
int pointRadius = ChartUtils.dp2px(this.density, line.getPointRadius());
this.pointPaint.setColor(line.getDarkenColor());
drawPoint(canvas, line, pointValue, rawX, rawY, this.touchToleranceMargin + pointRadius);
if (line.hasLabels() || line.hasLabelsOnlyForSelected()) {
drawLabel(canvas, line, pointValue, rawX, rawY, this.labelOffset + pointRadius);
}
}
}
private void drawLabel(Canvas canvas, Line line, PointValue pointValue, float rawX, float rawY, float offset) {
float top;
float bottom;
Rect contentRect = this.computator.getContentRectMinusAllMargins();
int numChars = line.getFormatter().formatChartValue(this.labelBuffer, pointValue);
if (numChars != 0) {
float labelWidth = this.labelPaint.measureText(this.labelBuffer, this.labelBuffer.length - numChars, numChars);
int labelHeight = Math.abs(this.fontMetrics.ascent);
float left = (rawX - (labelWidth / 2.0f)) - this.labelMargin;
float right = (labelWidth / 2.0f) + rawX + this.labelMargin;
if (pointValue.getY() >= this.baseValue) {
top = ((rawY - offset) - labelHeight) - (this.labelMargin * 2);
bottom = rawY - offset;
} else {
top = rawY + offset;
bottom = rawY + offset + labelHeight + (this.labelMargin * 2);
}
if (top < contentRect.top) {
top = rawY + offset;
bottom = rawY + offset + labelHeight + (this.labelMargin * 2);
}
if (bottom > contentRect.bottom) {
top = ((rawY - offset) - labelHeight) - (this.labelMargin * 2);
bottom = rawY - offset;
}
if (left < contentRect.left) {
left = rawX;
right = rawX + labelWidth + (this.labelMargin * 2);
}
if (right > contentRect.right) {
left = (rawX - labelWidth) - (this.labelMargin * 2);
right = rawX;
}
this.labelBackgroundRect.set(left, top, right, bottom);
drawLabelTextAndBackground(canvas, this.labelBuffer, this.labelBuffer.length - numChars, numChars, line.getDarkenColor());
}
}
private void drawArea(Canvas canvas, Line line) {
int lineSize = line.getValues().size();
if (lineSize >= 2) {
Rect contentRect = this.computator.getContentRectMinusAllMargins();
float baseRawValue = Math.min(contentRect.bottom, Math.max(this.computator.computeRawY(this.baseValue), contentRect.top));
float left = Math.max(this.computator.computeRawX(line.getValues().get(0).getX()), contentRect.left);
float right = Math.min(this.computator.computeRawX(line.getValues().get(lineSize - 1).getX()), contentRect.right);
this.path.lineTo(right, baseRawValue);
this.path.lineTo(left, baseRawValue);
this.path.close();
this.linePaint.setStyle(Paint.Style.FILL);
this.linePaint.setAlpha(line.getAreaTransparency());
canvas.drawPath(this.path, this.linePaint);
this.linePaint.setStyle(Paint.Style.STROKE);
}
}
private boolean isInArea(float x, float y, float touchX, float touchY, float radius) {
float diffX = touchX - x;
float diffY = touchY - y;
return Math.pow((double) diffX, 2.0d) + Math.pow((double) diffY, 2.0d) <= Math.pow((double) radius, 2.0d) * 2.0d;
}
}