Graph介绍以及使用(1)
发布于 4 年前 作者 duming 4710 次浏览 来自 分享

开场白

music 菊次郎的夏天

Graph工具包是什么?Js Canvas绘制究竟是什么梗?相信大家对Js Canvas绘制都很熟悉,Js Canvas绘制我们每天都会经常遇到的,但是你知道Graph工具包到底是什么吗?来随我一起看看吧。

简介

这会是系列文章,我会边做边写。有兴趣的朋友可以一起探讨。

项目地址:https://git.weixin.qq.com/eclipseglory/graph

Graph工具包(或者叫lib)将常用的CanvasRenderingContext2D绘制方法封装成类,便于使用。

以绘制一个基于中心位置旋转了45度的圆角矩形为例,直接使用Context 2D代码如下:

    ....
    // 矩形大小和位置以及圆角半径:
    let x = 100,y = 100,w = 100,h = 50, r = 10;
    let selector = wx.createSelectorQuery();
    selector.select('#canvas-id').fields({node:true,size:true})
        .exec(function(result){
            if(result[0]){
                let canvas = result[0].node;
                let ctx = canvas.getContext('2d');

                // 根据像素比初始化画布内存以及Context缩放:
                let dpr = wx.getSystemInfoSync().pixelRatio;
                canvas.width = result[0].width*dpr;
                canvas.height = result[0].height*dpr;
                ctx.scale(dpr,dpr);

                // 基于矩形中心旋转45度
                ctx.translate(50,50);
                ctx.rotate(45*Math.PI/180);
                ctx.translate(-50,-50);

                // 绘制圆角矩形
                ctx.beginPath();
                ctx.moveTo(x + r, y);
                ctx.lineTo(x + w - r, y);
                ctx.arc(x + w - r, y + r, r, -Math.PI/2, 0);
                ctx.lineTo(x + w, y + h - r);
                ctx.arc(x + w - r, y + h - r, r, 0, Math.PI/2);
                ctx.lineTo(x+r, y+h);
                ctx.arc(x + r, y + h - r, r, Math.PI/2, Math.PI);
                ctx.lineTo(x, y + r);
                ctx.arc(x + r, y + r, r, Math.PI, Math.PI *1.5);
                ctx.closePath();

                ctx.fillStyle= "some color";
                ctx.fill();
            }
        });
    ....

从上面代码可以得知,要利用Context2d绘制,除了要熟悉API外,还要知道如何进行transform的变换,代码繁琐。在一些情况下,为了加快绘制速度,还会用到临时Canvas的辅助以及一些线性代数的计算,甚至是卷积内核计算,这无疑给专注业务的开发人员增加了工作量。

Graph的目的在于,将图形、文字、图片等封装成一个一个的类,通过设置类的属性即可得到对应的图形以及图形变换,减少了代码编写,也不必知道过多的计算细节。

还以绘制圆角矩形为例,使用Graph的代码如下:

    const graphLib = require('../some path/graph.min.js');
    ....
    // 矩形大小和位置以及圆角半径:
    let x = 100,y = 100,w = 100,h = 50, r = 10;
    let selector = wx.createSelectorQuery();
    selector.select('#canvas-id').fields({node:true,size:true})
        .exec(function(result){
            if(result[0]){
                let canvas = result[0].node;
                // 新建一个Graph类:
                let graph = new graphLib.Graph(canvas,{
                    canvasWidth:result[0].width,
                    canvasHeight:result[0].height
                });
                // 新建一个Rectangle
                let rrect = new graphLib.shape.Rectangle({
                    x : 100, y : 100 , width:100 , height:100,
                    radius:10, rotate:45,
                    color:'some color'
                });

                // 将图形添加到Graph中:
                graph.addChild(rrect);

                // 刷新Graph得到绘制结果:
                graph.update();
            }
        });
    ....

Graph基本概念

概念

如果要绘制一个图形,我们可以将绘制的图形看作一个类,姑且称它为Figure,那这个类至少应该拥有以下这些属性:

  • X :左上角x坐标
  • Y :左上角y坐标
  • Width :图形绘制区域的宽度
  • Height :图形绘制区域的高度

并且这个类还应该提供一个可供调用的绘制方法,比如这个方法叫做draw

  • Draw() : 调用后即可绘制出这个类定义的图形。

如果有这么一个类,那当我们想要绘制它的时候 伪代码 会这么写:

    var figure = new Figure(); // 创建一个图形对象
    // 这个图形所在位置的左上角坐标为 (50,50)
    figure.x = 50, figure.y = 50; 
    // 这个图形的大小为100x100
    figure.width = 100,figure.height = 100;
    // 调用方法绘制它:
    figure.draw();

此外,我们还可以增加一些属性让图形绘制能做些“姿势”的变换,比如旋转、拉伸等:

    
    // 让这个图形旋转45度,并且x轴上拉伸为原来的两倍
    figure.rotate = 45;
    figure.scaleX = 2;
    // 调用方法绘制它:
    figure.draw();

我们并不关心具体是怎么画出来的,甚至不关心它画的是个什么图形,至少按照类的原则来设计,这就基本足够了。

在这些基本要素都具备的情况下,Figure还应该是自包含的类(Composite模式)。

一个Figure图形中,可能会有一些其他的图形对象,以此完成一个较为复杂的组合图形,那Figure就需要维护自身的“子Figure”。这些“子Figure”虽然有自己的坐标位置,但都是基于它们的“父节点”的,如果父节点发生了变化,比如旋转、拉伸、移动甚至移除等,这些子Figure也会随着一起发生变化。此时的父节点就可以看成是一个“容器”,假设我们想要在一个矩形的中心绘制一个圆形,伪代码如下:

    var rect = new Rectangle();// Rectangle是一个绘制矩形的类
    var circle = new Circle();//绘制圆形的类

    // 将圆形加入到矩形中,成为矩形的子图形:
    rect.addChild(circle);
    .... // 设置好各自大小和位置
    // 开始绘制一个矩形,它内部会绘制一个圆形:
    rect.draw();

Graph的设计

上述内容就是Graph工具包最基本的概念:一切皆为对象。

Graph工具包中最基础的类,就叫Figure,它定义了一个图形可能拥有的一些属性,比如坐标、大小、子Figure的List等,并且还进行一些绘制规则的设定以及基本的计算(转换矩阵的计算,顶点变换后的世界坐标计算等),但Figure并不具体负责绘制,可以视为一个抽象类(但JS里没有这个概念),所有具体的绘制都需要子类继承它后复写方法规定。比如一个矩形,图片,文字等,都是Graph中的一个类:

关于Graph类

Graph工具包中有一个类叫做Graph,这个类是一个最顶层的Figure,它并不具备自身绘制功能(如果不把清空整个画布看成绘制的话)。

构造Graph对象必须带入一个Canvas对象节点,好让Graph能控制绘制,而其他所要绘制的图形都需要作为Graph的子节点,这样一来,只需要调用Graphupdate方法就可以刷新整个Canvas,换句话说,Graph就是对应画布的一个类,一个顶层绘制节点。

示例

这里有个简单的绘制矩形的例子:https://git.weixin.qq.com/eclipseglory/graph/tree/master/examples/rectangle

小程序代码片段:
https://developers.weixin.qq.com/s/DLKwRlmI7ihs

主要是展示了如何使用Graph工具包,实际上还有一些其他例子,我会在以后的文章中提到。

结束语

大家可能会感到很诧异,Graph工具包就这个?但事实就是这样,作者我也感到非常诧异。那么以上就是今天老脸为大家整理的关于Graph工具包的内容。关于Graph工具包大家还有什么想说的吗?欢迎在评论区留言或者私信我哦~

回到顶部