乐趣区

关于可视化:gojs-实用高级用法

大家,新年好!

历史文章:

  • 数据可视化 gojs 简略应用介绍
  • gojs 如何实现虚线 (蚂蚁线) 动画?

本文介绍的是在应用 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 }));

心愿对你有帮忙,如果有帮忙,请点个攒,谢谢!

退出移动版