首页 > 其他分享 >Flutter 绘制探索 | 操作坐标系范围

Flutter 绘制探索 | 操作坐标系范围

时间:2023-06-19 14:32:44浏览次数:38  
标签:double range 坐标系 坐标轴 刻度 coordinate 绘制 Flutter


前言

在视频 【Flutter 绘制指南 | 第二集 · 坐标系】 中,实现了画板区域内的单位坐标系。今天来拓展一下,让坐标系支持变换,比如坐标系的平移和缩放,从而让坐标系的功能更加完备。

Flutter 绘制探索 | 操作坐标系范围_Android

本文要实现的效果如下,可以通过下方的七个按钮操作坐标系的范围,这样可以查看在当前定义域内的函数曲线,也就是移动坐标轴的功能:本文详细源码见 toly1994328/skeleton/lib/paint/coo


1. 坐标范围的定义

目前坐标的范围是 x:[0~1] , y:[0~1],而且是写死的数据。为了可以让坐标轴的范围值可调整,首先需要对刻度的表现进行优化。比如,使用者可以通过一个配置项指定横纵坐标的最大最小值,我们将这个配置项数据赋值为 AxisRange 类型,定义如下:

Flutter 绘制探索 | 操作坐标系范围_坐标轴_02

其中给出 xSpanySpanget 方法,用于获取横纵坐标轴的跨度。然后让 Coordinate 类持有坐标轴范围对象:

Flutter 绘制探索 | 操作坐标系范围_坐标轴_03

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 次即可:

Flutter 绘制探索 | 操作坐标系范围_Android_04

如下是 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,
  );
}

纵轴的刻度的绘制同理,这样只要指定坐标轴的范围,然后更新画板,坐标轴的对应刻度就会发生改变:


3. 坐标轴上的点

接下来就是最关键的一步,如何在坐标轴上描点。由于展示的坐标系上的点和实际的画板中绘制的逻辑像素并不相同,所以需要对坐标系上的点进行一下转换,使其称为画板中的绝对坐标。转换起来也并不是很困难,根据当前坐标占横纵坐标的分率,再结合画板尺寸就很容易算出当前点在画板中的绝对坐标:

Flutter 绘制探索 | 操作坐标系范围_flutter_05

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 之间:

Flutter 绘制探索 | 操作坐标系范围_架构师_06


4. 绘制函数

有了坐标轴,其实函数图像的绘制还是比较简单的,无非就是在当前坐标系下收集点,然后根据点画线罢了。比如在坐标系中绘制一个 sin 函数曲线,定义域在 [-1~1] 之间:

Flutter 绘制探索 | 操作坐标系范围_架构师_07

绘制逻辑如下,给定 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 函数:

Flutter 绘制探索 | 操作坐标系范围_坐标轴_08


5. 操作坐标系范围

现在一切准备就绪,接下来只要通过点击按钮,操作坐标系范围,即可实现如下效果:

Flutter 绘制探索 | 操作坐标系范围_架构师_09

Coordinate 类在提供 movescale 方法,移动就是将坐标轴的范围根据偏移量进行平移,缩放是将坐标轴范围乘以 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();
}

到这里,一个简单的坐标轴范围操作的案例就完成了,还有一些值得优化的部分:比如现在刻度是严格按照份数进行分割的,刻度数值比较乱;另外还可以让用户通过输入框确定坐标范围;对函数图像的绘制方式有待优化;这些会在后续逐步完善。那本文就到这里,谢谢观看 ~

作者:张风捷特烈



标签:double,range,坐标系,坐标轴,刻度,coordinate,绘制,Flutter
From: https://blog.51cto.com/u_16163442/6513368

相关文章

  • 关于flutter框架安卓应用抓包问题,以及解决方法
    参考文档https://bbs.kanxue.com/thread-261941.htm一.从安装的app所在文件夹目录中提出libflutter.socd/data/app/包名/lib/xxx/..../...libflutter.so二.将其拖入ida中进行分析字符串窗口搜索ssl_server按x进入F5看了一下和上面博客说的相似不理解上面说的也......
  • Flutter 3.7 正式发布
    新的Flutter稳定版加入了Material3更新、iOS平台优化及其他内容新年伊始,由Flutter3.7正式版来「打头阵」!我们与整个Flutter社区成员们继续在Flutter3.7中优化了框架,包括创建自定义菜单栏和层叠式菜单、更好的国际化工具支持、新的调试工具以及其他功能和特性等。新的......
  • FlutterUnit 工具集录 | IconFont 类代码自动生成
    1.IconFont类代码生成器的作用首先介绍一下FlutterUnit中,代码生成菜单下的IconFont工具的作用。它主要解决Flutter项目中自定义字体图标使用的问题:字体图标调用类代码的自动生成。pubspec.yaml中字体图标节点的自动配置。多个自定义字体图标节点的支持。一键自动生成相......
  • 2023 年第一弹, Flutter 3.7 发布啦,快来看看有什么新特性
    2023年新春之际,Flutter喜提了3.7的大版本更新,在Flutter3.7中主要有改进框架的性能,增加一些很棒的新功能,例如:创建自定义菜单栏、级联菜单、更好地支持国际化的工具、新的调试工具等等。另外Flutter3.7还改进了Globalselection、使用Impeller提升渲染能力、DevTools等......
  • 百度地图 鼠标绘制库 bmap-draw 避坑
    1.距离测量工具无法修改单位为米根据官方文档:距离测量类unit string 测量所用单位制,默认为千米'kilometers',另外可接受米'metric'无法对其进行修改this.distance=newDistanceMeasure(scene,{unit:"metric",isSeries,//不连续测量...m......
  • Flutter 绘制探索 | 扇形区域与点击校验
    作者:张风捷特烈0.前言今天来探索一个问题,如何绘制一块扇形区域路径,并且校验触点是否落在扇形区域之中。这个问题对于绘制饼图及处理手势事件校验非常重要。1.扇形区域的定义首先来明确一下扇形区域的表示,如下图所示,一个扇形区域通过五个属性进行描述:属性名类型作用centerO......
  • 快速入门|Flutter完整开发实战详解 谷歌架构师独家分享
    前言这几年在大前端的开发领域,选择跨端方案的公司和部门越来越多,一方面是跨平台的前端框架越来越成熟,另一方面也是因原生开发者正逐年减少。所以,在当下掌握一门跨平台的技术栈还是很有必要的,无论从广度还是从深度都会有所帮助。就目前来说有很多主流的跨平台框架,就比如:Flutter、Rea......
  • 【Python】在同一图形中更加优雅地绘制多个子图
    1.引言数据可视化非常重要,有一句俗语叫做一图顶千言,我相信好多小伙伴应该都听说过这句话;即使是有人第一次听到,我想应该也会觉得赞成,这足以说明数据可视化的重要性。我们在前一篇博客中,介绍了如何利用subplot来在一张子图里绘制多个子图,最近我又发现了一种更加优雅地实现,迫不及待地......
  • AM@空间直角坐标系@数量积和向量积@向量的外积在物理学中的相关概念
    文章目录空间直角坐标系坐标面分向量@坐标分解式余弦定理数量积的坐标表示公式向量积向量积的坐标表示公式向量的外积在物理学中的相关概念物理量ref角速度和向量积量纲Baseunit(measurement)Background......
  • flutter系列之:做一个图像滤镜
    目录简介我们的目标带滤镜的图片打造filter按钮打造可滑动按钮最后要解决的问题简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的,如果是h5页面,那么我们可以很容易的通过css滤镜来实现这个功能。那么如果在flutter中,如果要实现这样的滤镜功能应该怎么处理呢?一起来看看吧。......