/** * 计算同标签多柱形时的X分隔 * * @param XSteps X轴步长 * @param barNumber 柱形个数 * @return 返回单个柱形的宽度及间距 */ protected List<Float> calcBarWidthAndMargin(float XSteps, int barNumber) { /* int labelBarTotalWidth = (int) Math.round(XSteps * 0.9); int barTotalInnerMargin = (int) Math.round(labelBarTotalWidth * mBarInnerMargin); int barTotalWidth = labelBarTotalWidth - barTotalInnerMargin; int barInnerMargin = barTotalInnerMargin / barNumber; int barWidth = barTotalWidth / barNumber; */ float labelBarTotalWidth = MathHelper.getInstance().mul(XSteps, 0.9f); float barTotalInnerMargin = MathHelper.getInstance().mul(labelBarTotalWidth, (float) mBarInnerMargin); float barTotalWidth = MathHelper.getInstance().sub(labelBarTotalWidth, barTotalInnerMargin); float barInnerMargin = MathHelper.getInstance().div(barTotalInnerMargin, barNumber); float barWidth = MathHelper.getInstance().div(barTotalWidth, barNumber); List<Float> ret = new LinkedList<Float>(); ret.add(barWidth); ret.add(barInnerMargin); return ret; }
/** 绘制key */ protected void renderKey(Canvas canvas) { if (!getKeyVisible()) return; DrawHelper dw = new DrawHelper(); float textHeight = dw.getPaintFontHeight(getKeyPaint()); float rectWidth = 2 * textHeight; float currentX = 0.0f; float currentY = 0.0f; if (!isVerticalScreen()) // 横屏 { getKeyPaint().setTextAlign(Align.RIGHT); currentX = plotArea.getRight(); currentY = this.plotArea.getTop() + textHeight; } else { getKeyPaint().setTextAlign(Align.LEFT); currentX = plotArea.getLeft(); currentY = this.plotArea.getBottom(); } int totalTextWidth = 0; for (RadarData cData : mDataSet) { getKeyPaint().setColor(cData.getLineColor()); if (!isVerticalScreen()) // 横屏 { canvas.drawRect( currentX, currentY, currentX - rectWidth, currentY - textHeight, getKeyPaint()); canvas.drawText(cData.getLineKey(), currentX - rectWidth, currentY, getKeyPaint()); currentY = MathHelper.getInstance().add(currentY, textHeight); } else { // 竖屏 int keyTextWidth = dw.getTextWidth(getKeyPaint(), cData.getLineKey()); totalTextWidth += keyTextWidth; if (totalTextWidth > plotArea.getWidth()) { currentY += textHeight; currentX = plotArea.getLeft(); totalTextWidth = 0; } canvas.drawRect( currentX, currentY, currentX + rectWidth, currentY - textHeight, getKeyPaint()); canvas.drawText(cData.getLineKey(), currentX + rectWidth, currentY, getKeyPaint()); currentX = MathHelper.getInstance().add(currentX, rectWidth + keyTextWidth + 5); } } }
/** * 绘制数据区网络 * * @param canvas 画布 */ private void renderDataArea(Canvas canvas) { float cirX = plotArea.getCenterX(); float cirY = plotArea.getCenterY(); for (RadarData lineData : mDataSet) { // 画各自的网 List<Double> dataset = lineData.getLinePoint(); int dataSize = dataset.size(); if (dataSize < 3) { Log.e(TAG, "这几个数据可不够,最少三个起步."); continue; } Float[] arrayDataX = new Float[dataSize]; Float[] arrayDataY = new Float[dataSize]; int i = 0; for (Double data : dataset) { Double per = (data - dataAxis.getAxisMin()) / dataAxis.getAxisRange(); float curRadius = (float) (getRadius() * per); // 计算位置 MathHelper.getInstance().calcArcEndPointXY(cirX, cirY, curRadius, mArrayLabelAgent[i]); // 依Path还是Line来决定画线风格 arrayDataX[i] = MathHelper.getInstance().getPosX(); arrayDataY[i] = MathHelper.getInstance().getPosY(); i++; // 标签 } // 画线或填充 switch (lineData.getAreaStyle()) { case FILL: drawDataPath(canvas, lineData, arrayDataX, arrayDataY); break; case STROKE: renderDataLine(canvas, lineData, arrayDataX, arrayDataY); break; default: Log.e(TAG, "这类型不认识."); } } }
/** * 计算同标签多柱形时的Y分隔 * * @param YSteps Y轴步长 * @param barNumber 柱形个数 * @return 返回单个柱形的高度及间距 */ protected List<Float> calcBarHeightAndMargin(float YSteps, int barNumber) { /* int labelBarTotalHeight = (int) Math.round(YSteps * 0.9); int barTotalInnerMargin = (int) Math.round(labelBarTotalHeight * mBarInnerMargin); int barInnerMargin = barTotalInnerMargin / barNumber; int barHeight = (labelBarTotalHeight - barTotalInnerMargin) / barNumber; */ float labelBarTotalHeight = MathHelper.getInstance().mul(YSteps, 0.9f); float barTotalInnerMargin = MathHelper.getInstance().mul(labelBarTotalHeight, (float) mBarInnerMargin); float barInnerMargin = MathHelper.getInstance().div(barTotalInnerMargin, barNumber); float barHeight = MathHelper.getInstance() .div(MathHelper.getInstance().sub(labelBarTotalHeight, barTotalInnerMargin), barNumber); List<Float> ret = new LinkedList<Float>(); ret.add(barHeight); ret.add(barInnerMargin); return ret; }
/** * 将百分比转换为饼图显示角度 * * @return 圆心角度 */ public float getSliceAgent() { float agent = 0.0f; try { float currentValue = (float) this.getPercentage(); if (currentValue >= 101f || currentValue < 0.0f) { Log.e(TAG, "输入的百分比不合规范.须在0~100之间."); } else { // agent = (float) Math.rint( 360f * (currentValue / 100f) ); agent = MathHelper.getInstance().round(360f * (currentValue / 100f), 2); } } catch (Exception ex) { agent = -1f; } finally { } return agent; }
public PointF renderLabelLine( String text, float itemAngle, float cirX, float cirY, float radius, float calcAngle, Canvas canvas, Paint paintLabel, boolean showLabel, PlotLabelRender plotLabel) { float pointRadius = 0.0f; if (getLinePointStyle() == XEnum.LabelLinePoint.END || getLinePointStyle() == XEnum.LabelLinePoint.ALL) pointRadius = getRadius(); // 显示在扇形的外部 // 1/4处为起始点 float calcRadius = MathHelper.getInstance().sub(radius, radius / mBrokenStartPoint); MathHelper.getInstance().calcArcEndPointXY(cirX, cirY, calcRadius, calcAngle); float startX = MathHelper.getInstance().getPosX(); float startY = MathHelper.getInstance().getPosY(); // 延长原来半径的一半在外面 calcRadius = radius / 2f; MathHelper.getInstance().calcArcEndPointXY(startX, startY, calcRadius, calcAngle); float stopX = MathHelper.getInstance().getPosX(); float stopY = MathHelper.getInstance().getPosY(); float borkenline = getBrokenLine(); // 折线长度 float endX = 0.0f, endLabelX = 0.0f; if (Float.compare(stopX, cirX) == 0) { // 位于中间竖线上 if (Float.compare(stopY, cirY) == 1) // 中点上方,左折线 { paintLabel.setTextAlign(Align.LEFT); endX = stopX + borkenline; // + pointRadius; endLabelX = endX + pointRadius; } else { // 中点下方,右折线 paintLabel.setTextAlign(Align.RIGHT); endX = stopX - borkenline; endLabelX = endX - pointRadius; } } else if (Float.compare(stopY, cirY) == 0) { // 中线横向两端 endX = stopX; if (Float.compare(stopX, cirX) == 0 || Float.compare(stopX, cirX) == -1) // 左边 { paintLabel.setTextAlign(Align.RIGHT); endLabelX = endX - pointRadius; } else { paintLabel.setTextAlign(Align.LEFT); endLabelX = endX + pointRadius; } } else if (Float.compare(stopX + borkenline, cirX) == 1) // 右边 { paintLabel.setTextAlign(Align.LEFT); endX = stopX + borkenline; endLabelX = endX + pointRadius; } else if (Float.compare(stopX - borkenline, cirX) == -1) // 左边 { paintLabel.setTextAlign(Align.RIGHT); endX = stopX - borkenline; endLabelX = endX - pointRadius; } else { endLabelX = endX = stopX; paintLabel.setTextAlign(Align.CENTER); } if (mIsBZLine) { // 绘制贝塞尔曲线 drawBZLine(startX, startY, stopX, stopY, endX, canvas); } else { // 转折线 drawBrokenLine(startX, startY, stopX, stopY, endX, canvas); } // 标签点NONE,BEGIN,END,ALL drawPoint(startX, startY, stopX, stopY, endX, pointRadius, canvas); if (showLabel) // 标签 { if (null == plotLabel) { DrawHelper.getInstance() .drawRotateText(text, endLabelX, stopY, itemAngle, canvas, paintLabel); } else { plotLabel.drawLabel(canvas, paintLabel, text, endLabelX, stopY, itemAngle); } } return (new PointF(endLabelX, stopY)); }
/** 得到所有相关的交叉点坐标 */ private void calcAllPoint() { float cirX = plotArea.getCenterX(); float cirY = plotArea.getCenterY(); // 标签个数决定角的个数 int labelsCount = getPlotAgentNumber(); // 轴线tick总数 int dataAxisTickCount = getAxisTickCount(); // 扇形角度,依标签个数决定 float pAngle = MathHelper.getInstance().div(360f, labelsCount); // 72f; // 270为中轴线所处圆心角 float initOffsetAgent = MathHelper.getInstance().sub(270f, pAngle); // 依标签总个数算出环数,依数据刻度数决定 float avgRadius = MathHelper.getInstance().div(getRadius(), (dataAxisTickCount - 1)); // 当前半径 float curRadius = 0.0f; // 当前圆心角偏移量 float offsetAgent = 0.0f; // 坐标与圆心角 mArrayDotX = new Float[dataAxisTickCount][labelsCount]; mArrayDotY = new Float[dataAxisTickCount][labelsCount]; mArrayLabelAgent = new Float[labelsCount]; mArrayLabelX = new Float[dataAxisTickCount][labelsCount]; mArrayLabelY = new Float[dataAxisTickCount][labelsCount]; int labelHeight = DrawHelper.getInstance().getPaintFontHeight(getLabelPaint()); float labelRadius = this.getRadius() + labelHeight; float currAgent = 0.0f; for (int i = 0; i < dataAxisTickCount; i++) // 数据轴 { curRadius = avgRadius * i; // 当前半径长度,依此算出各节点坐标 for (int j = 0; j < labelsCount; j++) { offsetAgent = MathHelper.getInstance().add(initOffsetAgent, pAngle * j); currAgent = MathHelper.getInstance().add(offsetAgent, pAngle); // 计算位置 MathHelper.getInstance().calcArcEndPointXY(cirX, cirY, curRadius, currAgent); // 点的位置 mArrayDotX[i][j] = MathHelper.getInstance().getPosX(); mArrayDotY[i][j] = MathHelper.getInstance().getPosY(); // 记下每个标签对应的圆心角 if (0 == i) mArrayLabelAgent[j] = currAgent; // 外围标签位置 MathHelper.getInstance().calcArcEndPointXY(cirX, cirY, labelRadius, currAgent); mArrayLabelX[i][j] = MathHelper.getInstance().getPosX(); mArrayLabelY[i][j] = MathHelper.getInstance().getPosY(); } // end for labelCount } // end for datacount }
@Override protected boolean renderPlot(Canvas canvas) { // 数据源 List<PieData> chartDataSource = this.getDataSource(); if (null == chartDataSource) { Log.e(TAG, "数据源为空."); return false; } // 计算中心点坐标 float cirX = plotArea.getCenterX(); float cirY = plotArea.getCenterY(); float radius = getRadius(); // 确定去饼图范围 float arcLeft = sub(cirX, radius); float arcTop = sub(cirY, radius); float arcRight = add(cirX, radius); float arcBottom = add(cirY, radius); RectF arcRF0 = new RectF(arcLeft, arcTop, arcRight, arcBottom); // 画笔初始化 Paint paintArc = new Paint(); paintArc.setAntiAlias(true); float initOffsetAngle = mOffsetAngle; float offsetAngle = initOffsetAngle; // 3D float currentAngle = 0.0f; for (int i = 0; i < mRender3DLevel; i++) { canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.translate(0, mRender3DLevel - i); for (int j = 0; j < chartDataSource.size(); j++) { PieData cData = chartDataSource.get(j); paintArc.setColor(cData.getSliceColor()); currentAngle = cData.getSliceAngle(); if (Float.compare(currentAngle, 0.0f) == 0 || Float.compare(currentAngle, 0.0f) == -1) continue; if (cData.getSelected()) // 指定突出哪个块 { // 偏移圆心点位置(默认偏移半径的1/10) float newRadius = div(radius, SELECTED_OFFSET); // 计算百分比标签 MathHelper.getInstance() .calcArcEndPointXY(cirX, cirY, newRadius, add(offsetAngle, div(currentAngle, 2f))); float arcLeft2 = sub(MathHelper.getInstance().getPosX(), radius); float arcTop2 = sub(MathHelper.getInstance().getPosY(), radius); float arcRight2 = add(MathHelper.getInstance().getPosX(), radius); float arcBottom2 = add(MathHelper.getInstance().getPosY(), radius); RectF arcRF1 = new RectF(arcLeft2, arcTop2, arcRight2, arcBottom2); canvas.drawArc(arcRF1, offsetAngle, currentAngle, true, paintArc); } else { canvas.drawArc(arcRF0, offsetAngle, currentAngle, true, paintArc); } // 下次的起始角度 offsetAngle = add(offsetAngle, currentAngle); // k += 2; } canvas.restore(); offsetAngle = initOffsetAngle; } // 平面 currentAngle = 0.0f; offsetAngle = initOffsetAngle; for (int j = 0; j < chartDataSource.size(); j++) { PieData cData = chartDataSource.get(j); currentAngle = cData.getSliceAngle(); int darkColor = DrawHelper.getInstance().getDarkerColor((int) cData.getSliceColor()); paintArc.setColor(darkColor); if (cData.getSelected()) // 指定突出哪个块 { // 偏移圆心点位置(默认偏移半径的1/10) float newRadius = div(radius, SELECTED_OFFSET); // 计算百分比标签 MathHelper.getInstance() .calcArcEndPointXY(cirX, cirY, newRadius, add(offsetAngle, div(currentAngle, 2f))); float arcLeft2 = sub(MathHelper.getInstance().getPosX(), radius); float arcTop2 = sub(MathHelper.getInstance().getPosY(), radius); float arcRight2 = add(MathHelper.getInstance().getPosX(), radius); float arcBottom2 = add(MathHelper.getInstance().getPosY(), radius); RectF arcRF1 = new RectF(arcLeft2, arcTop2, arcRight2, arcBottom2); canvas.drawArc(arcRF1, offsetAngle, (float) currentAngle, true, paintArc); renderLabel( canvas, cData.getLabel(), MathHelper.getInstance().getPosX(), MathHelper.getInstance().getPosY(), radius, offsetAngle, currentAngle); } else { canvas.drawArc(arcRF0, offsetAngle, (float) currentAngle, true, paintArc); renderLabel(canvas, cData.getLabel(), cirX, cirY, radius, offsetAngle, currentAngle); } // 保存角度 saveArcRecord(j, cirX, cirY, radius, offsetAngle, currentAngle); // 下次的起始角度 offsetAngle = add(offsetAngle, currentAngle); } // 图KEY plotLegend.renderPieKey(canvas, this.getDataSource()); return true; }