Commit 0d07084b by 王宇航

首頁、廚房單打印

parent 70fa4320
apply plugin: 'com.android.library'
//apply plugin: 'com.github.dcendents.android-maven'
group='com.github.huangyanbin'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.david.chart">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>
package com.daivd.chart.component;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.component.base.IChartTitle;
import com.daivd.chart.component.base.PercentComponent;
import com.daivd.chart.data.style.FontStyle;
/**
* 绘制标题
* @author huangyanbin
*/
public class ChartTitle extends PercentComponent<String> implements IChartTitle {
/**
* 图表标题最大占比
*/
private static final float MAX_PERCENT =0.4f;
/**
* 标题字体样式
*/
private FontStyle fontStyle= new FontStyle();
private Path path = new Path();
/**
* 设置标题占比
* @param percent 百分比
*/
@Override
public void setPercent(float percent) {
if(percent > MAX_PERCENT){
percent = MAX_PERCENT;
}
super.setPercent(percent);
}
/**
* 绘制标题
* <p>通过设置标题方位绘制标题</p>
* @param canvas 画布
* @param chartName 图表标题
* @param paint 画笔
*/
@Override
public void draw(Canvas canvas, String chartName, Paint paint) {
fontStyle.fillPaint(paint);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
paint.setTextAlign(Paint.Align.LEFT);
float textHeight = fontMetrics.descent - fontMetrics.ascent;
int textWidth = (int)paint.measureText(chartName);
Rect rect = getRect();
int startY = rect.centerY();
int startX = rect.centerX();
path.rewind();
switch (direction) {
case TOP:
case BOTTOM:
startY-= textHeight/2;
startX -=textWidth/2;
canvas.drawText(chartName, startX, startY, paint);
break;
case LEFT:
case RIGHT:
path.moveTo(startX,rect.top);
path.lineTo(startX,rect.bottom);
canvas.drawTextOnPath(chartName,path,(rect.height()-textWidth)/2,0,paint);
break;
}
}
/**
* 获取标题字体样式
* @return 标题字体样式
*/
public FontStyle getFontStyle() {
return fontStyle;
}
/**
* 设置标题字体样式
* @param fontStyle 标题字体样式
*/
public void setFontStyle(FontStyle fontStyle) {
this.fontStyle = fontStyle;
}
}
package com.daivd.chart.component;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.component.base.IEmpty;
import com.daivd.chart.data.style.FontStyle;
/**
* 空白提示
* @author huangyanbin
*/
public class EmptyView implements IEmpty {
/**
* 空白提示字体样式
*/
private FontStyle fontStyle = new FontStyle();
/**
* 空白文字
*/
private String emptyTip = "No Data";
/**
* 空白范围
*/
private Rect rect;
/**
* 绘制空白
* @param canvas 画布
* @param paint 画笔
*/
@Override
public void draw(Canvas canvas, Paint paint) {
draw(canvas,emptyTip,paint);
}
/**
* 获取空白字体样式
* @return 空白字体样式
*/
public FontStyle getFontStyle() {
return fontStyle;
}
/**
* 设置空白字体样式
* @param fontStyle 空白字体样式
*/
public void setFontStyle(FontStyle fontStyle) {
this.fontStyle = fontStyle;
}
/**
* 设置空白提示
* @return 空白提示
*/
@Override
public String getEmptyTip() {
return emptyTip;
}
/**
* 获取空白提示
* @param emptyTip 空白提示
*/
@Override
public void setEmptyTip(String emptyTip) {
this.emptyTip = emptyTip;
}
/**
* 计算空白大小
* <p>因为空白提示是占整个图表不需要计算</>
* @param chartRect 图表范围
*/
@Override
public void computeRect(Rect chartRect) {
rect = chartRect;
}
/**
* 绘制空白
* @param canvas 画布
* @param emptyTip 空白提示
* @param paint 画笔
*/
@Override
public void draw(Canvas canvas, String emptyTip, Paint paint) {
fontStyle.fillPaint(paint);
paint.setTextAlign(Paint.Align.LEFT);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
int textHeight = (int) (fontMetrics.descent - fontMetrics.ascent);
int textWidth = (int) paint.measureText(emptyTip);
canvas.drawText(emptyTip,rect.left +(rect.right-rect.left-textWidth)/2,rect.top+(rect.bottom - rect.top-textHeight)/2,paint);
}
}
package com.daivd.chart.component;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.component.base.ILegend;
import com.daivd.chart.component.base.PercentComponent;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.listener.OnClickLegendListener;
import com.daivd.chart.provider.component.point.ILegendPoint;
import com.daivd.chart.provider.component.point.IPoint;
import com.daivd.chart.provider.component.point.LegendPoint;
import com.daivd.chart.provider.component.point.Point;
import java.util.List;
/**
* 图表图例
* @author huangyanbin
*/
public class Legend<C extends ColumnData> extends PercentComponent<ChartData<C>> implements ILegend<C> {
private FontStyle fontStyle;
private ILegendPoint point;
private int padding = 10;
private PointF pointF;
private boolean isSelectColumn = true;
private OnClickLegendListener<C> onClickLegendListener;
private boolean isDisplay = true;
public Legend(){
LegendPoint p = new LegendPoint();
p.getPointStyle().setWidth(p.getPointStyle().getWidth()*2);
point = p;
fontStyle = new FontStyle();
}
@Override
public void computeRect(Rect chartRect) {
if(isDisplay) {
super.computeRect(chartRect);
}
}
/**
* 绘制
* @param canvas 画布
* @param chartData 数据
* @param paint 画笔
*/
@Override
public void draw(Canvas canvas, ChartData<C> chartData, Paint paint) {
if(isDisplay) {
paint.setTextAlign(Paint.Align.LEFT);
Rect legendRect = getRect();
List<C> columnDataList = chartData.getColumnDataList();
int maxLegendNameLength = 0;
int columnDataSize = columnDataList.size();
String maxLengthColumnName = null;
for (int i = 0; i < columnDataSize; i++) {
ColumnData columnData = columnDataList.get(i);
String name = columnData.getName();
if (maxLegendNameLength < name.length()) {
maxLengthColumnName = name;
maxLegendNameLength = name.length();
}
}
fontStyle.fillPaint(paint);
int textWidth = (int) paint.measureText(maxLengthColumnName);//文本长度
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float textHeight = fontMetrics.descent - fontMetrics.ascent;
int maxLegendLength = (int) (point.getWidth() + padding * 3 + textWidth);
int columnSize = legendRect.width() / maxLegendLength; //列
columnSize = columnSize > 0 ? columnSize : 1;
int rowSize = columnDataSize / columnSize;
rowSize = rowSize > 0 ? rowSize : 1;
int perHeight = (int) (textHeight + padding);
int perWidth = legendRect.width() / columnSize;
int offsetY = (legendRect.height() - perHeight * rowSize) / 2;
offsetY = offsetY > 0 ? offsetY : 0;
int offsetX = columnDataSize < columnSize ? (columnSize - columnDataSize) * perWidth / 2 : 0;
for (int i = 0; i < columnDataList.size(); i++) {
int column = i % columnSize;
int row = i / columnSize;
int startX = offsetX + legendRect.left + column * perWidth + (perWidth - maxLegendLength) / 2;
int startY = legendRect.top + offsetY + row * perHeight;
C columnData = columnDataList.get(i);
String name = columnData.getName();
float pointWidth = point.getWidth();
float pointHeight = point.getHeight();
if (pointF != null && isClickRect(startX - pointWidth, startX + perWidth, startY - padding / 2, startY + perHeight + padding / 2)) {
if (isSelectColumn) {
columnData.setDraw(!columnData.isDraw());
}
pointF = null;
if (onClickLegendListener != null) {
onClickLegendListener.onClickLegend(columnData, this);
}
}
paint.setColor(columnData.getColor());
drawPoint(canvas, columnData.isDraw(), startX, (int) (startY - textHeight / 2 + pointHeight / 2), paint);
startX += pointWidth + padding;
drawText(canvas, startX, startY, name, paint);
}
}
}
@Override
public void setFontStyle(FontStyle fontStyle) {
this.fontStyle = fontStyle;
}
/**
* Determine whether to click or not rect
*/
private boolean isClickRect(float left, float right, float top, float bottom){
if(pointF != null) {
return pointF.x >= left && pointF.x <= right && pointF.y >= top && pointF.y <= bottom;
}
return false;
}
/**
* 绘制文字
*/
private void drawText(Canvas canvas, int startX, int startY, String content, Paint paint) {
fontStyle.fillPaint(paint);
canvas.drawText(content, startX, startY, paint);
}
private void drawPoint(Canvas canvas,boolean isDraw,int x, int y, Paint paint){
float w = point.getWidth();
x += w/2;
point.drawPoint(canvas,x,y,0,!isDraw,paint);
}
@Override
public FontStyle getFontStyle() {
return fontStyle;
}
@Override
public void onClickLegend(PointF pointF) {
this.pointF = pointF;
}
@Override
public void setOnClickLegendListener(OnClickLegendListener<C> onClickLegendListener) {
this.onClickLegendListener = onClickLegendListener;
}
@Override
public int getPadding() {
return padding;
}
@Override
public void setPadding(int padding) {
this.padding = padding;
}
public IPoint getPoint() {
return point;
}
public void setPoint(ILegendPoint point) {
this.point = point;
}
@Override
public void setSelectColumn(boolean selectColumn) {
isSelectColumn = selectColumn;
}
@Override
public void setDisplay(boolean isDisplay) {
this.isDisplay = isDisplay;
}
}
package com.daivd.chart.component;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import com.daivd.chart.data.PicOption;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by huang on 2017/10/30.
* 图片生成
*/
public class PicGeneration<V extends View> {
public boolean save(V v,PicOption option){
getChartBitmap(v);
return saveToGallery(v,option);
}
private Bitmap getChartBitmap(V v) {
// 创建一个bitmap 根据我们自定义view的大小
Bitmap returnedBitmap = Bitmap.createBitmap(v.getWidth(),
v.getHeight(), Bitmap.Config.RGB_565);
// 绑定canvas
Canvas canvas = new Canvas(returnedBitmap);
// 获取视图的背景
Drawable bgDrawable = v.getBackground();
if (bgDrawable != null)
// 如果有就绘制
bgDrawable.draw(canvas);
else
// 没有就绘制白色
canvas.drawColor(Color.WHITE);
// 绘制
v.draw(canvas);
return returnedBitmap;
}
private boolean saveToGallery(V v, PicOption option) {
String mFilePath;
// 控制图片质量
if (option.getQuality() < 0 || option.getQuality() > 100)
option.setQuality(50);
long currentTime = System.currentTimeMillis();
File extBaseDir = Environment.getExternalStorageDirectory();
File file = new File(extBaseDir.getAbsolutePath() + "/DCIM/" + option.getSubFolderPath());
if (!file.exists()) {
if (!file.mkdirs()) {
return false;
}
}
String mimeType = "";
String fileName = option.getFileName();
switch (option.getFormat()) {
case PNG:
mimeType = "image/png";
if (!fileName.endsWith(".png"))
fileName += ".png";
break;
case WEBP:
mimeType = "image/webp";
if (!fileName.endsWith(".webp"))
fileName += ".webp";
break;
case JPEG:
default:
mimeType = "image/jpeg";
if (!(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")))
fileName += ".jpg";
break;
}
mFilePath = file.getAbsolutePath() + "/" + fileName;
FileOutputStream out = null;
try {
out = new FileOutputStream(mFilePath);
Bitmap b = getChartBitmap(v);
b.compress(option.getFormat(), option.getQuality(), out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
long size = new File(mFilePath).length();
ContentValues values = new ContentValues(8);
// store the details
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.DATE_ADDED, currentTime);
values.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
values.put(MediaStore.Images.Media.DESCRIPTION, option.getFileDescription());
values.put(MediaStore.Images.Media.ORIENTATION, 0);
values.put(MediaStore.Images.Media.DATA, mFilePath);
values.put(MediaStore.Images.Media.SIZE, size);
return v.getContext().getContentResolver().
insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) != null;
}
}
package com.daivd.chart.component.axis;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.view.Gravity;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.format.IFormat;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.matrix.MatrixHelper;
/**
* 基本轴 负责轴的计算方位和绘制
* @author huangyanbin
*/
public abstract class BaseAxis<V> implements IAxis<V> {
/**
* 轴线样式
*/
protected LineStyle axisStyle = new LineStyle();
/**
* 刻度样式
*/
protected FontStyle scaleStyle = new FontStyle();
/**
* 网格样式
*/
protected LineStyle gridStyle = new LineStyle(); //网格样式
/**
* 是否绘制网格
*/
protected boolean isDrawGrid; //是否绘制网格
/**
* 是否显示轴线
*/
protected boolean isShowAxisLine = true;
/**
* 轴文字位置
*/
protected int gravity = Gravity.CENTER;
/**
* 轴方位(上下左右,横向轴可以设置上下,竖轴可以设置左右)
*/
protected int direction;
/**
* 是否是线性图
* 因为线性图一般从0开始绘制轴文字,而柱状图从每个间隔中间开始绘制
*/
protected boolean isLine;
/**
* 文字格式化
*/
private IFormat<V> format;
/**
* 是否显示轴
*/
private boolean isDisplay = true;
/**
*设置是否绘制网格
* @param drawGrid 是否绘制
*/
public void setDrawGrid(boolean drawGrid) {
isDrawGrid = drawGrid;
}
/**
* 获取轴样式
* 默认赋予样式,可以直接get来使用
* @return 轴样式
*/
public LineStyle getAxisStyle() {
return axisStyle;
}
/**
* 设置轴样式
* 如果你对LineStyle提供的样式不满意,可以自定义新的LineStyle
* @param axisStyle 轴样式
*/
public void setAxisStyle(LineStyle axisStyle) {
this.axisStyle = axisStyle;
}
/**
* 获取刻度字体样式
* 默认赋予样式,可以直接get来使用
* @return 刻度字体样式
*/
public FontStyle getScaleStyle() {
return scaleStyle;
}
/**
* 设置刻度字体样式
* 如果你对FontStyle提供的样式不满意,可以自定义新的FontStyle
* @param scaleStyle 刻度字体样式
*/
public void setScaleStyle(FontStyle scaleStyle) {
this.scaleStyle = scaleStyle;
}
/**
* 获取网格样式
* @return 网格样式
*/
public LineStyle getGridStyle() {
return gridStyle;
}
/**
* 设置网格样式
* @param gridStyle 网格样式
*/
public void setGridStyle(LineStyle gridStyle) {
this.gridStyle = gridStyle;
}
/**
* 设置轴偏移方位
* @param gravity 偏移方位
*/
public void setGravity(int gravity) {
this.gravity = gravity;
}
/**
* 是否是线性图表
* 因为线性图一般从0开始绘制轴文字,而柱状图从每个间隔中间开始绘制
* @param isLine 是否是线性图表
*/
public void isLine(boolean isLine) {
this.isLine = isLine;
}
/**
* 是否显示轴
* @return 是否显示轴
*/
public boolean isDisplay() {
return isDisplay;
}
/**
* 绘制轴
* 判断是否需要绘制以及调用绘制轴刻度和绘制轴线
* @param canvas 画布
* @param rect 绘制范围
* @param helper 缩放移动辅助类
* @param paint 画笔
* @param chartData 图表数据
*/
@Override
public void draw(Canvas canvas, Rect rect, MatrixHelper helper, Paint paint, ChartData<? extends BarData> chartData) {
if(isDisplay) {
drawScale(canvas, rect, helper, paint, chartData);
drawAxis(canvas, rect, paint, chartData);
}
}
/**
* 绘制轴刻度
* @param canvas 画布
* @param rect 绘制范围
* @param helper 缩放移动辅助类
* @param paint 画笔
* @param chartData 图表数据
*/
protected void drawScale(Canvas canvas, Rect rect, MatrixHelper helper, Paint paint, ChartData<? extends BarData> chartData) {
ScaleData scaleData = chartData.getScaleData();
Rect clipRect = new Rect(rect);
Rect scaleRect = scaleData.scaleRect;
Rect zoomRect = helper.getZoomProviderRect(scaleData.getOffsetRect(new Rect(rect), scaleRect));
chartData.getScaleData().zoom = helper.getZoom();
if (direction == AxisDirection.BOTTOM || direction == AxisDirection.TOP) {
zoomRect.top = rect.top;
zoomRect.bottom = rect.bottom;
clipRect.left = rect.left + scaleRect.left;
clipRect.right = rect.right - scaleRect.right;
} else {
zoomRect.left = rect.left;
zoomRect.right = rect.right;
clipRect.top = rect.top + scaleRect.top;
clipRect.bottom = rect.bottom - scaleRect.bottom;
}
drawScale(canvas, zoomRect, clipRect, paint, chartData);
}
/**
* 绘制轴线
* @param canvas 画布
* @param rect 绘制范围
* @param paint 画笔
* @param chartData 图表数据
*/
protected void drawAxis(Canvas canvas, Rect rect, Paint paint, ChartData<? extends BarData> chartData) {
if(isShowAxisLine) {
Rect scaleRect = chartData.getScaleData().scaleRect;
axisStyle.fillPaint(paint);
int[] r = calculation(rect, scaleRect);
Path path = new Path();
path.moveTo(r[0],r[1]);
path.lineTo(r[2],r[3]);
canvas.drawPath(path, paint);
}
}
/**
* 计算轴范围
* @param rect 原始范围
* @param scaleRect 缩放范围
* @return 轴上下左右的大小
*/
protected abstract int[] calculation(Rect rect, Rect scaleRect);
/**
* 提供给子类绘制刻度抽象方法
* @param canvas 画布
* @param rect 原始范围
* @param clipRect 裁切轴之后范围
* @param paint 画笔
* @param chartData 图表数据
*/
protected abstract void drawScale(Canvas canvas, Rect rect, Rect clipRect, Paint paint,ChartData<? extends BarData> chartData);
/**
* 获取文字格式化
* @return 文字格式化
*/
public IFormat<V> getFormat() {
return format;
}
/**
* 设置文字格式化
* @param format 文字格式化
*/
@Override
public void setFormat(IFormat<V> format) {
this.format = format;
}
/**
* 是否显示轴线
* @return 是否显示轴线
*/
public boolean isShowAxisLine() {
return isShowAxisLine;
}
/**
* 设置是否显示轴线
* @param showAxisLine 是否显示轴线
*/
public void setShowAxisLine(boolean showAxisLine) {
isShowAxisLine = showAxisLine;
}
/**
* 设置是否显示轴
* @param isShow 是否显示轴
*/
@Override
public void setDisplay(boolean isShow) {
this.isDisplay = isShow;
}
}
package com.daivd.chart.component.axis;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.view.Gravity;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.exception.ChartException;
import java.util.List;
/**
* 图表横轴
* @author huangyanbin
*/
public class HorizontalAxis extends BaseAxis<String> {
/**
* 横轴默认构造方法
* 默认方位在底部
*/
public HorizontalAxis() {
direction = AxisDirection.BOTTOM;
}
/**
* 文字旋转角度
*/
private int rotateAngle= 0;
/**
* 文字是否旋转
*/
private boolean isRotateAngle;
/**
* 文字宽度
*/
private int textWidth;
/**
* 文字高度
*/
private int textHeight;
/**
* 旋转文字高度
*/
private int rotateTextHeight;
/**
* 是否需要偏移来完整显示左右两边文字
*/
private boolean isShowFullValue; //是否显示全文字
/**
* 刻度数据
*/
private ScaleData scaleData;
/**
* 计算刻度大小
* <p>通过计算刻度的宽高得到轴的大小,然后保存到scaleData对象中,以便后面的计算</p>
* @param chartData 图表数据
* @param rect 图表原始范围
* @param paint 画笔
*/
@Override
public void computeScale(ChartData<? extends BarData> chartData, Rect rect, Paint paint) {
if(isDisplay()) {
scaleData = chartData.getScaleData();
scaleStyle.fillPaint(paint);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
textHeight = (int) (fontMetrics.descent - fontMetrics.ascent);
int maxLength = 0;
String maxLengthXData = "1";
for (String xData : chartData.getCharXDataList()) {
String formatData = formatData(xData);
if (maxLength < formatData.length()) {
maxLengthXData = formatData;
maxLength = formatData.length();
}
}
textWidth = (int) paint.measureText(maxLengthXData);
//计算旋转的高宽
int dis = textHeight;
if (isRotateAngle) {
int tempHeight = (int) Math.abs(textWidth * Math.sin(rotateAngle * Math.PI / 180)
+ textHeight * Math.cos(rotateAngle * Math.PI / 180));
int tempWidth = (int) Math.abs(textWidth * Math.cos(rotateAngle * Math.PI / 180)
+ textHeight * Math.sin(rotateAngle * Math.PI / 180));
rotateTextHeight = tempHeight;
dis += rotateTextHeight;
textWidth = tempWidth;
}
dis += (int) (scaleStyle.getPadding() * 2 + axisStyle.getWidth());
if (direction == AxisDirection.BOTTOM) {
scaleData.scaleRect.bottom = dis;
} else {
scaleData.scaleRect.top = dis;
}
}
}
/**
* 绘制刻度
* <p>通过zoomRect计算出每个刻度的宽度,迭代绘制刻度</p>
* @param canvas 画布
* @param zoomRect 缩放之后范围
* @param rect 原始范围
* @param paint 画笔
* @param chartData 图表数据
*/
protected void drawScale(Canvas canvas, Rect zoomRect, Rect rect, Paint paint, ChartData<? extends BarData> chartData) {
ScaleData scaleData = chartData.getScaleData();
List<String> groupDataList = chartData.getCharXDataList();
int rowSize = scaleData.rowSize;
int groupSize = groupDataList.size();
if (groupSize != rowSize) {
throw new ChartException("Horizontal Vertical axis data inconsistency");
}
float startY;
if (direction == AxisDirection.BOTTOM) {
startY = zoomRect.bottom -scaleData.scaleRect.bottom/2;
} else {
startY = zoomRect.top + scaleData.scaleRect.top/2;
}
int left = zoomRect.left ;
int width = zoomRect.right - left;
double perWidth = ((double) width) / (isLine? groupSize -1 : groupSize);
int filterMultiple = (int) (textWidth / perWidth +1);
for (int i = 0; i < groupSize; i++) {
String content = groupDataList.get(i);
int startX = getGravityStartX(left, i, perWidth);
//留1px缓冲
if (startX >= rect.left-1 && startX<= rect.right+1) {
if( i % filterMultiple == 0) {
drawText(canvas, content,startX, startY,i, paint);
drawGrid(canvas, startX, rect, scaleData.scaleRect, paint);
}
}
}
}
/**
* 获取刻度起始X的位置
* <p>根据gravity来判断偏移的值</p>
* @param left 左边
* @param position 位置
* @param perWidth 每个刻度的宽度
* @return 刻度起始X的位置
*/
private int getGravityStartX(int left, int position, double perWidth) {
int startX = (int) (left + position * perWidth);
if (gravity == Gravity.CENTER) {
startX += perWidth / 2;
} else if (gravity == Gravity.RIGHT) {
startX += perWidth;
}
return startX;
}
/**
* 绘制文字
* <p>完成文字偏移,文字旋转,绘制</p>
* @param canvas 画布
* @param contentStr 文字内容
* @param startX 文字绘制起始X位置
* @param startY 文字绘制起始Y位置
* @param position 刻度序号
* @param paint 画笔
*/
private void drawText(Canvas canvas, String contentStr, int startX, float startY, int position, Paint paint) {
String content = formatData(contentStr);
scaleStyle.fillPaint(paint);
paint.setTextAlign(Paint.Align.CENTER);
if (isShowFullValue && position == 0) {
int width = (int) paint.measureText(content);
startX+= width/2;
} else if (isShowFullValue && position == scaleData.rowSize - 1) {
int width = (int) paint.measureText(content);
startX-= width/2;
}
if (isRotateAngle) {
canvas.save();
canvas.rotate(rotateAngle, startX, startY);
canvas.drawText(content, startX, startY + textHeight / 2, paint);
canvas.restore();
} else {
canvas.drawText(content, startX, startY + textHeight / 2, paint);
}
}
/**
* 格式化文字
* @param data 文字
* @return 格式化完成之后的文字
*/
private String formatData(String data){
return getFormat()!= null ? getFormat().format(data) :data;
}
/**
* 绘制竖向网格
* @param canvas 画布
* @param startX 网格起始X位置
* @param rect 原始范围
* @param scaleRect 缩放范围
* @param paint 画布
*/
public void drawGrid(Canvas canvas, float startX, Rect rect, Rect scaleRect, Paint paint) {
if (gridStyle != null && isDrawGrid) {
gridStyle.fillPaint(paint);
Path path = new Path();
path.moveTo(startX, rect.top + scaleRect.top);
path.lineTo(startX, rect.bottom - scaleRect.bottom);
canvas.drawPath(path, paint);
}
}
/**
* 计算出裁切轴之后的范围
* @param rect 原始范围
* @param scaleRect 缩放范围
* @return 上下左右的大小
*/
protected int[] calculation(Rect rect, Rect scaleRect) {
int startX = rect.left + scaleRect.left;
int endX = rect.right - scaleRect.right;
int startY, endY;
if (direction == AxisDirection.BOTTOM) {
startY = rect.bottom - scaleRect.bottom;
} else {
startY = rect.top + scaleRect.top;
}
endY = startY;
return new int[]{startX, startY, endX, endY};
}
/**
* 设置轴方位
* <p>横轴只能设置上下方位</p>
* @param axisDirection 轴方位
*
*/
@Override
public void setAxisDirection(int axisDirection) {
if (axisDirection == AxisDirection.BOTTOM || axisDirection == AxisDirection.TOP) {
this.direction = axisDirection;
} else throw new ChartException("Can only set BOTTOM, TOP direction");
}
/**
* 设置文字旋转角度
* @param rotateAngle
*/
public void setRotateAngle(int rotateAngle) {
isRotateAngle = true;
this.rotateAngle = rotateAngle;
}
/**
* 是否需要偏移来完整显示左右两边文字
*
* @return 是否需要偏移
*/
public boolean isShowFullValue() {
return isShowFullValue;
}
/**
* 设置是否需要偏移来完整显示左右两边文字
*
* @param showFullValue 设置是否需要偏移
*/
public void setShowFullValue(boolean showFullValue) {
isShowFullValue = showFullValue;
}
}
package com.daivd.chart.component.axis;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.data.ScaleSetData;
import com.daivd.chart.exception.ChartException;
import java.util.List;
/**
* 图表竖轴
* @author huangyanbin
*/
public class VerticalAxis extends BaseAxis<Double> {
/**
* 图表刻度设置数据
* <p>用于保存用户设置最大,最小等数据</p>
*/
private ScaleSetData scaleSetData = new ScaleSetData();
/**
* 横轴构造方法
* <p>可以设置横轴方向 左右方位</p>
* @param direction 方位
*/
public VerticalAxis(int direction) {
this.direction = direction;
}
/**
* 小数点格式化
*/
private java.text.DecimalFormat df = new java.text.DecimalFormat("0");
/**
* 计算刻度大小
* <p>通过计算刻度的宽高得到轴的大小,然后保存到scaleData对象中,以便后面的计算</p>
* @param chartData 图表数据
* @param rect 图表原始范围
* @param paint 画笔
*/
@Override
public void computeScale(ChartData<? extends BarData> chartData, Rect rect, Paint paint) {
if(isDisplay()) {
ScaleData scaleData = chartData.getScaleData();
scaleData.resetScale(scaleSetData, direction);
scaleStyle.fillPaint(paint);
int length = Math.max(formatVerticalAxisData(scaleData.getMaxScaleValue(direction)).length(),
formatVerticalAxisData(scaleData.getMinScaleValue(direction)).length());
int textHeight = (int) (paint.measureText("1", 0, 1) * length);
int dis = (int) (textHeight + scaleStyle.getPadding() + axisStyle.getWidth());
if (direction == AxisDirection.LEFT) {
scaleData.scaleRect.left = dis;
} else {
scaleData.scaleRect.right = dis;
}
}
}
/**
* 绘制刻度
* <p>通过zoomRect计算出每个刻度的宽度,迭代绘制刻度</p>
* @param canvas 画布
* @param zoomRect 缩放之后范围
* @param clipRect 原始范围
* @param paint 画笔
* @param chartData 图表数据
*/
@Override
protected void drawScale(Canvas canvas, Rect zoomRect, Rect clipRect, Paint paint, ChartData<? extends BarData> chartData) {
ScaleData scaleData = chartData.getScaleData();
List<Double> scaleList = scaleData.getScaleList(direction);
float startX;
if (direction == AxisDirection.LEFT) {
startX = zoomRect.left + scaleData.scaleRect.right + scaleStyle.getPadding();
} else {
startX = zoomRect.right - scaleData.scaleRect.right + scaleStyle.getPadding();
}
int bottom = zoomRect.bottom;
int height = zoomRect.height();
float textHeight = paint.measureText("1", 0, 1);
int perHeight = height / (scaleList.size()-1);
for (int i = 0; i < scaleList.size(); i++) {
double value = scaleList.get(i);
float startY = bottom - i * perHeight;
if (clipRect.contains(clipRect.centerX(), (int) startY-1)) {
drawText(canvas, startX, startY + textHeight / 2, value, paint);
drawGrid(canvas, startY, zoomRect, scaleData.scaleRect, paint);
}
}
}
/**
* 绘制文字
*/
private void drawText(Canvas canvas, float startX, float startY, double value, Paint paint) {
scaleStyle.fillPaint(paint);
String content = formatVerticalAxisData(value);
paint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(content, startX, startY, paint);
}
/**
* 绘制网格
*/
private void drawGrid(Canvas canvas, float startY, Rect rect, Rect scaleRect, Paint paint) {
if (gridStyle != null && isDrawGrid) {
gridStyle.fillPaint(paint);
Path path = new Path();
path.moveTo(rect.left + scaleRect.left, startY);
path.lineTo(rect.right - scaleRect.right, startY);
canvas.drawPath(path, paint);
}
}
/**
* 计算出裁切轴之后的范围
* @param rect 原始范围
* @param scaleRect 缩放范围
* @return 上下左右的大小
*/
protected int[] calculation(Rect rect, Rect scaleRect) {
int startY = rect.top + scaleRect.top;
int endY = rect.bottom - scaleRect.bottom;
int startX, endX;
if (direction == AxisDirection.LEFT) {
startX = rect.left + scaleRect.left;
} else {
startX = rect.right - scaleRect.right;
}
endX = startX;
return new int[]{startX, startY, endX, endY};
}
/**
* 设置轴方位
* <p>竖轴只能设置左右方位</p>
* @param axisDirection 轴方位
*
*/
@Override
public void setAxisDirection(int axisDirection) {
if (axisDirection == AxisDirection.LEFT || axisDirection == AxisDirection.RIGHT) {
this.direction = axisDirection;
} else throw new ChartException("Can only set LEFT, RIGHT direction");
}
/**
* 格式化竖轴数据
* @param value 数值
* @return 格式化竖轴之后数据
*/
private String formatVerticalAxisData(double value) {
if(getFormat() != null){
return getFormat().format(value);
}
return df.format(value);
}
/**
* 设置刻度是否从0开始
*/
public void setStartZero(boolean isStartZero){
this.scaleSetData.setStartZoom(isStartZero);
}
/**
* 设置刻度最大值
* @param maxValue 最大值
*/
public void setMaxValue(double maxValue) {
this.scaleSetData.setMaxValue(maxValue);
}
/**
* 设置刻度最小值
* @param minValue 最大值
*/
public void setMinValue(double minValue) {
this.scaleSetData.setMinValue(minValue);
}
}
package com.daivd.chart.component.base;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.format.IFormat;
import com.daivd.chart.data.BarData;
import com.daivd.chart.matrix.MatrixHelper;
/**
* Created by huangYanBin on 2017/9/26.
* 轴接口
*/
public interface IAxis<V> {
void draw(Canvas canvas, Rect rect, MatrixHelper helper, Paint paint, ChartData<? extends BarData> chartData);
void computeScale(ChartData<? extends BarData> chartData, Rect rect, Paint paint);
void setAxisDirection(int axisDirection);
void setFormat(IFormat<V> format);
IFormat<V> getFormat();
void setDisplay(boolean isShow);
/**
* Created by huangYanBin on 2017/9/26.
* 轴方向
*/
interface AxisDirection {
int TOP = 1;
int BOTTOM=2;
int LEFT = 3;
int RIGHT = 4;
}
}
package com.daivd.chart.component.base;
import com.daivd.chart.data.style.FontStyle;
/**
* Created by huang on 2017/10/26.
*/
public interface IChartTitle extends IComponent<String> {
float getPercent();
void setPercent(float percent);
FontStyle getFontStyle();
int getDirection();
void setDirection(int direction);
void setFontStyle(FontStyle fontStyle);
}
package com.daivd.chart.component.base;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
/** 图表组件
* Created by huang on 2017/10/26.
*/
public interface IComponent<T> {
int LEFT = 0;
int TOP = 1;
int RIGHT =2;
int BOTTOM = 3;
/**
* 计算组件Rect
* @param chartRect
*/
void computeRect(Rect chartRect);
/**
* 绘制组件
* @param canvas 画布
* @param t 数据
* @param paint 画笔
*/
void draw(Canvas canvas, T t, Paint paint);
}
package com.daivd.chart.component.base;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.data.style.FontStyle;
/**
* Created by huang on 2017/9/30.
*/
public interface IEmpty extends IComponent<String> {
void draw(Canvas canvas, Paint paint);
FontStyle getFontStyle();
void setFontStyle(FontStyle fontStyle) ;
String getEmptyTip();
void setEmptyTip(String emptyTip);
}
package com.daivd.chart.component.base;
import android.graphics.PointF;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.provider.component.point.ILegendPoint;
import com.daivd.chart.provider.component.point.IPoint;
import com.daivd.chart.listener.OnClickLegendListener;
/**
* Created by huang on 2017/10/26.
*/
public interface ILegend<C extends ColumnData> extends IComponent<ChartData<C>> {
float getPercent();
void setPercent(float percent);
FontStyle getFontStyle();
int getDirection();
void setDirection(int direction);
void setFontStyle(FontStyle fontStyle);
void onClickLegend(PointF pointF);
void setOnClickLegendListener(OnClickLegendListener<C> onClickLegendListener);
int getPadding();
void setPadding(int padding);
IPoint getPoint();
void setPoint(ILegendPoint point);
void setSelectColumn(boolean selectColumn);
void setDisplay(boolean isDisplay);
}
\ No newline at end of file
package com.daivd.chart.component.base;
import android.graphics.Rect;
/**图表百分百组件
* Created by huang on 2017/10/26.
*/
public abstract class PercentComponent<T> implements IComponent<T> {
private static final float DEFAULT_PERCENT = 0.1f;
private float percent = DEFAULT_PERCENT;
private Rect rect = new Rect();
protected int direction;
@Override
public void computeRect(Rect chartRect) {
rect.left = chartRect.left;
rect.right = chartRect.right;
rect.top = chartRect.top;
rect.bottom = chartRect.bottom;
int h = (int) (chartRect.height()*percent);
int w = (int) (chartRect.width()*percent);
switch (direction){
case TOP:
rect.bottom = rect.top+h;
chartRect.top = chartRect.top+h;
break;
case LEFT:
rect.right = rect.left + w;
chartRect.left = chartRect.left + w;
break;
case RIGHT:
rect.left = rect.right -w;
chartRect.right = chartRect.right - w;
break;
case BOTTOM:
rect.top = rect.bottom -h;
chartRect.bottom = chartRect.bottom -h;
break;
}
}
public float getPercent() {
return percent;
}
public void setPercent(float percent) {
this.percent = percent;
}
public Rect getRect() {
return rect;
}
public void setRect(Rect rect) {
this.rect = rect;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseBarLineChart;
import com.daivd.chart.data.BarData;
import com.daivd.chart.provider.barLine.Bar3DProvider;
/**
* Created by huang on 2017/9/26.
* 3DBar图表
*/
public class Bar3DChart extends BaseBarLineChart<Bar3DProvider,BarData> {
public Bar3DChart(Context context) {
super(context);
}
public Bar3DChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Bar3DChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected Bar3DProvider initProvider() {
return new Bar3DProvider();
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseBarLineChart;
import com.daivd.chart.data.BarData;
import com.daivd.chart.provider.barLine.BarProvider;
/**
* Created by huang on 2017/9/26.
* 柱状图
*/
public class BarChart extends BaseBarLineChart<BarProvider<BarData>,BarData> {
public BarChart(Context context) {
super(context);
}
public BarChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BarChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected BarProvider initProvider() {
return new BarProvider();
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseBarLineChart;
import com.daivd.chart.data.BarLineData;
import com.daivd.chart.provider.barLine.BarLineProvider;
/**
* Created by huang on 2017/9/26.
* 柱状图
*/
public class BarLineChart extends BaseBarLineChart<BarLineProvider,BarLineData> {
public BarLineChart(Context context) {
super(context);
}
public BarLineChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BarLineChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected BarLineProvider initProvider() {
return new BarLineProvider();
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import com.daivd.chart.core.base.BaseBarLineChart;
import com.daivd.chart.data.LineData;
import com.daivd.chart.exception.ChartException;
import com.daivd.chart.provider.barLine.LineProvider;
import com.daivd.chart.provider.component.line.CurveLineModel;
import com.daivd.chart.provider.component.line.BrokenLineModel;
/**
* Created by huang on 2017/9/26.
* 线性图
*/
public class LineChart extends BaseBarLineChart<LineProvider,LineData> {
public static final int LINE_MODEL = 0;
public static final int CURVE_MODEL = 1;
public LineChart(Context context) {
super(context);
}
public LineChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected LineProvider initProvider() {
horizontalAxis.setGravity(Gravity.LEFT);
horizontalAxis.isLine(true);
return new LineProvider();
}
public void setLineModel(int model){
if(model == LINE_MODEL){
provider.setLineModel(new BrokenLineModel());
}else if( model == CURVE_MODEL){
provider.setLineModel(new CurveLineModel());
}else {
throw new ChartException("Please set the correct Line model");
}
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseRotateChart;
import com.daivd.chart.data.PieData;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.pie.Pie3DProvider;
/**
* Created by huang on 2017/10/9.
* 饼图
*/
public class Pie3DChart extends BaseRotateChart<Pie3DProvider,PieData> {
public Pie3DChart(Context context) {
super(context);
}
public Pie3DChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Pie3DChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected Pie3DProvider initProvider(RotateHelper rotateHelper) {
Pie3DProvider provider = new Pie3DProvider(getContext());
provider.setRotateHelper(rotateHelper);
return provider;
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseRotateChart;
import com.daivd.chart.data.PieData;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.pie.PieProvider;
/**
* Created by huang on 2017/10/9.
* 饼图
*/
public class PieChart extends BaseRotateChart<PieProvider,PieData> {
public PieChart(Context context) {
super(context);
}
public PieChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PieChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected PieProvider initProvider(RotateHelper rotateHelper) {
PieProvider provider = new PieProvider();
provider.setRotateHelper(rotateHelper);
return provider;
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseRotateChart;
import com.daivd.chart.data.RadarData;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.radar.RadarProvider;
/**
* Created by huang on 2017/10/9.
* 雷达图
*/
public class RadarChart extends BaseRotateChart<RadarProvider,RadarData> implements RotateHelper.OnRotateListener{
public RadarChart(Context context) {
super(context);
}
public RadarChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RadarChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected RadarProvider initProvider(RotateHelper rotateHelper) {
RadarProvider provider = new RadarProvider();
provider.setRotateHelper(rotateHelper);
return provider;
}
}
package com.daivd.chart.core;
import android.content.Context;
import android.util.AttributeSet;
import com.daivd.chart.core.base.BaseRotateChart;
import com.daivd.chart.data.RoseData;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.rose.RoseProvider;
/**
* Created by huang on 2017/10/9.
* 饼图
*/
public class RoseChart extends BaseRotateChart<RoseProvider,RoseData> {
public RoseChart(Context context) {
super(context);
}
public RoseChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoseChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected RoseProvider initProvider(RotateHelper rotateHelper) {
RoseProvider provider = new RoseProvider();
provider.setRotateHelper(rotateHelper);
return provider;
}
}
package com.daivd.chart.core.base;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import com.daivd.chart.component.axis.HorizontalAxis;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.component.axis.VerticalAxis;
import com.daivd.chart.data.BarData;
import com.daivd.chart.provider.IProvider;
/**
* Created by huang on 2017/9/26.
* 线性和柱状图
*/
public abstract class BaseBarLineChart<P extends IProvider<C>,C extends BarData> extends BaseChart<P,C> {
protected HorizontalAxis horizontalAxis; //横轴
protected VerticalAxis leftVerticalAxis;//竖轴
protected VerticalAxis rightVerticalAxis;//竖轴
public BaseBarLineChart(Context context) {
super(context);
}
public BaseBarLineChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BaseBarLineChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void init(){
horizontalAxis = new HorizontalAxis();
leftVerticalAxis = new VerticalAxis(IAxis.AxisDirection.LEFT);
rightVerticalAxis = new VerticalAxis(IAxis.AxisDirection.RIGHT);
super.init();
}
protected void drawContent(Canvas canvas){
horizontalAxis.computeScale(chartData, chartRect, paint);
if (chartData.getScaleData().isLeftHasValue)
leftVerticalAxis.computeScale(chartData, chartRect, paint);
if (chartData.getScaleData().isRightHasValue)
rightVerticalAxis.computeScale(chartData, chartRect, paint);
if (chartData.getScaleData().isLeftHasValue)
leftVerticalAxis.draw(canvas, chartRect, matrixHelper, paint, chartData);
if (chartData.getScaleData().isRightHasValue)
rightVerticalAxis.draw(canvas, chartRect, matrixHelper, paint, chartData);
horizontalAxis.draw(canvas, chartRect, matrixHelper, paint, chartData);
computeScaleRect();
provider.drawProvider(canvas, chartRect, matrixHelper, paint);
}
/**
* 计算绘制刻度之后的大小
*/
private void computeScaleRect(){
Rect rect = chartData.getScaleData().scaleRect;
computeChartRect(rect);
}
public void setHeightPercent(){
}
public HorizontalAxis getHorizontalAxis() {
return horizontalAxis;
}
public VerticalAxis getLeftVerticalAxis() {
return leftVerticalAxis;
}
public VerticalAxis getRightVerticalAxis() {
return rightVerticalAxis;
}
}
package com.daivd.chart.core.base;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import com.daivd.chart.component.Legend;
import com.daivd.chart.component.PicGeneration;
import com.daivd.chart.component.base.IChartTitle;
import com.daivd.chart.component.base.ILegend;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.data.PicOption;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.component.ChartTitle;
import com.daivd.chart.component.EmptyView;
import com.daivd.chart.component.base.IEmpty;
import com.daivd.chart.listener.OnChartChangeListener;
import com.daivd.chart.listener.OnClickColumnListener;
import com.daivd.chart.listener.OnClickLegendListener;
import com.daivd.chart.listener.ChartGestureObserver;
import com.daivd.chart.matrix.MatrixHelper;
import com.daivd.chart.provider.IProvider;
/**
* 基本图表
* Created by huang on 2017/9/26.
*/
public abstract class BaseChart<P extends IProvider<C>, C extends ColumnData> extends View
implements ChartGestureObserver, OnClickLegendListener<C>, OnChartChangeListener {
protected int width; //高
protected int height; //宽
protected int paddingLeft = 10;
protected int paddingRight = 10;
protected int paddingTop = 30;
protected int paddingBottom = 30;
protected Rect chartRect = new Rect();
protected ILegend<C> legend;
protected IChartTitle chartTitle;
protected P provider;//内容绘制者
protected Paint paint;
protected ChartData<C> chartData;
protected MatrixHelper matrixHelper;
protected boolean isShowChartName = true;
protected boolean isCharEmpty;
protected IEmpty emptyView;
private OnClickLegendListener<C> onClickLegendListener;
private boolean isFirstAnim = true;
public BaseChart(Context context) {
super(context);
init();
}
public BaseChart(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BaseChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* 初始化组件
*/
protected void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
chartTitle = new ChartTitle();
legend = new Legend<>();
legend.setOnClickLegendListener(this);
matrixHelper = new MatrixHelper(getContext());
matrixHelper.register(this);
matrixHelper.setOnTableChangeListener(this);
emptyView = new EmptyView();
provider = initProvider();
}
/**
* 将触摸事件交给Iouch处理
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
return matrixHelper.handlerTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
matrixHelper.onDisallowInterceptEvent(this, event);
return super.dispatchTouchEvent(event);
}
/**
* 获取大小
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
width = w;
height = h;
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (chartData != null) {
resetScaleData();
computePaddingRect();
if (isShowChartName) {
//计算标题的大小
chartTitle.computeRect(chartRect);
chartTitle.draw(canvas, chartData.getChartName(), paint);
}
if (!chartData.isEmpty()) {
//计算图例的大小
legend.computeRect(chartRect);
//绘制图例
legend.draw(canvas, chartData, paint);
}
if (!isCharEmpty) {
//绘制内容
drawContent(canvas);
} else {
//绘制空白
emptyView.computeRect(chartRect);
emptyView.draw(canvas, paint);
}
}
}
//待改善
private void resetScaleData() {
ScaleData scaleData = chartData.getScaleData();
scaleData.scaleRect.set(0, 0, 0, 0);
}
protected abstract void drawContent(Canvas canvas);
protected void computeChartRect(Rect rect) {
chartRect.left = chartRect.left + rect.left;
chartRect.top = chartRect.top + rect.top;
chartRect.bottom = chartRect.bottom - rect.bottom;
chartRect.right = chartRect.right - rect.right;
}
/**
* 计算图表的区域
*
* @return
*/
private void computePaddingRect() {
chartRect.left = paddingLeft;
chartRect.top = paddingTop;
chartRect.bottom = height - paddingBottom;
chartRect.right = width - paddingRight;
}
public void setPadding(int[] padding) {
this.paddingLeft = padding[0];
this.paddingTop = padding[1];
this.paddingRight = padding[2];
this.paddingBottom = padding[3];
}
protected abstract P initProvider();
/**
* 设置图内容绘制者
*/
public void setProvider(P provider) {
this.provider = provider;
}
public P getProvider() {
return provider;
}
public ChartData<C> getChartData() {
return chartData;
}
/**
* 设置图表数据源
*/
public void setChartData(ChartData<C> chartData) {
isCharEmpty = !provider.calculation(chartData);
this.chartData = chartData;
invalidate();
}
private int duration = 400;
private Interpolator interpolator;
/**
* 动画
*/
private void startChartAnim() {
if (interpolator == null)
startChartAnim(duration);
else
startChartAnim(duration, interpolator);
}
/**
* 动画
*
* @param duration 时间
*/
public void startChartAnim(int duration) {
new DecelerateInterpolator();
provider.startAnim(this, duration, new DecelerateInterpolator());
}
public void startChartAnim(int duration, Interpolator interpolator) {
this.duration = duration;
this.interpolator = interpolator;
provider.startAnim(this, duration, interpolator);
}
@Override
public void onClick(float x, float y) {
PointF pointF = new PointF(x, y);
provider.clickPoint(pointF);
legend.onClickLegend(pointF);
invalidate();
}
@Override
public void onClickLegend(C c, Legend<C> legend) {
isCharEmpty = !provider.calculation(chartData);
if (!isFirstAnim) {
startChartAnim();
}
if (onClickLegendListener != null) {
onClickLegendListener.onClickLegend(c, legend);
}
}
public IEmpty getEmptyView() {
return emptyView;
}
public void setEmptyView(IEmpty emptyView) {
this.emptyView = emptyView;
}
public boolean isShowChartName() {
return isShowChartName;
}
public void setShowChartName(boolean showChartName) {
isShowChartName = showChartName;
}
public IChartTitle getChartTitle() {
return chartTitle;
}
public void setChartTitle(IChartTitle chartTitle) {
this.chartTitle = chartTitle;
}
public ILegend<C> getLegend() {
return legend;
}
/**
* 设置是否可以缩放
*
* @param zoom
*/
public void setZoom(boolean zoom) {
matrixHelper.setCanZoom(zoom);
}
@Override
public void onTableChanged(float translateX, float translateY) {
invalidate();
}
public MatrixHelper getMatrixHelper() {
return matrixHelper;
}
public void setOnClickColumnListener(OnClickColumnListener<C> onClickColumnListener) {
provider.setOnClickColumnListener(onClickColumnListener);
}
public void setOnClickLegendListener(OnClickLegendListener<C> onClickLegendListener) {
this.onClickLegendListener = onClickLegendListener;
}
/**
* 是否动画只执行一次
*
* @param isFirstAnim
*/
public void setFirstAnim(boolean isFirstAnim) {
this.isFirstAnim = isFirstAnim;
}
public boolean save() {
return save(new PicOption(chartData.getChartName()));
}
public boolean save(PicOption picOption) {
return new PicGeneration<BaseChart>().save(this, picOption);
}
}
\ No newline at end of file
package com.daivd.chart.core.base;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.IProvider;
/**
* Created by huang on 2017/10/9.
* 饼图
*/
public abstract class BaseRotateChart<P extends IProvider<C>,C extends ColumnData> extends BaseChart<P,C> implements RotateHelper.OnRotateListener{
private RotateHelper rotateHelper;
private boolean isOnRotate;
public BaseRotateChart(Context context) {
super(context);
}
public BaseRotateChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BaseRotateChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void drawContent(Canvas canvas) {
provider.drawProvider(canvas, chartRect, matrixHelper, paint);
}
@Override
protected P initProvider() {
rotateHelper = new RotateHelper(this);
return initProvider(rotateHelper);
}
protected abstract P initProvider(RotateHelper rotateHelper);
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()== MotionEvent.ACTION_DOWN){
isOnRotate = rotateHelper.containsPoint(event);
}
if(isOnRotate){
super.onTouchEvent(event);
return rotateHelper.handlerTouchEvent(event);
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(isOnRotate){
rotateHelper.onDisallowInterceptEvent(this,event);
}
return super.dispatchTouchEvent(event);
}
public void setRotate(boolean rotate) {
if(rotate){
setZoom(false);
}
rotateHelper.setRotate(rotate);
}
@Override
public void onRotate(double angle) {
invalidate();
}
}
package com.daivd.chart.data;
import com.daivd.chart.component.base.IAxis;
import java.util.List;
/**
* Created by huang on 2017/9/26.
*/
public class BarData extends ColumnData<List<Double>> {
public BarData(String name, String unit, int color, List<Double> chartYDataList) {
super(name,unit,color,chartYDataList);
}
public BarData(String name, String unit, int direction, int color, List<Double> datas) {
super(name,unit,direction,color,datas);
}
}
package com.daivd.chart.data;
import java.util.List;
/**
* Created by huang on 2017/10/19.
*/
public class BarLineData extends BarData {
public static final int BROKEN= 0;
public static final int CURVE = 1;
public static final int BAR = 2;
private int model = BAR;
public BarLineData(String name, String unit, int color, List<Double> chartYDataList) {
super(name, unit, color, chartYDataList);
}
public BarLineData(String name, int model,String unit, int color,List<Double> chartYDataList) {
super(name, unit, color, chartYDataList);
this.model = model;
}
public BarLineData(String name, String unit, int direction, int color, List<Double> datas) {
super(name, unit, direction, color, datas);
}
public BarLineData(String name,int model, String unit, int direction, int color, List<Double> datas) {
super(name, unit, direction, color, datas);
this.model = model;
}
public int getModel() {
return model;
}
public void setModel(int model) {
this.model = model;
}
}
package com.daivd.chart.data;
import java.util.Arrays;
import java.util.List;
/**
* Created by huang on 2017/9/26.
* chart data
*/
public class ChartData<T extends ColumnData> {
private String chartName;
private List<String> charXDataList;
private ScaleData scaleData = new ScaleData();
private List<T> columnDataList;
public ChartData(String chartName,List<String> charXDataList, T... columnDataList){
this.chartName = chartName;
this.charXDataList = charXDataList;
this.columnDataList = Arrays.asList(columnDataList);
}
public ChartData(String chartName,List<String> charXDataList, List<T> columnDataList){
this.chartName = chartName;
this.charXDataList = charXDataList;
this.columnDataList = columnDataList;
}
public String getChartName() {
return chartName;
}
public void setChartName(String chartName) {
this.chartName = chartName;
}
public boolean isEmpty() {
return columnDataList== null || this.columnDataList.size() ==0 ;
}
public List<String> getCharXDataList() {
return charXDataList;
}
public void setCharXDataList(List<String> charXDataList) {
this.charXDataList = charXDataList;
}
public ScaleData getScaleData() {
return scaleData;
}
public void setScaleData(ScaleData scaleData) {
this.scaleData = scaleData;
}
public List<T> getColumnDataList() {
return columnDataList;
}
public void setColumnDataList(List<T> columnDataList) {
this.columnDataList = columnDataList;
}
}
package com.daivd.chart.data;
import com.daivd.chart.component.base.IAxis;
/**
* Created by huang on 2017/9/26.
*/
public class ColumnData<T> {
public String name;
private String unit;
private int color;
private boolean isDraw = true;
private int direction = IAxis.AxisDirection.LEFT;
private T chartYDataList;
public ColumnData(String name, String unit, int color, T chartYDataList) {
this.name = name;
this.unit = unit;
this.color = color;
this.chartYDataList = chartYDataList;
}
public ColumnData(String name, String unit, int direction, int color, T datas) {
this.name = name;
this.unit = unit;
this.color = color;
this.chartYDataList = datas;
if(direction == IAxis.AxisDirection.LEFT || direction == IAxis.AxisDirection.RIGHT){
this.direction = direction;
}
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public T getChartYDataList() {
return chartYDataList;
}
public void setChartYDataList(T chartYDataList) {
this.chartYDataList = chartYDataList;
}
public boolean isDraw() {
return isDraw;
}
public void setDraw(boolean draw) {
isDraw = draw;
}
}
package com.daivd.chart.data;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.provider.component.line.ILineModel;
import com.daivd.chart.provider.component.point.IPoint;
import java.util.List;
/**
* Created by huang on 2017/9/26.
*/
public class LineData extends BarData {
private IPoint point;
private ILineModel lineModel;
private LineStyle lineStyle;
public LineData(String name, String unit, int color, List<Double> chartYDataList) {
super(name,unit,color,chartYDataList);
}
public LineData(String name, String unit, int direction, int color, List<Double> datas) {
super(name,unit,direction,color,datas);
}
public IPoint getPoint() {
return point;
}
public void setPoint(IPoint point) {
this.point = point;
}
public ILineModel getLineModel() {
return lineModel;
}
public void setLineModel(ILineModel lineModel) {
this.lineModel = lineModel;
}
public LineStyle getLineStyle() {
return lineStyle;
}
public void setLineStyle(LineStyle lineStyle) {
this.lineStyle = lineStyle;
}
}
package com.daivd.chart.data;
import android.graphics.Bitmap;
/**
* Created by huang on 2017/10/30.
* 保存图片Option
*/
public class PicOption {
private String fileName;
private String subFolderPath ="chart";
private String fileDescription="chart pic";
private Bitmap.CompressFormat format= Bitmap.CompressFormat.PNG;
private int quality = 100;
public PicOption(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public String getSubFolderPath() {
return subFolderPath;
}
public PicOption setSubFolderPath(String subFolderPath) {
this.subFolderPath = subFolderPath;
return this;
}
public String getFileDescription() {
return fileDescription;
}
public PicOption setFileDescription(String fileDescription) {
this.fileDescription = fileDescription;
return this;
}
public Bitmap.CompressFormat getFormat() {
return format;
}
public PicOption setFormat(Bitmap.CompressFormat format) {
this.format = format;
return this;
}
public int getQuality() {
return quality;
}
public PicOption setQuality(int quality) {
this.quality = quality;
return this;
}
}
package com.daivd.chart.data;
import com.daivd.chart.component.base.IAxis;
/**
* Created by huang on 2017/9/26.
*/
public class PieData extends ColumnData<Double> {
public PieData(String name, String unit, int color, Double chartYDataList) {
super(name, unit, color, chartYDataList);
}
public PieData(String name, String unit, IAxis.AxisDirection direction, int color, Double datas) {
super(name, unit, color, datas);
}
}
package com.daivd.chart.data;
import java.util.List;
/**
* Created by huang on 2017/9/26.
*/
public class RadarData extends BarData {
public RadarData(String name, String unit, int color, List<Double> chartYDataList) {
super(name,unit,color,chartYDataList);
}
}
package com.daivd.chart.data;
import java.util.List;
/**
* Created by huang on 2017/9/26.
*/
public class RoseData extends BarData {
public RoseData(String name, String unit, int color, List<Double> chartYDataList) {
super(name,unit,color,chartYDataList);
}
}
package com.daivd.chart.data;
import android.graphics.Rect;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.matrix.MatrixHelper;
import java.util.ArrayList;
import java.util.List;
/**
* Created by huang on 2017/9/26.
* Scale data
*/
public class ScaleData {
public boolean isLeftHasValue = false;
public boolean isRightHasValue = false;
//竖轴数据
public double maxLeftValue; //最大值
public double minLeftValue; //最小值
//竖轴数据
public double maxRightValue; //最大值
public double minRightValue; //最小值
public int totalScale = 7; //刻度数量
public Rect scaleRect = new Rect();
//横轴数据
public int rowSize; //列数据
public float zoom = MatrixHelper.MIN_ZOOM; //放大比例
public List<Double> getScaleList(int direction){
List<Double> scaleList = new ArrayList<>();
int total = (int) (totalScale *zoom);
double scale = getTotalScaleLength(direction) /(total-1);
double minValue = getMinScaleValue(direction);
for(int i = 0;i < total;i++){
scaleList.add(minValue +scale*i);
}
return scaleList;
}
/**
* 获取最大刻度
* @param direction
* @return
*/
public double getMaxScaleValue(int direction){
if(direction == IAxis.AxisDirection.LEFT){
return maxLeftValue;
}
return maxRightValue;
}
/**
* 获取最小刻度
* @param direction
* @return
*/
public double getMinScaleValue(int direction){
if(direction == IAxis.AxisDirection.LEFT){
return minLeftValue;
}
return minRightValue;
}
/**
*获取总刻度值
* @param direction 方向
* @return 总刻度
*/
public double getTotalScaleLength(int direction){
if(direction == IAxis.AxisDirection.LEFT){
return maxLeftValue - minLeftValue;
}
return maxRightValue - minRightValue;
}
public Rect getOffsetRect(Rect rect, Rect offsetRect){
rect.left = rect.left + offsetRect.left;
rect.right = rect.right - offsetRect.right;
rect.top = rect.top + offsetRect.top;
rect.bottom = rect.bottom - offsetRect.bottom;
return rect;
}
public void resetScale(ScaleSetData scaleSetData,int direction){
if(direction == IAxis.AxisDirection.LEFT){
if(scaleSetData.isStartZoom()){
minLeftValue = 0;
}else {
if(scaleSetData.isHasMinValue()){
minLeftValue = scaleSetData.getMinValue();
}
}
if(scaleSetData.isHasMaxValue()){
maxLeftValue = scaleSetData.getMaxValue();
}
}else{
if(scaleSetData.isStartZoom()){
minRightValue = 0;
}else {
if(scaleSetData.isHasMinValue()){
minRightValue = scaleSetData.getMinValue();
}
}
if(scaleSetData.isHasMaxValue()){
maxRightValue = scaleSetData.getMaxValue();
}
}
}
}
package com.daivd.chart.data;
/**
* Created by huang on 2017/10/18.
*/
public class ScaleSetData {
private boolean isStartZoom;
private boolean isHasMaxValue;
private boolean isHasMinValue;
private double maxValue;
private double minValue;
public boolean isStartZoom() {
return isStartZoom;
}
public void setStartZoom(boolean startZoom) {
isHasMinValue = false;
isStartZoom = startZoom;
}
public boolean isHasMaxValue() {
return isHasMaxValue;
}
public boolean isHasMinValue() {
return isHasMinValue;
}
public double getMaxValue() {
return maxValue;
}
public void setMaxValue(double maxValue) {
isHasMaxValue = true;
this.maxValue = maxValue;
}
public double getMinValue() {
return minValue;
}
public void setMinValue(double minValue) {
isHasMinValue = true;
this.minValue = minValue;
}
}
package com.daivd.chart.data.format;
/**
* 格式化
* <p>用于横轴和竖轴文本格式化</p>
* @author huangyanbin
*/
public interface IFormat<T> {
String format( T t);
}
package com.daivd.chart.data.style;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import com.daivd.chart.utils.DensityUtils;
/**
* Created by huang on 2017/9/27.
*/
public class FontStyle implements IStyle{
public static int defaultFontSize = 12;
public static int defaultFontColor = Color.parseColor("#333333");
private int textSize;
private int textColor;
private int padding = 0;
public static void setDefaultTextSize(int defaultTextSize){
defaultFontSize = defaultTextSize;
}
public static void setDefaultTextSpSize(Context context,int defaultTextSpSize){
defaultFontSize = DensityUtils.sp2px(context,defaultTextSpSize);
}
public static void setDefaultTextColor(int defaultTextColor){
defaultFontColor = defaultTextColor;
}
public FontStyle() {
}
public FontStyle(int textSize, int textColor) {
this.textSize = textSize;
this.textColor = textColor;
}
public FontStyle(Context context,int sp, int textColor) {
this.textSize = DensityUtils.sp2px(context,sp);
this.textColor = textColor;
}
public int getTextSize() {
if(textSize == 0){
return defaultFontSize;
}
return textSize;
}
public FontStyle setTextSize(int textSize) {
this.textSize = textSize;
return this;
}
public FontStyle setTextSpSize(Context context,int sp){
this.setTextSize(DensityUtils.sp2px(context,sp));
return this;
}
public int getTextColor() {
if(textColor == 0){
return defaultFontColor;
}
return textColor;
}
public FontStyle setTextColor(int textColor) {
this.textColor = textColor;
return this;
}
public int getPadding() {
return padding;
}
public void setPadding(int padding) {
this.padding = padding;
}
@Override
public void fillPaint(Paint paint){
paint.setColor(getTextColor());
paint.setTextSize(getTextSize());
paint.setStyle(Paint.Style.FILL);
}
}
package com.daivd.chart.data.style;
import android.graphics.Paint;
/**
* Created by huang on 2017/9/27.
*/
public interface IStyle {
void fillPaint(Paint paint);
}
package com.daivd.chart.data.style;
import android.content.Context;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import com.daivd.chart.utils.DensityUtils;
/**
* Created by huang on 2017/9/27.
*/
public class LineStyle implements IStyle {
private float width;
private int color;
private PathEffect effect = new PathEffect();
private static float defaultLineSize = 2f;
private static int defaultLineColor = Color.parseColor("#888888");
public LineStyle() {
}
public LineStyle(float width, int color) {
this.width = width;
this.color = color;
}
public LineStyle(Context context,float dp, int color) {
this.width = DensityUtils.dp2px(context,dp);
this.color = color;
}
public static void setDefaultLineSize(float width){
defaultLineSize = width;
}
public static void setDefaultLineSize(Context context,float dp){
defaultLineSize = DensityUtils.dp2px(context,dp);
}
public static void setDefaultLineColor(int color){
defaultLineColor = color;
}
public float getWidth() {
if(width == 0){
return defaultLineSize;
}
return width;
}
public LineStyle setWidth(float width) {
this.width = width;
return this;
}
public LineStyle setWidth(Context context,int dp) {
this.width = DensityUtils.dp2px(context,dp);
return this;
}
public int getColor() {
if(color == 0){
return defaultLineColor;
}
return color;
}
public LineStyle setColor(int color) {
this.color = color;
return this;
}
public LineStyle setEffect(PathEffect effect) {
this.effect = effect;
return this;
}
@Override
public void fillPaint(Paint paint){
paint.setColor(getColor());
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(getWidth());
paint.setPathEffect(effect);
}
}
package com.daivd.chart.data.style;
import android.content.Context;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import com.daivd.chart.utils.DensityUtils;
/**
* Created by huang on 2017/9/27.
*/
public class PointStyle implements IStyle {
public static final int CIRCLE = 0;
public static final int SQUARE = 1;
public static final int RECT = 2;
private float width;
private int color;
private int shape;
private Paint.Style style;
private static float defaultPointSize = 10f;
private static int defaultPointColor = Color.parseColor("#888888");
private boolean isDraw = true;
public PointStyle() {
}
public PointStyle(float width, int color) {
this.width = width;
this.color = color;
}
public PointStyle(Context context, float dp, int color) {
this.width = DensityUtils.dp2px(context,dp);
this.color = color;
}
public static void setDefaultPointSize(float width){
defaultPointSize = width;
}
public static void setDefaultLineSize(Context context,float dp){
defaultPointSize = DensityUtils.dp2px(context,dp);
}
public static void setDefaultPointColor(int color){
defaultPointColor = color;
}
public float getWidth() {
if(width == 0){
return defaultPointSize;
}
return width;
}
public void setWidth(float width) {
this.width = width;
}
public void setWidth(Context context,int dp) {
this.width = DensityUtils.dp2px(context,dp);
}
public int getColor() {
if(color == 0){
return defaultPointColor;
}
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getShape() {
return shape;
}
public void setShape(int shape) {
this.shape = shape;
}
public Paint.Style getStyle() {
if(style == null){
return Paint.Style.FILL;
}
return style;
}
public void setStyle(Paint.Style style) {
this.style = style;
}
public boolean isDraw() {
return isDraw;
}
public void setDraw(boolean draw) {
isDraw = draw;
}
@Override
public void fillPaint(Paint paint){
paint.setColor(getColor());
paint.setStyle(getStyle());
paint.setStrokeWidth(getWidth());
}
}
package com.daivd.chart.exception;
/**
* Created by huang on 2017/9/26.
*/
public class ChartException extends RuntimeException {
public ChartException(String message) {
super(message);
}
}
package com.daivd.chart.listener;
/**
* Created by huang on 2017/9/29.
*/
public interface ChartGestureObserver {
void onClick(float x,float y);
}
package com.daivd.chart.listener;
import java.util.ArrayList;
import java.util.List;
/**
* Created by huang on 2017/9/29.
*/
public abstract class Observable<T> {
public final ArrayList<T> observables = new ArrayList<>();
/**AttachObserver(通过实例注册观察者)
**/
public void register(T observer){
if(observer==null) throw new NullPointerException();
synchronized(observables){
if(!observables.contains(observer)){
observables.add(observer);
}
}
}
/**UnattachObserver(注销观察者)
**/
public void unRegister(T observer){
if(observer==null) throw new NullPointerException();
if(observables.contains(observer)){
observables.remove(observer);
}
}
public void unRegisterAll(){
synchronized(observables){
observables.clear();
}
}
/**Ruturnthesizeofobservers*/
public int countObservers(){
synchronized(observables){
return observables.size();
}
}
/**
*notify all observer(通知所有观察者,在子类中实现)
*/
public abstract void notifyObservers(List<T> observers);
}
package com.daivd.chart.listener;
/**
* Created by huang on 2017/11/4.
*/
public interface OnChartChangeListener {
void onTableChanged(float translateX, float translateY);
}
package com.daivd.chart.listener;
import com.daivd.chart.data.ColumnData;
/**
* Created by huang on 2017/9/30.
*/
public interface OnClickColumnListener<C extends ColumnData> {
void onClickColumn(C c,int position);
}
package com.daivd.chart.listener;
import com.daivd.chart.component.Legend;
import com.daivd.chart.data.ColumnData;
/**
* Created by huang on 2017/9/30.
*/
public interface OnClickLegendListener<C extends ColumnData> {
void onClickLegend(C c, Legend<C> legend);
}
package com.daivd.chart.matrix;
import android.view.MotionEvent;
import com.daivd.chart.core.base.BaseChart;
/**
* Created by huang on 2017/10/18.
*/
public interface ITouch {
/**
* 用于判断是否请求不拦截事件
* 解决手势冲突问题
* @param chart
* @param event
*/
void onDisallowInterceptEvent(BaseChart chart, MotionEvent event);
/**
* 处理touchEvent
* @param event
*/
boolean handlerTouchEvent(MotionEvent event);
}
package com.daivd.chart.matrix;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import com.daivd.chart.core.base.BaseChart;
import com.daivd.chart.listener.Observable;
import com.daivd.chart.listener.ChartGestureObserver;
import com.daivd.chart.listener.OnChartChangeListener;
import java.util.List;
/**
* Created by huang on 2017/9/29.
* 图表放大缩小协助类
*/
public class MatrixHelper extends Observable<ChartGestureObserver> implements ITouch, ScaleGestureDetector.OnScaleGestureListener {
/**
* 最大缩放比
*/
private static final int MAX_ZOOM = 5;
/**
* 最小缩放比
*/
public static final int MIN_ZOOM = 1;
/**
* 当前缩放比
*/
private float zoom = MIN_ZOOM; //缩放比例 不得小于1
/**
* X轴位移的距离
*/
private int translateX; //以左上角为准,X轴位移的距离
/**
* y轴位移的距离
*/
private int translateY;//以左上角为准,y轴位移的距离
/**
* 缩放手势
*/
private ScaleGestureDetector mScaleGestureDetector;
/**
* 移动手势
*/
private GestureDetector mGestureDetector;
/**
* 是否可以缩放
*/
private boolean isCanZoom;
/**
* 是否正在缩放
*/
private boolean isScale; //是否正在缩放
/**
* 原始图表大小
*/
private Rect originalRect; //原始大小
/**
* 缩放之后的大小
*/
private Rect zoomRect;
/**
* 点击X,y点
*/
private float mDownX, mDownY;
/**
* 屏幕的手指点个数
*/
private int pointMode;
/**
* 宽缩放比
*/
private float widthMultiple =1;
/**
* 滚动辅助
*/
private Scroller scroller;
/**
* 最小速率
*/
private int mMinimumVelocity;
/**
* 是否正在飞滚
*/
private boolean isFling;
/**
* 飞滚速率
*/
private float flingRate = 0.8f; //速率
/**
* 图表缩放监听
*/
private OnChartChangeListener listener;
/**
* 缩放移动手势辅助类构造方法
* @param context context
*/
public MatrixHelper(Context context) {
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mGestureDetector = new GestureDetector(context, new OnChartGestureListener());
final ViewConfiguration configuration = ViewConfiguration.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
scroller = new Scroller(context);
}
/**
* 处理手势
*/
@Override
public boolean handlerTouchEvent(MotionEvent event) {
if (isCanZoom) {
mScaleGestureDetector.onTouchEvent(event);
}
mGestureDetector.onTouchEvent(event);
return true;
}
/**
* 判断是否需要接收触摸事件
*/
@Override
public void onDisallowInterceptEvent(BaseChart chart, MotionEvent event) {
if (!isCanZoom) {
return;
}
ViewParent parent = chart.getParent();
if (zoomRect == null || originalRect == null) {
parent.requestDisallowInterceptTouchEvent(false);
return;
}
switch (event.getAction()&MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
pointMode = 1;
//ACTION_DOWN的时候,赶紧把事件hold住
mDownX = event.getX();
mDownY = event.getY();
if(originalRect.contains((int)mDownX,(int)mDownY)){ //判断是否落在图表内容区中
parent.requestDisallowInterceptTouchEvent(true);
}else{
parent.requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
pointMode += 1;
parent.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (pointMode > 1) {
parent.requestDisallowInterceptTouchEvent(true);
return;
}
float disX = event.getX() - mDownX;
float disY = event.getY() - mDownY;
boolean isDisallowIntercept = true;
if (Math.abs(disX) > Math.abs(disY)) {
if ((disX > 0 && toRectLeft()) || (disX < 0 && toRectRight())) { //向右滑动
isDisallowIntercept = false;
}
} else {
/* if ((disY > 0 && toRectTop()) || (disY < 0 && toRectBottom())) {*/
isDisallowIntercept = false;
/* }*/
}
parent.requestDisallowInterceptTouchEvent(isDisallowIntercept);
break;
case MotionEvent.ACTION_POINTER_UP:
pointMode -= 1;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
pointMode = 0;
parent.requestDisallowInterceptTouchEvent(false);
}
}
private boolean toRectLeft() {
return translateX <= -(zoomRect.width() - originalRect.width()) / 2;
}
private boolean toRectRight() {
return translateX >= (zoomRect.width() - originalRect.width()) / 2;
}
private boolean toRectBottom() {
return translateY >= (zoomRect.height() - originalRect.height()) / 2;
}
private boolean toRectTop() {
return translateY <= -(zoomRect.height() - originalRect.height()) / 2;
}
@Override
public void notifyObservers(List<ChartGestureObserver> observers) {
}
private float tempScale = MIN_ZOOM; //缩放比例 不得小于1
private int tempTranslateX; //以左上角为准,X轴位移的距离
private int tempTranslateY;//以左上角为准,y轴位移的距离
class OnChartGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
translateX += distanceX;
translateY += distanceY;
notifyViewChanged();
return true;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
/**
* 飞滚
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if(Math.abs(velocityX) >mMinimumVelocity || Math.abs(velocityY) >mMinimumVelocity) {
scroller.setFinalX(0);
scroller.setFinalY(0);
tempTranslateX = translateX;
tempTranslateY = translateY;
scroller.fling(0,0,(int)velocityX,(int)velocityY,-50000,50000
,-50000,50000);
isFling = true;
startFilingAnim(false);
}
return true;
}
//双击
@Override
public boolean onDoubleTap(MotionEvent e) {
if (isCanZoom) {
float oldZoom = zoom;
if (isScale) { //缩小
zoom = zoom / 1.5f;
if (zoom < 1) {
zoom = MIN_ZOOM;
isScale = false;
}
} else { //放大
zoom = zoom * 1.5f;
if (zoom > MAX_ZOOM) {
zoom = MAX_ZOOM;
isScale = true;
}
}
float factor = zoom / oldZoom;
resetTranslate(factor);
notifyObservers(observables);
}
return true;
}
//单击
@Override
public boolean onSingleTapUp(MotionEvent e) {
notifyViewChanged();
for (ChartGestureObserver observer : observables) {
observer.onClick(e.getX(), e.getY());
}
return true;
}
}
private Point startPoint = new Point(0, 0);
private Point endPoint = new Point();
private TimeInterpolator interpolator = new DecelerateInterpolator();
private PointEvaluator evaluator= new PointEvaluator();
/**
* 开始飞滚
* @param doubleWay 双向飞滚
*/
private void startFilingAnim(boolean doubleWay) {
int scrollX =Math.abs(scroller.getFinalX());
int scrollY =Math.abs(scroller.getFinalY());
if(doubleWay){
endPoint.set((int) (scroller.getFinalX() * flingRate),
(int) (scroller.getFinalY() * flingRate));
}else {
if (scrollX > scrollY) {
endPoint.set((int) (scroller.getFinalX() * flingRate), 0);
} else {
endPoint.set(0, (int) (scroller.getFinalY() * flingRate));
}
}
final ValueAnimator valueAnimator = ValueAnimator.ofObject(evaluator,startPoint,endPoint);
valueAnimator.setInterpolator(interpolator);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if(isFling) {
Point point = (Point) animation.getAnimatedValue();
translateX = tempTranslateX - point.x;
translateY = tempTranslateY - point.y;
notifyViewChanged();
}else{
animation.cancel();
}
}
});
int duration = (int)(Math.max(scrollX,scrollY)*flingRate)/2;
valueAnimator.setDuration(duration>300 ?300:duration);
valueAnimator.start();
}
public void notifyViewChanged(){
if(listener != null) {
listener.onTableChanged(translateX, translateY);
}
}
/**
* 缩放开始
*/
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
tempScale = this.zoom;
return true;
}
/**
* 正在缩放
*/
@Override
public boolean onScale(ScaleGestureDetector detector) {
float oldZoom = zoom;
float scale = detector.getScaleFactor();
this.zoom = (float) (tempScale * Math.pow(scale, 2));
float factor = zoom / oldZoom;
resetTranslate(factor);
notifyObservers(observables);
if (this.zoom > MAX_ZOOM) {
this.zoom = MAX_ZOOM;
return true;
} else if (this.zoom < 1) {
this.zoom = 1;
return true;
}
return false;
}
/**
* 缩放结束
*/
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
/**
* 重新计算偏移量
* * @param factor
*/
private void resetTranslate(float factor) {
translateX = (int) (translateX * factor);
translateY = (int) (translateY * factor);
}
/**
* 获取图片内容的缩放大小
*
* @param providerRect 内容的大小
* @return 缩放后内容的大小
*/
public Rect getZoomProviderRect(Rect providerRect) {
originalRect = providerRect;
Rect scaleRect = new Rect();
int oldw = providerRect.width();
int oldh = providerRect.height();
int multipleWidth = (int) (oldw *widthMultiple);
int newWidth = (int) (multipleWidth * zoom);
int newHeight = (int) (oldh * zoom);
int offsetX = (int) (oldw*(zoom-1))/2;
int offsetY =(int) (oldh*(zoom-1))/2;
int maxTranslateLeft = (int)Math.abs(oldw*(zoom-1) / 2);
int maxTranslateRight = newWidth - oldw - offsetX;
int maxTranslateY = Math.abs(newHeight - oldh) / 2;
if(translateX >maxTranslateRight){
translateX = maxTranslateRight;
}
if(translateX < -maxTranslateLeft){
translateX = -maxTranslateLeft;
}
if (Math.abs(translateY) > maxTranslateY) {
translateY = translateY > 0 ? maxTranslateY : -maxTranslateY;
}
scaleRect.left = providerRect.left - offsetX - translateX;
scaleRect.right=scaleRect.left+newWidth;
scaleRect.top = providerRect.top - offsetY - translateY;
scaleRect.bottom = scaleRect.top+newHeight;
zoomRect = scaleRect;
return scaleRect;
}
/**
* 获取宽的倍数
* <p>一旦设置倍数,宽度会变大相应倍数,这样就可以横向滑动了。</p>
*/
public float getWidthMultiple() {
return widthMultiple;
}
/**
* 设置宽的倍数
* <p>一旦设置倍数,宽度会变大相应倍数,这样就可以横向滑动了。</p>
* @param widthMultiple 宽的倍数
*/
public void setWidthMultiple(float widthMultiple) {
this.widthMultiple = widthMultiple;
}
/**
* 是否可以缩放
* @return 是否可以缩放
*/
public boolean isCanZoom() {
zoom = 1f;
return isCanZoom;
}
/**
* 设置是否可以缩放
* @param canZoom 是否可以缩放
*/
public void setCanZoom(boolean canZoom) {
isCanZoom = canZoom;
}
/**
* 获取当前缩放比例
* @return 缩放比例
*/
public float getZoom() {
return zoom;
}
/**
* 设置缩放滚动监听
* @return 缩放滚动监听
*/
public OnChartChangeListener getOnTableChangeListener() {
return listener;
}
/**
* 获取缩放滚动监听
* @param onTableChangeListener 缩放滚动监听
*/
public void setOnTableChangeListener(OnChartChangeListener onTableChangeListener) {
this.listener = onTableChangeListener;
}
}
package com.daivd.chart.matrix;
import android.animation.TypeEvaluator;
import android.graphics.Point;
/**
* Created by huang on 2017/11/3.
*/
public class PointEvaluator implements TypeEvaluator {
private Point point = new Point();
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));
int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));
point.set(x,y);
return point;
}
}
package com.daivd.chart.matrix;
import android.graphics.Rect;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.ViewParent;
import com.daivd.chart.core.base.BaseChart;
/**
* Created by huang on 2017/10/10.
*/
public class RotateHelper implements ITouch {
private int mRadius;
/**
* 检测按下到抬起时旋转的角度
*/
private float mTmpAngle;
/**
* 检测按下到抬起时使用的时间
*/
private long mDownTime;
/**
* 判断是否正在自动滚动
*/
private boolean isFling;
/**
* 布局时的开始角度
*/
private double mStartAngle = 0;
/**
* 当每秒移动角度达到该值时,认为是快速移动
*/
private static final int FLINGABLE_VALUE = 300;
/**
* 如果移动角度达到该值,则屏蔽点击
*/
private static final int NOCLICK_VALUE = 3;
/**
* 当每秒移动角度达到该值时,认为是快速移动
*/
private int mFlingableValue = FLINGABLE_VALUE;
private Handler mHandler = new Handler();
/**
* 记录上一次的x,y坐标
*/
private float mLastX;
private float mLastY;
private boolean isRotate;
private Rect originRect;
/**
* 自动滚动的Runnable
*/
private AutoFlingRunnable mFlingRunnable;
private OnRotateListener listener;
public RotateHelper(OnRotateListener listener){
this.listener = listener;
}
@Override
public boolean handlerTouchEvent(MotionEvent event) {
if(!isRotate()){
return false;
}
float x = event.getX();
float y = event.getY();
// Log.e("TAG", "x = " + x + " , y = " + y);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
mDownTime = System.currentTimeMillis();
mTmpAngle = 0;
// 如果当前已经在快速滚动
if (isFling)
{
// 移除快速滚动的回调
mHandler.removeCallbacks(mFlingRunnable);
isFling = false;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
/**
* 获得开始的角度
*/
float start = getAngle(mLastX, mLastY);
/**
* 获得当前的角度
*/
float end = getAngle(x, y);
// Log.e("TAG", "start = " + start + " , end =" + end);
// 如果是一、四象限,则直接end-start,角度值都是正值
if (getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4)
{
mStartAngle += end - start;
mTmpAngle += end - start;
} else
// 二、三象限,色角度值是付值
{
mStartAngle += start - end;
mTmpAngle += start - end;
}
// 重新布局
listener.onRotate(mStartAngle);
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
// 计算,每秒移动的角度
float anglePerSecond = mTmpAngle * 1000
/ (System.currentTimeMillis() - mDownTime);
// Log.e("TAG", anglePrMillionSecond + " , mTmpAngel = " +
// mTmpAngle);
// 如果达到该值认为是快速移动
if (Math.abs(anglePerSecond) > mFlingableValue && !isFling)
{
// post一个任务,去自动滚动
mHandler.post(mFlingRunnable = new AutoFlingRunnable(anglePerSecond));
return true;
}
// 如果当前旋转角度超过NOCLICK_VALUE屏蔽点击
if (Math.abs(mTmpAngle) > NOCLICK_VALUE)
{
return true;
}
break;
}
return true;
}
@Override
public void onDisallowInterceptEvent(BaseChart chart, MotionEvent event){
ViewParent parent = chart.getParent();
if (!isRotate() || originRect == null) {
parent.requestDisallowInterceptTouchEvent(false);
return;
}
switch (event.getAction()&MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if(containsPoint(event)){
parent.requestDisallowInterceptTouchEvent(true);
}else {
parent.requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
parent.requestDisallowInterceptTouchEvent(false);
break;
}
}
public boolean containsPoint(MotionEvent event){
if(originRect != null) {
float x = event.getX();
float y = event.getY();
int centerY = originRect.centerY();
int centerX = originRect.centerX();
return x >= centerX - mRadius && x <= centerX + mRadius
&& y >= centerY - mRadius && y <= centerY + mRadius;
}
return false;
}
/**
* 自动滚动的任务
*
* @author zhy
*
*/
private class AutoFlingRunnable implements Runnable
{
private float angelPerSecond;
public AutoFlingRunnable(float velocity)
{
this.angelPerSecond = velocity;
}
public void run()
{
// 如果小于20,则停止
if ((int) Math.abs(angelPerSecond) < 20)
{
isFling = false;
return;
}
isFling = true;
// 不断改变mStartAngle,让其滚动,/30为了避免滚动太快
mStartAngle += (angelPerSecond / 30);
// 逐渐减小这个值
angelPerSecond /= 1.0666F;
mHandler.postDelayed(this, 30);
// 重新布局
listener.onRotate(mStartAngle);
}
}
/**
* 根据触摸的位置,计算角度
*
* @param xTouch
* @param yTouch
* @return
*/
private float getAngle(float xTouch, float yTouch)
{
double x = xTouch- originRect.left - (mRadius );
double y = yTouch- originRect.top - (mRadius );
return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
}
/**
* 根据当前位置计算象限
*
* @param x
* @param y
* @return
*/
private int getQuadrant(float x, float y)
{
int tmpX = (int) (x- originRect.left - mRadius );
int tmpY = (int) (y- originRect.top - mRadius );
if (tmpX >= 0)
{
return tmpY >= 0 ? 4 : 1;
} else
{
return tmpY >= 0 ? 3 : 2;
}
}
public interface OnRotateListener{
void onRotate(double angle);
}
public void setRadius(int radius) {
this.mRadius = radius;
}
public void setOriginRect(Rect originRect){
this.originRect = originRect;
}
public double getStartAngle() {
return mStartAngle;
}
public boolean isRotate() {
return isRotate;
}
public void setRotate(boolean rotate) {
isRotate = rotate;
}
}
package com.daivd.chart.provider;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.animation.Interpolator;
import com.daivd.chart.core.base.BaseChart;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.listener.OnClickColumnListener;
import com.daivd.chart.provider.component.mark.IMark;
import com.daivd.chart.matrix.MatrixHelper;
import com.daivd.chart.provider.component.text.IText;
/**
* Created by huang on 2017/9/26.
*/
public abstract class BaseProvider<C extends ColumnData> implements IProvider<C> {
private float progress = 1;
protected PointF pointF;
protected IMark<C> markView;
private boolean isOpenMark;
private boolean isShowText =true;
protected ChartData<C> chartData;
private Rect providerRect;
private IText text;
protected OnClickColumnListener<C> onClickColumnListener;
@Override
public boolean calculation(ChartData<C> chartData) {
this.chartData = chartData;
return calculationChild(chartData);
}
public abstract boolean calculationChild(ChartData<C> chartData);
@Override
public void drawProvider(Canvas canvas, Rect rect, MatrixHelper helper, Paint paint) {
providerRect = rect;
matrixRectStart(canvas,rect);
Rect zoomRect = helper.getZoomProviderRect(rect);
drawProvider(canvas,zoomRect,rect,paint);
matrixRectEnd(canvas,rect);
}
protected void matrixRectStart(Canvas canvas, Rect rect){
canvas.save();
canvas.clipRect(rect);
}
protected void matrixRectEnd(Canvas canvas, Rect rect){
canvas.restore();
}
protected abstract void drawProvider(Canvas canvas, Rect zoomRect,Rect rect, Paint paint);
@Override
public void clickPoint(PointF point) {
pointF = point;
}
@Override
public void startAnim(final BaseChart chartView, int duration, Interpolator interpolator) {
ValueAnimator animator = ValueAnimator.ofFloat(0,1);
animator.setDuration(duration);
animator.setInterpolator(interpolator);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
progress = (float) animation.getAnimatedValue();
chartView.invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
progress = 1;
chartView.invalidate();
}
@Override
public void onAnimationEnd(Animator animation) {
progress = 1;
chartView.invalidate();
}
});
animator.start();
}
public void drawPointText(Canvas canvas,double value,float x,float y,int position,int line,Paint paint){
if(text != null) {
String val = String.valueOf(value);
if (containsRect(x,y)) {
text.drawText(canvas,val,x,y,position,line,paint);
}
}
}
public boolean containsRect( float x,float y){
Rect rect = providerRect;
return y>= rect.top -1 && y<= rect.bottom+1
&& x>= rect.left-1 && x<= rect.right+1;
}
public boolean isOpenMark() {
return isOpenMark;
}
public void setOpenMark(boolean openMark) {
isOpenMark = openMark;
}
public abstract double[] setMaxMinValue(double maxMinValue, double minValue);
@Override
public void setMarkView(IMark markView) {
this.markView = markView;
}
protected float getAnimValue(float value){
return value*progress;
}
public Rect getProviderRect() {
return providerRect;
}
public float getProgress() {
return progress;
}
public boolean isShowText() {
return isShowText;
}
public void setShowText(boolean showText) {
isShowText = showText;
}
public void setOnClickColumnListener(OnClickColumnListener<C> onClickColumnListener) {
this.onClickColumnListener = onClickColumnListener;
}
public IText getText() {
return text;
}
public void setText(IText text) {
this.text = text;
}
}
package com.daivd.chart.provider;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.animation.Interpolator;
import com.daivd.chart.core.base.BaseChart;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.ColumnData;
import com.daivd.chart.listener.OnClickColumnListener;
import com.daivd.chart.provider.component.mark.IMark;
import com.daivd.chart.matrix.MatrixHelper;
/**
* Created by huang on 2017/9/26.
*/
public interface IProvider<C extends ColumnData> {
boolean calculation( ChartData<C> chartData);
void drawProvider(Canvas canvas, Rect rect, MatrixHelper helper, Paint paint);
void clickPoint(PointF point);
void startAnim(BaseChart chartView, int duration, Interpolator interpolator);
void setMarkView(IMark markView);
void setOnClickColumnListener(OnClickColumnListener<C> onClickColumnListener);
}
package com.daivd.chart.provider.barLine;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.data.BarData;
/**柱状内容绘制
* Created by huang on 2017/9/26.
*/
public class Bar3DProvider extends BarProvider<BarData> {
/**
* 绘制柱
* @param canvas 画布
* @param rect 范围
* @param value 数值
* @param position 位置
* @param line 线位置
* @param paint 画笔
*/
@Override
protected void drawBar(Canvas canvas,Rect rect,double value,int position,int line,Paint paint){
canvas.drawRect(rect, paint);
float w = rect.right - rect.left;
float offsetY= w/2;
float offsetX = w/3f;
Path path = new Path();
path.moveTo(rect.left,rect.top);
path.lineTo(rect.left+offsetX,rect.top-offsetY);
path.lineTo(rect.right+offsetX,rect.top-offsetY);
path.lineTo(rect.right,rect.top);
path.close();
canvas.drawPath(path,paint);
path.reset();
path.moveTo(rect.right,rect.top);
path.lineTo(rect.right,rect.bottom);
path.lineTo(rect.right+offsetX,rect.bottom-offsetY);
path.lineTo(rect.right+offsetX,rect.top-offsetY);
path.close();
canvas.drawPath(path,paint);
drawPointText(canvas,value,(rect.right + rect.left) / 2, rect.top-offsetY,position,line, paint );
}
@Override
public double[] setMaxMinValue(double maxValue, double minValue) {
double dis = Math.abs(maxValue -minValue);
maxValue = maxValue + dis*0.4;
if(minValue >0){
minValue = 0;
}else{
minValue = minValue - dis*0.4;
}
return new double[]{maxValue,minValue};
}
}
package com.daivd.chart.provider.barLine;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.data.BarLineData;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.exception.ChartException;
import com.daivd.chart.provider.component.line.BrokenLineModel;
import com.daivd.chart.provider.component.line.CurveLineModel;
import java.util.ArrayList;
import java.util.List;
/**状状图和线性图结合
* Created by huang on 2017/9/26.
*/
public class BarLineProvider extends BarProvider<BarLineData> {
private List<Float> pointX = new ArrayList<>();
private List<Float> pointY = new ArrayList<>();
private LineStyle lineStyle = new LineStyle();
@Override
public void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
paint.setStyle(Paint.Style.FILL);
List<BarLineData> columnDataList = chartData.getColumnDataList();
int barColumnSize = getBarColumnSize();
int rowSize = chartData.getCharXDataList().size();
double perWidth = zoomRect.width()/(barColumnSize*rowSize);
double perBarWidth =perWidth - getCategoryPadding() / 2;
int columnSize = columnDataList.size();
int barPosition =-1;
for (int i = 0; i < columnSize; i++) {
BarLineData columnData = columnDataList.get(i);
if (!columnData.isDraw()) {
continue;
}
if(columnData.getModel() == BarLineData.BAR) {
barPosition++;
}
for (int j = 0; j < rowSize; j++) {
double value = columnData.getChartYDataList().get(j);
int top = (int) getStartY(zoomRect, value, columnData.getDirection());
if(columnData.getModel() == BarLineData.BAR) {
int left = (int) (((j * barColumnSize + barPosition) * perBarWidth)
+ j * getCategoryPadding() + zoomRect.left);
int right = (int) (left + perBarWidth) - getSeriesPadding();
int bottom = zoomRect.bottom;
paint.setColor(columnData.getColor());
Rect barRect = new Rect(left, top, right, bottom);
drawBar(canvas, barRect, value,i,j, paint);
}else{
float x = (float)(zoomRect.left+perWidth*(j+0.5));
drawLine(canvas,j== 0,j == rowSize-1,columnData,x,top,value,i,j,paint);
}
}
}
drawLevelLine(canvas, zoomRect, paint);
}
protected void drawLine(Canvas canvas, boolean isNewBar,boolean isLast, BarLineData columnData, float x,float y, double value,int position,int line, Paint paint) {
if(columnData.getModel() ==BarLineData.CURVE
|| columnData.getModel() ==BarLineData.BROKEN){
if(isNewBar){
pointX.clear();
pointY.clear();
}
pointX.add(x);
pointY.add(y);
drawPointText(canvas,value,x, y,position,line,paint);
if(isLast){
Path path;
if(columnData.getModel() ==BarLineData.CURVE){
path = new CurveLineModel().getLinePath(pointX,pointY);
}else{
path = new BrokenLineModel().getLinePath(pointX,pointY);
}
lineStyle.setColor(paint.getColor());
lineStyle.fillPaint(paint);
canvas.drawPath(path,paint);
}
}
}
protected int getBarColumnSize() {
List<BarLineData> lineDates = chartData.getColumnDataList();
int barSize = 0;
for(int i =0;i < lineDates.size();i++){
if(lineDates.get(i).getModel() == BarLineData.BAR){
barSize++;
}
}
if(barSize == 0){
throw new ChartException("There must be a set of bar data!");
}
return barSize;
}
public LineStyle getLineStyle() {
return lineStyle;
}
public void setLineStyle(LineStyle lineStyle) {
this.lineStyle = lineStyle;
}
}
package com.daivd.chart.provider.barLine;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.data.BarData;
import com.daivd.chart.utils.ColorUtils;
import java.util.List;
/**
* 柱状内容绘制
* Created by huang on 2017/9/26.
*/
public class BarProvider<C extends BarData> extends BaseBarLineProvider<C> {
private int categoryPadding = 20;
private int seriesPadding = 10;
@Override
public void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
paint.setStyle(Paint.Style.FILL);
paint.setTextAlign(Paint.Align.LEFT);
List<C> columnDataList = chartData.getColumnDataList();
int columnSize = columnDataList.size();
int rowSize = chartData.getCharXDataList().size();
double width = (zoomRect.width()-(columnSize+1)*categoryPadding) / (columnSize * rowSize);
PointF clickPoint = null;
int clickPosition = 0;
int clickColumnPosition = 0;
boolean isClickRect1 = (pointF != null && rect.contains((int) pointF.x, (int) pointF.y));
boolean isClickRect = false;
for (int i = 0; i < columnSize; i++) {
for (int j = 0; j < rowSize; j++) {
C columnData = columnDataList.get(i);
if (!columnData.isDraw()) {
continue;
}
double value = columnData.getChartYDataList().get(j);
int left = (int) (((j * columnSize + i) * width)
+ j * categoryPadding + zoomRect.left);
int right = (int) (left + width) - seriesPadding;
int top = (int) getStartY(zoomRect, value, columnData.getDirection());
int bottom = zoomRect.bottom;
paint.setColor(columnData.getColor());
if (isClickRect1 && isClickRect(left, right, top, bottom)) {
paint.setColor(ColorUtils.getDarkerColor(columnData.getColor()));
isClickRect = true;
clickPoint = new PointF((left + right) / 2, top);
clickPosition = j;
clickColumnPosition = i;
if (onClickColumnListener != null) {
onClickColumnListener.onClickColumn(columnData, j);
}
}
Rect barRect = new Rect(left, top, right, bottom);
drawBar(canvas, barRect, value,i,j, paint);
drawTip(canvas,left+barRect.width()/2,top,columnData,j);
}
}
drawLevelLine(canvas, zoomRect, paint);
if (isClickRect && containsRect(clickPoint.x, clickPoint.y)) {
drawCross(canvas, clickPoint.x, clickPoint.y, zoomRect, paint);
super.matrixRectEnd(canvas, rect);
drawMark(canvas,clickPoint.x, clickPoint.y,rect, clickPosition, clickColumnPosition);
}
}
@Override
protected void matrixRectEnd(Canvas canvas, Rect rect) {
}
protected void drawBar(Canvas canvas, Rect rect,double value, int position,int line,Paint paint) {
canvas.drawRect(rect, paint);
drawPointText(canvas, value, (rect.right + rect.left) / 2, rect.top, position,line,paint);
}
private void drawCross(Canvas canvas, float x, float y, Rect rect, Paint paint) {
if (isOpenCross() && getCross() != null) {
PointF pointF = new PointF(x, y);
getCross().drawCross(canvas, pointF, rect, paint);
}
}
protected boolean isClickRect(float left, float right, float top, float bottom) {
return pointF != null && pointF.x >= left && pointF.x <= right && pointF.y >= top && pointF.y <= bottom;
}
@Override
public double[] setMaxMinValue(double maxValue, double minValue) {
double dis = Math.abs(maxValue - minValue);
maxValue = maxValue + dis * 0.2;
if (minValue > 0) {
minValue = 0;
} else {
minValue = minValue - dis * 0.2;
}
return new double[]{maxValue, minValue};
}
public int getSeriesPadding() {
return seriesPadding;
}
public void setSeriesPadding(int seriesPadding) {
this.seriesPadding = seriesPadding;
}
public int getCategoryPadding() {
return categoryPadding;
}
public void setCategoryPadding(int categoryPadding) {
this.categoryPadding = categoryPadding;
}
}
package com.daivd.chart.provider.barLine;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.provider.component.cross.ICross;
import com.daivd.chart.provider.component.grid.IGrid;
import com.daivd.chart.provider.component.level.ILevel;
import com.daivd.chart.provider.component.level.LevelLine;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.exception.ChartException;
import com.daivd.chart.provider.BaseProvider;
import com.daivd.chart.provider.component.path.IPath;
import com.daivd.chart.provider.component.tip.ITip;
import java.util.ArrayList;
import java.util.List;
/**线和柱状内容绘制
* Created by huang on 2017/9/26.
*/
public abstract class BaseBarLineProvider<C extends BarData> extends BaseProvider<C> {
private ICross cross;
private boolean isOpenCross;
protected ITip<C,?> tip;
private List<ILevel> levelLine = new ArrayList<>();
private float chartPercent = 1;
private boolean isFromBottom;
@Override
public boolean calculationChild( ChartData<C> chartData) {
this.chartData = chartData;
ScaleData scaleData =this.chartData.getScaleData();
List<C> columnDataList = chartData.getColumnDataList();
if(columnDataList == null || columnDataList.size() == 0){
return false;
}
scaleData.rowSize = chartData.getCharXDataList().size();
int columnSize = columnDataList.size();
for(int i = 0 ; i <columnSize; i++){
BarData columnData = columnDataList.get(i);
if(!columnData.isDraw()){
continue;
}
List<Double> chartYDataList = columnData.getChartYDataList();
if(chartYDataList == null || chartYDataList.size() == 0){
throw new ChartException("Please set up Column data");
}
// if(chartYDataList.size() != scaleData.rowSize){
// throw new ChartException("Column rows data inconsistency");
// }
double[] scale = getColumnScale(chartYDataList);
scale = setMaxMinValue(scale[0],scale[1]);
if(columnData.getDirection() == IAxis.AxisDirection.LEFT){
if(!scaleData.isLeftHasValue){
scaleData.maxLeftValue = scale[0];
scaleData.minLeftValue = scale[1];
scaleData.isLeftHasValue = true;
}else{
scaleData.maxLeftValue = Math.max( scaleData.maxLeftValue,scale[0]);
scaleData.minLeftValue = Math.min( scaleData.minLeftValue,scale[1]);
}
}else{
if(!scaleData.isRightHasValue){
scaleData.maxRightValue = scale[0];
scaleData.minRightValue= scale[1];
scaleData.isRightHasValue = true;
}else{
scaleData.maxRightValue = Math.max(scaleData.maxRightValue,scale[0]);
scaleData.minRightValue = Math.min(scaleData.minRightValue,scale[1]);
}
}
}
return chartData.getScaleData().rowSize != 0;
}
private double[] getColumnScale(List<Double> values) {
double maxValue = 0;
double minValue =0;
int size = values.size();
for(int j= 0;j < size;j++) {
double d = values.get(j) ;
if(j == 0){
maxValue = d;
minValue = d;
}
if (maxValue < d){
maxValue = d;
}else if(minValue >d){
minValue = d;
}
}
return new double[] {maxValue,minValue};
}
protected float getStartY(Rect zoomRect, double value, int direction){
ScaleData scaleData = chartData.getScaleData();
double minValue = scaleData.getMinScaleValue(direction);
double totalScaleLength = scaleData.getTotalScaleLength(direction);
float length = (float) ((value - minValue) * zoomRect.height()*chartPercent / totalScaleLength);
return zoomRect.bottom-(isFromBottom?0:(1-chartPercent)/2*zoomRect.height()) - length;
}
/**
* 绘制水平线
*/
void drawLevelLine(Canvas canvas, Rect zoomRect, Paint paint){
if(levelLine.size() > 0) {
for(ILevel level:levelLine){
float levelY = getStartY(zoomRect,level.getValue(),level.getAxisDirection());
if(containsRect(getProviderRect().centerX(),levelY)) {
level.drawLevel(canvas, getProviderRect(), levelY, paint);
}
}
}
}
/**
*绘制提示
*/
void drawTip(Canvas canvas,float x, float y,C c,int position){
if(tip != null){
tip.drawTip(canvas,x,y,getProviderRect(),c,position);
}
}
void drawMark(Canvas canvas,float x, float y,Rect rect, int position, int columnPosition) {
if (markView != null && isOpenMark()) {
markView.drawMark(canvas,x, y, rect,chartData.getCharXDataList().get(position),
chartData.getColumnDataList().get(columnPosition), position);
}
}
public abstract double[] setMaxMinValue(double maxMinValue, double minValue);
public void addLevelLine(ILevel levelLine) {
this.levelLine.add(levelLine);
}
public boolean isOpenCross() {
return isOpenCross;
}
public void setOpenCross(boolean openCross) {
isOpenCross = openCross;
}
public ICross getCross() {
return cross;
}
public void setCross(ICross cross) {
this.cross = cross;
}
public List<ILevel> getLevelLine() {
return levelLine;
}
public ITip<C,?> getTip() {
return tip;
}
public void setTip(ITip<C,?> tip) {
this.tip = tip;
}
public float getChartPercent() {
return chartPercent;
}
public boolean isFromBottom() {
return isFromBottom;
}
public void setFromBottom(boolean fromBottom) {
isFromBottom = fromBottom;
}
public void setChartPercent(float chartPercent) {
this.chartPercent = chartPercent;
}
}
package com.daivd.chart.provider.barLine;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.data.LineData;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.provider.component.grid.IGrid;
import com.daivd.chart.provider.component.line.BrokenLineModel;
import com.daivd.chart.provider.component.line.ILineModel;
import com.daivd.chart.provider.component.path.IPath;
import com.daivd.chart.provider.component.path.LinePath;
import com.daivd.chart.provider.component.point.IPoint;
import com.daivd.chart.utils.ColorUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 线内容绘制
* Created by huang on 2017/9/26.
*/
public class LineProvider extends BaseBarLineProvider<LineData> {
private LineStyle lineStyle = new LineStyle();
private IPoint point;
private int rowSize;
private boolean isArea; //是否打开面积图
private boolean isDrawLine = true;
private int filterPointTextCount = 30; //最多显示30个点文字
private ILineModel lineModel = new BrokenLineModel();
private IPath path;
private int perWidth;
private IGrid grid;
private boolean isStartZero = true;
private int areaAlpha = 125;
@Override
public void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
List<LineData> columnDataList = chartData.getColumnDataList();
int columnSize = columnDataList.size();
rowSize = chartData.getCharXDataList().size();
int filter = rowSize / filterPointTextCount;
filter = filter < 1 ? 1 : filter;
if (grid != null) {
grid.drawClickBg(canvas, pointF, zoomRect, perWidth, paint);
}
for (int i = 0; i < columnSize; i++) {
LineData lineData = columnDataList.get(i);
paint.setColor(lineData.getColor());
if (!lineData.isDraw()) {
continue;
}
List<Float> pointX = new ArrayList<>();
List<Float> pointY = new ArrayList<>();
List<Double> chartYDataList = lineData.getChartYDataList();
for (int j = 0; j < chartYDataList.size(); j++) {
double value = chartYDataList.get(j);
float x = getStartX(zoomRect, j);
float y = getStartY(zoomRect, value, lineData.getDirection());
if (grid != null && i == 0) {
grid.drawGrid(canvas, x, zoomRect, perWidth, paint);
grid.drawColumnContent(canvas, j, zoomRect, rect, perWidth, paint);
}
pointX.add(x);
pointY.add(y);
if (j % filter == 0) {
drawPointText(canvas, value, x, y, j, i, paint);
}
}
canvas.save();
canvas.clipRect(rect);
drawLine(canvas, rect, zoomRect, paint, lineData, pointX, pointY);
drawTip(canvas, pointX, pointY, lineData);
canvas.restore();
drawPoint(canvas, pointX, pointY, lineData, paint);
}
drawLevelLine(canvas, zoomRect, paint);
drawClickCross(canvas, rect, zoomRect, paint);
}
private void drawLine(Canvas canvas, Rect rect, Rect zoomRect, Paint paint, LineData lineData, List<Float> pointX, List<Float> pointY) {
LineStyle style = lineData.getLineStyle();
style = style == null ? lineStyle : style;
style.fillPaint(paint);
paint.setColor(lineData.getColor());
if (isDrawLine) {
ILineModel model = lineData.getLineModel();
model = model == null ? lineModel : model;
Path path = model.getLinePath(pointX, pointY);
if (isArea) {
paint.setStyle(Paint.Style.FILL);
path.lineTo(rect.right, rect.bottom);
path.lineTo(rect.left, rect.bottom);
path.close();
int alphaColor = ColorUtils.changeAlpha(paint.getColor(), areaAlpha);
paint.setColor(alphaColor);
}
getPath().drawPath(canvas, zoomRect, path, perWidth, paint, getProgress());
}
}
@Override
protected void matrixRectEnd(Canvas canvas, Rect rect) {
}
@Override
protected void matrixRectStart(Canvas canvas, Rect rect) {
}
private float getStartX(Rect zoomRect, int position) {
if (isStartZero) {
perWidth = (zoomRect.width()) / (rowSize - 1);
return (float) (position * perWidth + zoomRect.left);
} else {
perWidth = (zoomRect.width()) / rowSize;
return (float) (position * perWidth + perWidth / 2 + zoomRect.left);
}
}
private void drawClickCross(Canvas canvas, Rect rect, Rect zoomRect, Paint paint) {
if (pointF != null && (isOpenCross() || isOpenMark())) {
int minPositionX = 0, minPositionY = 0;
float centerX = 0, centerY = 0;
LineData clickLineData = null;
float minDisX = zoomRect.width();
for (int i = 0; i < rowSize; i++) {
float startX = getStartX(zoomRect, i);
float disX = Math.abs(pointF.x - startX);
if (disX < minDisX) {
minPositionX = i;
minDisX = disX;
centerX = startX;
} else {
break;
}
}
List<LineData> lineDates = chartData.getColumnDataList();
float minDisY = zoomRect.height();
boolean isHasLine = false;
for (int j = 0; j < lineDates.size(); j++) {
LineData lineData = lineDates.get(j);
if (!lineData.isDraw()) {
continue;
}
isHasLine = true;
double value;
if (minPositionX < lineData.getChartYDataList().size()) {
value = lineData.getChartYDataList().get(minPositionX);
} else{
break;
}
float startY = getStartY(zoomRect, value, lineData.getDirection());
float disY = Math.abs(pointF.y - startY);
if (disY < minDisY) {
centerY = startY;
minDisY = disY;
clickLineData = lineData;
minPositionY = j;
}
}
if (!isHasLine || !containsRect(centerX, centerY)) {
return;
}
if (onClickColumnListener != null) {
onClickColumnListener.onClickColumn(clickLineData, minPositionX);
}
if (isOpenCross() && getCross() != null) {
getCross().drawCross(canvas, new PointF(centerX, centerY), rect, paint);
}
drawMark(canvas, centerX, centerY, rect, minPositionX, minPositionY);
}
}
private void drawPoint(Canvas canvas, List<Float> pointX, List<Float> pointY, LineData lineData, Paint paint) {
IPoint linePoint = lineData.getPoint();
linePoint = linePoint == null ? point : linePoint;
if (linePoint != null) {
for (int i = 0; i < pointY.size(); i++) {
float x = pointX.get(i);
float y = pointY.get(i);
if (containsRect(x, y)) {
linePoint.drawPoint(canvas, x, y, i, false, paint);
}
}
}
}
private void drawTip(Canvas canvas, List<Float> pointX, List<Float> pointY, LineData lineData) {
if (tip != null) {
for (int i = 0; i < pointY.size(); i++) {
float x = pointX.get(i);
float y = pointY.get(i);
drawTip(canvas, x, y, lineData, i);
}
}
}
public LineStyle getLineStyle() {
return lineStyle;
}
@Override
public double[] setMaxMinValue(double maxValue, double minValue) {
double dis = Math.abs(maxValue - minValue);
maxValue = maxValue + dis * 0.3;
if (minValue > 0) {
minValue = 0;
} else {
minValue = minValue - dis * 0.3;
}
return new double[]{maxValue, minValue};
}
public IPath getPath() {
if (path == null) {
path = new LinePath();
}
return path;
}
public IGrid getGrid() {
return grid;
}
public void setGrid(IGrid grid) {
this.grid = grid;
}
public void setPath(IPath path) {
this.path = path;
}
public void setArea(boolean isArea) {
this.isArea = isArea;
}
/**
* 设置线模式
*
* @param lineModel
*/
public void setLineModel(ILineModel lineModel) {
this.lineModel = lineModel;
}
/**
* 设置是否绘制线
*
* @param drawLine 绘制线
*/
public void setDrawLine(boolean drawLine) {
isDrawLine = drawLine;
}
/**
* 过滤图表文本数量
* 当数据过多时,,来过滤文字显示,保持图表美观
*
* @return 过滤图表文本数量
*/
public int getFilterPointTextCount() {
return filterPointTextCount;
}
/**
* 过滤图表文本数量
* 当数据过多时,可以使用该方法,来过滤文字显示,保持图表美观
*
* @return
*/
public void setFilterPointTextCount(int filterPointTextCount) {
this.filterPointTextCount = filterPointTextCount;
}
public void setPoint(IPoint point) {
this.point = point;
}
/**
* 设置是否从0开始
*
* @return 从0开始
*/
public boolean isStartZero() {
return isStartZero;
}
/**
* 设置是否从0开始
*
* @param startZero 从0开始
*/
public void setStartZero(boolean startZero) {
isStartZero = startZero;
}
/**
* 获取面积图透明度
*
* @return 透明度 0-255
*/
public int getAreaAlpha() {
return areaAlpha;
}
/**
* 设置面积图的透明度
*
* @param areaAlpha 透明度 0-255
*/
public void setAreaAlpha(int areaAlpha) {
this.areaAlpha = areaAlpha;
}
}
package com.daivd.chart.provider.component.cross;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.data.style.LineStyle;
/**
* Created by huang on 2017/10/19.
* 双方向
*/
public class DoubleDriCross implements ICross{
LineStyle crossStyle = new LineStyle();
@Override
public void drawCross(Canvas canvas, PointF pointF, Rect rect, Paint paint) {
crossStyle.fillPaint(paint);
canvas.drawLine(pointF.x, rect.top, pointF.x, rect.bottom, paint);
canvas.drawLine(rect.left, pointF.y, rect.right, pointF.y, paint);
}
public LineStyle getCrossStyle() {
return crossStyle;
}
public void setCrossStyle(LineStyle crossStyle) {
this.crossStyle = crossStyle;
}
}
package com.daivd.chart.provider.component.cross;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
/**
* Created by huang on 2017/10/19.
* 十字轴
*/
public interface ICross {
void drawCross(Canvas canvas, PointF pointF, Rect rect, Paint paint);
}
package com.daivd.chart.provider.component.cross;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.provider.component.point.IPoint;
import com.daivd.chart.provider.component.point.Point;
/**
* Created by huang on 2017/10/19.
* 竖轴方向
*/
public class VerticalCross implements ICross {
LineStyle crossStyle = new LineStyle();
IPoint point = new Point();
@Override
public void drawCross(Canvas canvas, PointF pointF, Rect rect, Paint paint) {
crossStyle.fillPaint(paint);
canvas.drawLine(pointF.x, rect.top, pointF.x, rect.bottom, paint);
if (point != null) {
point.drawPoint(canvas, pointF.x, pointF.y, 0, false, paint);
}
}
public IPoint getPoint() {
return point;
}
public void setPoint(IPoint point) {
this.point = point;
}
public LineStyle getCrossStyle() {
return crossStyle;
}
public void setCrossStyle(LineStyle crossStyle) {
this.crossStyle = crossStyle;
}
}
package com.daivd.chart.provider.component.grid;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
/**
* Created by huang on 2017/12/1.
*/
public interface IGrid {
/**
* 绘制网格
* @param canvas
* @param x
* @param rect
* @param perWidth
* @param paint
*/
void drawGrid(Canvas canvas, float x, Rect rect, int perWidth, Paint paint);
/**
* 绘制点击背景
* @param canvas
* @param pointF
* @param rect
* @param perWidth
* @param paint
*/
void drawClickBg(Canvas canvas, PointF pointF, Rect rect, int perWidth, Paint paint);
/**
* 绘制列内容
* @param canvas
* @param position
* @param rect
* @param perWidth
* @param paint
*/
void drawColumnContent(Canvas canvas, int position, Rect zoomRect, Rect rect, int perWidth, Paint paint);
}
package com.daivd.chart.provider.component.level;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
/**
* Created by huang on 2017/10/19.
*/
public interface ILevel {
int getAxisDirection();
void drawLevel(Canvas canvas, Rect rect, float y, Paint paint);
double getValue();
}
package com.daivd.chart.provider.component.level;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.data.style.LineStyle;
/**
* Created by huang on 2017/9/30.
* LevelLine
*/
public class LevelLine implements ILevel{
public static int left = 0;
public static int right = 1;
private LineStyle lineStyle = new LineStyle();
private double value;
private int textDirection = right;
private FontStyle textStyle = new FontStyle();
private int direction = IAxis.AxisDirection.LEFT;
public LevelLine(double value) {
this.value = value;
}
public LineStyle getLineStyle() {
return lineStyle;
}
public void setLineStyle(LineStyle lineStyle) {
this.lineStyle = lineStyle;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public int getTextDirection() {
return textDirection;
}
public void setTextDirection(int textDirection) {
this.textDirection = textDirection;
}
public FontStyle getTextStyle() {
return textStyle;
}
public int getAxisDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public void setTextStyle(FontStyle textStyle) {
this.textStyle = textStyle;
}
@Override
public void drawLevel(Canvas canvas, Rect rect, float y, Paint paint) {
getLineStyle().fillPaint(paint);
Path path = new Path();
path.moveTo(rect.left, y);
path.lineTo(rect.right, y);
canvas.drawPath(path, paint);
getTextStyle().fillPaint(paint);
float textHeight = paint.measureText("1", 0, 1);
float startX;
float startY = y - textHeight + getLineStyle().getWidth();
String levelLineValue = String.valueOf(getValue());
if (getTextDirection() == LevelLine.left) {
startX = rect.left;
} else {
startX = rect.right - textHeight * levelLineValue.length();
}
canvas.drawText(levelLineValue, startX, startY, paint);
}
}
package com.daivd.chart.provider.component.line;
import android.graphics.Path;
import java.util.List;
public class BrokenLineModel implements ILineModel {
@Override
public Path getLinePath(List<Float> pointX, List<Float> pointY) {
Path path = new Path();
for(int i = 0; i < pointY.size();i++){
float x = pointX.get(i);
float y = pointY.get(i);
if(i == 0){
path.moveTo(x,y);
}else{
path.lineTo(x,y);
}
}
return path;
}
}
package com.daivd.chart.provider.component.line;
import android.graphics.Path;
import java.util.LinkedList;
import java.util.List;
/**曲线内容绘制
* Created by huang on 2017/9/27.
*/
public class CurveLineModel implements ILineModel {
private final int STEP = 12;
@Override
public Path getLinePath(List<Float> pointX, List<Float> pointY) {
List<Cubic> calculate_x = calculate(pointX);
List<Cubic> calculate_y = calculate(pointY);
Path path = new Path();
if (null != calculate_x && null != calculate_y && calculate_y.size() >= calculate_x.size()) {
path.moveTo(calculate_x.get(0).eval(0), calculate_y.get(0).eval(0));
for (int i = 0; i < calculate_x.size(); i++) {
for (int j = 1; j <= STEP; j++) {
float u = j / (float) STEP;
path.lineTo(calculate_x.get(i).eval(u), calculate_y.get(i).eval(u));
}
}
}
return path;
}
/**
* 计算曲线.
* @param x
* @return
*/
private List<Cubic> calculate(List<Float> x) {
if (null != x && x.size() > 0) {
int n = x.size() - 1;
float[] gamma = new float[n + 1];
float[] delta = new float[n + 1];
float[] D = new float[n + 1];
int i;
gamma[0] = 1.0f / 2.0f;
for (i = 1; i < n; i++) {
gamma[i] = 1 / (4 - gamma[i - 1]);
}
gamma[n] = 1 / (2 - gamma[n - 1]);
delta[0] = 3 * (x.get(1) - x.get(0)) * gamma[0];
for (i = 1; i < n; i++) {
delta[i] = (3 * (x.get(i + 1) - x.get(i - 1)) - delta[i - 1]) * gamma[i];
}
delta[n] = (3 * (x.get(n) - x.get(n - 1)) - delta[n - 1]) * gamma[n];
D[n] = delta[n];
for (i = n - 1; i >= 0; i--) {
D[i] = delta[i] - gamma[i] * D[i + 1];
}
List<Cubic> cubicList = new LinkedList<>();
for (i = 0; i < n; i++) {
Cubic c = new Cubic(x.get(i), D[i], 3 * (x.get(i + 1) - x.get(i)) - 2 * D[i] - D[i + 1], 2 * (x.get(i) - x.get(i + 1)) + D[i] + D[i + 1]);
cubicList.add(c);
}
return cubicList;
}
return null;
}
private class Cubic {
float a, b, c, d; /* a + b*u + c*u^2 +d*u^3 */
Cubic(float a, float b, float c, float d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
/** evaluate cubic */
float eval(float u) {
return (((d * u) + c) * u + b) * u + a;
}
}
}
package com.daivd.chart.provider.component.line;
import android.graphics.Path;
import java.util.List;
/**
* Created by huang on 2017/10/15.
*/
public interface ILineModel {
Path getLinePath(List<Float> pointX, List<Float> pointY);
}
package com.daivd.chart.provider.component.mark;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.provider.component.tip.SingleLineBubbleTip;
import com.daivd.chart.data.BarData;
import com.daivd.chart.utils.DensityUtils;
import com.david.chart.R;
/**
* Created by huang on 2017/9/28.
*/
public class BubbleMarkView<C extends BarData> implements IMark<C> {
private SingleLineBubbleTip<String> bubbleTip;
private Paint paint;
public BubbleMarkView(Context context) {
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(DensityUtils.sp2px(context,13));
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
bubbleTip = new SingleLineBubbleTip<String>(context,R.mipmap.round_rect,R.mipmap.triangle,paint){
@Override
public boolean isShowTip(String s,int position) {
return true;
}
@Override
public String format(String s, int position) {
return s;
}
};
}
public Paint getPaint() {
return paint;
}
@Override
public void drawMark(Canvas canvas, float x, float y, Rect rect, String content, BarData data, int position) {
String text = content + data.getChartYDataList().get(position) + data.getUnit();
bubbleTip.drawTip(canvas, x, y, rect, text,position);
}
}
package com.daivd.chart.provider.component.mark;
import android.graphics.Canvas;
import android.graphics.Rect;
import com.daivd.chart.data.ColumnData;
/**
* Created by huang on 2017/9/28.
*/
public interface IMark<C extends ColumnData> {
/**
* 绘制Mark
*/
void drawMark(Canvas canvas,float x, float y,Rect rect, String content, C data, int position);
}
package com.daivd.chart.provider.component.path;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
/**
* Created by huang on 2017/11/30.
*/
public interface IPath {
void drawPath(Canvas canvas, Rect rect, Path path, int perWidth, Paint paint, float progress);
}
package com.daivd.chart.provider.component.path;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
/**
* Created by huang on 2017/11/30.
*/
public class LinePath implements IPath{
public void drawPath(Canvas canvas, Rect rect, Path path, int perWidth, Paint paint,float progress){
canvas.drawPath(path, paint);
}
}
package com.daivd.chart.provider.component.point;
/**
* Created by huang on 2017/12/13.
*/
public interface ILegendPoint extends IPoint{
float getWidth();
float getHeight();
}
package com.daivd.chart.provider.component.point;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by huang on 2017/10/20.
*/
public interface IPoint {
void drawPoint(Canvas canvas, float x, float y, int position, boolean isShowDefaultColor, Paint paint);
}
package com.daivd.chart.provider.component.point;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.daivd.chart.data.style.PointStyle;
/**
* Created by huang on 2017/10/20.
*/
public class LegendPoint implements ILegendPoint {
private PointStyle pointStyle = new PointStyle();
public void drawPoint(Canvas canvas, float x, float y, int position,boolean isShowDefaultColor, Paint paint){
float w = pointStyle.getWidth();
if(isShowDefaultColor){
pointStyle.fillPaint(paint);
}else {
int oldColor =paint.getColor();
pointStyle.fillPaint(paint);
paint.setColor(oldColor);
}
if (pointStyle.getShape() == PointStyle.CIRCLE) {
canvas.drawCircle(x, y, w/2, paint);
} else if (pointStyle.getShape() == PointStyle.SQUARE) {
canvas.drawRect(x - w/2 , y - w/2 , x + w/2, y + w/2 , paint);
} else if (pointStyle.getShape() == PointStyle.RECT) {
canvas.drawRect(x - w * 2 / 3, y - w/2 , x + w * 2 / 3, y + w/2, paint);
}
}
@Override
public float getWidth() {
if(pointStyle.getShape() == PointStyle.RECT){
return pointStyle.getWidth() * 4/ 3;
}
return pointStyle.getWidth();
}
@Override
public float getHeight() {
return pointStyle.getWidth();
}
public PointStyle getPointStyle() {
return pointStyle;
}
}
package com.daivd.chart.provider.component.point;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.daivd.chart.data.style.PointStyle;
/**
* Created by huang on 2017/10/20.
*/
public class Point implements IPoint {
private PointStyle pointStyle = new PointStyle();
public void drawPoint(Canvas canvas,float x, float y,int position,boolean isShowDefaultColor, Paint paint){
float w = pointStyle.getWidth();
if(isShowDefaultColor){
pointStyle.fillPaint(paint);
}else {
int oldColor =paint.getColor();
pointStyle.fillPaint(paint);
paint.setColor(oldColor);
}
if (pointStyle.getShape() == PointStyle.CIRCLE) {
canvas.drawCircle(x, y, w/2, paint);
} else if (pointStyle.getShape() == PointStyle.SQUARE) {
canvas.drawRect(x - w/2 , y - w/2 , x + w/2, y + w/2 , paint);
} else if (pointStyle.getShape() == PointStyle.RECT) {
canvas.drawRect(x - w * 2 / 3, y - w/2 , x + w * 2 / 3, y + w/2, paint);
}
}
public PointStyle getPointStyle() {
return pointStyle;
}
}
package com.daivd.chart.provider.component.text;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by huang on 2017/11/30.
*/
public interface IText {
void drawText(Canvas canvas, String value, float x, float y, int position, int line, Paint paint);
}
package com.daivd.chart.provider.component.tip;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import com.daivd.chart.utils.DensityUtils;
/**
* Created by huang on 2017/10/20.
* 气泡提示
*/
public abstract class BaseBubbleTip<C,S> implements ITip<C,S>{
public static final int INVALID = -1;
private Rect tipRect;
private Paint paint;
private int verticalPadding;
private int horizontalPadding;
private Bitmap triangleBitmap;
private NinePatch ninePatch;
private boolean isReversal = false;
protected int deviation;
private float alpha;
private int colorFilter = INVALID;
public BaseBubbleTip(Context context, int backgroundDrawableID, int triangleDrawableID, Paint paint){
tipRect = new Rect();
this.paint = paint;
triangleBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(context.getResources(), triangleDrawableID));
if(ninePatch == null) {
Bitmap bmp_9 = BitmapFactory.decodeResource(context.getResources(),
backgroundDrawableID);
ninePatch = new NinePatch(bmp_9, bmp_9.getNinePatchChunk(), null);
}
verticalPadding = DensityUtils.dp2px(context,5);
horizontalPadding = verticalPadding;
deviation = DensityUtils.dp2px(context,5);
}
public void drawTip(Canvas canvas, float x, float y, Rect rect,C c,int position) {
if(isShowTip(c,position)) {
S content = format(c,position);
int triangleWidth = triangleBitmap.getWidth();
int triangleHeight = triangleBitmap.getHeight();
int textWidth = getTextWidth(content);
int textHeight = getTextHeight(content);
int w = textWidth + horizontalPadding * 2;
int h = textHeight + verticalPadding * 2;
tipRect.left = (int) x - w / 2;
tipRect.right = (int) x + w / 2;
tipRect.bottom = (int) y - triangleHeight + triangleWidth / 8;
tipRect.top = tipRect.bottom - h;
int tranX = 0;
if(x > rect.left && x < rect.right) {
if (tipRect.left < rect.left) {
tranX = rect.left - tipRect.left - triangleWidth / 2;
} else if (tipRect.right > rect.right) {
tranX = rect.right - tipRect.right + triangleWidth / 2;
}
if (tipRect.top < rect.top) {
showBottom(canvas, x, y, content, textWidth, textHeight, tranX);
} else if (tipRect.bottom > rect.bottom) {
showTop(canvas, x, y, content, textWidth, textHeight, tranX);
} else if (isReversal) {
showBottom(canvas, x, y, content, textWidth, textHeight, tranX);
} else {
showTop(canvas, x, y, content, textWidth, textHeight, tranX);
}
}
}
}
public abstract int getTextHeight(S content);
public abstract int getTextWidth(S content);
public abstract void drawText(Canvas canvas,Rect tipRect,S content,int textWidth,int textHeight,Paint paint);
private void showTop(Canvas canvas, float x, float y, S content, int textWidth, int textHeight,int tranX) {
canvas.save();
int triangleWidth = triangleBitmap.getWidth();
int triangleHeight = triangleBitmap.getHeight();
startColorFilter();
// paint.setShadowLayer(40, 10, 50, Color.BLACK);
canvas.drawBitmap(triangleBitmap,x-triangleWidth/2,
y-triangleHeight,paint);
// paint.clearShadowLayer();
canvas.translate(tranX,0);
ninePatch.draw(canvas, tipRect);
clearColorFilter();
drawText(canvas, tipRect,content,textWidth,textHeight,paint);
canvas.restore();
}
private void showBottom(Canvas canvas, float x, float y, S content, int textWidth,int textHeight,int tranX) {
canvas.save();
int triangleWidth = triangleBitmap.getWidth();
int triangleHeight = triangleBitmap.getHeight();
canvas.rotate(180,x,y);
startColorFilter();
canvas.drawBitmap(triangleBitmap,x-triangleWidth/2,
y-triangleHeight,paint);
canvas.translate(-tranX,0);
ninePatch.draw(canvas, tipRect);
clearColorFilter();
paint.setColorFilter(null);
canvas.rotate(180, tipRect.centerX(), tipRect.centerY());
drawText(canvas, tipRect,content,textWidth,textHeight,paint);
canvas.restore();
}
private void startColorFilter() {
if (colorFilter != INVALID){
paint.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.SRC_IN));
ninePatch.setPaint(paint);
paint.setAlpha((int) (alpha*255));
}
}
private void clearColorFilter(){
if(colorFilter != INVALID) {
paint.setColorFilter(null);
paint.setAlpha(255);
}
}
public Paint getPaint() {
return paint;
}
public void setPaint(Paint paint) {
this.paint = paint;
}
public boolean isReversal() {
return isReversal;
}
public void setReversal(boolean reversal) {
isReversal = reversal;
}
public void setVerticalPadding(int verticalPadding) {
this.verticalPadding = verticalPadding;
}
public int getVerticalPadding() {
return verticalPadding;
}
public int getHorizontalPadding() {
return horizontalPadding;
}
public void setHorizontalPadding(int horizontalPadding) {
this.horizontalPadding = horizontalPadding;
}
public int getColorFilter() {
return colorFilter;
}
public void setColorFilter(int colorFilter) {
this.colorFilter = colorFilter;
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
}
}
package com.daivd.chart.provider.component.tip;
import android.graphics.Canvas;
import android.graphics.Rect;
/**
* Created by huang on 2017/10/20.
*/
public interface ITip<C,S> {
void drawTip(Canvas canvas, float x, float y, Rect rect, C content,int position);
boolean isShowTip(C c,int position);
S format(C c,int position);
}
package com.daivd.chart.provider.component.tip;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import com.daivd.chart.utils.DensityUtils;
/**
* Created by huang on 2017/10/20.
* 气泡提示
*/
public abstract class MultiLineBubbleTip<C> extends BaseBubbleTip<C,String[]>{
private int lineSpacing;
public MultiLineBubbleTip(Context context, int backgroundDrawableID, int triangleDrawableID, Paint paint) {
super(context, backgroundDrawableID, triangleDrawableID, paint);
lineSpacing = DensityUtils.dp2px(context,3);
}
@Override
public int getTextHeight(String[] content) {
Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
int textHeight= (int) (fontMetrics.bottom - fontMetrics.top);
return (textHeight +lineSpacing)*content.length - lineSpacing;
}
@Override
public int getTextWidth(String[] content) {
int maxLength = 0;
for(int i = 0;i < content.length;i++) {
int length = (int) getPaint().measureText(content[i]);
if (length > maxLength) {
maxLength = length;
}
}
return maxLength;
}
@Override
public void drawText(Canvas canvas, Rect tipRect, String[] content, int textWidth, int textHeight, Paint paint) {
int lineHeight =textHeight/content.length;
for(int i = 0;i < content.length;i++) {
String c = content[i];
int bottom = tipRect.top+getVerticalPadding()+lineHeight+ (lineHeight)*i - lineSpacing-deviation/2;
int left = tipRect.centerX()-textWidth/2;
canvas.drawText(c,left,bottom,paint);
}
}
}
package com.daivd.chart.provider.component.tip;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
/**
* Created by huang on 2017/10/20.
* 单行气泡提示
*/
public abstract class SingleLineBubbleTip<C> extends BaseBubbleTip<C,String> {
public SingleLineBubbleTip(Context context, int backgroundDrawableID, int triangleDrawableID, Paint paint){
super(context,backgroundDrawableID,triangleDrawableID,paint);
}
@Override
public int getTextHeight(String content) {
Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
return (int) (fontMetrics.bottom - fontMetrics.top);
}
@Override
public int getTextWidth(String content) {
return (int) getPaint().measureText(content);
}
@Override
public void drawText(Canvas canvas, Rect tipRect, String content, int textWidth,int textHeight, Paint paint) {
canvas.drawText(content,tipRect.centerX()-textWidth/2,tipRect.centerY()+textHeight/2-deviation/2,paint);
}
}
package com.daivd.chart.provider.pie;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.PieData;
/**
* Created by huang on 2017/10/9.
* 3D饼图
* 试验中,未完成
*/
public class Pie3DProvider extends PieProvider {
private int borderWidth = 20;
//提供摄像头
private Camera camera = new Camera();
public Pie3DProvider(Context context){
//拉远摄像头Z轴
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float newZ = -displayMetrics.density * 6;
camera.setLocation(0,0,newZ);
}
@Override
public boolean calculationChild(ChartData<PieData> chartData) {
return true;
}
/**
* 变形开始
*
*/
@Override
protected void matrixRectStart(Canvas canvas, Rect rect) {
canvas.save();
camera.save();
canvas.translate(rect.centerX(),rect.centerY());
camera.rotateX(60);
camera.applyToCanvas(canvas);
canvas.translate(-rect.centerX(),-rect.centerY());
canvas.clipRect(rect);
if(rotateHelper != null && rotateHelper.isRotate()){
canvas.rotate((float) rotateHelper.getStartAngle(),rect.centerX(),rect.centerY());
}
}
@Override
protected void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
super.drawProvider(canvas, zoomRect, rect, paint);
PointF centerPoint = getCenterPoint();
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.parseColor("#80FFFFFF"));
int radius = getCenterRadius();
canvas.drawCircle(centerPoint.x,centerPoint.y,radius*getCenterCirclePercent()+borderWidth/2,paint);
canvas.drawCircle(centerPoint.x,centerPoint.y,radius-borderWidth/2,paint);
}
/**
* 变形结束
*
*/
@Override
protected void matrixRectEnd(Canvas canvas, Rect rect) {
camera.restore();
super.matrixRectEnd(canvas, rect);
}
}
package com.daivd.chart.provider.pie;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.format.IFormat;
import com.daivd.chart.data.PieData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.BaseProvider;
import com.daivd.chart.utils.ColorUtils;
import java.util.List;
/**
* Created by huang on 2017/10/9.
*/
public class PieProvider extends BaseProvider<PieData> {
private RectF oval;
private int totalAngle = 360;
private PointF centerPoint;
private int centerRadius;
private double clickAngle = -1;
private final float startAngle = -90;
protected RotateHelper rotateHelper;
private FontStyle textStyle = new FontStyle();
private float centerCirclePercent = 0.3f;
private boolean isClick;
private IFormat<Double> valueFormat;
private PorterDuffXfermode porterDuffXfermode;
@Override
public boolean calculationChild(ChartData<PieData> chartData) {
return true;
}
/**
*变形开始
*/
@Override
protected void matrixRectStart(Canvas canvas, Rect rect) {
super.matrixRectStart(canvas, rect);
if(rotateHelper != null && rotateHelper.isRotate()){
canvas.rotate((float) rotateHelper.getStartAngle(),rect.centerX(),rect.centerY());
}
}
/**
* 绘制内容
*/
@Override
protected void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
int layerId = canvas.saveLayer(rect.left,rect.top,rect.right,rect.bottom, null, Canvas.ALL_SAVE_FLAG);
float startAngle = this.startAngle;
float totalAngle = getAnimValue(this.totalAngle);
paint.setStyle(Paint.Style.FILL);
int h = zoomRect.height();
int w = zoomRect.width();
int maxRadius = Math.min(w/2, h/2);
int x = maxRadius / 10;
centerRadius = maxRadius - x;
if(oval == null) {
oval = new RectF(zoomRect.centerX() - centerRadius, zoomRect.centerY() - centerRadius,
zoomRect.centerX() + centerRadius, zoomRect.centerY() + centerRadius);
centerPoint = new PointF(zoomRect.centerX(), zoomRect.centerY());
}
if(rotateHelper != null){
rotateHelper.setRadius(centerRadius);
rotateHelper.setOriginRect(rect);
}
List<PieData> pieDataList = chartData.getColumnDataList();
float totalScores = 0f;
for (PieData pieData: pieDataList) {
totalScores += pieData.getChartYDataList();
}
for (int i = 0; i < pieDataList.size(); i++) {
PieData pieData = pieDataList.get(i);
double value = pieData.getChartYDataList();
float sweepAngle = (float) (totalAngle * value / totalScores);
if(pieData.isDraw()) {
paint.setColor(pieData.getColor());
if (clickAngle != -1 && clickAngle > startAngle && clickAngle < startAngle + sweepAngle) {
paint.setColor(ColorUtils.getDarkerColor(pieData.getColor()));
if(isClick && onClickColumnListener != null){
onClickColumnListener.onClickColumn(pieData,0);
isClick = false;
}
}
canvas.drawArc(oval, startAngle, sweepAngle, true, paint);
if(isShowText()) {
canvas.save();
canvas.rotate(startAngle + sweepAngle / 2 - this.startAngle, zoomRect.centerX(), zoomRect.centerY());
textStyle.fillPaint(paint);
int textHeight = (int) paint.measureText("1", 0, 1);
String val =valueFormat != null ?valueFormat.format(value):String.valueOf(value);
canvas.drawText(val, zoomRect.centerX() - val.length() * textHeight / 2, zoomRect.centerY() - maxRadius / 2, paint);
canvas.restore();
}
}
startAngle += sweepAngle;
}
//裁切中间圆
if(porterDuffXfermode == null){
porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT);
}
paint.setXfermode(porterDuffXfermode);
if(centerCirclePercent >0) {
paint.setColor(Color.TRANSPARENT);
canvas.drawCircle(rect.centerX(),rect.centerY(),centerRadius *centerCirclePercent,paint);
}
canvas.restoreToCount(layerId);
paint.setXfermode(null);
}
@Override
public double[] setMaxMinValue(double maxMinValue, double minValue) {
return new double[0];
}
@Override
public void clickPoint(PointF point) {
super.clickPoint(point);
if(centerPoint != null){
int x = (int) (point.x - centerPoint.x);
int y = (int) (point.y - centerPoint.y);
int z = (int) Math.sqrt(Math.pow(Math.abs(x), 2) + Math.pow(Math.abs(y), 2));
if (/*z >= centerRadius - circleBorder / 2 &&*/ z <= centerRadius + 20) {
double angle = Math.abs(Math.toDegrees(Math.atan((point.y - centerPoint.y) / (point.x - centerPoint.x))));
if (x >= 0 && y < 0) {
angle = 90 - angle;
} else if (x >= 0 && y >= 0) {
angle = 90 + angle;
} else if (x < 0 && y >= 0) {
angle = 270 - angle;
} else {
angle = 270 + angle;
}
angle = (angle -rotateHelper.getStartAngle())%360;
angle = angle <0 ? 360+angle:angle;
clickAngle = angle + startAngle;
isClick = true;
return;
}
clickAngle = -1;
}
}
public PointF getCenterPoint() {
return centerPoint;
}
public void setCenterPoint(PointF centerPoint) {
this.centerPoint = centerPoint;
}
public int getCenterRadius() {
return centerRadius;
}
public void setCenterRadius(int centerRadius) {
this.centerRadius = centerRadius;
}
public void setValueFormat(IFormat<Double> valueFormat) {
this.valueFormat = valueFormat;
}
public void setCenterCirclepercent(float centerCirclePercent) {
this.centerCirclePercent = centerCirclePercent;
}
public float getCenterCirclePercent() {
return centerCirclePercent;
}
public void setCenterCirclePercent(float centerCirclePercent) {
this.centerCirclePercent = centerCirclePercent;
}
public void setRotateHelper(RotateHelper rotateHelper) {
this.rotateHelper = rotateHelper;
}
}
package com.daivd.chart.provider.radar;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.format.IFormat;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.RadarData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.exception.ChartException;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.BaseProvider;
import java.util.List;
/**
* Created by huang on 2017/10/9.
*雷达图内容绘制
*/
public class RadarProvider extends BaseProvider<RadarData> {
private int centerRadius;
private RotateHelper rotateHelper;
private FontStyle scaleStyle = new FontStyle();
private LineStyle lineStyle = new LineStyle();
protected LineStyle gridStyle = new LineStyle(); //网格样式
private int textHeight;
private boolean isShowScale;
private IFormat<Double> scaleFormat;
@Override
protected void matrixRectStart(Canvas canvas, Rect rect) {
super.matrixRectStart(canvas, rect);
if(rotateHelper != null && rotateHelper.isRotate()){
canvas.rotate((float) rotateHelper.getStartAngle(),rect.centerX(),rect.centerY());
}
}
@Override
protected void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
int w = zoomRect.width();
int h = zoomRect.height();
int maxRadius = Math.min(w/2, h/2);
textHeight = (int) (paint.measureText("1",0,1));
scaleStyle.fillPaint(paint);
String oneXData = chartData.getCharXDataList().get(0);
int x = maxRadius / 10 + textHeight * oneXData.length();
centerRadius = maxRadius - x;
if(rotateHelper != null){
rotateHelper.setOriginRect(rect);
rotateHelper.setRadius(centerRadius);
}
drawRadarBorder(canvas,zoomRect,paint);
drawRadarLines(canvas,zoomRect,paint);
drawLinePath(canvas,zoomRect,paint);
drawQuadrantText(canvas,zoomRect,paint);
}
private void drawLinePath(Canvas canvas,Rect zoomRect,Paint paint){
List<String> charXDataList = chartData.getCharXDataList();
int count = charXDataList.size();
ScaleData scaleData = chartData.getScaleData();
List<RadarData> columnDataList = chartData.getColumnDataList();
double scaleLength = scaleData.getTotalScaleLength(IAxis.AxisDirection.LEFT);
float angle = (float) (Math.PI*2/count);
Path path = new Path();
lineStyle.fillPaint(paint);
for(int i = 0;i <columnDataList.size();i++){
BarData columnData = columnDataList.get(i);
if(columnData.isDraw()) {
paint.setColor(columnData.getColor());
path.reset();
for (int j = 0; j < columnData.getChartYDataList().size(); j++) {
double value = columnData.getChartYDataList().get(j);
float curR = getAnimValue((float) ( value * centerRadius / scaleLength));
if (j == 0) {
path.moveTo(zoomRect.centerX() + curR, zoomRect.centerY());
} else {
//根据半径,计算出蜘蛛丝上每个点的坐标
float x = (float) (zoomRect.centerX() + curR * Math.cos(angle * j));
float y = (float) (zoomRect.centerY() + curR * Math.sin(angle * j));
path.lineTo(x, y);
}
}
path.close();
canvas.drawPath(path, paint);
}
}
}
private void drawRadarBorder(Canvas canvas,Rect zoomRect,Paint paint){
List<String> charXDataList = chartData.getCharXDataList();
int count = charXDataList.size();
float angle = (float) (Math.PI*2/count);
ScaleData scaleData = chartData.getScaleData();
List<Double> scaleList= scaleData.getScaleList(IAxis.AxisDirection.LEFT);
double maxScale = scaleData.getMaxScaleValue(IAxis.AxisDirection.LEFT);
Path path = new Path();
for(int i = 0;i < scaleList.size();i++){
path.reset();
double value = scaleList.get(i);
float curR = (float)(value*centerRadius/maxScale);
for(int j = 0; j <count;j++){
float y;
float x;
if(j==0){
x = zoomRect.centerX()+curR;
y = zoomRect.centerY();
path.moveTo(x,y);
}else{
//根据半径,计算出蜘蛛丝上每个点的坐标
x= (float) (zoomRect.centerX()+curR*Math.cos(angle*j));
y = (float) (zoomRect.centerY()+curR*Math.sin(angle*j));
path.lineTo(x,y);
}
}
gridStyle.fillPaint(paint);
path.close();
canvas.drawPath(path,paint);
scaleStyle.fillPaint(paint);
int textHeight = (int) paint.measureText("1",0,1);
if(isShowScale) {
String valueStr = getFormatValue(value);
canvas.drawText(valueStr, zoomRect.centerX() - textHeight*valueStr.length()/2 , (float)( zoomRect.centerY() - curR*Math.sin(Math.PI/3)), paint);
}
}
}
private String getFormatValue(double value){
return scaleFormat !=null ? scaleFormat.format(value):String.valueOf(value);
}
/**
* 绘制象限文字
* @param canvas
*/
private void drawQuadrantText(Canvas canvas,Rect zoomRect,Paint paint){
scaleStyle.fillPaint(paint);
List<String> charXDataList = chartData.getCharXDataList();
int count = charXDataList.size();
float angle = (float) (Math.PI*2/count);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float fontHeight = fontMetrics.descent - fontMetrics.ascent;
for(int i=0;i<count;i++){
String xData = charXDataList.get(i);
float x = (float) (zoomRect.centerX()+(centerRadius+fontHeight/2)*Math.cos(angle*i));
float y = (float) (zoomRect.centerY()+(centerRadius+fontHeight/2)*Math.sin(angle*i));
if(angle*i>=0&&angle*i<=Math.PI/2){//第4象限
canvas.drawText(xData, x,y,paint);
}else if(angle*i>=3*Math.PI/2&&angle*i<=Math.PI*2){//第3象限
canvas.drawText(xData, x,y,paint);
}else if(angle*i>Math.PI/2&&angle*i<=Math.PI){//第2象限
float dis = paint.measureText(xData);//文本长度
canvas.drawText(xData, x-dis,y,paint);
}else if(angle*i>=Math.PI&&angle*i<3*Math.PI/2){//第1象限
float dis = paint.measureText(xData);//文本长度
canvas.drawText(xData, x-dis,y,paint);
}
}
}
/**
* 绘制直线
*/
private void drawRadarLines(Canvas canvas,Rect zoomRect,Paint paint){
gridStyle.fillPaint(paint);
Path path = new Path();
int count = chartData.getCharXDataList().size();
float angle = (float) (Math.PI*2/count);
for(int i=0;i<count;i++){
path.reset();
path.moveTo(zoomRect.centerX(), zoomRect.centerY());
float x = (float) (zoomRect.centerX()+centerRadius*Math.cos(angle*i));
float y = (float) (zoomRect.centerY()+centerRadius*Math.sin(angle*i));
path.lineTo(x, y);
canvas.drawPath(path, paint);
}
}
/* @Override
public void clickPoint(PointF point) {
super.clickPoint(point);
if(centerPoint != null){
int x = (int) (point.x - centerPoint.x);
int y = (int) (point.y - centerPoint.y);
int z = (int) Math.sqrt(Math.pow(Math.abs(x), 2) + Math.pow(Math.abs(y), 2));
if (*//*z >= centerRadius - circleBorder / 2 &&*//* z <= centerRadius + 20) {
double angle = Math.abs(Math.toDegrees(Math.atan((point.y - centerPoint.y) / (point.x - centerPoint.x))));
if (x >= 0 && y < 0) {
angle = 90 - angle;
} else if (x >= 0 && y >= 0) {
angle = 90 + angle;
} else if (x < 0 && y >= 0) {
angle = 270 - angle;
} else {
angle = 270 + angle;
}
angle = (angle -rotateHelper.getStartAngle())%360;
angle = angle <0 ? 360+angle:angle;
clickAngle = angle + startAngle;
return;
}
clickAngle = -1;
}
}*/
@Override
public boolean calculationChild( ChartData<RadarData> chartData) {
this.chartData = chartData;
ScaleData scaleData =this.chartData.getScaleData();
List<RadarData> columnDatas = chartData.getColumnDataList();
if(columnDatas == null || columnDatas.size() == 0){
return false;
}
int columnSize = columnDatas.size();
for(int i = 0 ; i <columnSize; i++){
BarData columnData = columnDatas.get(i);
if(!columnData.isDraw()){
continue;
}
List<Double> datas = columnData.getChartYDataList();
if(datas == null || datas.size() == 0){
throw new ChartException("Please set up Column data");
}
scaleData.rowSize = datas.size();
if(datas.size() != scaleData.rowSize){
throw new ChartException("Column rows data inconsistency");
}
double[] scale = getColumnScale(datas);
scale = setMaxMinValue(scale[0],scale[1]);
if(columnData.getDirection() == IAxis.AxisDirection.LEFT){
if(!scaleData.isLeftHasValue){
scaleData.maxLeftValue = scale[0];
scaleData.minLeftValue = scale[1];
scaleData.isLeftHasValue = true;
}else{
scaleData.maxLeftValue = Math.max( scaleData.maxLeftValue,scale[0]);
scaleData.minLeftValue = Math.min( scaleData.minLeftValue,scale[1]);
}
}else{
if(!scaleData.isRightHasValue){
scaleData.maxRightValue = scale[0];
scaleData.minRightValue= scale[1];
scaleData.isRightHasValue = true;
}else{
scaleData.maxRightValue = Math.max(scaleData.maxRightValue,scale[0]);
scaleData.minRightValue = Math.min(scaleData.minRightValue,scale[1]);
}
}
}
if(chartData.getScaleData().rowSize == 0){
return false;
}
return true;
}
@Override
public double[] setMaxMinValue(double maxValue, double minValue) {
double dis = Math.abs(maxValue -minValue);
maxValue = maxValue + dis*0.2;
if(minValue >0){
minValue = 0;
}else{
minValue = minValue - dis*0.2;
}
return new double[]{maxValue,minValue};
}
private double[] getColumnScale(List<Double> values) {
double maxValue = 0;
double minValue =0;
int size = values.size();
for(int j= 0;j < size;j++) {
double d = values.get(j) ;
if(j == 0){
maxValue = d;
minValue = d;
}
if (maxValue < d){
maxValue = d;
}else if(minValue >d){
minValue = d;
}
}
return new double[] {maxValue,minValue};
}
public FontStyle getScaleStyle() {
return scaleStyle;
}
public LineStyle getLineStyle() {
return lineStyle;
}
public LineStyle getGridStyle() {
return gridStyle;
}
public void setRotateHelper(RotateHelper rotateHelper) {
this.rotateHelper = rotateHelper;
}
public void setScaleFormat(IFormat<Double> scaleFormat) {
this.scaleFormat = scaleFormat;
}
public void setShowScale(boolean showScale) {
isShowScale = showScale;
}
}
package com.daivd.chart.provider.rose;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.format.IFormat;
import com.daivd.chart.data.BarData;
import com.daivd.chart.data.RoseData;
import com.daivd.chart.data.ScaleData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.exception.ChartException;
import com.daivd.chart.matrix.RotateHelper;
import com.daivd.chart.provider.BaseProvider;
import java.util.List;
/**
* Created by huang on 2017/10/9.
*/
public class RoseProvider extends BaseProvider<RoseData> {
private int centerRadius;
private RotateHelper rotateHelper;
private FontStyle scaleStyle = new FontStyle();
private LineStyle lineStyle = new LineStyle();
private float startAngle=0;
protected LineStyle gridStyle = new LineStyle(); //网格样式
private int textHeight;
private boolean isShowScale;
private IFormat<Double> scaleFormat;
@Override
protected void matrixRectStart(Canvas canvas, Rect rect) {
super.matrixRectStart(canvas, rect);
if (rotateHelper != null && rotateHelper.isRotate()) {
canvas.rotate((float) rotateHelper.getStartAngle(), rect.centerX(), rect.centerY());
}
}
@Override
protected void drawProvider(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
int w = zoomRect.width();
int h = zoomRect.height();
int maxRadius = Math.min(w / 2, h / 2);
textHeight = (int) (paint.measureText("1", 0, 1));
scaleStyle.fillPaint(paint);
String oneXData = chartData.getCharXDataList().get(0);
int x = maxRadius / 10 + textHeight * oneXData.length();
centerRadius = maxRadius - x;
if (rotateHelper != null) {
rotateHelper.setOriginRect(rect);
rotateHelper.setRadius(centerRadius);
}
drawRadarBorder(canvas, zoomRect, paint);
drawRadarLines(canvas, zoomRect, paint);
drawLinePath(canvas, zoomRect, rect, paint);
drawQuadrantText(canvas, zoomRect, paint);
drawScale(canvas,zoomRect,paint);
}
private void drawLinePath(Canvas canvas, Rect zoomRect, Rect rect, Paint paint) {
List<String> charXDataList = chartData.getCharXDataList();
int count = charXDataList.size();
ScaleData scaleData = chartData.getScaleData();
List<RoseData> columnDataList = chartData.getColumnDataList();
double maxScale = scaleData.getMaxScaleValue(IAxis.AxisDirection.LEFT);
float angle = 360f / count;
startAngle = angle/2;
paint.setStyle(Paint.Style.FILL);
for (int j = 0; j < count; j++) {
double value = 0;
for (BarData lineData :columnDataList) {
if(lineData.isDraw()) {
value += lineData.getChartYDataList().get(j);
}
}
for (int i = columnDataList.size() - 1; i >= 0; i--) {
BarData lineData = columnDataList.get(i);
if(lineData.isDraw()) {
float curR = getAnimValue((float) (value * centerRadius / maxScale));
RectF rectF = new RectF(zoomRect.centerX() - curR, zoomRect.centerY() - curR, zoomRect.centerX() + curR, zoomRect.centerY() + curR);
paint.setColor(lineData.getColor());
canvas.drawArc(rectF, angle * j + angle / 6 - startAngle - 90, angle - angle / 6, true, paint);
value -= lineData.getChartYDataList().get(j);
}
}
}
}
private void drawRadarBorder(Canvas canvas, Rect zoomRect, Paint paint) {
gridStyle.fillPaint(paint);
canvas.drawCircle(zoomRect.centerX(), zoomRect.centerY(), centerRadius, paint);
canvas.drawCircle(zoomRect.centerX(), zoomRect.centerY(), centerRadius / 2, paint);
}
private void drawScale(Canvas canvas, Rect zoomRect, Paint paint){
double maxScale = chartData.getScaleData().getMaxScaleValue(IAxis.AxisDirection.LEFT);
if(isShowScale) {
scaleStyle.fillPaint(paint);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float fontHeight = fontMetrics.descent - fontMetrics.ascent;
canvas.drawText(getFormatValue(maxScale),
zoomRect.centerX(), zoomRect.centerY() - centerRadius+fontHeight, paint);
canvas.drawText(getFormatValue(maxScale/2),
zoomRect.centerX(),zoomRect.centerY()-centerRadius/2+fontHeight,paint);
}
}
/**
* 绘制象限文字
*
* @param canvas
*/
private void drawQuadrantText(Canvas canvas, Rect zoomRect, Paint paint) {
scaleStyle.fillPaint(paint);
List<String> charXDataList = chartData.getCharXDataList();
int count = charXDataList.size();
float angle = (float) (Math.PI*2/count);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float fontHeight = fontMetrics.descent - fontMetrics.ascent;
for(int i=0;i<count;i++){
float realAngle = (float) (angle*i - Math.PI/2);
String xData = charXDataList.get(i);
float x = (float) (zoomRect.centerX()+(centerRadius+fontHeight/2)*Math.cos(realAngle));
float y = (float) (zoomRect.centerY()+(centerRadius+fontHeight/2)*Math.sin(realAngle))+5;
if(realAngle>=0&&realAngle<=Math.PI/2){//第4象限
canvas.drawText(xData, x,y,paint);
}else if(realAngle<0){//第3象限
canvas.drawText(xData, x,y,paint);
}else if(realAngle>Math.PI/2&&realAngle<=Math.PI){//第2象限
float dis = paint.measureText(xData);//文本长度
canvas.drawText(xData, x-dis,y,paint);
}else if(realAngle>=Math.PI&&realAngle<3*Math.PI/2){//第1象限
float dis = paint.measureText(xData);//文本长度
canvas.drawText(xData, x-dis,y,paint);
}
}
}
/**
* 绘制直线
*/
private void drawRadarLines(Canvas canvas, Rect zoomRect, Paint paint) {
gridStyle.fillPaint(paint);
Path path = new Path();
int count = chartData.getCharXDataList().size();
float angle = (float) (Math.PI * 2 / count);
for (int i = 0; i < count; i++) {
path.reset();
path.moveTo(zoomRect.centerX(), zoomRect.centerY());
float x = (float) (zoomRect.centerX() + centerRadius * Math.cos(angle * i-Math.PI/2));
float y = (float) (zoomRect.centerY() + centerRadius * Math.sin(angle * i-Math.PI/2));
path.lineTo(x, y);
canvas.drawPath(path, paint);
}
}
private String getFormatValue(double value){
return scaleFormat !=null ? scaleFormat.format(value):String.valueOf(value);
}
/* @Override
public void clickPoint(PointF point) {
super.clickPoint(point);
if(centerPoint != null){
int x = (int) (point.x - centerPoint.x);
int y = (int) (point.y - centerPoint.y);
int z = (int) Math.sqrt(Math.pow(Math.abs(x), 2) + Math.pow(Math.abs(y), 2));
if (*//*z >= centerRadius - circleBorder / 2 &&*//* z <= centerRadius + 20) {
double angle = Math.abs(Math.toDegrees(Math.atan((point.y - centerPoint.y) / (point.x - centerPoint.x))));
if (x >= 0 && y < 0) {
angle = 90 - angle;
} else if (x >= 0 && y >= 0) {
angle = 90 + angle;
} else if (x < 0 && y >= 0) {
angle = 270 - angle;
} else {
angle = 270 + angle;
}
angle = (angle -rotateHelper.getStartAngle())%360;
angle = angle <0 ? 360+angle:angle;
clickAngle = angle + startAngle;
return;
}
clickAngle = -1;
}
}*/
void setSelection(int position) {
}
@Override
public boolean calculationChild(ChartData<RoseData> chartData) {
this.chartData = chartData;
ScaleData scaleData = this.chartData.getScaleData();
scaleData.maxLeftValue = 0;
List<RoseData> columnDatas = chartData.getColumnDataList();
if (columnDatas == null || columnDatas.size() == 0) {
return false;
}
int columnSize = columnDatas.size();
for (int j = 0; j < chartData.getCharXDataList().size(); j++) {
float maxValue = 0;
for (int i = 0; i < columnSize; i++) {
BarData columnData = columnDatas.get(i);
if (!columnData.isDraw()) {
continue;
}
List<Double> datas = columnData.getChartYDataList();
if (datas == null || datas.size() == 0) {
throw new ChartException("Please set up Column data");
}
scaleData.rowSize = datas.size();
if (datas.size() != scaleData.rowSize) {
throw new ChartException("Column rows data inconsistency");
}
double value = datas.get(j);
if (value < 0) {
throw new ChartException("The value cannot be <0");
}
maxValue += value;
}
if (!scaleData.isLeftHasValue) {
scaleData.maxLeftValue = maxValue;
scaleData.isLeftHasValue = true;
} else {
scaleData.maxLeftValue = Math.max(maxValue, scaleData.maxLeftValue);
}
}
scaleData.maxLeftValue = setMaxMinValue(scaleData.maxLeftValue, 0)[0];
return true;
}
@Override
public double[] setMaxMinValue ( double maxValue, double minValue){
double dis = Math.abs(maxValue - minValue);
maxValue = maxValue + dis * 0.5;
return new double[]{maxValue, minValue};
}
public FontStyle getScaleStyle() {
return scaleStyle;
}
public LineStyle getLineStyle() {
return lineStyle;
}
public LineStyle getGridStyle() {
return gridStyle;
}
public void setRotateHelper(RotateHelper rotateHelper) {
this.rotateHelper = rotateHelper;
}
public void setScaleFormat(IFormat<Double> scaleFormat) {
this.scaleFormat = scaleFormat;
}
public void setShowScale(boolean showScale) {
isShowScale = showScale;
}
}
package com.daivd.chart.utils;
import android.graphics.Color;
/**
* Created by huang on 2017/9/28.
*/
public class ColorUtils {
public static int getDarkerColor(int color){
float[] hsv = new float[3];
Color.colorToHSV(color, hsv); // convert to hsv
// make darker
hsv[1] = hsv[1] + 0.1f; // more saturation
hsv[2] = hsv[2] - 0.1f; // less brightness
int darkerColor = Color.HSVToColor(hsv);
return darkerColor ;
}
public static int getBrighterColor(int color){
float[] hsv = new float[3];
Color.colorToHSV(color, hsv); // convert to hsv
hsv[1] = hsv[1] - 0.1f; // less saturation
hsv[2] = hsv[2] + 0.1f; // more brightness
int darkerColor = Color.HSVToColor(hsv);
return darkerColor ;
}
/**
* 修改颜色透明度
* @param color
* @param alpha
* @return
*/
public static int changeAlpha(int color, int alpha) {
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
}
package com.daivd.chart.utils;
import android.content.Context;
import android.util.TypedValue;
//常用单位转换的辅助类
public class DensityUtils {
private DensityUtils() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* dp转px
*
* @param context
* @return
*/
public static int dp2px(Context context, float dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.getResources().getDisplayMetrics());
}
/**
* sp转px
*
* @param context
* @return
*/
public static int sp2px(Context context, float spVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, context.getResources().getDisplayMetrics());
}
/**
* px转dp
*
* @param context
* @param pxVal
* @return
*/
public static float px2dp(Context context, float pxVal)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (pxVal / scale);
}
/**
* px转sp
*
* @param pxVal
* @return
*/
public static float px2sp(Context context, float pxVal)
{
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
}
}
\ No newline at end of file
package com.daivd.chart.utils;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import com.daivd.chart.data.style.FontStyle;
/**
* Created by huang on 2017/11/1.
*/
public class DrawUtils {
public static int getTextHeight(FontStyle style, Paint paint){
style.fillPaint(paint);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
return (int) (fontMetrics.descent - fontMetrics.ascent);
}
public static int getTextHeight(Paint paint){
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
return (int) (fontMetrics.descent - fontMetrics.ascent);
}
public static float getTextCenterY(int centerY,Paint paint){
return centerY-((paint.descent() + paint.ascent()) / 2);
}
public static boolean isMixRect(Rect rect,int left,int top,int right,int bottom){
return rect.bottom>= top && rect.right >= left && rect.top <bottom && rect.left< right;
}
public static boolean isClick(int left, int top, int right, int bottom, PointF clickPoint){
return clickPoint.x >= left && clickPoint.x <=right && clickPoint.y>=top && clickPoint.y <=bottom;
}
public static boolean isMixHorizontalRect(Rect rect,int left,int right){
return rect.right >= left && rect.left<= right;
}
public static boolean isVerticalMixRect(Rect rect,int top,int bottom){
return rect.bottom>= top && rect.top <=bottom;
}
}
<vector android:height="24dp" android:viewportHeight="1024.0"
android:viewportWidth="1024.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#4096EE" android:pathData="M846.4,359.1c137.9,84.4 138.2,220.9 0,305.5l-523.7,320.4C184.9,1069.4 73.1,1006.2 73.1,845.9V178C73.1,16.7 184.5,-45.9 322.7,38.7l523.7,320.5z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
<resources>
<string name="app_name">Smartchart</string>
</resources>
...@@ -53,5 +53,7 @@ dependencies { ...@@ -53,5 +53,7 @@ dependencies {
// } // }
testImplementation rootProject.ext.dependencies["junit"] testImplementation rootProject.ext.dependencies["junit"]
implementation rootProject.ext.dependencies["BaseRecyclerViewAdapter"] implementation rootProject.ext.dependencies["BaseRecyclerViewAdapter"]
implementation 'com.github.Liberuman:ShadowDrawable:0.1'//陰影背景
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'//報表圖
implementation project(':chart')
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package="com.gingersoft.gsa.cloud.main"> package="com.gingersoft.gsa.cloud.main">
<application> <application>
<activity android:name=".mvp.ui.activity.NewMainActivity"/>
<activity android:name=".mvp.ui.activity.MainActivity"/> <activity android:name=".mvp.ui.activity.MainActivity"/>
</application> </application>
</manifest> </manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gingersoft.gsa.cloud.main"> package="com.gingersoft.gsa.cloud.main">
...@@ -17,9 +18,9 @@ ...@@ -17,9 +18,9 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".mvp.ui.activity.MainActivity"/>
<activity <activity
android:name=".mvp.ui.activity.MainActivity" android:name=".mvp.ui.activity.NewMainActivity"
android:theme="@style/MainTheme"> android:theme="@style/MainTheme">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
...@@ -32,7 +33,6 @@ ...@@ -32,7 +33,6 @@
<meta-data <meta-data
android:name="network.config.GlobalConfiguration" android:name="network.config.GlobalConfiguration"
android:value="ConfigModule" /> android:value="ConfigModule" />
<meta-data <meta-data
android:name="design_width_in_dp" android:name="design_width_in_dp"
android:value="360" /> android:value="360" />
...@@ -42,4 +42,3 @@ ...@@ -42,4 +42,3 @@
</application> </application>
</manifest> </manifest>
\ No newline at end of file
...@@ -5,6 +5,7 @@ import com.billy.cc.core.component.CCResult; ...@@ -5,6 +5,7 @@ import com.billy.cc.core.component.CCResult;
import com.billy.cc.core.component.CCUtil; import com.billy.cc.core.component.CCUtil;
import com.billy.cc.core.component.IComponent; import com.billy.cc.core.component.IComponent;
import com.gingersoft.gsa.cloud.main.mvp.ui.activity.MainActivity; import com.gingersoft.gsa.cloud.main.mvp.ui.activity.MainActivity;
import com.gingersoft.gsa.cloud.main.mvp.ui.activity.NewMainActivity;
public class ComponentMain implements IComponent { public class ComponentMain implements IComponent {
...@@ -71,7 +72,7 @@ public class ComponentMain implements IComponent { ...@@ -71,7 +72,7 @@ public class ComponentMain implements IComponent {
} }
private void openActivity(CC cc) { private void openActivity(CC cc) {
CCUtil.navigateTo(cc, MainActivity.class); CCUtil.navigateTo(cc, NewMainActivity.class);
CC.sendCCResult(cc.getCallId(), CCResult.success()); CC.sendCCResult(cc.getCallId(), CCResult.success());
} }
......
package com.gingersoft.gsa.cloud.main.di.component;
import dagger.BindsInstance;
import dagger.Component;
import com.jess.arms.di.component.AppComponent;
import com.gingersoft.gsa.cloud.main.di.module.MainTopModule;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainTopContract;
import com.jess.arms.di.scope.FragmentScope;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.MainTopFragment;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
@Component(modules = MainTopModule.class, dependencies = AppComponent.class)
public interface MainTopComponent {
void inject(MainTopFragment fragment);
@Component.Builder
interface Builder {
@BindsInstance
MainTopComponent.Builder view(MainTopContract.View view);
MainTopComponent.Builder appComponent(AppComponent appComponent);
MainTopComponent build();
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.component;
import dagger.BindsInstance;
import dagger.Component;
import com.jess.arms.di.component.AppComponent;
import com.gingersoft.gsa.cloud.main.di.module.NewMainModule;
import com.gingersoft.gsa.cloud.main.mvp.contract.NewMainContract;
import com.jess.arms.di.scope.ActivityScope;
import com.gingersoft.gsa.cloud.main.mvp.ui.activity.NewMainActivity;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@ActivityScope
@Component(modules = NewMainModule.class, dependencies = AppComponent.class)
public interface NewMainComponent {
void inject(NewMainActivity activity);
@Component.Builder
interface Builder {
@BindsInstance
NewMainComponent.Builder view(NewMainContract.View view);
NewMainComponent.Builder appComponent(AppComponent appComponent);
NewMainComponent build();
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.module;
import com.jess.arms.di.scope.FragmentScope;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainTopContract;
import com.gingersoft.gsa.cloud.main.mvp.model.MainTopModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@Module
public abstract class MainTopModule {
@Binds
abstract MainTopContract.Model bindMainTopModel(MainTopModel model);
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.module;
import com.jess.arms.di.scope.ActivityScope;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import com.gingersoft.gsa.cloud.main.mvp.contract.NewMainContract;
import com.gingersoft.gsa.cloud.main.mvp.model.NewMainModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@Module
public abstract class NewMainModule {
@Binds
abstract NewMainContract.Model bindNewMainModel(NewMainModel model);
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.contract;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;
import java.util.Map;
import io.reactivex.Observable;
import okhttp3.RequestBody;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public interface MainTopContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
void loadBusinessInfo(Map<String, HomeTurnoverBean.DataBean> dataBeanMap);
}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
Observable<HomeTurnoverBean> getRestaurantReport(RequestBody requestBody);
}
}
package com.gingersoft.gsa.cloud.main.mvp.contract;
import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public interface NewMainContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
}
}
package com.gingersoft.gsa.cloud.main.mvp.model;
import android.app.Application;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.gingersoft.gsa.cloud.main.mvp.model.service.HomeService;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;
import com.jess.arms.di.scope.FragmentScope;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainTopContract;
import io.reactivex.Observable;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.RequestBody;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class MainTopModel extends BaseModel implements MainTopContract.Model {
@Inject
Gson mGson;
@Inject
Application mApplication;
@Inject
public MainTopModel(IRepositoryManager repositoryManager) {
super(repositoryManager);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}
@Override
public Observable<HomeTurnoverBean> getRestaurantReport(RequestBody requestBody) {
RetrofitUrlManager.getInstance().putDomain("common", "https://m.ricepon.com/member-web/api/");
return mRepositoryManager.obtainRetrofitService(HomeService.class)
.getRestaurantReport(requestBody);
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.model;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;
import com.jess.arms.di.scope.ActivityScope;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.NewMainContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@ActivityScope
public class NewMainModel extends BaseModel implements NewMainContract.Model {
@Inject
Gson mGson;
@Inject
Application mApplication;
@Inject
public NewMainModel(IRepositoryManager repositoryManager) {
super(repositoryManager);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.presenter;
import android.app.Application;
import com.gingersoft.gsa.cloud.base.utils.constans.HttpsConstans;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.FragmentScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.schedulers.Schedulers;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import me.jessyan.rxerrorhandler.handler.ErrorHandleSubscriber;
import okhttp3.FormBody;
import okhttp3.RequestBody;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainTopContract;
import com.jess.arms.utils.RxLifecycleUtils;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class MainTopPresenter extends BasePresenter<MainTopContract.Model, MainTopContract.View> {
@Inject
RxErrorHandler mErrorHandler;
@Inject
Application mApplication;
@Inject
ImageLoader mImageLoader;
@Inject
AppManager mAppManager;
@Inject
public MainTopPresenter(MainTopContract.Model model, MainTopContract.View rootView) {
super(model, rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}
public void getRestaurantReport(String restaurantId) {
RequestBody requestBody = new FormBody.Builder()
.add("restaurantId", restaurantId)
.add("startTime", TimeUtils.getYesterdayTime(TimeUtils.DATE_FORMAT_DATE))
.add("endTime", TimeUtils.getCurrentTimeInString(TimeUtils.DATE_FORMAT_DATE))
.build();
mModel.getRestaurantReport(requestBody)
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> mRootView.showLoading(""))
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doAfterTerminate(() -> mRootView.hideLoading())
.compose(RxLifecycleUtils.bindToLifecycle(mRootView))
.subscribe(new ErrorHandleSubscriber<HomeTurnoverBean>(mErrorHandler) {
@Override
public void onNext(@NonNull HomeTurnoverBean info) {
if (info != null && info.isSuccess()) {
if (info.getData() != null) {
mRootView.loadBusinessInfo(info.getData());
}
} else {
mRootView.showMessage("營業報表獲取失敗");
}
}
@Override
public void onComplete() {
super.onComplete();
RetrofitUrlManager.getInstance().putDomain("common", HttpsConstans.ROOT_SERVER_ADDRESS_FORMAL);
}
@Override
public void onError(Throwable t) {
super.onError(t);
RetrofitUrlManager.getInstance().putDomain("common", HttpsConstans.ROOT_SERVER_ADDRESS_FORMAL);
}
});
}
}
package com.gingersoft.gsa.cloud.main.mvp.presenter;
import android.app.Application;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.ActivityScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.NewMainContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@ActivityScope
public class NewMainPresenter extends BasePresenter<NewMainContract.Model, NewMainContract.View> {
@Inject
RxErrorHandler mErrorHandler;
@Inject
Application mApplication;
@Inject
ImageLoader mImageLoader;
@Inject
AppManager mAppManager;
@Inject
public NewMainPresenter(NewMainContract.Model model, NewMainContract.View rootView) {
super(model, rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}
}
...@@ -73,8 +73,6 @@ public class MainActivity extends BaseFragmentActivity<MainPresenter> implements ...@@ -73,8 +73,6 @@ public class MainActivity extends BaseFragmentActivity<MainPresenter> implements
public void initData(@Nullable Bundle savedInstanceState) { public void initData(@Nullable Bundle savedInstanceState) {
initTabs(); initTabs();
initPagers(); initPagers();
// mPresenter.initAdapter(this);
// mPresenter.initItemClickListener(this);
} }
private void initPagers() { private void initPagers() {
......
package com.gingersoft.gsa.cloud.main.mvp.ui.activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.billy.cc.core.component.CC;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.gingersoft.gsa.cloud.main.R2;
import com.gingersoft.gsa.cloud.main.di.component.DaggerNewMainComponent;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionHeader;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionItem;
import com.gingersoft.gsa.cloud.main.mvp.ui.adapter.HomeFunctionAdapter;
import com.gingersoft.gsa.cloud.main.mvp.ui.adapter.MainOrderingAdapter;
import com.jess.arms.base.BaseActivity;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import com.gingersoft.gsa.cloud.main.mvp.contract.NewMainContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.NewMainPresenter;
import com.gingersoft.gsa.cloud.main.R;
import com.qmuiteam.qmui.widget.section.QMUISection;
import com.sxu.shadowdrawable.ShadowDrawable;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import static com.jess.arms.utils.Preconditions.checkNotNull;
import static com.qmuiteam.qmui.util.QMUIDisplayHelper.dpToPx;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:14
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public class NewMainActivity extends BaseActivity<NewMainPresenter> implements NewMainContract.View {
@BindView(R2.id.rv_ordering_meals)
RecyclerView rvOrdering;//點餐
@BindView(R2.id.rv_management)
RecyclerView rvManagement;//管理
@BindView(R2.id.rv_staff_management)
RecyclerView rvStaffManagement;//管理
@Override
public void setupActivityComponent(@NonNull AppComponent appComponent) {
DaggerNewMainComponent //如找不到该类,请编译一下项目
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}
@Override
public int initView(@Nullable Bundle savedInstanceState) {
return R.layout.activity_new_main; //如果你不需要框架帮你设置 setContentView(id) 需要自行设置,请返回 0
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
ShadowDrawable.setShadowDrawable(findViewById(R.id.layout_ordering_meals), Color.parseColor("#FFFFFF"), dpToPx(5),
Color.parseColor("#73888888"), dpToPx(5), 0, 2);
ShadowDrawable.setShadowDrawable(findViewById(R.id.layout_management), Color.parseColor("#FFFFFF"), dpToPx(5),
Color.parseColor("#00000000"), dpToPx(5), 0, 2);
List<SectionItem> data = new ArrayList<>();
data.add(new SectionItem(R.drawable.ic_dining_table_mode, "餐檯模式"));
data.add(new SectionItem(R.drawable.ic_delivery_mode, "外送模式"));
data.add(new SectionItem(R.drawable.ic_outsourcing_model, "外賣模式"));
data.add(new SectionItem(R.drawable.ic_pre_order_mode, "預點餐模式"));
MainOrderingAdapter adapter = new MainOrderingAdapter(R.layout.main_home_funcation_item, data);
rvOrdering.setLayoutManager(new GridLayoutManager(mContext, 4) {
@Override
public boolean canScrollVertically() {
return false;
}
});
adapter.setOnItemClickListener((adapter1, view, position) -> {
if(data.get(position).getText().equals("餐檯模式")){
CC.obtainBuilder("Component.Table")
.setActionName("showTableActivity")
.build()
.call();
}
});
rvOrdering.setAdapter(adapter);
List<SectionItem> managementData = new ArrayList<>();
managementData.add(new SectionItem(R.drawable.ic_meals_menu_management, "餐牌管理"));
managementData.add(new SectionItem(R.drawable.ic_dining_table_management, "餐檯管理"));
managementData.add(new SectionItem(R.drawable.ic_print_management, "打印管理"));
managementData.add(new SectionItem(R.drawable.ic_pay_management, "支付管理"));
managementData.add(new SectionItem(R.drawable.ic_discount_management, "折扣管理"));
MainOrderingAdapter managementAdapter = new MainOrderingAdapter(R.layout.main_home_management_funcation_item, managementData);
rvManagement.setLayoutManager(new GridLayoutManager(mContext, 5) {
@Override
public boolean canScrollVertically() {
return false;
}
});
rvManagement.setAdapter(managementAdapter);
managementAdapter.setOnItemClickListener((adapter12, view, position) -> {
if(managementData.get(position).getText().equals("打印管理")){
CC.obtainBuilder("Component.Print")
.setActionName("showPrintActivity")
.build()
.call();
}
});
List<SectionItem> staffData = new ArrayList<>();
staffData.add(new SectionItem(R.drawable.ic_staff_management, "員工管理"));
staffData.add(new SectionItem(R.drawable.ic_authority_management, "權限管理"));
staffData.add(new SectionItem(R.drawable.ic_operation_record, "操作記錄"));
MainOrderingAdapter staffAdapter = new MainOrderingAdapter(R.layout.main_home_management_funcation_item, staffData);
rvStaffManagement.setLayoutManager(new GridLayoutManager(mContext, 5) {
@Override
public boolean canScrollVertically() {
return false;
}
});
rvStaffManagement.setAdapter(staffAdapter);
}
@Override
public void initIntent() {
}
@Override
public void initTopBar() {
}
@Override
public void initLanguage() {
}
@Override
public void initLayoutParams() {
}
@Override
public void initLayoutVisible() {
}
@Override
public void showLoading(String message) {
}
@Override
public void hideLoading() {
}
@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}
@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}
@Override
public void killMyself() {
finish();
}
}
package com.gingersoft.gsa.cloud.main.mvp.ui.adapter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionItem;
import java.util.List;
import androidx.annotation.Nullable;
/**
* Created by Wyh on 2020/2/19.
* 首頁點餐
*/
public class MainOrderingAdapter extends BaseQuickAdapter<SectionItem, BaseViewHolder> {
public MainOrderingAdapter(int layoutResId, @Nullable List<SectionItem> data) {
super(layoutResId, data);
}
// public MainOrderingAdapter(@Nullable List<SectionItem> data) {
// super(R.layout.main_home_funcation_item, data);
// }
@Override
protected void convert(BaseViewHolder helper, SectionItem item) {
helper.setImageResource(R.id.iv_main_home_item_function_icon, item.getImage());
helper.setText(R.id.tv_main_home_item_function_name, item.getText());
}
}
package com.gingersoft.gsa.cloud.main.mvp.ui.fragment;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.daivd.chart.component.axis.BaseAxis;
import com.daivd.chart.component.axis.HorizontalAxis;
import com.daivd.chart.component.axis.VerticalAxis;
import com.daivd.chart.component.base.IAxis;
import com.daivd.chart.core.LineChart;
import com.daivd.chart.data.ChartData;
import com.daivd.chart.data.LineData;
import com.daivd.chart.data.style.FontStyle;
import com.daivd.chart.data.style.LineStyle;
import com.daivd.chart.data.style.PointStyle;
import com.daivd.chart.listener.OnClickColumnListener;
import com.daivd.chart.provider.component.point.Point;
import com.daivd.chart.provider.component.tip.MultiLineBubbleTip;
import com.daivd.chart.utils.DensityUtils;
import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.main.R2;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.gingersoft.gsa.cloud.main.mvp.ui.activity.MainActivity;
import com.jess.arms.base.BaseFragment;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import com.gingersoft.gsa.cloud.main.di.component.DaggerMainTopComponent;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainTopContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.MainTopPresenter;
import com.gingersoft.gsa.cloud.main.R;
import com.sxu.shadowdrawable.ShadowDrawable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.ButterKnife;
import static com.jess.arms.utils.Preconditions.checkNotNull;
import static com.qmuiteam.qmui.util.QMUIDisplayHelper.dpToPx;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 02/18/2020 17:21
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public class MainTopFragment extends BaseFragment<MainTopPresenter> implements MainTopContract.View {
// line_chart_view
@BindView(R2.id.line_chart_view)
LineChart lineChart;
@BindView(R2.id.tv_today_amount)
TextView tvTurnover;
@BindView(R2.id.tv_today_time)
TextView time;
@BindView(R2.id.tv_total_amount_project)
TextView tvProjectAmount;//項目總金額
@BindView(R2.id.tv_consumers_number)
TextView tvConsumersNumber;//消費人數
@BindView(R2.id.tv_bill_number)
TextView tvBillNumber;//賬單數
public static MainTopFragment newInstance() {
MainTopFragment fragment = new MainTopFragment();
return fragment;
}
@Override
public void setupFragmentComponent(@NonNull AppComponent appComponent) {
DaggerMainTopComponent //如找不到该类,请编译一下项目
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}
@Override
public View initView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main_top, container, false);
ButterKnife.bind(this, view);
ShadowDrawable.setShadowDrawable(view.findViewById(R.id.cv_white_bg), Color.parseColor("#FFFFFF"), dpToPx(5),
Color.parseColor("#73888888"), dpToPx(5), 0, 2);
ShadowDrawable.setShadowDrawable(view.findViewById(R.id.layout_info), Color.parseColor("#FFFFFF"), dpToPx(5),
Color.parseColor("#73888888"), dpToPx(5), 0, 2);
return view;
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
mPresenter.getRestaurantReport( "26");//GsaCloudApplication.getRestaurantId(mContext) 獲取餐廳營業信息
time.setText(TimeUtils.getCurrentTimeInString(new SimpleDateFormat("YYYY-MM-dd E")));
loadReport();//加載報表線形圖
}
private void loadReport() {
Resources res = getResources();
FontStyle.setDefaultTextSpSize(mContext, 12);
List<String> chartYDataList = new ArrayList<>();
chartYDataList.add("00:00");
chartYDataList.add("04:00");
chartYDataList.add("08:00");
chartYDataList.add("12:00");
chartYDataList.add("16:00");
chartYDataList.add("20:00");
chartYDataList.add("24:00");
List<LineData> ColumnDatas = new ArrayList<>();
//第一條線
ArrayList<Double> tempList1 = new ArrayList<>();
tempList1.add(12350d);
tempList1.add(12340d);
tempList1.add(2450d);
tempList1.add(1470d);
tempList1.add(1690d);
tempList1.add(1570d);
final LineData columnData1 = new LineData("今日", "℃", getResources().getColor(R.color.theme_color), tempList1);
columnData1.setLineStyle(new LineStyle(mContext, 5, getResources().getColor(R.color.theme_color)));
//第二條線
ArrayList<Double> humidityList = new ArrayList<>();
humidityList.add(1340d);
humidityList.add(1320d);
humidityList.add(480d);
humidityList.add(590d);
humidityList.add(360d);
humidityList.add(1830d);
humidityList.add(1980d);
humidityList.add(1490d);
LineData columnData2 = new LineData("昨日", "", getResources().getColor(R.color.today_line), humidityList);
columnData2.setLineStyle(new LineStyle(mContext, 5, getResources().getColor(R.color.today_line)));
ColumnDatas.add(columnData1);
ColumnDatas.add(columnData2);
ChartData<LineData> chartData2 = new ChartData<>("Line chart", chartYDataList, ColumnDatas);
//設置曲線圖樣式
lineChart.setLineModel(LineChart.CURVE_MODEL);
//獲取左側垂直軸線
VerticalAxis verticalAxis = lineChart.getLeftVerticalAxis();
//獲取橫向軸線
HorizontalAxis horizontalAxis = lineChart.getHorizontalAxis();
//右側軸線
VerticalAxis rightAxis = lineChart.getRightVerticalAxis();
//設置右側軸線不顯示
rightAxis.setDisplay(false);
//设置竖轴方向在左側
verticalAxis.setAxisDirection(IAxis.AxisDirection.LEFT);
verticalAxis.setStartZero(true);
verticalAxis.setMaxValue(18000);
//设置网格
verticalAxis.setDrawGrid(true);
//设置横轴方向
horizontalAxis.setAxisDirection(IAxis.AxisDirection.BOTTOM);
//不顯示網格
horizontalAxis.setDrawGrid(false);
horizontalAxis.getAxisStyle().setWidth(mContext,1).setColor(res.getColor(R.color.theme_color));
//设置线条样式
verticalAxis.getAxisStyle().setWidth(mContext, 1).setColor(res.getColor(R.color.theme_color));
//設置網格虛線樣式
DashPathEffect effects = new DashPathEffect(new float[]{1, 2, 4, 8}, 1);
verticalAxis.setGridStyle(new LineStyle(0.5f, res.getColor(R.color.report_dotted_line_color)));
verticalAxis.getGridStyle().setEffect(effects);
FontStyle scaleStyle = new FontStyle(mContext, 9, res.getColor(R.color.report_left_scale));
horizontalAxis.setScaleStyle(scaleStyle);
verticalAxis.setScaleStyle(scaleStyle);
lineChart.setZoom(false);
//开启十字架
lineChart.getProvider().setOpenCross(true);
//设置显示点
Point point = new Point();
point.getPointStyle().setShape(PointStyle.CIRCLE);
//设置显示点的样式
lineChart.getProvider().setPoint(point);
//设置显示标题
lineChart.setShowChartName(false);
//底部不顯示顏色代表的意思
lineChart.getLegend().setDisplay(false);
lineChart.getMatrixHelper().setWidthMultiple(0.9f);
lineChart.getHorizontalAxis().setRotateAngle(0);//設置底部文字旋轉角度
lineChart.setFirstAnim(false);
lineChart.setChartData(chartData2);
lineChart.setOnClickColumnListener((lineData, pos) -> {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(DensityUtils.sp2px(mContext, 13));
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
MultiLineBubbleTip tip = new MultiLineBubbleTip<LineData>(mContext,
R.mipmap.round_rect, R.mipmap.triangle, paint) {
@Override
public boolean isShowTip(LineData lineData, int position) {
return position == pos;
}
@Override
public String[] format(LineData lineData, int position) {
String title = lineData.getName();
String value = lineData.getChartYDataList().get(position) + lineData.getUnit();
return new String[]{title, value};
}
};
tip.setColorFilter(Color.parseColor("#FA8072"));
tip.setAlpha(0.8f);
lineChart.getProvider().setTip(tip);
lineChart.invalidate();
});
}
/**
* 通过此方法可以使 Fragment 能够与外界做一些交互和通信, 比如说外部的 Activity 想让自己持有的某个 Fragment 对象执行一些方法,
* 建议在有多个需要与外界交互的方法时, 统一传 {@link Message}, 通过 what 字段来区分不同的方法, 在 {@link #setData(Object)}
* 方法中就可以 {@code switch} 做不同的操作, 这样就可以用统一的入口方法做多个不同的操作, 可以起到分发的作用
* <p>
* 调用此方法时请注意调用时 Fragment 的生命周期, 如果调用 {@link #setData(Object)} 方法时 {Fragment#onCreate(Bundle)} 还没执行
* 但在 {@link #setData(Object)} 里却调用了 Presenter 的方法, 是会报空的, 因为 Dagger 注入是在 {Fragment#onCreate(Bundle)} 方法中执行的
* 然后才创建的 Presenter, 如果要做一些初始化操作,可以不必让外部调用 {@link #setData(Object)}, 在 {@link #initData(Bundle)} 中初始化就可以了
* <p>
* Example usage:
* <pre>
* public void setData(@Nullable Object data) {
* if (data != null && data instanceof Message) {
* switch (((Message) data).what) {
* case 0:
* loadData(((Message) data).arg1);
* break;
* case 1:
* refreshUI();
* break;
* default:
* //do something
* break;
* }
* }
* }
*
* // call setData(Object):
* Message data = new Message();
* data.what = 0;
* data.arg1 = 1;
* fragment.setData(data);
* </pre>
*
* @param data 当不需要参数时 {@code data} 可以为 {@code null}
*/
@Override
public void setData(@Nullable Object data) {
}
@Override
public void showLoading(String message) {
}
@Override
public void hideLoading() {
}
@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}
@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}
@Override
public void killMyself() {
}
@Override
public void loadBusinessInfo(Map<String, HomeTurnoverBean.DataBean> dataBeanMap) {
HomeTurnoverBean.DataBean bean = dataBeanMap.get(TimeUtils.getCurrentTimeInString(TimeUtils.DATE_FORMAT_DATE));//TimeUtils.getCurrentTimeInString(TimeUtils.DATE_FORMAT_DATE)
if (bean != null) {
tvTurnover.setText(bean.getBusiness_amount());
tvProjectAmount.setText(bean.getSales());
tvConsumersNumber.setText(bean.getPeople());
tvBillNumber.setText(bean.getNumber_bill());
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_4" />
<solid android:color="@color/white" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:endColor="#015EEA"
android:startColor="#00C0FA" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#F0edf1"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<fragment
android:id="@+id/main_top_fragment"
android:name="com.gingersoft.gsa.cloud.main.mvp.ui.fragment.MainTopFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/layout_ordering_meals"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_10"
android:orientation="vertical"
android:paddingTop="@dimen/dp_15"
android:paddingBottom="@dimen/dp_20">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_22"
android:text="點餐"
android:textColor="#181818"
android:textSize="@dimen/sp_17" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:layout_marginTop="@dimen/dp_11"
android:background="#F0F0F0" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_ordering_meals"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/main_recyclerview_marginLeft"
android:layout_marginTop="@dimen/dp_5"
android:layout_marginRight="@dimen/main_recyclerview_marginRight" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_management"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_10"
android:background="@color/white"
android:orientation="vertical"
android:paddingTop="@dimen/dp_16"
android:paddingBottom="@dimen/dp_16">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_15"
android:text="管理"
android:textColor="#181818"
android:textSize="@dimen/sp_14" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_management"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/main_recyclerview_marginLeft"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginRight="@dimen/main_recyclerview_marginRight" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:layout_marginTop="@dimen/dp_20"
android:background="#F0F0F0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_20"
android:text="員工"
android:layout_marginLeft="@dimen/dp_15"
android:textColor="#181818"
android:textSize="@dimen/sp_14" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_staff_management"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/main_recyclerview_marginLeft"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginRight="@dimen/main_recyclerview_marginRight" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/shape_main_top_bg"
app:layout_constraintBottom_toBottomOf="@id/tv_today_time"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_title_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/dp_20"
android:paddingTop="@dimen/dp_7"
android:paddingRight="@dimen/dp_12"
android:paddingBottom="@dimen/dp_7"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="@dimen/dp_22"
android:layout_height="@dimen/dp_25"
android:src="@drawable/ic_personal_center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="店鋪名稱"
android:textColor="@color/white"
android:textSize="@dimen/sp_18"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="@dimen/dp_26"
android:layout_height="@dimen/dp_28"
android:src="@drawable/ic_msg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_today_amount_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:text="今日營業額($)"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_title_layout" />
<TextView
android:id="@+id/tv_today_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:includeFontPadding="false"
android:text="0"
android:textColor="@color/white"
android:textSize="@dimen/sp_40"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_today_amount_text" />
<TextView
android:id="@+id/tv_compare_today_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:text="較昨日:"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_compare_today_state"
app:layout_constraintTop_toBottomOf="@id/tv_today_amount" />
<TextView
android:id="@+id/tv_compare_today_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="↑"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@id/tv_compare_today_text"
app:layout_constraintLeft_toRightOf="@id/tv_compare_today_text"
app:layout_constraintRight_toLeftOf="@id/tv_compare_today_size"
app:layout_constraintTop_toTopOf="@id/tv_compare_today_text" />
<TextView
android:id="@+id/tv_compare_today_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@id/tv_compare_today_text"
app:layout_constraintLeft_toRightOf="@id/tv_compare_today_state"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_compare_today_text" />
<View
android:id="@+id/cv_white_bg"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_250"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_16"
android:layout_marginRight="@dimen/dp_10"
android:background="@color/white"
app:layout_constraintTop_toBottomOf="@id/tv_compare_today_text" />
<TextView
android:id="@+id/tv_today_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_35"
android:elevation="@dimen/dp_1"
android:paddingBottom="@dimen/dp_6"
android:textColor="#181818"
android:textSize="@dimen/sp_15"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_compare_today_text" />
<com.daivd.chart.core.LineChart
android:id="@+id/line_chart_view"
android:layout_width="0dp"
android:layout_height="160dp"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_10"
android:paddingRight="@dimen/dp_10"
app:layout_constraintLeft_toLeftOf="@id/cv_white_bg"
app:layout_constraintRight_toRightOf="@id/cv_white_bg"
app:layout_constraintTop_toBottomOf="@id/tv_today_time" />
<TextView
android:id="@+id/tv_more_report"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_10"
android:elevation="@dimen/dp_1"
android:text="更多報表 >"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@id/cv_white_bg"
app:layout_constraintLeft_toLeftOf="@id/cv_white_bg"
app:layout_constraintRight_toRightOf="@id/cv_white_bg" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/layout_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_10"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="@dimen/dp_20"
android:paddingTop="@dimen/dp_15"
android:paddingRight="@dimen/dp_20"
android:paddingBottom="@dimen/dp_15"
app:layout_constraintTop_toBottomOf="@id/cl_top">
<!-- 項目總金額-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_total_amount_project"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_17"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="項目總金額"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="较昨日:"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<ImageView
android:layout_width="@dimen/dp_8"
android:layout_height="@dimen/dp_9"
android:src="@drawable/ic_rise" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
</LinearLayout>
</LinearLayout>
<!-- 消費人數-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_consumers_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_17"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="消費人數"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="平均:1000"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="较昨日:"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<ImageView
android:layout_width="@dimen/dp_8"
android:layout_height="@dimen/dp_9"
android:src="@drawable/ic_rise" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1000"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
</LinearLayout>
</LinearLayout>
<!-- 賬單單數-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_bill_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_17"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="賬單單數"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="平均:1000"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="较昨日:"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
<ImageView
android:layout_width="@dimen/dp_8"
android:layout_height="@dimen/dp_9"
android:src="@drawable/ic_down" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1000"
android:textColor="#3c3c3c"
android:textSize="@dimen/sp_12" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -3,9 +3,7 @@ ...@@ -3,9 +3,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical">
android:paddingTop="@dimen/dp_10"
android:paddingBottom="@dimen/dp_10">
<ImageView <ImageView
android:id="@+id/iv_main_home_item_function_icon" android:id="@+id/iv_main_home_item_function_icon"
...@@ -19,6 +17,7 @@ ...@@ -19,6 +17,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:text="餐檯模式" android:text="餐檯模式"
android:layout_marginTop="@dimen/dp_8"
android:textColor="@color/normal_color" android:textColor="@color/normal_color"
android:textSize="@dimen/sp_14" /> android:textSize="@dimen/sp_14" />
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_main_home_item_function_icon"
android:layout_width="@dimen/dp_30"
android:layout_height="@dimen/dp_30"
android:src="@drawable/ic_dining_table" />
<TextView
android:id="@+id/tv_main_home_item_function_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="餐檯模式"
android:layout_marginTop="@dimen/dp_8"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_13" />
</LinearLayout>
\ No newline at end of file
<resources> <resources>
<dimen name="main_fab_margin">16dp</dimen> <dimen name="main_fab_margin">16dp</dimen>
<dimen name="main_recyclerview_marginLeft">@dimen/dp_15</dimen>
<dimen name="main_recyclerview_marginRight">@dimen/dp_15</dimen>
</resources> </resources>
...@@ -81,9 +81,11 @@ public class PrintActivity extends BaseActivity<PrintPresenter> implements Print ...@@ -81,9 +81,11 @@ public class PrintActivity extends BaseActivity<PrintPresenter> implements Print
* 0:上菜紙 * 0:上菜紙
* 1:印單 * 1:印單
* 2:結賬單 * 2:結賬單
* 3:廚房單
*/ */
private int type = -1; private int type = -1;
private Bitmap bitmap; private Bitmap bitmap;
@Override @Override
public void setupActivityComponent(@NonNull AppComponent appComponent) { public void setupActivityComponent(@NonNull AppComponent appComponent) {
DaggerPrintComponent //如找不到该类,请编译一下项目 DaggerPrintComponent //如找不到该类,请编译一下项目
...@@ -102,16 +104,20 @@ public class PrintActivity extends BaseActivity<PrintPresenter> implements Print ...@@ -102,16 +104,20 @@ public class PrintActivity extends BaseActivity<PrintPresenter> implements Print
@Override @Override
public void initData(@Nullable Bundle savedInstanceState) { public void initData(@Nullable Bundle savedInstanceState) {
type = CCUtil.getNavigateParam(this, "type", 1001); type = CCUtil.getNavigateParam(this, "type", 1001);
if(type == 0){ if (type == 0) {
//上菜紙 //上菜紙
List<Food> foods = CCUtil.getNavigateParam(this, "NewFoods", new ArrayList<>()); List<Food> foods = CCUtil.getNavigateParam(this, "NewFoods", new ArrayList<>());
bitmap = PrintUtils.getPrintBitmap(mContext, foods); bitmap = PrintUtils.getPrintBitmap(mContext, foods);
} else if(type == 1){ } else if (type == 1) {
//印單 //印單
bitmap = PrintUtils.getPrintBitmap(mContext); bitmap = PrintUtils.getPrintBitmap(mContext);
} else if(type == 2){ } else if (type == 2) {
//結賬單 //結賬單
bitmap = PrintUtils.getPrintBillBitmap(mContext); bitmap = PrintUtils.getPrintBillBitmap(mContext);
} else if (type == 3) {
//廚房單
List<Food> foods = CCUtil.getNavigateParam(this, "NewFoods", new ArrayList<>());
bitmap = PrintUtils.getKitChenPrintBitmap(mContext,foods);
} else { } else {
ToastUtils.show(mContext, "打印失敗"); ToastUtils.show(mContext, "打印失敗");
finish(); finish();
......
package com.gingersoft.gsa.cloud.base.adapter.print;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.gingersoft.gsa.cloud.base.R;
import com.gingersoft.gsa.cloud.database.bean.Food;
import java.util.List;
import androidx.annotation.Nullable;
/**
* Created by Wyh on 2020/2/20.
*/
public class KitChenPrintFoodAdapter extends BaseQuickAdapter<Food, BaseViewHolder> {
public KitChenPrintFoodAdapter(@Nullable List<Food> data) {
super(R.layout.print_kitchen_item_food, data);
}
@Override
protected void convert(BaseViewHolder helper, Food item) {
helper.setText(R.id.tv_food_number, item.getNumber() +"");
helper.setText(R.id.tv_food_name, item.getFoodName());
}
}
...@@ -21,6 +21,8 @@ public class GsaCloudApplication extends BaseApplication { ...@@ -21,6 +21,8 @@ public class GsaCloudApplication extends BaseApplication {
public static boolean isLogin = false; public static boolean isLogin = false;
public static String userName = "";
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
...@@ -32,7 +34,7 @@ public class GsaCloudApplication extends BaseApplication { ...@@ -32,7 +34,7 @@ public class GsaCloudApplication extends BaseApplication {
initGreenDao(); initGreenDao();
AppCrashHandler.getInstance().init(this,"test"); AppCrashHandler.getInstance().init(this, "test");
} }
...@@ -55,7 +57,6 @@ public class GsaCloudApplication extends BaseApplication { ...@@ -55,7 +57,6 @@ public class GsaCloudApplication extends BaseApplication {
} }
//获取登陆token //获取登陆token
public static String getLoginToken(Context context) { public static String getLoginToken(Context context) {
return (String) SPUtils.get(context, UserConstans.token, ""); return (String) SPUtils.get(context, UserConstans.token, "");
......
...@@ -10,6 +10,8 @@ import com.gingersoft.gsa.cloud.base.R; ...@@ -10,6 +10,8 @@ import com.gingersoft.gsa.cloud.base.R;
import com.gingersoft.gsa.cloud.base.adapter.print.BillAdapter; import com.gingersoft.gsa.cloud.base.adapter.print.BillAdapter;
import com.gingersoft.gsa.cloud.base.adapter.print.BillTypeAdapter; import com.gingersoft.gsa.cloud.base.adapter.print.BillTypeAdapter;
import com.gingersoft.gsa.cloud.base.adapter.print.FoodAdapter; import com.gingersoft.gsa.cloud.base.adapter.print.FoodAdapter;
import com.gingersoft.gsa.cloud.base.adapter.print.KitChenPrintFoodAdapter;
import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.base.common.bean.BillingBean; import com.gingersoft.gsa.cloud.base.common.bean.BillingBean;
import com.gingersoft.gsa.cloud.base.common.bean.TableBean; import com.gingersoft.gsa.cloud.base.common.bean.TableBean;
import com.gingersoft.gsa.cloud.base.common.bean.mealManage.MyOrderManage; import com.gingersoft.gsa.cloud.base.common.bean.mealManage.MyOrderManage;
...@@ -20,7 +22,9 @@ import com.gingersoft.gsa.cloud.base.utils.view.LayoutToBitmapUtils; ...@@ -20,7 +22,9 @@ import com.gingersoft.gsa.cloud.base.utils.view.LayoutToBitmapUtils;
import com.gingersoft.gsa.cloud.database.bean.Food; import com.gingersoft.gsa.cloud.database.bean.Food;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
...@@ -35,6 +39,7 @@ public class PrintUtils { ...@@ -35,6 +39,7 @@ public class PrintUtils {
public static Bitmap getPrintBitmap(Context context) { public static Bitmap getPrintBitmap(Context context) {
return getPrintBitmap(context, MyOrderManage.getInstance().getOrderFoodList()); return getPrintBitmap(context, MyOrderManage.getInstance().getOrderFoodList());
} }
/** /**
* 獲取"印單"圖片 * 獲取"印單"圖片
* *
...@@ -180,4 +185,50 @@ public class PrintUtils { ...@@ -180,4 +185,50 @@ public class PrintUtils {
//580為程序支持的打印紙最大寬度 //580為程序支持的打印紙最大寬度
return ImageUtils.zoomDrawable(LayoutToBitmapUtils.loadBitmapFromView(view), 580);//将view轉bitmap return ImageUtils.zoomDrawable(LayoutToBitmapUtils.loadBitmapFromView(view), 580);//将view轉bitmap
} }
/**
* 獲取"廚房單"圖片
*
* @param context
* @return
*/
public static Bitmap getKitChenPrintBitmap(Context context, List<Food> foodList) {
View view = LinearLayout.inflate(context, R.layout.print_kitchen, null);
TextView tvTableNumber = view.findViewById(R.id.tv_kitchen_print_table_number);
TextView tvOpeningTime = view.findViewById(R.id.tv_opening_time);
TextView tvOrderTime = view.findViewById(R.id.tv_order_time);
TextView tvKitChenLocation = view.findViewById(R.id.tv_kitchen_location);
TextView tvPeople = view.findViewById(R.id.tv_people);
TextView tvOperator = view.findViewById(R.id.tv_operator);
RecyclerView rvFood = view.findViewById(R.id.rv_kitchen_food);
TextView tvTableNumber2 = view.findViewById(R.id.tv_kitchen_print_table_number2);
if(foodList != null && foodList.size() > 0) {
KitChenPrintFoodAdapter foodAdapter = new KitChenPrintFoodAdapter(foodList);
rvFood.setLayoutManager(new LinearLayoutManager(context));
rvFood.setAdapter(foodAdapter);
//廚房位置
tvKitChenLocation.setText(foodList.get(0).getPrintseting());
}
if (OpenTableContract.getDefault().getTableBean() != null) {
// 台號
tvTableNumber.setText(OpenTableContract.getDefault().getTableBean().getTableName() + "");
tvTableNumber2.setText(OpenTableContract.getDefault().getTableBean().getTableName() + "");
//人數
tvPeople.setText(OpenTableContract.getDefault().getTableBean().getPeopleNumber() + "");
//開台時間
Date time = new Date(OpenTableContract.getDefault().getTableBean().getCreateTime());
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
tvOpeningTime.setText(sdf.format(time));
}
//落單時間
tvOrderTime.setText(TimeUtils.getCurrentTimeInString(TimeUtils.DEFAULT_DATE_MDHM));
//操作人員
tvOperator.setText(GsaCloudApplication.userName);
LayoutToBitmapUtils.layoutView(context, view);//先测量view
//580為程序支持的打印紙最大寬度
return ImageUtils.zoomDrawable(LayoutToBitmapUtils.loadBitmapFromView(view), 580);//将view轉bitmap
}
} }
...@@ -16,6 +16,9 @@ public class TimeUtils { ...@@ -16,6 +16,9 @@ public class TimeUtils {
public static final SimpleDateFormat DATE_FORMAT_DATE = new SimpleDateFormat("yyyy-MM-dd"); public static final SimpleDateFormat DATE_FORMAT_DATE = new SimpleDateFormat("yyyy-MM-dd");
public static final SimpleDateFormat DATE_FORMAT_DATE1 = new SimpleDateFormat( public static final SimpleDateFormat DATE_FORMAT_DATE1 = new SimpleDateFormat(
"HH:mm"); "HH:mm");
public static final SimpleDateFormat DEFAULT_DATE_MDHM = new SimpleDateFormat("MM-dd HH:mm");//, Locale.CHINESE
/** /**
* 时间日期格式化到年月日. * 时间日期格式化到年月日.
*/ */
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--廚房單-->
<!-- 台號-->
<TextView
android:id="@+id/tv_kitchen_print_table_number"
style="@style/Print_large_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="19" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/dp_10">
<TextView
android:id="@+id/tv_opening_time_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開檯時間:"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_opening_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="01-04 18:32"
app:layout_constraintLeft_toRightOf="@id/tv_opening_time_text"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_order_time_text"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="落單時間:"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_opening_time_text" />
<TextView
android:id="@+id/tv_order_time"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="01-04 19:32"
app:layout_constraintLeft_toRightOf="@id/tv_order_time_text"
app:layout_constraintTop_toBottomOf="@id/tv_opening_time_text" />
<TextView
android:id="@+id/tv_kitchen_location"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:text="K1 廚房"
app:layout_constraintLeft_toRightOf="@id/tv_order_time"
app:layout_constraintTop_toTopOf="@id/tv_order_time" />
<TextView
android:id="@+id/tv_people_text"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="人數:"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_order_time_text" />
<TextView
android:id="@+id/tv_people"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10"
app:layout_constraintBottom_toBottomOf="@id/tv_people_text"
app:layout_constraintLeft_toRightOf="@id/tv_people_text"
app:layout_constraintTop_toTopOf="@id/tv_people_text" />
<TextView
android:id="@+id/tv_operator"
style="@style/Print_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="gsadmin"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_people" />
<TextView
android:id="@+id/line_kitchen_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="——————————————————————————————————————————————————"
app:layout_constraintTop_toBottomOf="@id/tv_people_text" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_kitchen_food"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@id/line_kitchen_info" />
<TextView
android:id="@+id/tv_kitchen_print_table_number2"
style="@style/Print_large_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="19"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_kitchen_food" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_food_number"
style="@style/Print_large_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:gravity="center"
android:text="1" />
<TextView
android:id="@+id/tv_food_name"
style="@style/Print_large_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:text="秘製火鍋雞" />
</LinearLayout>
\ No newline at end of file
...@@ -13,6 +13,11 @@ ...@@ -13,6 +13,11 @@
</style> </style>
<style name="Print_text_style"> <style name="Print_text_style">
<item name="android:textColor">#333</item> <item name="android:textColor">#333</item>
<item name="android:textSize">30sp</item> <item name="android:textSize">24sp</item>
</style>
<style name="Print_large_text_style">
<item name="android:textColor">#333</item>
<item name="android:textSize">35sp</item>
</style> </style>
</resources> </resources>
...@@ -6,6 +6,8 @@ import org.greenrobot.greendao.annotation.Id; ...@@ -6,6 +6,8 @@ import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Transient; import org.greenrobot.greendao.annotation.Transient;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
/** /**
* 作者:ELEGANT_BIN * 作者:ELEGANT_BIN
* 版本:1.6.0 * 版本:1.6.0
...@@ -15,8 +17,9 @@ import org.jetbrains.annotations.NotNull; ...@@ -15,8 +17,9 @@ import org.jetbrains.annotations.NotNull;
*/ */
@Entity @Entity
public class Food { public class Food implements Serializable {
private static final long serialVersionUID = -3341972316262518814L;
@Id(autoincrement = true) @Id(autoincrement = true)
private Long id; private Long id;
private long orderId; private long orderId;
...@@ -31,6 +34,8 @@ public class Food { ...@@ -31,6 +34,8 @@ public class Food {
private int isSold; private int isSold;
private String plu; private String plu;
private double lunchboxPrice; private double lunchboxPrice;
private String printseting;//打印設定,用逗號分隔,*=切紙
/** /**
* 自定義字段 * 自定義字段
*/ */
...@@ -74,9 +79,9 @@ public class Food { ...@@ -74,9 +79,9 @@ public class Food {
this.number = 1; this.number = 1;
} }
@Generated(hash = 55791116) @Generated(hash = 449660732)
public Food(Long id, long orderId, int parentId, String foodName, int restaurantId, double price, int totalSold, public Food(Long id, long orderId, int parentId, String foodName, int restaurantId, double price, int totalSold,
int isSold, String plu, double lunchboxPrice) { int isSold, String plu, double lunchboxPrice, String printseting) {
this.id = id; this.id = id;
this.orderId = orderId; this.orderId = orderId;
this.parentId = parentId; this.parentId = parentId;
...@@ -87,6 +92,7 @@ public class Food { ...@@ -87,6 +92,7 @@ public class Food {
this.isSold = isSold; this.isSold = isSold;
this.plu = plu; this.plu = plu;
this.lunchboxPrice = lunchboxPrice; this.lunchboxPrice = lunchboxPrice;
this.printseting = printseting;
} }
public double getLunchboxPrice() { public double getLunchboxPrice() {
...@@ -117,6 +123,14 @@ public class Food { ...@@ -117,6 +123,14 @@ public class Food {
return number; return number;
} }
public String getPrintseting() {
return printseting;
}
public void setPrintseting(String printseting) {
this.printseting = printseting;
}
public void setNumber(int number) { public void setNumber(int number) {
this.number = number; this.number = number;
} }
......
...@@ -34,6 +34,7 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -34,6 +34,7 @@ public class FoodDao extends AbstractDao<Food, Long> {
public final static Property IsSold = new Property(7, int.class, "isSold", false, "IS_SOLD"); public final static Property IsSold = new Property(7, int.class, "isSold", false, "IS_SOLD");
public final static Property Plu = new Property(8, String.class, "plu", false, "PLU"); public final static Property Plu = new Property(8, String.class, "plu", false, "PLU");
public final static Property LunchboxPrice = new Property(9, double.class, "lunchboxPrice", false, "LUNCHBOX_PRICE"); public final static Property LunchboxPrice = new Property(9, double.class, "lunchboxPrice", false, "LUNCHBOX_PRICE");
public final static Property Printseting = new Property(10, String.class, "printseting", false, "PRINTSETING");
} }
...@@ -58,7 +59,8 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -58,7 +59,8 @@ public class FoodDao extends AbstractDao<Food, Long> {
"\"TOTAL_SOLD\" INTEGER NOT NULL ," + // 6: totalSold "\"TOTAL_SOLD\" INTEGER NOT NULL ," + // 6: totalSold
"\"IS_SOLD\" INTEGER NOT NULL ," + // 7: isSold "\"IS_SOLD\" INTEGER NOT NULL ," + // 7: isSold
"\"PLU\" TEXT," + // 8: plu "\"PLU\" TEXT," + // 8: plu
"\"LUNCHBOX_PRICE\" REAL NOT NULL );"); // 9: lunchboxPrice "\"LUNCHBOX_PRICE\" REAL NOT NULL ," + // 9: lunchboxPrice
"\"PRINTSETING\" TEXT);"); // 10: printseting
} }
/** Drops the underlying database table. */ /** Drops the underlying database table. */
...@@ -92,6 +94,11 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -92,6 +94,11 @@ public class FoodDao extends AbstractDao<Food, Long> {
stmt.bindString(9, plu); stmt.bindString(9, plu);
} }
stmt.bindDouble(10, entity.getLunchboxPrice()); stmt.bindDouble(10, entity.getLunchboxPrice());
String printseting = entity.getPrintseting();
if (printseting != null) {
stmt.bindString(11, printseting);
}
} }
@Override @Override
...@@ -119,6 +126,11 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -119,6 +126,11 @@ public class FoodDao extends AbstractDao<Food, Long> {
stmt.bindString(9, plu); stmt.bindString(9, plu);
} }
stmt.bindDouble(10, entity.getLunchboxPrice()); stmt.bindDouble(10, entity.getLunchboxPrice());
String printseting = entity.getPrintseting();
if (printseting != null) {
stmt.bindString(11, printseting);
}
} }
@Override @Override
...@@ -138,7 +150,8 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -138,7 +150,8 @@ public class FoodDao extends AbstractDao<Food, Long> {
cursor.getInt(offset + 6), // totalSold cursor.getInt(offset + 6), // totalSold
cursor.getInt(offset + 7), // isSold cursor.getInt(offset + 7), // isSold
cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8), // plu cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8), // plu
cursor.getDouble(offset + 9) // lunchboxPrice cursor.getDouble(offset + 9), // lunchboxPrice
cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10) // printseting
); );
return entity; return entity;
} }
...@@ -155,6 +168,7 @@ public class FoodDao extends AbstractDao<Food, Long> { ...@@ -155,6 +168,7 @@ public class FoodDao extends AbstractDao<Food, Long> {
entity.setIsSold(cursor.getInt(offset + 7)); entity.setIsSold(cursor.getInt(offset + 7));
entity.setPlu(cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8)); entity.setPlu(cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8));
entity.setLunchboxPrice(cursor.getDouble(offset + 9)); entity.setLunchboxPrice(cursor.getDouble(offset + 9));
entity.setPrintseting(cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10));
} }
@Override @Override
......
...@@ -37,5 +37,5 @@ android { ...@@ -37,5 +37,5 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.github.hackware1993:MagicIndicator:1.5.0' implementation 'com.github.hackware1993:MagicIndicator:1.5.0'
implementation 'io.github.meetsl:SCardView:1.0'
} }
...@@ -11,6 +11,12 @@ ...@@ -11,6 +11,12 @@
<!-- <color name="theme_color">#BF1C42</color>--> <!-- <color name="theme_color">#BF1C42</color>-->
<color name="theme_color">#0099CC</color> <color name="theme_color">#0099CC</color>
<color name="normal_color">#333333</color> <color name="normal_color">#333333</color>
<!-- 首页报表“昨日”线条颜色-->
<color name="today_line">#FFCC8F</color>
<!-- 報表虛線顏色-->
<color name="report_dotted_line_color">#8CA0B3</color>
<!-- 報表左側刻度文字顏色-->
<color name="report_left_scale">#777</color>
<color name="theme_white_color">#FFFFFFFF</color> <color name="theme_white_color">#FFFFFFFF</color>
<color name="theme_333_color">#333</color> <color name="theme_333_color">#333</color>
......
...@@ -15,5 +15,6 @@ include 'cc-register', ...@@ -15,5 +15,6 @@ include 'cc-register',
'table-mode', 'table-mode',
'demo_interceptors', 'demo_interceptors',
'print-module', 'print-module',
'chart',
rootProject.name = 'GSA-Cloud' , 'pools' rootProject.name = 'GSA-Cloud' , 'pools'
...@@ -257,12 +257,14 @@ public class MealStandPresenter extends BasePresenter<MealStandContract.Model, M ...@@ -257,12 +257,14 @@ public class MealStandPresenter extends BasePresenter<MealStandContract.Model, M
/** /**
* 打印上菜紙 * 打印上菜紙
* 打印廚房單
*/ */
private void printSendOrder(List<Food> newFoods) { private void printSendOrder(List<Food> newFoods) {
//打印廚房單
CC.obtainBuilder("Component.Print") CC.obtainBuilder("Component.Print")
.setActionName("printActivity") .setActionName("printActivity")
.addParam("NewFoods", newFoods) .addParam("NewFoods", newFoods)
.addParam("type", 0) .addParam("type", 3)
.build() .build()
.callAsync((cc, result) -> { .callAsync((cc, result) -> {
if (result.isSuccess()) { if (result.isSuccess()) {
...@@ -270,6 +272,20 @@ public class MealStandPresenter extends BasePresenter<MealStandContract.Model, M ...@@ -270,6 +272,20 @@ public class MealStandPresenter extends BasePresenter<MealStandContract.Model, M
mRootView.killMyself(); mRootView.killMyself();
} }
}); });
//打印上菜紙
// CC.obtainBuilder("Component.Print")
// .setActionName("printActivity")
// .addParam("NewFoods", newFoods)
// .addParam("type", 0)
// .build()
// .callAsync((cc, result) -> {
// if (result.isSuccess()) {
// //打印成功
// mRootView.killMyself();
// }
// });
} }
public void deleteFood(long id) { public void deleteFood(long id) {
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gingersoft.gsa.cloud.user.login"> package="com.gingersoft.gsa.cloud.user.login">
<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" /> <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/user_login_name" android:label="@string/user_login_name"
tools:replace="android:label"
android:networkSecurityConfig="@xml/network_android" android:networkSecurityConfig="@xml/network_android"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gingersoft.gsa.cloud.user.login"> package="com.gingersoft.gsa.cloud.user.login">
<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" /> <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/user_login_name" android:label="@string/user_login_name"
tools:replace="android:label"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
......
...@@ -92,9 +92,9 @@ public class LoginPresenter extends BasePresenter<LoginContract.Model, LoginCont ...@@ -92,9 +92,9 @@ public class LoginPresenter extends BasePresenter<LoginContract.Model, LoginCont
@Override @Override
public void onNext(@NonNull LoginBean info) { public void onNext(@NonNull LoginBean info) {
Log.e("login", "" + info);
if (info != null && info.isSuccess()) { if (info != null && info.isSuccess()) {
GsaCloudApplication.isLogin = true; GsaCloudApplication.isLogin = true;
GsaCloudApplication.userName = info.getData().getUser().getUserName();
mRootView.showMessage("登陸成功"); mRootView.showMessage("登陸成功");
mRootView.loginSuccess(info); mRootView.loginSuccess(info);
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment