NekoX/TMessagesProj/src/main/java/org/telegram/ui/Charts/DoubleLinearChartView.java

333 lines
13 KiB
Java

package org.telegram.ui.Charts;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Charts.data.ChartData;
import org.telegram.ui.Charts.data.DoubleLinearChartData;
import org.telegram.ui.Charts.view_data.ChartHorizontalLinesData;
import org.telegram.ui.Charts.view_data.LineViewData;
public class DoubleLinearChartView extends BaseChartView<DoubleLinearChartData, LineViewData> {
public DoubleLinearChartView(Context context) {
super(context);
}
@Override
protected void init() {
useMinHeight = true;
super.init();
}
@Override
protected void drawChart(Canvas canvas) {
if (chartData != null) {
float fullWidth = (chartWidth / (pickerDelegate.pickerEnd - pickerDelegate.pickerStart));
float offset = fullWidth * (pickerDelegate.pickerStart) - HORIZONTAL_PADDING;
canvas.save();
float transitionAlpha = 1f;
if (transitionMode == TRANSITION_MODE_PARENT) {
transitionAlpha = transitionParams.progress > 0.5f ? 0 : 1f - transitionParams.progress * 2f;
canvas.scale(
1 + 2 * transitionParams.progress, 1f,
transitionParams.pX, transitionParams.pY
);
} else if (transitionMode == TRANSITION_MODE_CHILD) {
transitionAlpha = transitionParams.progress < 0.3f ? 0 : transitionParams.progress;
canvas.save();
canvas.scale(
transitionParams.progress, transitionParams.progress,
transitionParams.pX, transitionParams.pY
);
} else if (transitionMode == TRANSITION_MODE_ALPHA_ENTER) {
transitionAlpha = transitionParams.progress;
}
for (int k = 0; k < lines.size(); k++) {
LineViewData line = lines.get(k);
if (!line.enabled && line.alpha == 0) continue;
int j = 0;
int[] y = line.line.y;
line.chartPath.reset();
boolean first = true;
float p;
if (chartData.xPercentage.length < 2) {
p = 1f;
} else {
p = chartData.xPercentage[1] * fullWidth;
}
int additionalPoints = (int) (HORIZONTAL_PADDING / p) + 1;
int localStart = Math.max(0, startXIndex - additionalPoints);
int localEnd = Math.min(chartData.xPercentage.length - 1, endXIndex + additionalPoints);
for (int i = localStart; i <= localEnd; i++) {
if (y[i] < 0) continue;
float xPoint = chartData.xPercentage[i] * fullWidth - offset;
float yPercentage = ((float) y[i] * chartData.linesK[k] - currentMinHeight) / (currentMaxHeight - currentMinHeight);
float padding = line.paint.getStrokeWidth() / 2f;
float yPoint = getMeasuredHeight() - chartBottom - padding - (yPercentage) * (getMeasuredHeight() - chartBottom - SIGNATURE_TEXT_HEIGHT - padding);
if (USE_LINES) {
if (j == 0) {
line.linesPath[j++] = xPoint;
line.linesPath[j++] = yPoint;
} else {
line.linesPath[j++] = xPoint;
line.linesPath[j++] = yPoint;
line.linesPath[j++] = xPoint;
line.linesPath[j++] = yPoint;
}
} else {
if (first) {
first = false;
line.chartPath.moveTo(xPoint, yPoint);
} else {
line.chartPath.lineTo(xPoint, yPoint);
}
}
}
if (endXIndex - startXIndex > 100) {
line.paint.setStrokeCap(Paint.Cap.SQUARE);
} else {
line.paint.setStrokeCap(Paint.Cap.ROUND);
}
line.paint.setAlpha((int) (255 * line.alpha * transitionAlpha));
if (!USE_LINES) canvas.drawPath(line.chartPath, line.paint);
else canvas.drawLines(line.linesPath, 0, j, line.paint);
}
canvas.restore();
}
}
@Override
protected void drawPickerChart(Canvas canvas) {
int bottom = getMeasuredHeight() - PICKER_PADDING;
int top = getMeasuredHeight() - pikerHeight - PICKER_PADDING;
int nl = lines.size();
if (chartData != null) {
for (int k = 0; k < nl; k++) {
LineViewData line = lines.get(k);
if (!line.enabled && line.alpha == 0) continue;
line.bottomLinePath.reset();
int n = chartData.xPercentage.length;
int j = 0;
int[] y = line.line.y;
line.chartPath.reset();
for (int i = 0; i < n; i++) {
if (y[i] < 0) continue;
float xPoint = chartData.xPercentage[i] * pickerWidth;
float h = ANIMATE_PICKER_SIZES ? pickerMaxHeight : chartData.maxValue;
float yPercentage = (float) y[i] * chartData.linesK[k] / h;
float yPoint = (1f - yPercentage) * (bottom - top);
if (USE_LINES) {
if (j == 0) {
line.linesPathBottom[j++] = xPoint;
line.linesPathBottom[j++] = yPoint;
} else {
line.linesPathBottom[j++] = xPoint;
line.linesPathBottom[j++] = yPoint;
line.linesPathBottom[j++] = xPoint;
line.linesPathBottom[j++] = yPoint;
}
} else {
if (i == 0) {
line.bottomLinePath.moveTo(xPoint, yPoint);
} else {
line.bottomLinePath.lineTo(xPoint, yPoint);
}
}
}
line.linesPathBottomSize = j;
if (!line.enabled && line.alpha == 0) continue;
line.bottomLinePaint.setAlpha((int) (255 * line.alpha));
if (USE_LINES)
canvas.drawLines(line.linesPathBottom, 0, line.linesPathBottomSize, line.bottomLinePaint);
else
canvas.drawPath(line.bottomLinePath, line.bottomLinePaint);
}
}
}
@Override
protected void drawSelection(Canvas canvas) {
if (selectedIndex < 0 || !legendShowing) return;
int alpha = (int) (chartActiveLineAlpha * selectionA);
float fullWidth = (chartWidth / (pickerDelegate.pickerEnd - pickerDelegate.pickerStart));
float offset = fullWidth * (pickerDelegate.pickerStart) - HORIZONTAL_PADDING;
float xPoint = chartData.xPercentage[selectedIndex] * fullWidth - offset;
selectedLinePaint.setAlpha(alpha);
canvas.drawLine(xPoint, 0, xPoint, chartArea.bottom, selectedLinePaint);
tmpN = lines.size();
for (tmpI = 0; tmpI < tmpN; tmpI++) {
LineViewData line = lines.get(tmpI);
if (!line.enabled && line.alpha == 0) continue;
float yPercentage = ((float) line.line.y[selectedIndex] * chartData.linesK[tmpI] - currentMinHeight) / (currentMaxHeight - currentMinHeight);
float yPoint = getMeasuredHeight() - chartBottom - (yPercentage) * (getMeasuredHeight() - chartBottom - SIGNATURE_TEXT_HEIGHT);
line.selectionPaint.setAlpha((int) (255 * line.alpha * selectionA));
selectionBackgroundPaint.setAlpha((int) (255 * line.alpha * selectionA));
canvas.drawPoint(xPoint, yPoint, line.selectionPaint);
canvas.drawPoint(xPoint, yPoint, selectionBackgroundPaint);
}
}
@Override
protected void drawSignaturesToHorizontalLines(Canvas canvas, ChartHorizontalLinesData a) {
int n = a.values.length;
int rightIndex = chartData.linesK[0] == 1 ? 1 : 0;
int leftIndex = (rightIndex + 1) % 2;
float additionalOutAlpha = 1f;
if (n > 2) {
float v = (a.values[1] - a.values[0]) / (float) (currentMaxHeight - currentMinHeight);
if (v < 0.1) {
additionalOutAlpha = v / 0.1f;
}
}
float transitionAlpha = 1f;
if (transitionMode == TRANSITION_MODE_PARENT) {
transitionAlpha = 1f - transitionParams.progress;
} else if (transitionMode == TRANSITION_MODE_CHILD) {
transitionAlpha = transitionParams.progress;
} else if (transitionMode == TRANSITION_MODE_ALPHA_ENTER) {
transitionAlpha = transitionParams.progress;
}
linePaint.setAlpha((int) (a.alpha * 0.1f * transitionAlpha));
int chartHeight = getMeasuredHeight() - chartBottom - SIGNATURE_TEXT_HEIGHT;
int textOffset = (int) (SIGNATURE_TEXT_HEIGHT - signaturePaint.getTextSize());
for (int i = 0; i < n; i++) {
int y = (int) ((getMeasuredHeight() - chartBottom) - chartHeight * ((a.values[i] - currentMinHeight) / (currentMaxHeight - currentMinHeight)));
if (a.valuesStr != null && lines.size() > 0) {
if (a.valuesStr2 == null || lines.size() < 2) {
signaturePaint.setColor(Theme.getColor(Theme.key_statisticChartSignature));
signaturePaint.setAlpha((int) (a.alpha * signaturePaintAlpha * transitionAlpha * additionalOutAlpha));
} else {
signaturePaint.setColor(lines.get(leftIndex).lineColor);
signaturePaint.setAlpha((int) (a.alpha * lines.get(leftIndex).alpha * transitionAlpha * additionalOutAlpha));
}
canvas.drawText(a.valuesStr[i], HORIZONTAL_PADDING, y - textOffset, signaturePaint);
}
if (a.valuesStr2 != null && lines.size() > 1) {
signaturePaint2.setColor(lines.get(rightIndex).lineColor);
signaturePaint2.setAlpha((int) (a.alpha * lines.get(rightIndex).alpha * transitionAlpha * additionalOutAlpha));
canvas.drawText(a.valuesStr2[i], getMeasuredWidth() - HORIZONTAL_PADDING, y - textOffset, signaturePaint2);
}
}
}
@Override
public LineViewData createLineViewData(ChartData.Line line) {
return new LineViewData(line);
}
public int findMaxValue(int startXIndex, int endXIndex) {
if (lines.isEmpty()) {
return 0;
}
int n = lines.size();
int max = 0;
for (int i = 0; i < n; i++) {
int localMax = lines.get(i).enabled ? (int) (chartData.lines.get(i).segmentTree.rMaxQ(startXIndex, endXIndex) * chartData.linesK[i]) : 0;
if (localMax > max) max = localMax;
}
return max;
}
public int findMinValue(int startXIndex, int endXIndex) {
if (lines.isEmpty()) {
return 0;
}
int n = lines.size();
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
int localMin = lines.get(i).enabled ? (int) (chartData.lines.get(i).segmentTree.rMinQ(startXIndex, endXIndex) * chartData.linesK[i]) : Integer.MAX_VALUE;
if (localMin < min) min = localMin;
}
return min;
}
protected void updatePickerMinMaxHeight() {
if (!ANIMATE_PICKER_SIZES) return;
if (lines.get(0).enabled) {
super.updatePickerMinMaxHeight();
return;
}
int max = 0;
for (LineViewData l : lines) {
if (l.enabled && l.line.maxValue > max) max = l.line.maxValue;
}
if (lines.size() > 1) {
max = (int) (max * chartData.linesK[1]);
}
if (max > 0 && max != animatedToPickerMaxHeight) {
animatedToPickerMaxHeight = max;
if (pickerAnimator != null) pickerAnimator.cancel();
pickerAnimator = createAnimator(pickerMaxHeight, animatedToPickerMaxHeight, new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
pickerMaxHeight = (float) animation.getAnimatedValue();
invalidatePickerChart = true;
invalidate();
}
});
pickerAnimator.start();
}
}
protected ChartHorizontalLinesData createHorizontalLinesData(int newMaxHeight, int newMinHeight) {
float k;
if (chartData.linesK.length < 2) {
k = 1;
} else {
int rightIndex = chartData.linesK[0] == 1 ? 1 : 0;
k = chartData.linesK[rightIndex];
}
return new ChartHorizontalLinesData(newMaxHeight, newMinHeight, useMinHeight, k);
}
}