Everybody, happy New Year!
Historical articles:
This article describes the use of gojs Some solutions to the problems you may encounter in the process of drawing.
gojs is a very powerful js library for visualizing relationships.
1. Cancel updating animation
Problem: when updating data, rendering will be triggered, rendering animation is available, and the user experience is poor.
Scheme: initial data drawing with animation; Update data drawing, no animation.
Code implementation:
// The diagram s used later are instances created by gojs // diagram_container is the domain ID of the graph container diagram = $(go.Diagram, 'diagram_container')
Scheme I:
function updateData (nodeArr = [], linkArr = [], hasAnimation = true ) { if (hasAnimation) { diagram.model = new go.GraphLinksModel(nodeArr, linkArr); } else { diagram.model.nodeDataArray = nodeArr diagram.model.linkDataArray = linkArr } } // After initializing an instance, it is processed only once diagram.animationManager.canStart = function(reason) { if (reason === 'Model') return false return true }
Scheme II:
// Bind the data to the diagram and draw the 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() } }
Scheme III:
// Bind the data to the diagram and draw the diagram function updateData (nodeArr = [], linkArr = [], hasAnimation = true) { diagram.model = new go.GraphLinksModel(nodeArr, linkArr); if (diagram.animationManager) { // Default has animation, None has no animation diagram.animationManager.initialAnimationStyle = hasAnimation ? go.AnimationManager.Default : go.AnimationManager.None; } }
2. Export diagram (including the part outside the visual area)
Problem: the exported image, which is realized by using the relevant api of the native canvas, only contains the images in the visual area
Solution: use the api provided by gojs to process
Principle behind it: use the data to redraw a graph, all data nodes are in the visible area of the graph, and then use the native canvas related api to export the picture
Code implementation:
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. Disable ctrl related shortcut keys
// Disable ctl related operations diagram.commandHandler.doKeyDown = function() { const e = diagram.lastInput const control = e.control || e.meta const key = e.key // Cancel Ctrl + A / Z / Y / g a-select all, z-undo, y-redo, G-group if (control && ['A', 'Z', 'Y', 'G'].includes(key)) return // Cancel Del/Backspace delete key if (key === 'Del' || key === 'Backspace') return go.CommandHandler.prototype.doKeyDown.call(this) }
4. Canvas scrolling mode, unlimited scrolling or local scrolling
Problem: the touch key on the mac can slide left and right to control the forward and backward of the browser page, which is easy to trigger
Scheme: enable unlimited scrolling to avoid the user accidentally triggering the forward and backward of the browser
Code implementation:
function infiniteScroll = (infiniteScroll) { this.diagram.scrollMode = infiniteScroll ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll }
5. Expand and collapse multi-level nested groups
Problem: groups are nested in multiple layers. After all the groups are expanded, click a single group to collapse. The first click is invalid, and the second click is effective
Code implementation:
Method 1: nodeArr does not bind the expand / collapse attribute
// groupIds is the ids of all group s, from outside to inside. The assembly data is collected at the beginning of traversal // groupIdsReverse is the ids of all group s, from inside to outside // Expand all, from outside to inside // Put it all away, from inside to outside function setExpandCollapse (isExpand, groupIds, groupIdsReverse) { // Unfolding and folding need to be handled from two directions. Only when unfolding and folding again can the interaction be normal. Otherwise, the first point is invalid and the second point is limited let arr = isExpand ? groupIds : groupIdsReverse; let group; arr.forEach(id => { group = diagram.findNodeForKey(id); group.isSubGraphExpanded = isExpand; }) },
Method 2: nodeArr binding expands and retracts the attribute isExpanded
function setExpandCollapse (isExpand) { const { nodeDataArray, linkDataArray } = diagram.model const newNodeArr = nodeDataArray.map(v => { if (v.isGroup) { return {...v, isExpanded: isExpand} } return v }) // The above method updateData(newNodeArr, linkArr, false) }
6. Animate drawing elements
- Dashed animation
- icon loading rotation animation
Code implementation:
function loop = () { const animationTimer = setTimeout(() => { clearTimeout(animationTimer) const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; // Dashed animation diagram.links.each((link: any) => { const dashedLinkShape = link.findObject("dashedLink"); if (dashedLinkShape) { const off = dashedLinkShape.strokeDashOffset - 3; // Animate (move) strokes dashedLinkShape.strokeDashOffset = (off <= 0) ? 60 : off; } }); // loading rotation diagram.nodes.each((node: any) => { const loadingShape = node.findObject("loading"); if (loadingShape) { const angle = loadingShape.angle + 20; // Animate (move) strokes loadingShape.angle = (angle == 0) ? 360 : angle; } }); diagram.skipsUndoManager = oldskips; loop(); }, 180); } loop()
7. Modify the selected style
Problem: box selection style: the default is red, which does not match the custom drawing color
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 }));
I hope it will help you. If it helps, please save it. Thank you!