ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021SC@SDUSC山东大学软件学院软件工程应用与实践--quark renderer代码分析 第十二篇 绘画系统分析(3):连线(line)

2021-12-18 13:59:26  阅读:146  来源: 互联网

标签:2021SC y1 摆线 -- ctx quark x2 var y2


这是绘画系统的第撒个大部分,连线,连线的内容包括最上层的链接线抽象类,和细分的直线,折线,贝塞尔曲线以及内外旋轮曲线五个部分。

首先是连接线抽象类。

连接线抽象类,需要成为连接线的类都可以混入此抽象类的实现。为了方便实现一些复杂的连接场景,特别注意:
1.连接线总是画在全局坐标系中。
2.连接线可以移动位置,但不能缩放、旋转、斜切。
3.连接线只有两个端点,即使是折线,也是两个端点,不会有更多。
4.连线不属于任何分组。
5.混入此实现的类默认假定已经混入了 Eventful ,因为我们需要事件系统。

function CableLike() {
  this.isCable = false;
  this.showLinkHooks = false;
  this.startBounding = null; // 起始形状的边界矩形

  this.endBounding = null; // 结束形状的边界矩形

  this.arrowType = 'both'; // 结束,开始,两者都有

  this.arrowAngel = Math.PI / 8;
  this.arrowLength = 10;
  this.fromId = ''; // 开始元素的ID。

  this.toId = ''; // 结束元素的ID。

  this.fromPosition = ''; // 起始元素的连接位置

  this.toPosition = ''; // 结束元素的连接位置

  this.startHook = new LinkHook({
    el: this,
    name: 'START'
  });
  this.endHook = new LinkHook({
    el: this,
    name: 'END'
  });
  this.on('afterRender', this.afterRenderHandler, this);
}

这里是对连线的基本属性的定义过程,其中加了注释,包括了起始和结束的边界形状,箭头式的情况下是起始还是结束还是两者都有箭头,起始和结束的元素以及两者的位置。

后面大段的定义了不同方式的调用以及渲染方式,这里就不多作展示了。

__renderArrow: function __renderArrow(twoPoints) {
    var _this$ctx;

    var p1 = twoPoints[0];
    var p2 = twoPoints[1]; 

    p2[0] = p2[0] - p1[0];
    p2[1] = p2[1] - p1[1]; 

    var cosp2 = matrixUtil.cosx.apply(matrixUtil, _toConsumableArray(p2));
    var sinp2 = matrixUtil.sinx.apply(matrixUtil, _toConsumableArray(p2));
    var cosArrow = mathCos(this.arrowAngel);
    var sinArrow = mathSin(this.arrowAngel);
    var x1 = this.arrowLength * (cosp2 * cosArrow - sinp2 * sinArrow);
    var y1 = this.arrowLength * (sinp2 * cosArrow + cosp2 * sinArrow);
    var x2 = this.arrowLength * (cosp2 * cosArrow + sinp2 * sinArrow);
    var y2 = this.arrowLength * (sinp2 * cosArrow - cosp2 * sinArrow); 

    x1 += p1[0];
    y1 += p1[1];
    x2 += p1[0];
    y2 += p1[1]; 

    this.ctx.save();
    this.ctx.strokeStyle = this.style.stroke;
    this.ctx.fillStyle = this.style.stroke;
    this.ctx.beginPath();

    (_this$ctx = this.ctx).moveTo.apply(_this$ctx, _toConsumableArray(p1));

    this.ctx.lineTo(x1, y1);
    this.ctx.lineTo(x2, y2);
    this.ctx.closePath();
    this.ctx.stroke();
    this.ctx.fill();
    this.ctx.restore();
  },

这是连线的过程,大体上可以分为四步:

1.将原点移动到终点

2.求出变化的角度

3.将原点移回(0,0)

4.利用刚才的数据画出路径,期间会利用返回参数的不同调用不同的函数。

接着就是最有代表性的直线绘制

直线。所有线条的特征是:

1.线条可以移动位置,但不能进行其它仿射变换,scale/rotate/skew 都不可以。所以计算线条的相关参数时可以做简化,只要计算 position 和 translate 就可以了。

2.线条总是画在全局空间中。

3.线条不能加到 Group 中。

首先是构造线条的函数

function Line(options) {
    var _this;

    _classCallCheck(this, Line);

    _this = _super.call(this, dataUtil.merge({
      shape: {
        x1: 0,
        y1: 0,
        x2: 0,
        y2: 0,
        percent: 1
      },
      style: {
        stroke: '#000',
        fill: null
      }
    }, options, true));
   
    _this.type = 'line';
    classUtil.inheritProperties(_assertThisInitialized(_this), CableLike, _this.options);
    classUtil.copyOwnProperties(_assertThisInitialized(_this), _this.options, ['style', 'shape']);
    _this.transformable = false;
    return _this;
  }

在获得来自前面抽象类的信息后会开始进行这一内容调用,通过规定线的开始结束百分比等数据来构造线段,百分比用于后期获取线上特定点。

_createClass(Line, [{
    key: "buildPath",
    value: function buildPath(ctx, shape) {
      var x1;
      var y1;
      var x2;
      var y2;

      if (this.subPixelOptimize) {
        var subPixelOptimizeOutputShape = {};
        subPixelOptimizeLine(subPixelOptimizeOutputShape, shape, this.style);
        x1 = subPixelOptimizeOutputShape.x1;
        y1 = subPixelOptimizeOutputShape.y1;
        x2 = subPixelOptimizeOutputShape.x2;
        y2 = subPixelOptimizeOutputShape.y2;
      } else {
        x1 = shape.x1;
        y1 = shape.y1;
        x2 = shape.x2;
        y2 = shape.y2;
      }

      var percent = shape.percent;

      if (percent === 0) {
        return;
      }

      ctx.moveTo(x1, y1);

      if (percent < 1) {
        x2 = x1 * (1 - percent) + x2 * percent;
        y2 = y1 * (1 - percent) + y2 * percent;
      }

      ctx.lineTo(x2, y2);
    }

这里就是构建当前线条的路径,数据结构类似前面讲过的SVG中的 path 属性,方法也大同小异

key: "renderTransformControls",
    value: function renderTransformControls(ctx, prevEl) {}

 这里是关键,也是比较特殊的地方,其作用为禁用 Elemnet 类上的 renderTransformControls 方法,因为我们不希望在线条上使用几何变换。

后面获取百分比位置的点的功能与前面几何中的线内容极为相似,就不多说了。

后面主要就是几种不同的线,构建的基本方法是一样的,思路也完全相同,只是因为线的特征而算法不同。

其中内外旋轮类曲线可分为:外切外摆线、渐开线、内切外摆线、内摆线和直滚摆线。该分类的规律是:

(1)从外切外摆线到渐开线是滚圆曲率半径由小变无限大;

(2)从渐开线到内切外摆线是滚圆曲率改变方向

(3)从内切外摆线到内摆线是滚圆曲率半径由大变到小于基圆半径;

(4)从内摆线到直滚摆线是基圆曲率半径由小变无限大。

从这个变化规律可以看出摆线和渐开线是性质上相同的曲线,可以把它们归入一族,将它们取名为摆线族曲线。

而贝塞尔曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。详细内容感兴趣的可以自己去查一下,我在这里三言两语也说不清楚。

总之连线部分的内容就这么多了。

标签:2021SC,y1,摆线,--,ctx,quark,x2,var,y2
来源: https://blog.csdn.net/Poerking/article/details/122011226

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有