package com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.render; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Entry; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Line; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.data.Lines; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.manager.MappingManager; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.model.HighLight; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.SingleF_XY; import com.mm.android.deviceaddmodule.mobilecommon.widget.linechart.utils.Utils; public class HighLightRender extends BaseRender { private final static double UN_CHOOSE = Double.MIN_VALUE; Lines _lines; HighLight _highLight; Paint paintHighLight; Paint paintCircle; Paint paintHint; Context context; private enum DIRECTION{TOP, LEFT, BOTTOM, RIGHT} boolean TAG = false; public HighLightRender(Context context, RectF rectMain, MappingManager _MappingManager, Lines lines, HighLight highLight) { super(rectMain, _MappingManager); this._lines = lines; this._highLight = highLight; this.context = context; paintHighLight = new Paint(Paint.ANTI_ALIAS_FLAG); paintHint = new Paint(Paint.ANTI_ALIAS_FLAG); paintCircle = new Paint(Paint.ANTI_ALIAS_FLAG); } double highValueX = UN_CHOOSE; double hightValueY = UN_CHOOSE; int record_LineIndex = -1;// 记录哪条线 int record_EntryIndex = -1;// 记录哪条entry boolean isClick = false; public void highLight_ValueXY(double x, double y) { highValueX = x; hightValueY = y; isClick = true; } public void highLightLeft() { record_EntryIndex--; } public void highLightRight() { record_EntryIndex++; } public void render(Canvas canvas) { if (!_highLight.isEnable()) { return; } if (_lines == null) { return; } if (_lines.getLines().size() == 0) { return; } if (highValueX == UN_CHOOSE || hightValueY == UN_CHOOSE) { return; } // if (TAG) { // canvas.save(); // canvas.drawText("", 0, 0, new Paint()); // canvas.restore(); // TAG = false; // } else { canvas.save(); // canvas.clipRect(_rectMain); // 限制绘制区域 RectF rectF = new RectF(_rectMain); rectF.top = _rectMain.top - 100; rectF.bottom = _rectMain.bottom + 100; canvas.clipRect(rectF); // 限制绘制区域 drawHighLight_Hint(canvas); canvas.restore(); // } } private void drawHighLight_Hint(Canvas canvas) { double closeX = Double.MAX_VALUE; double closeY = Double.MAX_VALUE; Entry hitEntry = null; if (isClick) { // 点击光标进来的 int tempIndexEntry = -1; int tempLineIndex = -1; for (int i = 0; i < _lines.getLines().size(); i++) { Line line = _lines.getLines().get(i); if (!line.isEnable()) { continue; } int indexEntry = Line.getEntryIndex(line.getEntries(), highValueX, Line.Rounding.CLOSEST); if (indexEntry < 0 || indexEntry >= line.getEntries().size()) { continue; } Entry entry = line.getEntries().get(indexEntry); // 到点击的距离 double dx = Math.abs(entry.getX() - highValueX); double dy = Math.abs(entry.getY() - hightValueY); // 先考虑 x if (dx <= closeX) { closeX = dx; // 再考虑 y if (dy <= closeY) { closeY = dy; hitEntry = entry; tempIndexEntry = indexEntry; tempLineIndex = i; } } } if (record_EntryIndex == tempIndexEntry && record_LineIndex == tempLineIndex){ //点击的是同一个点,重置掉 record_LineIndex = -1; record_EntryIndex = -1; isClick = false; return; }else { record_EntryIndex = tempIndexEntry; record_LineIndex = tempLineIndex; } } else { // 左右移动进来的 try { Line line = _lines.getLines().get(record_LineIndex); if (line.isEnable()) { hitEntry = line.getEntries().get(record_EntryIndex); } } catch (Exception e) { hitEntry = null; } } if (hitEntry == null) { return; } // 考虑断掉的点 if (hitEntry.isNull_Y()) { return; } highValueX = hitEntry.getX();// real indexX SingleF_XY xy = _MappingManager.getPxByEntry(hitEntry); // draw high line if (_highLight.isDrawHighLine()) { //获取当前line的颜色,作为highLine的颜色 int lineSize = _lines.getLines().size(); Line line = lineSize > 0 && record_LineIndex < lineSize ? _lines.getLines().get(record_LineIndex) : null; int highLineColor = _highLight.getHighLightColor(); if (highLineColor == 0 && line != null) { highLineColor = line.getLineColor(); } //DRAW ROUND RING PIC //mid white ring float hightLightwidth = _highLight.getHighLightWidth(); paintCircle.setStrokeWidth( (int) Utils.dp2px(0.8f) ); //the radius of inner ball is 3dp. white ring width is 2dp paintCircle.setColor(Color.WHITE); paintCircle.setStyle(Paint.Style.STROKE); canvas.drawCircle(xy.getX(), xy.getY(), (int)Utils.dp2px(2+0.8f), paintCircle); //outside color ring paintCircle.setStrokeWidth((int)Utils.dp2px(1)); //color ring width is 2dp paintCircle.setColor(highLineColor); paintCircle.setStyle(Paint.Style.STROKE); canvas.drawCircle(xy.getX(), xy.getY(), (int)Utils.dp2px(2+0.8f+1), paintCircle); //DRAW HIGH VERTICAL LINE paintHighLight.setStrokeWidth(_highLight.getHighLightWidth()); //气泡颜色暂时默认都设置成灰色,隐藏横竖定位线 // paintHighLight.setColor(highLineColor); // canvas.drawLine(_rectMain.left, xy.getY(), _rectMain.right, xy.getY(), paintHighLight); //绘制highLight横线 // canvas.drawLine(xy.getX(), _rectMain.top, xy.getX(), _rectMain.bottom, paintHighLight); //DRAW LC HINT //绘制气泡 Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setTextSize(Utils.sp2px(14)); paint.setAntiAlias(true); String xStr = _highLight.getxValueAdapter().value2String(hitEntry.getX()+1); //文字内容 String yStr = _highLight.getyValueAdapter().value2String(hitEntry.getY()) + "人"; //文字长度 float textLen = Math.max(paint.measureText(xStr), paint.measureText(yStr)); Paint.FontMetrics fm = paint.getFontMetrics(); float textHeight1 = Utils.textHeight(paint); paint.setTextSize(Utils.sp2px(12)); float textHeight2 = Utils.textHeight(paint); float triangleWidth = Utils.dp2px(8); //三角宽高 float trianglePadding = 0; //三角距离数据原点的间距 float rectWidth = Math.min(Utils.dp2px(100), textLen + Utils.dp2px(5)*2); //矩形宽度 float rectHeight = Utils.dp2px(4) * 3 + textHeight1 + textHeight2; //矩形高度 //判断气泡画在哪个方向,必须先判断Y轴方向 DIRECTION direction = DIRECTION.LEFT; if (xy.getY() - rectHeight/2 < 0){ direction = DIRECTION.BOTTOM; }else if (xy.getY() + rectHeight/2 > _rectMain.bottom){ direction = DIRECTION.TOP; }else if (xy.getX() - triangleWidth - trianglePadding - rectWidth > _rectMain.left){ direction = DIRECTION.LEFT; }else { direction = DIRECTION.RIGHT; } //画三角 Path path = new Path(); float triangleX; //三角指向圆圈的角的X float triangleY; //三角指向圆圈的角的Y float rectRight = 0; //矩形右边 float rectLeft = 0; //矩形左边 float rectTop = 0; //矩形上边 float rectBottom = 0; //矩形下边 float text1X = 0; float text1Y = 0; float text2X = 0; float text2Y = 0; switch(direction){ case TOP : //三角 triangleX = xy.getX(); triangleY = xy.getY() - triangleWidth - trianglePadding; path.moveTo(triangleX, triangleY); path.lineTo(triangleX - triangleWidth/2, triangleY - triangleWidth); path.lineTo(triangleX + triangleWidth/2, triangleY - triangleWidth); path.close(); //矩形 rectLeft = triangleX - rectWidth/2; rectRight = triangleX + rectWidth/2; rectTop = triangleY - triangleWidth - rectHeight; rectBottom = triangleY - triangleWidth; //文字 text1X = rectLeft + Utils.dp2px(5); text1Y = rectTop + rectHeight/2 - 14; text2X = rectLeft + Utils.dp2px(5); text2Y = rectTop + rectHeight/2 - 6; break; case BOTTOM : triangleX = xy.getX(); triangleY = xy.getY() + triangleWidth + trianglePadding; path.moveTo(triangleX, triangleY); path.lineTo(triangleX + triangleWidth/2, triangleY + triangleWidth); path.lineTo(triangleX - triangleWidth/2, triangleY + triangleWidth); path.close(); //矩形 rectLeft = triangleX - rectWidth/2; rectRight = triangleX + rectWidth/2; rectTop = triangleY + triangleWidth; rectBottom = triangleY + triangleWidth + rectHeight; //文字 text1X = rectLeft + Utils.dp2px(5); text1Y = rectTop + rectHeight/2 - 14; text2X = rectLeft + Utils.dp2px(5); text2Y = rectTop + rectHeight/2 - 6; break; case LEFT : triangleX = xy.getX() - triangleWidth - trianglePadding; triangleY = xy.getY(); path.moveTo(triangleX, triangleY); path.lineTo(triangleX - triangleWidth, triangleY + triangleWidth/2); path.lineTo(triangleX - triangleWidth, triangleY - triangleWidth/2); path.close(); //矩形 rectLeft = triangleX - triangleWidth - rectWidth; rectRight = triangleX - triangleWidth; rectTop = triangleY - rectHeight/2; rectBottom = triangleY + rectHeight/2; //文字 text1X = rectLeft + Utils.dp2px(5); text1Y = triangleY - 14; text2X = rectLeft + Utils.dp2px(5); text2Y = triangleY - 6; break; case RIGHT : triangleX = xy.getX() + triangleWidth + trianglePadding; triangleY = xy.getY(); path.moveTo(triangleX, triangleY); path.lineTo(triangleX + triangleWidth, triangleY + triangleWidth/2); path.lineTo(triangleX + triangleWidth, triangleY - triangleWidth/2); path.close(); //矩形 rectLeft = triangleX + triangleWidth; rectRight = triangleX + triangleWidth + rectWidth; rectTop = triangleY - rectHeight/2; rectBottom = triangleY + rectHeight/2; //文字 text1X = rectLeft + Utils.dp2px(5); text1Y = triangleY - 14; text2X = rectLeft + Utils.dp2px(5); text2Y = triangleY - 6; break; default: break; } //气泡全部设置成灰色,外发光 paintHighLight.setARGB(229,73,73,73); // paintHighLight.setShadowLayer(20, 2, 2, Color.argb(229,98,98,98)); // paintHighLight.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID)); canvas.drawRect(rectLeft, rectTop, rectRight, rectBottom, paintHighLight); canvas.drawPath(path, paintHighLight); canvas.drawText(xStr, text1X, text1Y, paint); canvas.drawText(yStr, text2X, text2Y + textHeight1, paint); // paintHighLight.clearShadowLayer(); // paintHighLight.setMaskFilter(null); } // draw hint if (_highLight.isDrawHint()) { paintHint.setColor(_highLight.getHintColor()); paintHint.setTextSize(_highLight.getHintTextSize()); String xStr = _highLight.getxValueAdapter().value2String(hitEntry.getX()); String yStr = _highLight.getyValueAdapter().value2String(hitEntry.getY()); float txtHeight = Utils.textHeight(paintHint); float txtWidth = Math.max(Utils.textWidth(paintHint, xStr), Utils.textWidth(paintHint, yStr)); float x = _rectMain.right - txtWidth - 10; float y = _rectMain.top + Utils.dp2px(20); canvas.drawText(xStr, x, y, paintHint); canvas.drawText(yStr, x, y + txtHeight, paintHint); } // callback if (isClick) { isClick = false; Line line = _lines.getLines().get(record_LineIndex); hitEntry = line.getEntries().get(record_EntryIndex); Line.CallBack_OnEntryClick cb = line.getOnEntryClick(); if (cb != null) { cb.onEntry(line, hitEntry); } } } public void onDataChanged(Lines lines) { _lines = lines; } }