大家,新年好!

历史文章:

本文介绍的是在使用 gojs 制作图的过程中,你可能会碰到的问题的一些解决方案。

gojs 是一个非常强大的可视化关系的js库。

1. 取消更新动画

问题:更新数据的时候,会触发渲染,有渲染动画,用户体验不好。

方案:初始数据绘制,有动画;更新数据绘制,无动画。

代码实现:

// 后面所用到的 diagram 都是 gojs 创建的实例
// diagram_container 为图容器dom id
diagram = $(go.Diagram, 'diagram_container')

方案一:

function updateData (nodeArr = [], linkArr = [], hasAnimation = true ) {
if (hasAnimation) {
diagram.model = new go.GraphLinksModel(nodeArr, linkArr);
} else {
diagram.model.nodeDataArray = nodeArr
diagram.model.linkDataArray = linkArr
}
} // 初始化实例后处理,只用一次
diagram.animationManager.canStart = function(reason) {
if (reason === 'Model') return false
return true
}

方案二:

// 绑定数据至 diagram,绘制图
function updateData (nodeArr = [], linkArr = [], hasAnimation = true ) {
if (hasAnimation) {
diagram.model = new go.GraphLinksModel(nodeArr, linkArr);
} else {
diagram.model.nodeDataArray = nodeArr
diagram.model.linkDataArray = linkArr
diagram.animationManager.stopAnimation()
}
}

方案三:

// 绑定数据至 diagram,绘制图
function updateData (nodeArr = [], linkArr = [], hasAnimation = true) {
diagram.model = new go.GraphLinksModel(nodeArr, linkArr);
if (diagram.animationManager) {
// Default 有动画,None 没有动画
diagram.animationManager.initialAnimationStyle = hasAnimation ? go.AnimationManager.Default : go.AnimationManager.None;
}
}

2. 导出图(含可视区外的部分)

问题:导出图,利用原生 canvas 相关 api 实现的导出图片,只包含可视区内的

解决:利用 gojs 提供的 api 处理

背后原理:利用数据重新绘制一份图,所有数据节点都在的图可视区内,然后利用原生 canvas 相关 api 实现导出图片

代码实现:

function downloadImg = ({
imgName = 'dag',
bgColor = 'white',
imgType = 'image/png'
}= {}) {
diagram.makeImageData({
scale: 2,
padding: new go.Margin(50, 70),
maxSize: new go.Size(Infinity, Infinity),
background: bgColor,
type: imgType,
returnType: 'blob',
callback: (blob: any) => {
const url = window.URL.createObjectURL(blob)
const fileName = imgName + '.png'
const aEl = document.createElement('a')
aEl.style.display = 'none'
aEl.href = url
aEl.download = fileName // IE 11
if (window.navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, fileName)
return
} document.body.appendChild(aEl)
requestAnimationFrame(function() {
aEl.click()
window.URL.revokeObjectURL(url)
document.body.removeChild(aEl)
})
}
})
}

3. 禁用 ctrl 相关快捷键

// 禁用 ctl 相关操作
diagram.commandHandler.doKeyDown = function() {
const e = diagram.lastInput
const control = e.control || e.meta
const key = e.key // 取消 Ctrl+A/Z/Y/G A-全选、Z-撤销、Y-重做、G-分组
if (control && ['A', 'Z', 'Y', 'G'].includes(key)) return
// 取消 Del/Backspace 删除键
if (key === 'Del' || key === 'Backspace') return go.CommandHandler.prototype.doKeyDown.call(this)
}

4. 画布滚动模式,无限滚动 or 局部滚动

问题:mac 上 触摸键能左滑右滑控制浏览器页面前进后退,很容易触发

方案:开启无限滚动,避免用户不小心触发了浏览器的前进后退

代码实现:

function infiniteScroll = (infiniteScroll) {
this.diagram.scrollMode = infiniteScroll ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll
}

5. 展开收起多层嵌套的组

问题:组多层嵌套,全部展开后,点击单个组收起第一次无效,第二次点击才生效

代码实现:

方式一:nodeArr 没有绑定 展开收起 属性

// groupIds 为所有 group 的ids,从外到内。 一开始遍历组装数据的时候就收集好
// groupIdsReverse 为所有 group 的ids,从内到外
// 全部展开,从外到内
// 全部收起,从内到外
function setExpandCollapse (isExpand, groupIds, groupIdsReverse) {
// 展开和折叠需要从两个方向处理,再次展开折叠交互才正常,否则第一次点无效,需要点第二次材有限
let arr = isExpand ? groupIds : groupIdsReverse;
let group; arr.forEach(id => {
group = diagram.findNodeForKey(id);
group.isSubGraphExpanded = isExpand;
})
},

方式二:nodeArr 绑定 展开收起 属性 isExpanded

function setExpandCollapse (isExpand) {
const { nodeDataArray, linkDataArray } = diagram.model
const newNodeArr = nodeDataArray.map(v => {
if (v.isGroup) {
return {...v, isExpanded: isExpand}
}
return v
}) // 上面的方法
updateData(newNodeArr, linkArr, false)
}

6. 给图元素加动画

  • 虚线动画
  • icon loading 旋转动画

代码实现:

function loop = () {
const animationTimer = setTimeout(() => {
clearTimeout(animationTimer)
const oldskips = diagram.skipsUndoManager;
diagram.skipsUndoManager = true; // 虚线动画
diagram.links.each((link: any) => {
const dashedLinkShape = link.findObject("dashedLink");
if (dashedLinkShape) {
const off = dashedLinkShape.strokeDashOffset - 3;
// 设置(移动)笔划划动画
dashedLinkShape.strokeDashOffset = (off <= 0) ? 60 : off;
}
}); // loading 旋转
diagram.nodes.each((node: any) => {
const loadingShape = node.findObject("loading");
if (loadingShape) {
const angle = loadingShape.angle + 20;
// 设置(移动)笔划划动画
loadingShape.angle = (angle == 0) ? 360 : angle;
}
}); diagram.skipsUndoManager = oldskips;
loop();
}, 180);
}
loop()

7. 修改框选的样式

问题:框选样式:默认是红色的,和自定义的图颜色不匹配

diagram.toolManager.dragSelectingTool.box = $(go.Part,
{ layerName: "Tool", selectable: false },
$(go.Shape,
{ name: "SHAPE", fill: 'rgba(104, 129, 255, 0.2)', stroke: 'rgba(104, 129, 255, 0.5)', strokeWidth: 2 }));

希望对你有帮助,如果有帮助,请点个攒,谢谢!

gojs 实用高级用法的更多相关文章

  1. linux中find命令高级用法

    前言 在<Linux中的文件查找技巧>一文中,我们已经知道了文件查找的基本方法,今天我们介绍find命令的一些高级使用技巧.它能满足我们一些更加复杂的需求. 查找空文件或空目录 有时候需要 ...

  2. git log 高级用法

    转自:https://github.com/geeeeeeeeek/git-recipes/wiki/5.3-Git-log%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95 内 ...

  3. sed高级用法:模式空间(pattern space)和保持空间(hold space)

    摘自:https://blog.csdn.net/ITsenlin/article/details/21129405 sed高级用法:模式空间(pattern space)和保持空间(hold spa ...

  4. Fiddler 高级用法:Fiddler Script 与 HTTP 断点调试

    转载自 https://my.oschina.net/leejun2005/blog/399108 1.Fiddler Script 1.1 Fiddler Script简介 在web前端开发的过程中 ...

  5. Python——迭代器的几个高级用法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第8篇文章. 今天我们依然介绍的是迭代器,不过介绍的是几个比较常用的高级用法,在实际场景当中非常实用,可以帮助我们大 ...

  6. Python pip高级用法

    1.pip 高级用法为了便于用户安装和管理第三方库和软件,越来越多的编程语言拥有自己的包管理工 具,如 nodejs 的 npm, ruby 的 gem. Python 也不例外,现在 Python ...

  7. Bash 脚本编程的一些高级用法

    概述 偶然间发现 man bash 上其实详细讲解了 shell 编程的语法,包括一些很少用却很实用的高级语法.就像发现了宝藏的孩子,兴奋莫名.于是参考man bash,结合自己的理解,整理出了这篇文 ...

  8. Nmap在实战中的高级用法(详解)

    @ 目录 Nmap在实战中的高级用法(详解) Nmap简单的扫描方式: 一.Nmap高级选项 1.查看本地路由与接口 2.指定网口与IP地址 3.定制探测包 二.Nmap扫描防火墙 1.SYN扫描 2 ...

  9. Visual Studio 宏的高级用法

    因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS. 在上一篇中,我已经介绍了如何编 ...

随机推荐

  1. 零基础学习java------day17------缓冲字节流,转换字节流,简化流,缓冲字符流,序列化和对象流

    1. 缓冲字节流 缓冲区:缓冲区实质上是一个数组.通常它是一个字节数组,但是也可以使用其他种类的数组.但是一个缓冲区不 仅仅 是一个数组.缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程 ...

  2. static JAVA

    static 关键字:使用static修饰的变量是类变量,属于该类本身,没有使用static修饰符的成员变量是实例变量,属于该类的实例.由于同一个JVM内只对应一个Class对象,因此同一个JVM内的 ...

  3. Javaj基础知识runtime error

    遇到的java 运行时错误: NullPointerException空指针  ,简单地说就是调用了未经初始化的对象或者是不存在的对象,这个错误经常出现在创建图片,调用数组这些操作中,比如图片未经初始 ...

  4. 【编程思想】【设计模式】【结构模式Structural】桥梁模式/桥接模式bridge

    Python版 https://github.com/faif/python-patterns/blob/master/structural/bridge.py #!/usr/bin/env pyth ...

  5. Unity实现“笼中窥梦”的渲染效果

    效果 思路 5个面用5个RenderTexture来接受5个摄像机分别获取的小场景图像: RenderTexture就当成屏幕来理解,MainCamera是把画面显示在屏幕上,屏幕就是最大的Rende ...

  6. Wireshark(五):TCP窗口与拥塞处理

    原文出处: EMC中文支持论坛 TCP通过滑动窗口机制检测丢包,并在丢包发生时调整数据传输速率.滑动窗口机制利用数据接收端的接收窗口来控制数据流. 接收窗口值由数据接收端指定,以字节数形式存储于TCP ...

  7. FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台

    FFmpeg和SDL开发专栏(点击传送门) 上一篇:<FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放>下一篇:敬请期待   前言   将ffmpeg移植到海思H ...

  8. CF1108A Two distinct points 题解

    Content 有 \(q\) 次询问,每次询问给定四个数 \(l_1,r_1,l_2,r_2\).对于每次询问,找到两个数 \(a,b\),使得 \(l_1\leqslant a\leqslant ...

  9. epoll linux和协程gevent的区别

    epoll linux  底层是libevent.so模块实现的 gevent也是IO多路复用,底层是libevent.so模块实现的是更上层的封装 Twsited异步网络框架.代码量非常大.在开源p ...

  10. TFTP协议介绍-python实现tftp客户端

    1. TFTP协议介绍 TFTP(Trivial File Transfer Protocol,简单文件传输协议) 是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议 特点: ...