Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Non-Realtime Dragging</title>
  <meta name="description" content="A modification of DraggingTool to show a ghost image of what is being moved, rather than moving the nodes and links in realtime." />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Copyright 1998-2019 by Northwoods Software Corporation. -->

  <script src="https://gojs.net/latest/release/go-debug.js"></script>
 
</head>
<body>
<div id="sample">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:900px"></div>
</div>
</body>
</html>
              
            
!

CSS

              
                
              
            
!

JS

              
                var $ = go.GraphObject.make;
		  go.Shape.defineArrowheadGeometry("CustomArrowHead", go.Geometry.parse("M0.854,7.854C0.756,7.951,0.628,8,0.5,8S0.244,7.951,0.146,7.854c-0.195-0.195-0.195-0.512,0-0.707L3.293,4L0.146,0.853 c-0.195-0.195-0.195-0.512,0-0.707s0.512-0.195,0.707,0l3.5,3.5c0.195,0.195,0.195,0.512,0,0.707", true));
		  
		  
		  myDiagram =
			$(go.Diagram, "myDiagramDiv",
			  {
				scale: 5,
				"rotatingTool.handleAngle": 300,
				"rotatingTool.handleDistance": 5,
				"rotatingTool.snapAngleMultiple": 15,
				"rotatingTool.snapAngleEpsilon": 15,
				"undoManager.isEnabled": true
			  });
	  
		  var Tools = {
			LinkHelpers: {
				imageTop: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMHB0IiBoZWlnaHQ9IjMwcHQiIHZpZXdCb3g9IjAgMCAzMCAzMCIgdmVyc2lvbj0iMS4xIj48ZyBpZD0ic3VyZmFjZTEiPjxwYXRoIHN0eWxlPSIgc3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7ZmlsbDpyZ2IoMTAwJSwxMDAlLDEwMCUpO2ZpbGwtb3BhY2l0eToxOyIgZD0iTSAyNi4yNSAyNC4zNzUgQyAyNi4yNSAyNS4zOTg0MzggMjUuMzk4NDM4IDI2LjI1IDI0LjM3NSAyNi4yNSBMIDUuNjI1IDI2LjI1IEMgNC42MDE1NjIgMjYuMjUgMy43NSAyNS4zOTg0MzggMy43NSAyNC4zNzUgTCAzLjc1IDUuNjI1IEMgMy43NSA0LjYwMTU2MiA0LjYwMTU2MiAzLjc1IDUuNjI1IDMuNzUgTCAyNC4zNzUgMy43NSBDIDI1LjM5ODQzOCAzLjc1IDI2LjI1IDQuNjAxNTYyIDI2LjI1IDUuNjI1IFogTSAyNi4yNSAyNC4zNzUgIi8+PHBhdGggc3R5bGU9IiBzdHJva2U6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtmaWxsOnJnYigyOC42Mjc0NTElLDU2LjA3ODQzMSUsODguMjM1Mjk0JSk7ZmlsbC1vcGFjaXR5OjE7IiBkPSJNIDMwIDI0LjM3NSBMIDMwIDUuNjI1IEMgMzAgMi41MjM0MzggMjcuNSAwIDI0LjM3NSAwIEwgNS42MjUgMCBDIDIuNTIzNDM4IDAgMCAyLjUyMzQzOCAwIDUuNjI1IEwgMCAyNC4zNzUgQyAwIDI3LjUgMi41MjM0MzggMzAgNS42MjUgMzAgTCAyNC4zNzUgMzAgQyAyNy41IDMwIDMwIDI3LjUgMzAgMjQuMzc1IFogTSAyNi4yNSAyNC4zNzUgQyAyNi4yNSAyNS4zOTg0MzggMjUuMzk4NDM4IDI2LjI1IDI0LjM3NSAyNi4yNSBMIDUuNjI1IDI2LjI1IEMgNC42MDE1NjIgMjYuMjUgMy43NSAyNS4zOTg0MzggMy43NSAyNC4zNzUgTCAzLjc1IDUuNjI1IEMgMy43NSA0LjYwMTU2MiA0LjYwMTU2MiAzLjc1IDUuNjI1IDMuNzUgTCAyNC4zNzUgMy43NSBDIDI1LjM5ODQzOCAzLjc1IDI2LjI1IDQuNjAxNTYyIDI2LjI1IDUuNjI1IFogTSAyNi4yNSAyNC4zNzUgIi8+PHBhdGggc3R5bGU9IiBzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOnJnYigyOC42Mjc0NTElLDU2LjA3ODQzMSUsODguMjM1Mjk0JSk7ZmlsbC1vcGFjaXR5OjE7IiBkPSJNIDE2LjM5ODQzOCAxMC44OTg0MzggTCAxNi4zOTg0MzggMjEuNTc0MjE5IEMgMTYuMzk4NDM4IDIyLjM1MTU2MiAxNS43NzM0MzggMjIuOTc2NTYyIDE1IDIyLjk3NjU2MiBDIDE0LjIyNjU2MiAyMi45NzY1NjIgMTMuNjAxNTYyIDIyLjM1MTU2MiAxMy42MDE1NjIgMjEuNTc0MjE5IEwgMTMuNjAxNTYyIDEwLjg5ODQzOCBMIDEwLjM3NSAxNC4xMjUgQyA5LjgyNDIxOSAxNC42NzU3ODEgOC45MjU3ODEgMTQuNjc1NzgxIDguMzc1IDE0LjEyNSBDIDcuODI0MjE5IDEzLjU3NDIxOSA3LjgyNDIxOSAxMi42NzU3ODEgOC4zNzUgMTIuMTI1IEwgMTQgNi41IEMgMTQuNTUwNzgxIDUuOTQ5MjE5IDE1LjQ0OTIxOSA1Ljk0OTIxOSAxNiA2LjUgTCAyMS42MjUgMTIuMTI1IEMgMjEuODk4NDM4IDEyLjM5ODQzOCAyMi4wMjM0MzggMTIuNzczNDM4IDIyLjAyMzQzOCAxMy4xMjUgQyAyMi4wMjM0MzggMTMuNDc2NTYyIDIxLjg5ODQzOCAxMy44NTE1NjIgMjEuNjI1IDE0LjEyNSBDIDIxLjA3NDIxOSAxNC42NzU3ODEgMjAuMTc1NzgxIDE0LjY3NTc4MSAxOS42MjUgMTQuMTI1IFogTSAxNi4zOTg0MzggMTAuODk4NDM4ICIvPjwvZz48L3N2Zz4=',
				imageLeft: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMHB0IiBoZWlnaHQ9IjMwcHQiIHZpZXdCb3g9IjAgMCAzMCAzMCIgdmVyc2lvbj0iMS4xIj48ZyBpZD0ic3VyZmFjZTEiPjxwYXRoIHN0eWxlPSIgc3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7ZmlsbDpyZ2IoMTAwJSwxMDAlLDEwMCUpO2ZpbGwtb3BhY2l0eToxOyIgZD0iTSAyNC4zNzUgMy43NSBDIDI1LjM5ODQzOCAzLjc1IDI2LjI1IDQuNjAxNTYyIDI2LjI1IDUuNjI1IEwgMjYuMjUgMjQuMzc1IEMgMjYuMjUgMjUuMzk4NDM4IDI1LjM5ODQzOCAyNi4yNSAyNC4zNzUgMjYuMjUgTCA1LjYyNSAyNi4yNSBDIDQuNjAxNTYyIDI2LjI1IDMuNzUgMjUuMzk4NDM4IDMuNzUgMjQuMzc1IEwgMy43NSA1LjYyNSBDIDMuNzUgNC42MDE1NjIgNC42MDE1NjIgMy43NSA1LjYyNSAzLjc1IFogTSAyNC4zNzUgMy43NSAiLz48cGF0aCBzdHlsZT0iIHN0cm9rZTpub25lO2ZpbGwtcnVsZTpldmVub2RkO2ZpbGw6cmdiKDI4LjYyNzQ1MSUsNTYuMDc4NDMxJSw4OC4yMzUyOTQlKTtmaWxsLW9wYWNpdHk6MTsiIGQ9Ik0gMjQuMzc1IDAgTCA1LjYyNSAwIEMgMi41MjM0MzggMCAwIDIuNSAwIDUuNjI1IEwgMCAyNC4zNzUgQyAwIDI3LjQ3NjU2MiAyLjUyMzQzOCAzMCA1LjYyNSAzMCBMIDI0LjM3NSAzMCBDIDI3LjUgMzAgMzAgMjcuNDc2NTYyIDMwIDI0LjM3NSBMIDMwIDUuNjI1IEMgMzAgMi41IDI3LjUgMCAyNC4zNzUgMCBaIE0gMjQuMzc1IDMuNzUgQyAyNS4zOTg0MzggMy43NSAyNi4yNSA0LjYwMTU2MiAyNi4yNSA1LjYyNSBMIDI2LjI1IDI0LjM3NSBDIDI2LjI1IDI1LjM5ODQzOCAyNS4zOTg0MzggMjYuMjUgMjQuMzc1IDI2LjI1IEwgNS42MjUgMjYuMjUgQyA0LjYwMTU2MiAyNi4yNSAzLjc1IDI1LjM5ODQzOCAzLjc1IDI0LjM3NSBMIDMuNzUgNS42MjUgQyAzLjc1IDQuNjAxNTYyIDQuNjAxNTYyIDMuNzUgNS42MjUgMy43NSBaIE0gMjQuMzc1IDMuNzUgIi8+PHBhdGggc3R5bGU9IiBzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOnJnYigyOC42Mjc0NTElLDU2LjA3ODQzMSUsODguMjM1Mjk0JSk7ZmlsbC1vcGFjaXR5OjE7IiBkPSJNIDEwLjg5ODQzOCAxMy42MDE1NjIgTCAyMS41NzQyMTkgMTMuNjAxNTYyIEMgMjIuMzUxNTYyIDEzLjYwMTU2MiAyMi45NzY1NjIgMTQuMjI2NTYyIDIyLjk3NjU2MiAxNSBDIDIyLjk3NjU2MiAxNS43NzM0MzggMjIuMzUxNTYyIDE2LjM5ODQzOCAyMS41NzQyMTkgMTYuMzk4NDM4IEwgMTAuODk4NDM4IDE2LjM5ODQzOCBMIDE0LjEyNSAxOS42MjUgQyAxNC42NzU3ODEgMjAuMTc1NzgxIDE0LjY3NTc4MSAyMS4wNzQyMTkgMTQuMTI1IDIxLjYyNSBDIDEzLjU3NDIxOSAyMi4xNzU3ODEgMTIuNjc1NzgxIDIyLjE3NTc4MSAxMi4xMjUgMjEuNjI1IEwgNi41IDE2IEMgNS45NDkyMTkgMTUuNDQ5MjE5IDUuOTQ5MjE5IDE0LjU1MDc4MSA2LjUgMTQgTCAxMi4xMjUgOC4zNzUgQyAxMi4zOTg0MzggOC4xMDE1NjIgMTIuNzczNDM4IDcuOTc2NTYyIDEzLjEyNSA3Ljk3NjU2MiBDIDEzLjQ3NjU2MiA3Ljk3NjU2MiAxMy44NTE1NjIgOC4xMDE1NjIgMTQuMTI1IDguMzc1IEMgMTQuNjc1NzgxIDguOTI1NzgxIDE0LjY3NTc4MSA5LjgyNDIxOSAxNC4xMjUgMTAuMzc1IFogTSAxMC44OTg0MzggMTMuNjAxNTYyICIvPjwvZz48L3N2Zz4=',
				imageRight: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMHB0IiBoZWlnaHQ9IjMwcHQiIHZpZXdCb3g9IjAgMCAzMCAzMCIgdmVyc2lvbj0iMS4xIj48ZyBpZD0ic3VyZmFjZTEiPjxwYXRoIHN0eWxlPSIgc3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7ZmlsbDpyZ2IoMTAwJSwxMDAlLDEwMCUpO2ZpbGwtb3BhY2l0eToxOyIgZD0iTSA1LjYyNSAyNi4yNSBDIDQuNjAxNTYyIDI2LjI1IDMuNzUgMjUuMzk4NDM4IDMuNzUgMjQuMzc1IEwgMy43NSA1LjYyNSBDIDMuNzUgNC42MDE1NjIgNC42MDE1NjIgMy43NSA1LjYyNSAzLjc1IEwgMjQuMzc1IDMuNzUgQyAyNS4zOTg0MzggMy43NSAyNi4yNSA0LjYwMTU2MiAyNi4yNSA1LjYyNSBMIDI2LjI1IDI0LjM3NSBDIDI2LjI1IDI1LjM5ODQzOCAyNS4zOTg0MzggMjYuMjUgMjQuMzc1IDI2LjI1IFogTSA1LjYyNSAyNi4yNSAiLz48cGF0aCBzdHlsZT0iIHN0cm9rZTpub25lO2ZpbGwtcnVsZTpldmVub2RkO2ZpbGw6cmdiKDI4LjYyNzQ1MSUsNTYuMDc4NDMxJSw4OC4yMzUyOTQlKTtmaWxsLW9wYWNpdHk6MTsiIGQ9Ik0gNS42MjUgMzAgTCAyNC4zNzUgMzAgQyAyNy40NzY1NjIgMzAgMzAgMjcuNSAzMCAyNC4zNzUgTCAzMCA1LjYyNSBDIDMwIDIuNTIzNDM4IDI3LjQ3NjU2MiAwIDI0LjM3NSAwIEwgNS42MjUgMCBDIDIuNSAwIDAgMi41MjM0MzggMCA1LjYyNSBMIDAgMjQuMzc1IEMgMCAyNy41IDIuNSAzMCA1LjYyNSAzMCBaIE0gNS42MjUgMjYuMjUgQyA0LjYwMTU2MiAyNi4yNSAzLjc1IDI1LjM5ODQzOCAzLjc1IDI0LjM3NSBMIDMuNzUgNS42MjUgQyAzLjc1IDQuNjAxNTYyIDQuNjAxNTYyIDMuNzUgNS42MjUgMy43NSBMIDI0LjM3NSAzLjc1IEMgMjUuMzk4NDM4IDMuNzUgMjYuMjUgNC42MDE1NjIgMjYuMjUgNS42MjUgTCAyNi4yNSAyNC4zNzUgQyAyNi4yNSAyNS4zOTg0MzggMjUuMzk4NDM4IDI2LjI1IDI0LjM3NSAyNi4yNSBaIE0gNS42MjUgMjYuMjUgIi8+PHBhdGggc3R5bGU9IiBzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOnJnYigyOC42Mjc0NTElLDU2LjA3ODQzMSUsODguMjM1Mjk0JSk7ZmlsbC1vcGFjaXR5OjE7IiBkPSJNIDE5LjEwMTU2MiAxNi4zOTg0MzggTCA4LjQyNTc4MSAxNi4zOTg0MzggQyA3LjY0ODQzOCAxNi4zOTg0MzggNy4wMjM0MzggMTUuNzczNDM4IDcuMDIzNDM4IDE1IEMgNy4wMjM0MzggMTQuMjI2NTYyIDcuNjQ4NDM4IDEzLjYwMTU2MiA4LjQyNTc4MSAxMy42MDE1NjIgTCAxOS4xMDE1NjIgMTMuNjAxNTYyIEwgMTUuODc1IDEwLjM3NSBDIDE1LjMyNDIxOSA5LjgyNDIxOSAxNS4zMjQyMTkgOC45MjU3ODEgMTUuODc1IDguMzc1IEMgMTYuNDI1NzgxIDcuODI0MjE5IDE3LjMyNDIxOSA3LjgyNDIxOSAxNy44NzUgOC4zNzUgTCAyMy41IDE0IEMgMjQuMDUwNzgxIDE0LjU1MDc4MSAyNC4wNTA3ODEgMTUuNDQ5MjE5IDIzLjUgMTYgTCAxNy44NzUgMjEuNjI1IEMgMTcuNjAxNTYyIDIxLjg5ODQzOCAxNy4yMjY1NjIgMjIuMDIzNDM4IDE2Ljg3NSAyMi4wMjM0MzggQyAxNi41MjM0MzggMjIuMDIzNDM4IDE2LjE0ODQzOCAyMS44OTg0MzggMTUuODc1IDIxLjYyNSBDIDE1LjMyNDIxOSAyMS4wNzQyMTkgMTUuMzI0MjE5IDIwLjE3NTc4MSAxNS44NzUgMTkuNjI1IFogTSAxOS4xMDE1NjIgMTYuMzk4NDM4ICIvPjwvZz48L3N2Zz4=',
				imageBottom: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMHB0IiBoZWlnaHQ9IjMwcHQiIHZpZXdCb3g9IjAgMCAzMCAzMCIgdmVyc2lvbj0iMS4xIj48ZyBpZD0ic3VyZmFjZTEiPjxwYXRoIHN0eWxlPSIgc3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7ZmlsbDpyZ2IoMTAwJSwxMDAlLDEwMCUpO2ZpbGwtb3BhY2l0eToxOyIgZD0iTSAzLjc1IDUuNjI1IEMgMy43NSA0LjYwMTU2MiA0LjYwMTU2MiAzLjc1IDUuNjI1IDMuNzUgTCAyNC4zNzUgMy43NSBDIDI1LjM5ODQzOCAzLjc1IDI2LjI1IDQuNjAxNTYyIDI2LjI1IDUuNjI1IEwgMjYuMjUgMjQuMzc1IEMgMjYuMjUgMjUuMzk4NDM4IDI1LjM5ODQzOCAyNi4yNSAyNC4zNzUgMjYuMjUgTCA1LjYyNSAyNi4yNSBDIDQuNjAxNTYyIDI2LjI1IDMuNzUgMjUuMzk4NDM4IDMuNzUgMjQuMzc1IFogTSAzLjc1IDUuNjI1ICIvPjxwYXRoIHN0eWxlPSIgc3Ryb2tlOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7ZmlsbDpyZ2IoMjguNjI3NDUxJSw1Ni4wNzg0MzElLDg4LjIzNTI5NCUpO2ZpbGwtb3BhY2l0eToxOyIgZD0iTSAwIDUuNjI1IEwgMCAyNC4zNzUgQyAwIDI3LjQ3NjU2MiAyLjUgMzAgNS42MjUgMzAgTCAyNC4zNzUgMzAgQyAyNy40NzY1NjIgMzAgMzAgMjcuNDc2NTYyIDMwIDI0LjM3NSBMIDMwIDUuNjI1IEMgMzAgMi41IDI3LjQ3NjU2MiAwIDI0LjM3NSAwIEwgNS42MjUgMCBDIDIuNSAwIDAgMi41IDAgNS42MjUgWiBNIDMuNzUgNS42MjUgQyAzLjc1IDQuNjAxNTYyIDQuNjAxNTYyIDMuNzUgNS42MjUgMy43NSBMIDI0LjM3NSAzLjc1IEMgMjUuMzk4NDM4IDMuNzUgMjYuMjUgNC42MDE1NjIgMjYuMjUgNS42MjUgTCAyNi4yNSAyNC4zNzUgQyAyNi4yNSAyNS4zOTg0MzggMjUuMzk4NDM4IDI2LjI1IDI0LjM3NSAyNi4yNSBMIDUuNjI1IDI2LjI1IEMgNC42MDE1NjIgMjYuMjUgMy43NSAyNS4zOTg0MzggMy43NSAyNC4zNzUgWiBNIDMuNzUgNS42MjUgIi8+PHBhdGggc3R5bGU9IiBzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOnJnYigyOC42Mjc0NTElLDU2LjA3ODQzMSUsODguMjM1Mjk0JSk7ZmlsbC1vcGFjaXR5OjE7IiBkPSJNIDEzLjYwMTU2MiAxOS4xMDE1NjIgTCAxMy42MDE1NjIgOC40MjU3ODEgQyAxMy42MDE1NjIgNy42NDg0MzggMTQuMjI2NTYyIDcuMDIzNDM4IDE1IDcuMDIzNDM4IEMgMTUuNzczNDM4IDcuMDIzNDM4IDE2LjM5ODQzOCA3LjY0ODQzOCAxNi4zOTg0MzggOC40MjU3ODEgTCAxNi4zOTg0MzggMTkuMTAxNTYyIEwgMTkuNjI1IDE1Ljg3NSBDIDIwLjE3NTc4MSAxNS4zMjQyMTkgMjEuMDc0MjE5IDE1LjMyNDIxOSAyMS42MjUgMTUuODc1IEMgMjIuMTc1NzgxIDE2LjQyNTc4MSAyMi4xNzU3ODEgMTcuMzI0MjE5IDIxLjYyNSAxNy44NzUgTCAxNiAyMy41IEMgMTUuNDQ5MjE5IDI0LjA1MDc4MSAxNC41NTA3ODEgMjQuMDUwNzgxIDE0IDIzLjUgTCA4LjM3NSAxNy44NzUgQyA4LjEwMTU2MiAxNy42MDE1NjIgNy45NzY1NjIgMTcuMjI2NTYyIDcuOTc2NTYyIDE2Ljg3NSBDIDcuOTc2NTYyIDE2LjUyMzQzOCA4LjEwMTU2MiAxNi4xNDg0MzggOC4zNzUgMTUuODc1IEMgOC45MjU3ODEgMTUuMzI0MjE5IDkuODI0MjE5IDE1LjMyNDIxOSAxMC4zNzUgMTUuODc1IFogTSAxMy42MDE1NjIgMTkuMTAxNTYyICIvPjwvZz48L3N2Zz4='
			}
		};

		function makePort(name, align, spot, output, input, horizontal) {
			return $(go.Shape,
				{
					fill: "transparent",  // changed to a color in the mouseEnter event handler
					strokeWidth: 0,  // no stroke
					width: horizontal ? NaN : 8,  // if not stretching horizontally, just 8 wide
					height: !horizontal ? NaN : 8,  // if not stretching vertically, just 8 tall
					alignment: align,  // align the port on the main Shape
					stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical),
					portId: name,  // declare this object to be a "port"
					fromSpot: spot,  // declare where links may connect at this port
					fromLinkable: false,  // declare whether the user may draw links from here
					toSpot: spot,  // declare where links may connect at this port
					fromLinkableSelfNode: false,
					fromLinkableDuplicates: true,
					toLinkableSelfNode: false,
					toLinkableDuplicates: true,
					toLinkable: true
				}
			);
		}
		function makeHelperArrow(name, align, spot, output, input, imageType) {
			let horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
			let alignmentFocus = align.opposite();
			alignmentFocus.offsetX = 0;
			alignmentFocus.offsetY = 0;
			alignmentFocus.x = alignmentFocus.x === 1 || alignmentFocus.x === 0 ? alignmentFocus.x : 0.5;
			alignmentFocus.y = alignmentFocus.y === 1 || alignmentFocus.y === 0 ? alignmentFocus.y : 0.5;
			return $(go.Picture, Tools.LinkHelpers[imageType],
				{
					name: name,
					cursor: "copy",
					desiredSize: new go.Size(8, 8),
					alignment: align,
					portId: name,
					fromSpot: spot,
					toSpot: spot,
					toLinkable: false,
					fromLinkable: true,
					opacity: 0,
					alignmentFocus: alignmentFocus,
					mouseEnter: (e, node) => {

						let fromLinkable = true;
						node.cursor = fromLinkable ? "copy" : "default";

						let items = ["T_H", "L_H", "R_H", "B_H"];
						node.opacity = fromLinkable ? .8 : 0;

						for (let i = 0; i <= items.length; i++) {
							if (node.name !== items[i]) {
								if (node.part.findObject(items[i])) {
									node.part.findObject(items[i]).opacity = fromLinkable ? .4 : 0;
								}
							}
						}
					},
				}
			);
		}

		function getNodeShape() {
			return $(go.Panel, "Viewbox",
						{
							cursor: "move",
							background: "transparent",
							padding: 1
						},
						$(go.Panel, "Auto",
						$(go.Shape, "RoundedRectangle", { name: "ViewPort", fill: "transparent", strokeWidth: 0, parameter1: 10 }),
						$(go.Picture, { desiredSize: new go.Size(35, 35), source: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1OCIgaGVpZ2h0PSI1OCIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA1OCA1OCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTggNTg7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48ZyBpZD0iZmx3X3g1Rl9ub3RpZmljYXRpb24iPjxnPjxjaXJjbGUgc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6Y3VycmVudENvbG9yOyIgY3g9IjQzIiBjeT0iMzMiIHI9IjEwIi8+PC9nPjxnPjxwYXRoIHN0eWxlPSJmaWxsOiNGRkZGRkY7IiBkPSJNNDIuMjIzLDM3LjE1NHYtNi4wMDNoLTEuMTg4di0xLjM4OWgyLjc2djcuMzkyaDEuMTd2MS4zODloLTMuOTJ2LTEuMzg5SDQyLjIyM3ogTTQyLjIyMywyOC4yNXYtMS43OTNoMS41NzJ2MS43OTNINDIuMjIzeiIvPjwvZz48Zz48cGF0aCBzdHlsZT0iZmlsbDpzdHJva2VDb2xvcjsiIGQ9Ik00Ni45NzMsNTBIMTFjLTAuNTI4LDAtMC45NjUtMC40MS0wLjk5OC0wLjkzN2MtMC4zODYtNi4wOTUsMy4xMDYtNy44MjcsMy4yNjItNy45Yy0wLjAwMS0wLjAwMiw0LjY5MS0yLjU5Miw3LjUxMS00LjEyOGMyLjE2Ny0xLjE4MSwyLjA4OS0yLjc1OSwyLjA4NS0yLjgyNWwtMC4wMDMtMy4xNzljLTIuMjI2LTIuNzktMi45MTUtNS4yOTktMy4xMTktNi4zNjNjLTAuODU0LTAuNjI2LTEuMTQzLTEuNjI3LTEuMTcyLTIuMTkxbC0wLjAwMS0zLjQ4NGMwLTAuOTEzLDAuNDkyLTEuNTg4LDAuODcxLTEuOTc0YzAuMDI1LTEuMDUsMC4wOS0zLjc4OCwwLjEyOS01Ljg3OGMwLjA4OC00LjczNyw0Ljc5NS02Ljg1Niw5LjQyNC02Ljg1NmMwLjAwNCwwLDAuMDA4LDAsMC4wMTIsMGM0LjQzLDAuMDAzLDkuMjI3LDEuODAyLDkuNDA1LDYuODM5YzAuMDc0LDIuMDg0LDAuMTE5LDQuODM4LDAuMTM1LDUuOWMwLjM3OCwwLjM4NiwwLjg2NiwxLjA2LDAuODY2LDEuOTY5djIuNjA1YzAsMC41NTItMC40NDcsMS0xLDFzLTEtMC40NDgtMS0xdi0yLjYwNWMwLTAuMzA3LTAuMzI1LTAuNjE0LTAuNDM5LTAuNjk3Yy0wLjI1NC0wLjE4Ni0wLjQxNy0wLjQ4OC0wLjQyMS0wLjgwM2MwLTAuMDM3LTAuMDQ3LTMuNjk4LTAuMTM5LTYuMjk3Yy0wLjE2Mi00LjU1MS01LjcxMi00LjkwOS03LjQwOS00LjkxYzAsMC0wLjAwMSwwLTAuMDAyLDBjLTAuMzI3LDAtNy4zNDIsMC4wNi03LjQzMiw0Ljg5M2MtMC4wNDksMi42NDUtMC4xNCw2LjMyNy0wLjE0LDYuMzI3Yy0wLjAwOCwwLjMxOS0wLjE2NywwLjYxNS0wLjQzLDAuNzk3Yy0wLjEwNCwwLjA3Ni0wLjQzLDAuMzgzLTAuNDMsMC42OXYzLjQzMmMwLTAuMDAxLDAtMC4wMDIsMC0wLjAwMmMwLjAwNCwwLDAuMDY4LDAuNTI1LDAuNDg5LDAuNzA5YzAuMzM1LDAuMTQ2LDAuNTY0LDAuNDY1LDAuNTk1LDAuODNjMC4wMDIsMC4wMjMsMC4zMDQsMi44NTUsMi45NzcsNi4wNzVjMC4xNDksMC4xOCwwLjIzLDAuNDA1LDAuMjMsMC42Mzl2My40MjFjMC4wMjQsMC40NzMtMC4wMDUsMi45OTUtMy4xMjUsNC42OTVjLTIuODMzLDEuNTQzLTcuNTU2LDQuMTUtNy41NTcsNC4xNUMxNC4wNDQsNDMuMDEsMTIuMDIsNDQuMDk3LDExLjk3Myw0OGgzNC4wMjZjLTAuMDEyLTAuOTk5LTAuMTU1LTEuODk2LTAuNDI5LTIuNjc3Yy0wLjE4Mi0wLjUyMSwwLjA5My0xLjA5MiwwLjYxNC0xLjI3NGMwLjUyMy0wLjE4MiwxLjA5MiwwLjA5NCwxLjI3NCwwLjYxNGMwLjQ0MywxLjI3MSwwLjYxNiwyLjc1MSwwLjUxMiw0LjRDNDcuOTM4LDQ5LjU5LDQ3LjUsNTAsNDYuOTczLDUweiIvPjwvZz48L2c+PGcgaWQ9IkxheWVyXzEiPjwvZz48L3N2Zz4=' }))
					);
		}
		
		const nodeSelectionAdornmentTemplate = $(go.Adornment, "Auto",
					$(go.Shape, { fill: null, stroke: "#dbe9f9", strokeWidth: 1.5 }),
					$(go.Shape, "XLine", { visible: false, alignment: new go.Spot(0, 0, -2, 0), cursor: "default", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.35, stroke: "#72a8e8" }
					),
					$(go.Shape, "XLine", { visible: false, alignment: go.Spot.TopRight, cursor: "default", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.35, stroke: "#72a8e8" }
					),
					$(go.Shape, "XLine", { visible: false, alignment: go.Spot.BottomLeft, cursor: "default", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.35, stroke: "#72a8e8" }
					),
					$(go.Shape, "XLine", { visible: false, alignment: go.Spot.BottomRight, cursor: "default", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.35, stroke: "#72a8e8" }
					),
					$(go.Placeholder, { padding: 1 })
				)
	  
	  const rotateImage = 'M14.968,10.312c0.575-3.917-1.748-7.643-5.521-8.859C6.752,0.585,3.86,1.195,1.732,3.012l0.24-2.18   c0.039-0.41-0.251-0.782-0.663-0.827C0.897-0.041,0.527,0.256,0.481,0.668L0.006,4.984C-0.022,5.199,0.05,5.408,0.193,5.566   c0.142,0.159,0.345,0.249,0.559,0.249l4.346-0.004C5.5,5.811,5.827,5.496,5.847,5.099c0.001-0.013,0.001-0.025,0.001-0.039   c0-0.414-0.337-0.75-0.751-0.749L2.533,4.314c0.013-0.015,0.019-0.028,0.032-0.043c1.744-1.574,4.169-2.116,6.422-1.39   c2.835,0.913,4.639,3.567,4.539,6.475c-0.052,1.485-0.588,2.929-1.595,4.089c-0.015,0.013-0.027,0.019-0.042,0.033l-0.047-2.563   c-0.008-0.414-0.349-0.744-0.763-0.736c-0.013,0-0.026,0.001-0.039,0.002c-0.396,0.027-0.705,0.36-0.698,0.762l0.079,4.346   c0.004,0.214,0.099,0.415,0.26,0.554c0.161,0.139,0.371,0.208,0.586,0.176l4.306-0.558c0.411-0.053,0.701-0.429,0.647-0.84   c-0.053-0.411-0.431-0.694-0.84-0.647l-2.175,0.282C14.129,13.129,14.746,11.703,14.968,10.312z';

	  const nodeRotateAdornmentTemplate = $(go.Adornment,
			{ locationSpot: go.Spot.Center, locationObjectName: "CIRCLE" },
			$(go.Panel, "Auto", { cursor: "pointer", stretch: go.GraphObject.Fill, background: "transparent" },
			$(go.Shape, { name: "CIRCLE", cursor: "pointer", geometry: go.Geometry.parse(rotateImage, true), strokeWidth: 0, fill: "#72a8e8", width: 8, height: 8 })
			)
		);


	  const nodeResizeAdornmentTemplate = $(go.Adornment, "Spot",
				{ locationSpot: go.Spot.Right },
				$(go.Placeholder),
				$(go.Shape, "Rectangle", { alignment: go.Spot.TopLeft, cursor: "nw-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.Top, cursor: "n-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.TopRight, cursor: "ne-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.Left, cursor: "w-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.Right, cursor: "e-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.BottomLeft, cursor: "se-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.Bottom, cursor: "s-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" }),
				$(go.Shape, "Rectangle", { alignment: go.Spot.BottomRight, cursor: "sw-resize", desiredSize: new go.Size(3, 3), fill: "#fff", strokeWidth: 0.5, stroke: "#72a8e8" })
			);

			myDiagram.nodeTemplate = $(go.Node, "Spot", {
				zOrder: 5,
				locationObjectName: "Shape",
				locationSpot: go.Spot.Center,
				selectionAdornmentTemplate: nodeSelectionAdornmentTemplate,
				selectionObjectName: "Shape",
				resizeObjectName: "Shape",
				rotateObjectName: "Shape",
				resizeAdornmentTemplate: nodeResizeAdornmentTemplate,
				resizable: false,
				rotatable: true,
				rotateAdornmentTemplate: nodeRotateAdornmentTemplate,
				isShadowed: true,
				shadowVisible: false,
				shadowBlur: 10,
				background: "transparent",
				shadowOffset: new go.Point(0, 0),
				mouseEnter: (e, node) => {
					let fromLinkable = true;
					let items = ["T_H", "L_H", "R_H", "B_H"];
					for (let i = 0; i <= items.length; i++) {
						if (node.part.findObject(items[i])) {
							node.part.findObject(items[i]).opacity = fromLinkable ? .4 : 0;
							node.part.findObject(items[i]).opacity = fromLinkable ? e.diagram.findObjectAt(e.documentPoint).portId === items[i] ? .8 : .4 : 0;
						}
					}
				},
				mouseLeave: (e, node) => {
					let items = ["T_H", "L_H", "R_H", "B_H"];
					for (let i = 0; i <= items.length; i++) {
						if (node.part.findObject(items[i])) {
							node.part.findObject(items[i]).opacity = 0;
						}
					}
				},
				click: function(e, obj) {
					if (obj && obj.part && obj.part.data && obj.part.data.nodeConfig && obj.part.data.nodeConfig.isLock) {
						this.diagram.select(obj.part);
					}
				 }
			  },
			  new go.Binding("location", "loc", go.Point.parse),
			  new go.Binding("movable", "isLock", function (val) {
				  return val ? false : true;
			  }),
			  new go.Binding("deletable", "isLock", function (val) {
				  return val ? false : true;
			  }),
			  new go.Binding("rotatable", "isLock", function (val) {
				  return val ? false : true;
			  }),
			  new go.Binding("resizable", "isLock", function (val) {
				  return val ? false : true;
			  }),
			  $(go.Panel, "Vertical",
					$(go.Panel, "Spot",
						$(go.Panel, "Spot",
							{
								shadowVisible: false,
								name: "Shape"
							},
							getNodeShape()
						),
						makePort("T", new go.Spot(0.5, 0, 0, -6), go.Spot.TopSide, false, true, 1),
						makePort("L", new go.Spot(0, 0.5, -6, 0), go.Spot.LeftSide, false, true, 0),
						makePort("R", new go.Spot(1, 0.5, 6, 0), go.Spot.RightSide, false, true, 0),
						makeHelperArrow("T_H", new go.Spot(0.5, 0, 0, -2), go.Spot.TopSide, false, true, "imageTop"),
						makeHelperArrow("L_H", new go.Spot(0, 0.5, -2, 0), go.Spot.LeftSide, true, true, "imageLeft"),
						makeHelperArrow("R_H", new go.Spot(1, 0.5, 2, 0), go.Spot.RightSide, true, true, "imageRight")
					),
					$(go.Panel, "Spot", { margin: new go.Margin(2.5, 0, 0, 0) },
						$(go.Panel, "Auto",
							$(go.Shape, "RoundedRectangle", { fill: "rgba(0, 0, 0, 0.05)", strokeWidth: 0 }),
							$(go.TextBlock,
								{
									editable: true,
									stroke: "black",
									font: "6pt sans-serif",
									verticalAlignment: go.Spot.Center,
									alignment: go.Spot.Center,
									margin: new go.Margin(1, 5, 0, 5),
									background: "transparent"
								},
								 new go.Binding("text", "text"),
							)
						),
						makePort("B", new go.Spot(0.5, 1, 0, 4.5), go.Spot.BottomSide, false, true, 1),
						makeHelperArrow("B_H", new go.Spot(0.5, 1, 0, 0.5), go.Spot.BottomSide, true, false, "imageBottom")
					)
				)
			);


	function linkDrawnEvent(e) {
			let link = e.subject;
			myDiagram.model.setDataProperty(link.data, "linkConfig", lastLinkData);
			myDiagram.model.setDataProperty(link.data, "fromPort", link.data.fromPort.replace("_H", ""));
			myDiagram.model.setDataProperty(link.data, "toPort", link.data.toPort.replace("_H", ""));

			lastPortSnap.part.findObject("ViewPort").fill = 'transparent';

			link.updateTargetBindings();
		}
	myDiagram.addDiagramListener("LinkDrawn", linkDrawnEvent);

	var lastPortSnap = null;
	myDiagram.toolManager.linkingTool.portTargeted = (node, port, tempNode, tempPort, toEnd) => {
				let templink = myDiagram.toolManager.linkingTool.temporaryLink;
				if (!port) {
					templink.fromEndSegmentLength = 20;
					templink.toSpot = go.Spot.None;
				} else {
					templink.fromEndSegmentLength = 50;
					if (port.portId === "L") {
						templink.toSpot = go.Spot.LeftSide;
					} else if (port.portId === "R") {
						templink.toSpot = go.Spot.RightSide;
					} else if (port.portId === "T") {
						templink.toSpot = go.Spot.TopSide;
					} else if (port.portId === "B") {
						templink.toSpot = go.Spot.BottomSide;
					}
				}

				if (port && port.portId && toEnd) {
					if (lastPortSnap) {
						lastPortSnap.part.findObject("ViewPort").fill = 'transparent';
					}
					node.part.findObject("ViewPort").fill = 'rgba(219, 233, 249, 0.50)';
					lastPortSnap = node;
				} else {
					if (lastPortSnap) {
						lastPortSnap.part.findObject("ViewPort").fill = 'transparent';
					}
				}
			}


	myDiagram.linkTemplate = $(go.Link,
					{
						curve: go.Link.Bezier,
						toShortLength: 0.5,
						fromEndSegmentLength: 20, toEndSegmentLength: 50,
						zOrder: -1, reshapable: true,
						mouseEnter: (e, link) => {
							link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
							var setVisible = true;
							if (setVisible) {
								link.findObject("linkTextBlockBackground").visible = setVisible;
								link.findObject("linkTextBlock").visible = setVisible;
							}
						},
						mouseLeave: (e, link) => {
							link.findObject("HIGHLIGHT").stroke = "transparent";

							let setVisible = false;
							if (!setVisible) {
								link.findObject("linkTextBlockBackground").visible = setVisible;
								link.findObject("linkTextBlock").visible = setVisible;
							}
						},
					},
					{
						selectionAdornmentTemplate:
							$(go.Adornment,
								$(go.Shape,
									{ isPanelMain: true, stroke: "dodgerblue", strokeWidth: 1 }),
								$(go.Shape,
									{ toArrow: "CustomArrowHead", fill: "dodgerblue", stroke: null })
							)
					},
					$(go.Shape,  // the highlight shape, normally transparent
						{
							isPanelMain: true,
							strokeWidth: 2,
							stroke: "transparent",
							name: "HIGHLIGHT"
						}
					),
					$(go.Shape, "RoundedRectangle", // the link path shape
						{
							isPanelMain: true,
							strokeWidth: 1,
							stroke: 'green'
						}
					),
					$(go.Shape,  // the arrowhead
						{
							toArrow: "CustomArrowHead",
							strokeWidth: 0,
							fill: 'green'
						},
            new go.Binding("fill", "color")
					),
					$(go.Panel, "Auto",
						{
							_isLinkLabel: true
						},
						$(go.Shape, "RoundedRectangle",  // the label background, which becomes transparent around the edges
							{
								name: "linkTextBlockBackground"
							}
						),
						$(go.TextBlock, "transition",  // the label text
							{
								name: "linkTextBlock",
								textAlign: "center",
								isMultiline: false,
								font: "4.5pt sans-serif",
								margin: new go.Margin(0.7, 0.7, 0.31, 0.7),
								editable: true,
								text: "Test",
								stroke: "red"
							}
						)
					)
				);


	 myDiagram.toolManager.linkingTool.temporaryLink =
				$(go.Link,
					{
						curve: go.Link.Bezier,
						toShortLength: 0.5,
						fromSpot: go.Spot.Right, toSpot: go.Spot.None,
						fromEndSegmentLength: 20, toEndSegmentLength: 75,
					},
					$(go.Shape, "RoundedRectangle",
						{
							isPanelMain: true,
							strokeWidth: 1,
							stroke: "#777"
						}
					),
					$(go.Shape, {
						toArrow: "CustomArrowHead",
						strokeWidth: 0,
						fill: "#777"
					})
				)
			
			myDiagram.grid = $(go.Panel, "Grid",
					{
						gridCellSize: new go.Size(20, 20)
					},
					$(go.Shape, "LineH", { stroke: "rgba(234, 234, 234, 0.3)" }),
					$(go.Shape, "LineV", { stroke: "rgba(215, 232, 250, 0.3)" })
				);
			myDiagram.toolManager.draggingTool.isGridSnapEnabled = true;
		  myDiagram.model = new go.GraphLinksModel([
			{ key: 1, text: "FlowMail1", color: "lightblue", loc: "0 0", isLock: true }
		  ]);

	myDiagram.model.linkDataArray = [];

	function getLinkingAdornment() {
		return $(go.Node, {
			   layerName: "Background"
		   }
		);
	}

	myDiagram.toolManager.linkingTool.portGravity = 10;
	myDiagram.toolManager.linkingTool.temporaryFromNode = getLinkingAdornment();
	myDiagram.toolManager.linkingTool.temporaryToNode = getLinkingAdornment();
	myDiagram.toolManager.relinkingTool.temporaryFromNode = getLinkingAdornment();
	myDiagram.toolManager.relinkingTool.temporaryToNode = getLinkingAdornment();

	myDiagram.model.linkFromPortIdProperty = "fromPort";  // necessary to remember portIds
	myDiagram.model.linkToPortIdProperty = "toPort";
              
            
!
999px

Console