android - 如何使用 AndroidPlot 绘制圆角(平滑)线

标签 android androidplot

我在绘制图表时遇到了一个小问题。下面的图片是我已经完成的。


图表应表示可用 Wi-Fi 网络的实际信号强度。这是一个简单的 XYPlot,这里的数据用 SimpleXYSeries 表示(值是动态创建的)。

这是一小段代码(仅作为示例):

plot = (XYPlot) findViewById(R.id.simplexyPlot);
series1 = new SimpleXYSeries(Arrays.asList(series1Numbers),
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Link 1");
f1 = new LineAndPointFormatter(color.getColor(), null,
Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);

图中的例子是dB变化的动态模拟。我想一切正常,但我想要实现的是与“圆角”对齐(请参阅图片了解我的意思)。

我已经尝试自定义 LineFormatter:

f1.getFillPaint().setStrokeJoin(Join.ROUND);
f1.getFillPaint().setStrokeWidth(8);

但这并没有像预期的那样工作。

Enter image description here

注意:Wifi Analyzer应用程序有一个类似的图形,它的图形有我想要的圆角。它看起来像这样:

Enter image description here

最佳答案

您可以使用 Path.cubicTo()方法。它使用三次样条算法绘制一条线,从而产生您想要的平滑效果。

查看 similar question here 的答案,其中一个人在谈论三次样条。有一个简短的算法展示了如何为 Path.cubicTo() 方法计算输入参数。您可以使用分频器值来实现所需的平滑度。例如,在下图中我除以 5 而不是 3。希望这有帮助。

Example of a polylyne drawn using Path.cubicTo() method

我花了一些时间实现了一个 SplineAndPointFormatter 类,它可以完成您在 androidplot 库中需要的东西。它使用相同的技术。这是 androidplot 示例应用程序的样子。您只需要使用它来代替 LineAndPointFormatter

Androidplot example with SplineLineAndPointFormatter

这是代码示例和我编写的类。

f1 = new SplineLineAndPointFormatter(color.getColor(), null, 
      Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);

这是施展魔法的类(class)。它基于 androidplot 的 0.6.1 版图书馆。

package com.androidplot.xy;

import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;

import com.androidplot.ui.SeriesRenderer;
import com.androidplot.util.ValPixConverter;

public class SplineLineAndPointFormatter extends LineAndPointFormatter {

    public SplineLineAndPointFormatter() { }

    public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor) {
        super(lineColor, vertexColor, fillColor, null);
    }

    public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor, FillDirection fillDir) {
        super(lineColor, vertexColor, fillColor, null, fillDir);
    }

    @Override
    public Class<? extends SeriesRenderer> getRendererClass() {
        return SplineLineAndPointRenderer.class;
    }

    @Override
    public SeriesRenderer getRendererInstance(XYPlot plot) {
        return new SplineLineAndPointRenderer(plot);
    }

    public static class SplineLineAndPointRenderer extends LineAndPointRenderer<BezierLineAndPointFormatter> {

        static class Point {
            public float x, y, dx, dy;
            public Point(PointF pf) { x = pf.x; y = pf.y; }
        }

        private Point prev, point, next;
        private int pointsCounter;

        public SplineLineAndPointRenderer(XYPlot plot) {
            super(plot);
        }

        @Override
        protected void appendToPath(Path path, final PointF thisPoint, PointF lastPoint) {
            pointsCounter--;

            if (point == null) {
                point = new Point(thisPoint);
                point.dx = ((point.x - prev.x) / 5);
                point.dy = ((point.y - prev.y) / 5);
                return;

            } else if (next == null) {
                next = new Point(thisPoint);
            } else {
                prev = point;
                point = next;
                next = new Point(thisPoint);
            }

            point.dx = ((next.x - prev.x) / 5);
            point.dy = ((next.y - prev.y) / 5);
            path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);

            if (pointsCounter == 1) { // last point
                next.dx = ((next.x - point.x) / 5);
                next.dy = ((next.y - point.y) / 5);
                path.cubicTo(point.x + point.dx, point.y + point.dy, next.x - next.dx, next.y - next.dy, next.x, next.y);
            }

        }

        @Override
        protected void drawSeries(Canvas canvas, RectF plotArea, XYSeries series, LineAndPointFormatter formatter) {

            Number y = series.getY(0);
            Number x = series.getX(0);
            if (x == null || y == null) throw new IllegalArgumentException("no null values in xyseries permitted");

            XYPlot p = getPlot();
            PointF thisPoint = ValPixConverter.valToPix(x, y, plotArea,
                    p.getCalculatedMinX(), p.getCalculatedMaxX(), p.getCalculatedMinY(), p.getCalculatedMaxY());

            prev = new Point(thisPoint);
            point = next = null;
            pointsCounter = series.size();

            super.drawSeries(canvas, plotArea, series, formatter);
        }
    }
}

关于android - 如何使用 AndroidPlot 绘制圆角(平滑)线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18014834/

相关文章:

java - 尝试视频通话时,Android WireApp记录UnsatisfiedLink错误:“wcall_set_video_send_state”

AndroidPlot - XYplot 未显示在 xml 中的图形布局上

AndroidPlot:从 1 到 11 的域标签

Android plot 删除黑色边框或将边框颜色更改为白色

Androidplot:Increment_by_vals

javascript - 如何使以下代码更快?

java - 为什么这段代码不能在Java中运行?

android - 获取并显示从开始 Activity 开始耗时 (Android)

android - 如何重置日期选择器

java - AndroidPlot:LineAndPointFormatter 在传入 Context 和 Colors.xml 资源 ID 时导致崩溃