绘制图表时遇到一个小问题。在下面的图片是我已经做过的。
该图表应代表可用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);
但这并没有像预期的那样奏效。
注意:Wifi Analyzer应用程序具有类似的图形,其图形具有我想要的圆角。它看起来像这样:
答案 0 :(得分:12)
您可以使用Path.cubicTo()方法。它使用三次样条算法绘制一条线,从而产生您想要的平滑效果。
查看similar question here的答案,其中一个人正在谈论三次样条曲线。有一个简短的算法显示如何计算Path.cubicTo()
方法的输入参数。您可以使用分隔值来实现所需的平滑度。例如,在下面的图片中,我除以5而不是3.希望这会有所帮助。
我花了一些时间并实现了一个SplineLineAndPointFormatter
类,它可以在androidplot库中完成你需要的东西。它使用相同的技术。以下是androidplot示例应用程序的外观。您只需使用它而不是LineAndPointFormatter
。
这是代码示例和我写的类。
f1 = new SplineLineAndPointFormatter(color.getColor(), null,
Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);
这是做魔术的课程。它基于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);
}
}
}
答案 1 :(得分:8)
1 - 我猜你只用几个点来绘制信号图。所有图形/图表应用程序都尝试使用直线连接点,然后会显示您的图表。因此,如果您只使用三个点,您的图形将看起来像一个三角形!如果您希望曲线图是弯曲的,则必须添加更多点。然后它就像一条曲线。
2 - 或者您可以找到任何可以绘制sin
图表的库,例如GraphView Library
。然后尝试绘制这个函数:
所以它看起来像这样:
然后将其翻译为(a,0)
,结果看起来就像你想要的那样。
3 - 另一种方式,您可以在Java中使用内置的Math.sin
:
选择范围a
到b
的1000点,并为每个点计算上述函数的值,最后创建一个path
并在画布中显示它们。
您可以使用quadTo (float x1, float y1, float x2, float y2)为您简化绘图quad curves
。文档说:
从最后一点添加二次贝塞尔曲线,接近控制点 (x1,y1),并以(x2,y2)结束。如果没有调用moveTo()调用 此轮廓,第一个点自动设置为(0,0)。
参数
x1二次曲线上控制点的x坐标
y1二次曲线上控制点的y坐标
x2二次曲线上终点的x坐标
y2二次曲线上终点的y坐标
最后,我添加了一个扩展View
的简单类,可以绘制一个看起来像你想要的曲线:
public class SinWave extends View {
private float first_X = 50;
private float first_Y = 230;
private float end_X = 100;
private float end_Y = 230;
private float Max = 50;
public SinWave(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint() {
{
setStyle(Paint.Style.STROKE);
setStrokeCap(Paint.Cap.ROUND);
setStrokeWidth(0.7f);
setAntiAlias(true);
setColor(0xFFFF00FF);
}
};
final Path path = new Path();
path.moveTo(first_X, first_Y);
path.quadTo((first_X + end_X)/2, Max, end_X, end_Y);
canvas.drawPath(path, paint);
}
}
结果必须如下:
您可以向该类添加更多方法并进行更改以提高性能!
答案 2 :(得分:0)
在Androidplot中,它总是一个平滑的线条渲染器:BezierLineAndPointRenderer,就像上面的实现一样,使用Android内置的Bezier绘图程序 cubicTo(...)&amp;的 quadTo(...)即可。问题是使用贝塞尔曲线以这种方式绘制平滑线会产生一个假线,通过改变数量来超过实际控制点,如果仔细观察上面的图像,就会发现这种情况。
解决方案是使用Catmull-Rom样条插值,现在Androidplot最终支持。详情请见http://androidplot.com/smooth-curves-and-androidplot/
答案 3 :(得分:0)
使用ChartFactory.getCubeLineChartView代替ChartFactory.getLineChartView使用achart引擎
答案 4 :(得分:-1)
试试这个:
symbol = new Path(); paint = new Paint(); paint.setAntiAlias(true); paint.setStrokeWidth(2); paint.setColor(-7829368); paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too paint.setPathEffect(new CornerPathEffect(10) ); paint.setStyle(Paint.Style.STROKE); symbol.moveTo(50.0F, 230.0F); symbol.lineTo(75.0F, 100.0F); symbol.lineTo(100.0F, 230.0F);
找到大部分信息here