行业知识
图形系统开发实战课程:进阶篇(上)——7.图形交互操作: 视点控制与动画
图形开发学院|GraphAnyWhere
- 课程名称:图形系统开发实战课程:进阶篇(上)
- 课程章节:“图形交互操作: 视点控制与动画”
- 原���地址:https://www.graphanywhere.com/graph/advanced/2-7.html
第七章 图形交互操作: 视点控制与动画
\quad 视点控制是指在图形系统中,通过调整视点的位置和角度,来改变用户观察图形的范围。本章我们讲述如何在图形初始化时控制图形视点,以及通过API控制图形视点。
1. 视图对象
\quad 在第二章 图形管理类(Graph)中讲述过图形管理对象相关的类包括:Graph类、Layer类、View类、GraphRenderer类,其中Graph类是这几个类的核心,负责构建另外几个类,并提供外部访问api接口;GraphRenderer类是负责图形的渲染过程、Layer类负责图层属性、图层数据和图层的渲染、View类负责图形的视点控制。
\quad 本节我们来讲述视图控制类 View,这几个类的关系如下图所示:
\quad 视图对象主要用于控制图形的显示范围。下图显示的是某个图形的全图,而红色框内的是当前屏幕中显示的内容,称之为当前视点范围或图形显示范围。
\quad 在第五章 图形交互操作:平移和缩放中,我们讲述过,实现图形的缩放与平移其核心思路是改变图形的显示范围,而不是改变图形中各图形对象的坐标值。图形显示范围(Extent) 是指图形在屏幕或窗口中的可视区域,是一个由显示的图形中最小坐标值(min)和最大坐标值(max)确定的矩形区域,图形显示范围采用图形坐标来表达,可记录为[minX, minY, maxX, maxY]。
\quad 在SVG图形中,当前图形视点范围称之为 ViewBox,在SVG文件中由根节点的 viewBox 属性指定,例如 viewBox='40 20 300 200' ;此外还有一个 ViewPort 属性,指的是当前图形在浏览器中显示的宽度和高度,在SVG文件中由根节点的 width 和 height 属性指定。
\quad 在 anyGraph 中,也存在上述两个概念,图形显示范围 对应的就是 viewBox ,而 Canvas 画布大小对应的就是 viewPort。而 视图对象 除了包含图形显示范围这些属性之外,还提供了 视图约束 方面的属性。
1.1 属性
名称 说明 center 当前的中心点坐标 resolution 当前的分辨率 viewPortSize viewPort大小 resolutions 图形分辨率数组 minResolution 最小分辨率 maxResolution 最大分辨率 extentConstrain 允许显示的最大图形范围 说明:
- center 和 resolution 这两个属性是View类中最常用的两个属性,表达的是当前图形显示范围的中心点坐标和分辨率;
- viewPortSize viewPort大小,本质上就是Canvas尺寸;
- resolutions 分辨率数组,常用于分级缩放的图形系统中,表达的是每一个缩放级别的分辨率;
- minResolution 最小分辨率,是指在图形缩放时所允许的最小分辨率;
- maxResolution 最大分辨率,是指在图形缩放时所允许的最大分辨率;
- extentConstrain 属性用于约束图形移动的范围;
1.2 方法
名称 说明 setCenter(center) 设置中心点坐标 setResolution(resolution) 设置当前分辨率 calculateCenterZoom(resolution, anchor) 根据锚点和分辨率计算中心点 fill(extent, size) 改变视图位置,根据四角坐标和窗口像素宽高 getExtent() 获取图形显示范围 getCenter() 获取中心点坐标 getResolution() 返回当前的分辨率 getZoom() 返还当前的zoom level 说明:
- setCenter(center) 设置中心点坐标,该坐标将限制在 extentConstrain 范围内;
- setResolution(resolution) 设置当前分辨率,分辨率也将限制在 minResolution 和 maxResolution的范围内;
2. 图形初始化时控制视点
\quad anyGraph 通过 视图对象(View) 控制图形的显示。在初始化 Graph 对象的时候如果指定了 view 属性,则按照 view 属性指定的信息显示图形。如果没有指定 view 属性,则默认按照图形坐标与 Canvas坐标 1:1 的方式显示图形,此外还提供了 fullView 属性,设置为 true 时可在初始化的时候显示全图。
\quad 下面我们通过几个示例来熟悉视图控制方面的功能。
2.1 显示默认图形
\quad 在初始化Graph对象时,如果没有指定任何显示相关的属性,图形初始化之后将按照图形坐标与Canvas坐标1:1的方式(即 resolution=1 )显示图形。如果图形的内容较多,这种方式只会显示图形的一部分。
\quad 下面这段代码在初始化时没有指定任何显示相关的属性,源代码如下:
import { Graph, VectorSource, Layer, debug } from "../../../src/index.js"; // 初始化graph对象 let graph = new Graph({ "target": "graphWrapper", "layers": [ new Layer({ source: new VectorSource({ "fileUrl": "../../../data/geom.json" }), zIndex: 10010, name: "数据层" }) ] }); // 显示辅助网格 debug.generateGrid(Object.assign({ "interval": 10, "graph": graph }, graph.getSize())); // 图形渲染 graph.render();\quad 运行效果如下图所示:
2.2 显示全图
\quad 下面这个示例,在初始化 Graph 对象时,通过 fullView=true 属性,指定图形初始化之后显示全图,如果图形内容较少,则会放大图形充满整个Canvas画布,如果图形内容较多,则会缩小图形至Canvas画布中。
import { Graph, VectorSource, Layer, debug } from "../../../src/index.js"; // 初始化graph对象 let graph = new Graph({ "target": "graphWrapper", "fullView": true, "layers": [ new Layer({ source: new VectorSource({ "fileUrl": "../../../data/geom.json" }), zIndex: 10010, name: "数据层" }) ] }); // 显示辅助网格 debug.generateGrid(Object.assign({ "interval": 10, "graph": graph }, graph.getSize())); // 图形渲染 graph.render();\quad 运行效果如下图所示:
2.3 显示指定位置
\quad 下面这个示例,在初始化Graph对象时,设置 view 属性,在该属性中指定了初始视图的中心点坐标 center 和分辨率 resolution ,Graph 对象初始完成之后将按照这两个信息显示图形位置。
import { Graph, View, VectorSource, Layer, debug } from "../../../src/index.js"; // 初始化graph对象 let graph = new Graph({ "target": "graphWrapper", "fullView": true, "layers": [ new Layer({ source: new VectorSource({ "fileUrl": "../../../data/geom.json" }), zIndex: 10010, name: "数据层" }) ], "view": new View({ center: [220, 240], // 初始中心点 resolution: 0.5 // 初始分辨率 }) }); // 显示辅助网格 debug.generateGrid(Object.assign({ "interval": 10, "graph": graph }, graph.getSize())); // 图形渲染 graph.render();\quad 运行效果如下图所示:
3. 使用API控制视点
\quad Graph 类中包含了对 视图对象的实例,可通过 setView() 和 getView() 方法设置和获取 视图对象,同时还提供了以下几个方法通过修改视图对象属性而控制图形的当前视点。
名称 说明 showExtent(extent) 设置图形显示范围,并重绘图形 setView(view) 设置中心点和密度,并重绘图形 getFullExtent() 根据各图层的数据计算当前图形的最大范围 3.1 显示全图
\quad 下面这段代码,可将当前图形的显示范围改变为显示全图。
let maxExtent = graph.getFullExtent();graph.showExtent(maxExtent);
3.2 显示指定坐标
\quad 下面这段代码,可将当前图形的显示范围改变为显示指定坐标位置,并按指定分辨率控制图形大小。
let center = [280, 200];let resolution = 0.25;if (graph.getView().setResolution(resolution)) { graph.getView().setCenter(center);}graph.render();3.3 显示指定范围
\quad 下面这段代码,可将当前图形的显示范围改变为显示指定的图形范围。
let extent = [200, 120, 400, 220];graph.showExtent(extent);
4. 动画
\quad 在图形系统中,动画是由一系列叫做“帧(frame)”的图形组成的,通过一系列连续的画面来展示物体或场景的运动和变化。它们以一定的帧率(即每秒显示的帧数)进行播放,从而在视觉上呈现出连续的运动效果。
\quad 一帧即对应了一幅图形,在1秒内如果能够重复绘制15帧以上,图形看起来就不卡了,通常所说的60帧是指每秒重绘60次,这已经超过了人眼的极限,可以达到非常流畅的效果。
\quad 在图形系统开发实战课程-第八章动画 中讲述了在浏览器中实现动画功能的几种方法,分别是setInterval() 、 setTimeout() 和 requestAnimationFrame() 。从对动画的精确控制和节省计算机资源等角度,推荐在浏览器中使用requestAnimationFrame() 实现动画。
\quad 图形系统中通常按以下几个步骤实现动画:
- 清空Canvas
- 绘制当前帧图形
- 计算下一帧图形数据
- 循环,重复上述过程
\quad 直接使用 requestAnimationFrame() 实现动画时,需要在每一帧绘制完成后再次调用 requestAnimationFrame() 且需要自己编程实现帧率的控制,或是自己编码实现动画持续的时间等功能。anyGraph 中提供了一个 Animation 工具类,封装了这几个功能。
4.1 Animation 工具类
Animation 工具类提供了以下几个方法:
名称 说明 start(callback, duration, frameRate) 开始动画 stop(animationId) 停止动画 frame(callback) 显示一帧动画 start()
下表为该方法的参数:
名称 说明 callback 回调函数 duration 持续时间 frameRate 帧率 \quad 该方法用于开始一段动画,callback 参数用于指定回调函数,对于图形系统而言,我们在该回调方法中重绘图形。 duration 用于指定动画持续的时间,如果没有指定该参数,则动画一直重复下去,直至通过 stop 方法来停止该动画。 frameRate 用于指定帧率,即每秒执行的次数,对于某些不需要在1秒内频繁刷新的动画(例如时钟),我们可通过该参数来降低系统运行资源。
\quad 由于采用了 window.requestAnimationFrame(frame) 动画技术,该方式为根据屏幕刷新率控制帧率,因此屏幕刷新率即为最大帧率。
stop()
\quad 在执行 star() 方法开始一段动画时,star() 方法会返回一个整数类型的 “动画ID”,调用stop()方法时通过该 “动画ID” 结束该动画。
Animation源代码
\quad 以下为Animation的源代码:
/** * 动画工具类 */const Animation = (function (window) { // 缺省帧率60帧/秒 let TIME = Math.floor(1000 / 60); let stop, frame; let frames = {}; let lastFrameTime = 0; let counter = 0; let loops = {}; if (typeof window.requestAnimationFrame === 'function' && typeof window.cancelAnimationFrame === 'function') { frame = function (callback) { let id = Math.random(); frames[id] = requestAnimationFrame(function onFrame(time) { if (lastFrameTime === time || lastFrameTime + TIME - 1 0 ? duration : Number.POSITIVE_INFINITY; if(frameRate > 0) { TIME = Math.floor(1000 / frameRate); } let id = ++counter; let start = Date.now(); loops[id] = function () { if (loops[id] && Date.now() - start callback(); if (loops[id]) { frame(loops[id]); } } else { delete loops[id]; } }; frame(loops[id]); return id; } return { frame, // 执行一次 callback start, // 开始循环执行 callback stop // 停止动画 };}(window)); Graph, Circle, debug, Animation, Easing } from "../../../src/index.js"; // 初始化graph对象 let graph = new Graph({ "target": "graphWrapper" }); // 增加数据层 let layer = graph.addLayer({ "name": "数据层" }); let ball = layer.getSource().add( new Circle({ "x": 50, "y": 100, "radius": 20, "style": { "color": "none", "fillStyle": 1, "fillColor": "#FF0000" } }) ) // 动画相关变量 let minX = 50, maxX = 800; let totalTimes = 10; let times = 0; let rafId = -1; // 绘制帧图形 function frame() { // 计算小球移动的距离 let dx = (maxX - minX) * Easing.easeIn(times / totalTimes); ball.moveTo(minX + dx, 100); // 图形渲染 graph.render(); // 动画停止条件 if (times\quad 在这个方法中,我们先记录当前的中心点坐标和分辨率,根据缓动方法计算当前中心点和目标点坐标之间的线性差值,计算当前分辨率和目标分辨率之间的线性差值,逐帧进行图形重绘,从而实现移动的动画效果。缺省动画时间为500毫秒,如果按照每秒60帧计算,这个过程共绘制了30次图形。
\quad 其调用示例如下:
let center = [280, 200];let resolution = 0.25;graph.animailMove(center, resolution, 600);
\quad 运行效果如下:
5.2 缩放动画
\quad 在 animailZoom() 方法中,通过使用 Animation 类和 Easing.easeOut() 减速缓动功能,实现了动画效果的图形缩放,其源码如下:
/** * 具有动画效果的图形缩放 * @param {Number} scale 缩放倍率 * @param {Coord} anchor 锚点坐标 */animailZoom(scale = 1.5, anchor, duration = 500) { let originalRes = this.getView().getResolution(); let targetRes = this.getView().getResolution() * scale; let start = Date.now(); let that = this; // 缺省锚点为中心点 if(anchor == null) { anchor = Extent.getCenter(this.getExtent()); } // 开始动画 Animation.start(function () { let drawTime = Date.now() - 1; let delta = Easing.easeOut((drawTime - start) / duration); let res = originalRes + delta * (targetRes - originalRes); let center = that.getView().calculateCenterZoom(res, anchor); that.getView().setCenter(center); that.getView().setResolution(res); that.renderSync(); }, duration);}\quad 在这个方法中,我们先获取当前分辨率和计算目标分辨率,根据缓动方法计算当前分辨率和目标分辨率之间的线性差值,逐帧进行图形重绘,从而实现图形缩放的动画效果。缺省动画时间为500毫秒,如果按照每秒60帧计算,这个过程共绘制了30次图形。
\quad 其调用示例如下:
let scale = 1.5; // 放大// let scale = 0.67; // 缩小graph.animailZoom(scale);
\quad 运行效果如下:
\quad “图形系统实战开发-进阶篇 第七章 图形交互操作:视点控制与动画” 的内容讲解到这里就结束了,如果觉得对你有帮助有收获,可以关注我们的官方账号,持续关注更多精彩内容。
相关资料
▶ 系列教程及代码资料:https://GraphAnyWhere.com
▶ 图形系统开发实战课程:进阶篇(上)——前言
▶ 图形系统开发实战课程:进阶篇(上)——1.基础知识
▶ 图形系统开发实战课程:进阶篇(上)——2.图形管理类(Graph)
▶ 图形系统开发实战课程:进阶篇(上)——3.图层类(Layer)
▶ 图形系统开发实战课程:进阶篇(上)——4.图形基本形状
▶ 图形系统开发实战课程:进阶篇(上)——5.图形交互操作:平移和缩放
▶ 图形系统开发实战课程:进阶篇(上)——6.图形交互操作:拾取
作者信息
作者 : 图形开发学院
CSDN: https://blog.csdn.net/2301_81340430?type=blog
官网:https://graphanywhere.com
上一篇:浪潮服务器怎么选系统设置?
下一篇:云服务器怎么软件更新?