Flutter 绘制探索 | 操作坐标系范围
Posted datian1234
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 绘制探索 | 操作坐标系范围相关的知识,希望对你有一定的参考价值。
前言
在视频 【Flutter 绘制指南 | 第二集 · 坐标系】 中,实现了画板区域内的单位坐标系。今天来拓展一下,让坐标系支持变换,比如坐标系的平移和缩放,从而让坐标系的功能更加完备。
本文要实现的效果如下,可以通过下方的七个按钮操作坐标系的范围,这样可以查看在当前定义域内的函数曲线,也就是移动坐标轴的功能:本文详细源码见 toly1994328/skeleton/lib/paint/coo
1. 坐标范围的定义
目前坐标的范围是 x:[0~1]
, y:[0~1]
,而且是写死的数据。为了可以让坐标轴的范围值可调整,首先需要对刻度的表现进行优化。比如,使用者可以通过一个配置项指定横纵坐标的最大最小值,我们将这个配置项数据赋值为 AxisRange
类型,定义如下:
其中给出 xSpan
和 ySpan
的 get
方法,用于获取横纵坐标轴的跨度。然后让 Coordinate
类持有坐标轴范围对象:
class AxisRange
final double maxX;
final double minX;
final double maxY;
final double minY;
const AxisRange(
this.maxX = 1.0,
this.minX = -1.0,
this.maxY = 1.0,
this.minY = -1.0,
);
double get xSpan => maxX - minX;
double get ySpan => maxY - minY;
2. 刻度值的绘制优化
接下来,就要根据坐标轴的范围来绘制刻度和网格。拿坐标系横轴来说,刻度个数 xScaleCount
由用户指定,这样很容易计算出每个刻度间的步长 step
。横轴最左侧是坐标轴横轴范围的最小值,最右侧是范围最大值。然后遍历 xScaleCount
次即可:
如下是 x 轴刻度遍历绘制的逻辑刻度和竖向网格线的逻辑:其中刻度的偏移量,由当前刻度值处占总长的分率乘以区域宽度计算得出。
double stepX = (range.xSpan / xScaleCount);
for(int i =0;i<=xScaleCount;i++)
double value = range.minX+stepX*i;
double offsetX = (value - range.minX) / range.xSpan * size.width;
textPainter.text = TextSpan(
text: value.toStringAsFixed(2),
style: const TextStyle(fontSize: 12, color: Colors.black),
);
textPainter.layout();
// 绘制文字
textPainter.paint(
canvas,
Offset(offsetX - textPainter.size.width / 2, 5),
);
// 绘制网格
canvas.drawLine(
Offset(offsetX, 0),
Offset(offsetX, -size.height),
gridAxisPaint,
);
纵轴的刻度的绘制同理,这样只要指定坐标轴的范围,然后更新画板,坐标轴的对应刻度就会发生改变:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5hBBYcsl-1672920319553)(null)]
3. 坐标轴上的点
接下来就是最关键的一步,如何在坐标轴上描点。由于展示的坐标系上的点和实际的画板中绘制的逻辑像素并不相同,所以需要对坐标系上的点进行一下转换,使其称为画板中的绝对坐标。转换起来也并不是很困难,根据当前坐标占横纵坐标的分率,再结合画板尺寸就很容易算出当前点在画板中的绝对坐标:
void _drawPoint(Canvas canvas, Size size)
Offset p = const Offset(0.6, 0.6);
double x = (p.dx - coordinate.range.minX)/coordinate.range.xSpan*size.width;
double y = (p.dy - coordinate.range.minY)/coordinate.range.ySpan*size.height;
canvas.drawCircle(Offset(x, y), 10, _mainPainter);
这样无论坐标轴的范围如何变化,都不会影响坐标点在坐标系中的位置,如下横坐标范围在 0.10~2.10
之间:
4. 绘制函数
有了坐标轴,其实函数图像的绘制还是比较简单的,无非就是在当前坐标系下收集点,然后根据点画线罢了。比如在坐标系中绘制一个 sin 函数曲线,定义域在 [-1~1] 之间:
绘制逻辑如下,给定 pointCount
表示曲线中点的个数,个数越多曲线越精细,相对来说绘制也就越耗时。思路是遍历 pointCount
次,每次遍历时使用函数关系取点,将点连接就可以得到折线,只不过取的点很多就呈现了曲线效果。后面也可以少取一下点,通过贝塞尔曲线拟合点。
void _drawFn(Canvas canvas, Size size,)
List<Offset> points = [];
int pointCount = 500;
double step = coordinate.range.xSpan/pointCount;
for(int i =0;i<pointCount;i++)
double dx = coordinate.range.minX+step*i;
double dy = 0.6*sin(dx*5);
double x = (dx - coordinate.range.minX)/coordinate.range.xSpan*size.width;
double y = (dy - coordinate.range.minY)/coordinate.range.ySpan*size.height;
points.add(Offset(x, y));
canvas.drawPoints(PointMode.polygon, points, _mainPainter..color=Colors.blue);
这样多收集几条点集,就可以绘制多条曲线,比如下面红色是 y=x
函数,紫色是 y = x*x*x/20
函数:
5. 操作坐标系范围
现在一切准备就绪,接下来只要通过点击按钮,操作坐标系范围,即可实现如下效果:
在 Coordinate
类在提供 move
和 scale
方法,移动就是将坐标轴的范围根据偏移量进行平移,缩放是将坐标轴范围乘以 rate
倍率:
---->[coordinate.dart]----
void move(Offset offset)
range = AxisRange(
minY: range.minY + offset.dy,
maxY: range.maxY + offset.dy,
minX: range.minX + offset.dx,
maxX: range.maxX + offset.dx,
);
void scale(double rate)
range = AxisRange(
minY: range.minY * rate,
maxY: range.maxY * rate,
minX: range.minX * rate,
maxX: range.maxX * rate,
);
在点击按钮时触发 _onTapCtrl
方法,其中根据 CtrlType
执行对应方法即可,比如点击左上右下时让坐标轴进行移动:
void _onTapCtrl(CtrlType type)
if(type == CtrlType.right)
coordinate.move(const Offset(0.1, 0));
if(type == CtrlType.left)
coordinate.move(const Offset(-0.1, 0));
if(type == CtrlType.up)
coordinate.move(const Offset(0, 0.1));
if(type == CtrlType.down)
coordinate.move(const Offset(0, -0.1));
pointValues.repaint();
到这里,一个简单的坐标轴范围操作的案例就完成了,还有一些值得优化的部分:比如现在刻度是严格按照份数进行分割的,刻度数值比较乱;另外还可以让用户通过输入框确定坐标范围;对函数图像的绘制方式有待优化;这些会在后续逐步完善。那本文就到这里,谢谢观看 ~
作者:张风捷特烈
链接:https://juejin.cn/post/7185014176501727288
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓
以上是关于Flutter 绘制探索 | 操作坐标系范围的主要内容,如果未能解决你的问题,请参考以下文章
matplotlib 的使用技巧(局部放大图坐标轴设置边框设置横纵比设置)