{"id":2279,"date":"2020-04-16T15:30:31","date_gmt":"2020-04-16T15:30:31","guid":{"rendered":"https:\/\/mindfusion.eu\/blog\/?p=2279"},"modified":"2021-01-25T16:12:14","modified_gmt":"2021-01-25T16:12:14","slug":"pan-and-zoom-programmatically-in-a-javascript-diagram","status":"publish","type":"post","link":"https:\/\/mindfusion.dev\/blog\/pan-and-zoom-programmatically-in-a-javascript-diagram\/","title":{"rendered":"Pan and Zoom Programmatically in a JavaScript Diagram"},"content":{"rendered":"<p>We will build a diagram with 50 random nodes and we will zoom and pan this diagram programmatically. Here is a screenshot of the final diagram, which is a link to the sample:<\/p>\n<p><a title=\"Programmatic Pan and Zoom in JavaScript\" href=\"https:\/\/mindfusion.dev\/javascript-demo.html?sample=mouse-events\"><img decoding=\"async\" title=\"JavaScript Diagram: Pan and Zoom Programmatically\" src=\"https:\/\/mindfusion.dev\/samples\/javascript\/diagram\/mouse_events.png\" \/><\/a><\/p>\n<p>We will use the <a title=\"JavaScript Diagram Library\" href=\"https:\/\/mindfusion.dev\/javascript-diagram.html\">MindFusion Diagramming library for JavaScript.<\/a><\/p>\n<p><strong>I. Project Setup<\/strong><\/p>\n<p>We add a reference to the MindFusion.Diagramming.js and MindFusion.Common.js files. We also add a reference to another file called MouseEvents.js. This is our code-behind file.<\/p>\n<pre>&lt;script src=\"MindFusion.Common.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;\n&lt;script src=\"MindFusion.Diagramming.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;\n&lt;script src=\"MouseEvents.js\" type=\"text\/javascript\"&gt;&lt;\/script&gt;<\/pre>\n<p>In the BODY of the web page we create a Canvas element, to which we assign an id. This is important, because we will refer to the Canvas in code:<\/p>\n<pre>&lt;div style=\"width: 100%; height: 100%; overflow: auto;\"&gt;\n    &lt;canvas id=\"diagram_canvas\" width=\"2100\" height=\"2100\"&gt;\n        This page requires a browser that supports HTML 5 Canvas element.\n    &lt;\/canvas&gt;\n&lt;\/div&gt;<\/pre>\n<p><strong>II. Diagram Settings<\/strong><\/p>\n<p>In the code-behind file that we called MouseEvents.js we use the DOMContentLoaded event to initialize the diagram.<\/p>\n<pre>document.addEventListener(\"DOMContentLoaded\", function ()\n{\n    \/\/ create a Diagram component that wraps the \"diagram_canvas\" canvas\n    diagram = MindFusion.AbstractionLayer.createControl(Diagram, null, null, null, document.getElementById(\"diagram_canvas\"));\n    diagram.setBounds(new Rect(5, 5, 2000, 1000));<\/pre>\n<p>We use the <a title=\"MindFusion Diagramming Library for JavaScript: createControl\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_SelectOnlyBehavior_createController_1_Object.htm\">createControl<\/a> method of the AbstractionLayer class to create an instance of the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> class. The <a title=\"MindFusion Diagramming Library for JavaScript: setBounds\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Drawing_Canvas_setBounds_1_Rect.htm\">setBounds<\/a> method determines the size of the diagram&#8217;s drawing area. If this size is bigger than the size of the Canvas, the diagram automatically shows scrollbars. Note that only if the diagram&#8217;s area is larger than the canvas we can use panning.<\/p>\n<p>We use some settings of the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> class to customize the application:<\/p>\n<pre>diagram.setDefaultShape(\"Rectangle\");\ndiagram.setRouteLinks(true);\ndiagram.setRoundedLinks(true);\ndiagram.setShowGrid(false);<\/pre>\n<p>The links will be routed and rounded and no grid will be rendered.<\/p>\n<p><strong>III. Diagram Items<\/strong><\/p>\n<p>We create the diagram nodes with the <a title=\"MindFusion Diagramming Library for JavaScript: createShapeNode\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_Factory_createShapeNode_5_Rect_Number_Number_Number_Number.htm\">createShapeNode<\/a> method of the <a title=\"MindFusion Diagramming Library for JavaScript: Factory\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Factory_Methods_0.htm\">Factory<\/a> class. The <a title=\"MindFusion Diagramming Library for JavaScript: Factory\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Factory_Methods_0.htm\">Factory<\/a> class as an instance is available through the <a title=\"MindFusion Diagramming Library for JavaScript: getFactory()\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_Diagram_getFactory_0.htm\">getFactory()<\/a> method:<br \/>\nfor(var i = 0; i &lt; 50; i++)<\/p>\n<pre>    {\n        var colorIndex = Math.floor(Math.random() * 3);  \n        var shape = diagram.getFactory().createShapeNode(new Rect(136, 36, 20, 10));\n        shape.setBrush({ type: 'SolidBrush', color: colors[colorIndex] });\n        if(i % 3   == 0)\n            shape.setShape('Ellipse');\n        else \n            shape.setShape('Rectangle');\n        if( i % 7 == 0)\n        {\n            shape.setBounds(new Rect(136, 36, 16, 8));\t\n        }\n\t\t\n        shape.setText(\"Node \" + (i + 1).toString());\n        shape.setTextColor(\"white\");\n    }<\/pre>\n<p>We make each third shape Ellipse and we choose the brush on a random principle out of three brushes, that we initialized in an array. Each seventh shape is slightly smaller &#8211; that is set with the setBounds method, which takes as an argument a <a title=\"MindFusion Diagramming Library for JavaScript: Rect,\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?T_MindFusion_Drawing_Rect.htm\">Rect,<\/a> that is slightly smaller than the <a title=\"MindFusion Diagramming Library for JavaScript: Rect\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?T_MindFusion_Drawing_Rect.htm\">Rect<\/a> instance that we use when we create the shape nodes.<\/p>\n<p>The connectors among the nodes are created with the <a title=\"MindFusion Diagramming Library for JavaScript: createDiagramLink\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_Factory_createDiagramLink_2_Point_Point.htm\">createDiagramLink<\/a> method of <a title=\"MindFusion Diagramming Library for JavaScript: Factory\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Factory_Methods_0.htm\">Factory<\/a> . We cycle through all 50 nodes and connect each one of them with a randomly taken node from the diagram nodes collection. This collection is available through the <a title=\"MindFusion Diagramming Library for JavaScript: nodes\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?F_MindFusion_Diagramming_Diagram_nodes.htm\">nodes<\/a> proeprty of the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> class:<\/p>\n<pre>diagram.nodes.forEach(function(node)\n{\n    var nodeIndex = Math.floor(Math.random() * 50);  \n\n    var node2 = diagram.nodes[nodeIndex];\n    var link = diagram.getFactory().createDiagramLink(node, node2);\n    link.setHeadShape(\"Circle\");\n})<\/pre>\n<p>We customize the appearance of the link through the <a title=\"MindFusion Diagramming Library for JavaScript: setHeadShape\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_DiagramLink_setHeadShape_1_Shape.htm\">setHeadShape<\/a> method. We choose the &#8216;Circle&#8217; shape as a head to each link.<\/p>\n<p>We have created the diagram items with the same bounds, which means they are on top of each other. The best way to arrange them is with one of the automatic layout algorithms, available with the JsDiagram. They are members of the MindFusion.Graphs namespace &#8211; you can check the rest. In our sample we&#8217;ve chosen the <a title=\"MindFusion Diagramming Library for JavaScript: LayeredLayout\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?T_MindFusion_Graphs_LayeredLayout_Members.htm\">LayeredLayout<\/a> ,which provides quite nice result. We set its <a title=\"MindFusion Diagramming Library for JavaScript: direction\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?F_MindFusion_Graphs_LayeredLayout_direction.htm\">direction<\/a> to <a title=\"MindFusion Diagramming Library for JavaScript: LayoutDirection\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?T_MindFusion_Graphs_LayoutDirection.htm\">LayoutDirection<\/a> .There a few other properties that we&#8217;ve set that regulate the node distance, the layer distance and more:<\/p>\n<pre>var layout = new MindFusion.Graphs.LayeredLayout();\nlayout.direction = MindFusion.Graphs.LayoutDirection.LeftToRight;\nlayout.siftingRounds = 0;\nlayout.nodeDistance = 8;\nlayout.layerDistance = 8;\ndiagram.arrange(layout);<\/pre>\n<p>All layouts are applies through the arrange method of the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> that takes an instance of the layout as an argument.<\/p>\n<p><strong>IV. Pan and Zoom<\/strong><\/p>\n<p>We will implement pan and zoom by handling standard DOM events. The first one is the &#8220;wheel&#8221; event, which we attach to the diagram canvas element:<\/p>\n<pre>var dgrm = document.getElementById('diagram_canvas');\n\ndgrm.addEventListener('wheel', function(e)\n{\n    var zoom = diagram.getZoomFactor();\n    zoom -= e.deltaY \/ 10;\n    if (zoom &gt; 10)\n        diagram.setZoomFactor(zoom);\n\n    e.preventDefault(); \/\/ do not scroll\n});<\/pre>\n<p>We use the <a title=\"MindFusion Diagramming Library for JavaScript: getZoomFactor\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Drawing_Canvas_getZoomFactor_0.htm\">getZoomFactor<\/a> and <a title=\"MindFusion Diagramming Library for JavaScript: setZoomFactor\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Drawing_Canvas_setZoomFactor_1_Number.htm\">setZoomFactor<\/a> methods of the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> , to manipulate the zoom ratio. The zoom step is calculated based on the deltaY value of the event args. You can command the amount of zoom by dividing by a smaller or a larger number. It is important that we call preventDefault() on the event arguments, to surpass the default response of the canvas to the wheel event.<\/p>\n<p>The panning is implemented by handling the mousedown and mouseup DOM events of the Canvas.<\/p>\n<pre>\/* events fired on the draggable target *\/\ndgrm.addEventListener('mousedown', function(e)\n{\n if( e.ctrlKey)\n\tdiagram.setBehavior(MindFusion.Diagramming.Behavior.Pan);\n \n}, false);\n\ndgrm.addEventListener('mouseup', function(e)\n{\n if( e.ctrlKey)\n\tdiagram.setBehavior(MindFusion.Diagramming.Behavior.LinkShapes);\n \n}, false);<\/pre>\n<p>If we want to make the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> pan we need simply to change the diagram&#8217;s behavior with the <a title=\"MindFusion Diagramming Library for JavaScript: setBehavior\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?M_MindFusion_Diagramming_Diagram_setBehavior_1_Behavior.htm\">setBehavior<\/a> method. The options are members of the <a title=\"MindFusion Diagramming Library for JavaScript: Behavior\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Behavior_0.htm\">Behavior<\/a> enumeration. When the user clicks on the <a title=\"MindFusion Diagramming Library for JavaScript: Diagram\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_Diagram_Members_0.htm\">Diagram<\/a> and the Ctrl key is pressed, we change the diagram&#8217;s behavior to &#8220;Pan&#8221;. When the mouse is up, but the Ctrl key is pressed, we rest the behavior back to LinkShapes. This is the default behavior, where dragging with the mouse creates new shapes, while dragging between existing <a title=\"MindFusion Diagramming Library for JavaScript: DiagramShape\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_ShapeNode_Members_0.htm\">DiagramShape<\/a> -s, creates <a title=\"MindFusion Diagramming Library for JavaScript: DiagramLink\" href=\"https:\/\/www.mindfusion.dev\/onlinehelp\/jsdiagram\/index.htm?CC_T_MindFusion_Diagramming_DiagramLink_Methods_0.htm\">DiagramLink<\/a> -s.<\/p>\n<p>With that our sample is ready. You can download the source code from this link:<\/p>\n<p align=\"center\"><a title=\"Download the Source Code of the Mouse Events Sample\" href=\"https:\/\/mindfusion.dev\/samples\/javascript\/diagram\/MouseEvents.zip\">Download the Mouse Events Sample with JavaScript Diagram<\/a><\/p>\n<p>Technical support is available through MindFusion <a title=\"Js Diagram Discussion Board\" href=\"https:\/\/mindfusion.dev\/Forum\/YaBB.pl?board=jsdiag_disc\">forum here.<\/a><\/p>\n<p><i>About Diagramming for JavaScript:<\/i> This native JavaScript library provides developers with the ability to create and customize any type of diagram, decision tree, flowchart, class hierarchy, graph, genealogy tree, BPMN diagrams and much more. The control offers rich event set, numerous customization options, animations, graph operations, styling and themes. You have more than 100 predefined nodes, table nodes and more than 15 automatic layout algorithms. Learn more about Diagramming for JavaScript at <a title=\"JavaScript Diagram Library\" href=\"https:\/\/mindfusion.dev\/javascript-diagram.html\">https:\/\/mindfusion.dev\/javascript-diagram.html<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We will build a diagram with 50 random nodes and we will zoom and pan this diagram programmatically. Here is a screenshot of the final diagram, which is a link to the sample: We will use the MindFusion Diagramming library &hellip; <a href=\"https:\/\/mindfusion.dev\/blog\/pan-and-zoom-programmatically-in-a-javascript-diagram\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[95,513,74],"tags":[473,624,491,645,50],"class_list":["post-2279","post","type-post","status-publish","format-standard","hentry","category-diagramming-2","category-javascript","category-sample-code","tag-javascript-diagram","tag-javascript-library","tag-js-flowchart","tag-user-interaction","tag-zoom"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3RlKs-AL","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/comments?post=2279"}],"version-history":[{"count":12,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2279\/revisions"}],"predecessor-version":[{"id":2656,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2279\/revisions\/2656"}],"wp:attachment":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/media?parent=2279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/categories?post=2279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/tags?post=2279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}