Pan and Zoom Programmatically in a JavaScript Diagram

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 for JavaScript.

I. Project Setup

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.

<script src="MindFusion.Common.js" type="text/javascript"></script>
<script src="MindFusion.Diagramming.js" type="text/javascript"></script>
<script src="MouseEvents.js" type="text/javascript"></script>

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:

<div style="width: 100%; height: 100%; overflow: auto;">
    <canvas id="diagram_canvas" width="2100" height="2100">
        This page requires a browser that supports HTML 5 Canvas element.
    </canvas>
</div>

II. Diagram Settings

In the code-behind file that we called MouseEvents.js we use the DOMContentLoaded event to initialize the diagram.

document.addEventListener("DOMContentLoaded", function ()
{
    // create a Diagram component that wraps the "diagram_canvas" canvas
    diagram = MindFusion.AbstractionLayer.createControl(Diagram, null, null, null, document.getElementById("diagram_canvas"));
    diagram.setBounds(new Rect(5, 5, 2000, 1000));

We use the createControl method of the AbstractionLayer class to create an instance of the Diagram class. The setBounds method determines the size of the diagram’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’s area is larger than the canvas we can use panning.

We use some settings of the Diagram class to customize the application:

diagram.setDefaultShape("Rectangle");
diagram.setRouteLinks(true);
diagram.setRoundedLinks(true);
diagram.setShowGrid(false);

The links will be routed and rounded and no grid will be rendered.

III. Diagram Items

We create the diagram nodes with the createShapeNode method of the Factory class. The Factory class as an instance is available through the getFactory() method:
for(var i = 0; i < 50; i++)

    {
        var colorIndex = Math.floor(Math.random() * 3);  
        var shape = diagram.getFactory().createShapeNode(new Rect(136, 36, 20, 10));
        shape.setBrush({ type: 'SolidBrush', color: colors[colorIndex] });
        if(i % 3   == 0)
            shape.setShape('Ellipse');
        else 
            shape.setShape('Rectangle');
        if( i % 7 == 0)
        {
            shape.setBounds(new Rect(136, 36, 16, 8));	
        }
		
        shape.setText("Node " + (i + 1).toString());
        shape.setTextColor("white");
    }

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 – that is set with the setBounds method, which takes as an argument a Rect, that is slightly smaller than the Rect instance that we use when we create the shape nodes.

The connectors among the nodes are created with the createDiagramLink method of Factory . 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 nodes proeprty of the Diagram class:

diagram.nodes.forEach(function(node)
{
    var nodeIndex = Math.floor(Math.random() * 50);  

    var node2 = diagram.nodes[nodeIndex];
    var link = diagram.getFactory().createDiagramLink(node, node2);
    link.setHeadShape("Circle");
})

We customize the appearance of the link through the setHeadShape method. We choose the ‘Circle’ shape as a head to each link.

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 – you can check the rest. In our sample we’ve chosen the LayeredLayout ,which provides quite nice result. We set its direction to LayoutDirection .There a few other properties that we’ve set that regulate the node distance, the layer distance and more:

var layout = new MindFusion.Graphs.LayeredLayout();
layout.direction = MindFusion.Graphs.LayoutDirection.LeftToRight;
layout.siftingRounds = 0;
layout.nodeDistance = 8;
layout.layerDistance = 8;
diagram.arrange(layout);

All layouts are applies through the arrange method of the Diagram that takes an instance of the layout as an argument.

IV. Pan and Zoom

We will implement pan and zoom by handling standard DOM events. The first one is the “wheel” event, which we attach to the diagram canvas element:

var dgrm = document.getElementById('diagram_canvas');

dgrm.addEventListener('wheel', function(e)
{
    var zoom = diagram.getZoomFactor();
    zoom -= e.deltaY / 10;
    if (zoom > 10)
        diagram.setZoomFactor(zoom);

    e.preventDefault(); // do not scroll
});

We use the getZoomFactor and setZoomFactor methods of the Diagram , 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.

The panning is implemented by handling the mousedown and mouseup DOM events of the Canvas.

/* events fired on the draggable target */
dgrm.addEventListener('mousedown', function(e)
{
 if( e.ctrlKey)
	diagram.setBehavior(MindFusion.Diagramming.Behavior.Pan);
 
}, false);

dgrm.addEventListener('mouseup', function(e)
{
 if( e.ctrlKey)
	diagram.setBehavior(MindFusion.Diagramming.Behavior.LinkShapes);
 
}, false);

If we want to make the Diagram pan we need simply to change the diagram’s behavior with the setBehavior method. The options are members of the Behavior enumeration. When the user clicks on the Diagram and the Ctrl key is pressed, we change the diagram’s behavior to “Pan”. 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 DiagramShape -s, creates DiagramLink -s.

With that our sample is ready. You can download the source code from this link:

Download the Mouse Events Sample with JavaScript Diagram

Technical support is available through MindFusion forum here.

About Diagramming for JavaScript: 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 https://mindfusion.eu/javascript-diagram.html.

JavaScript Diagram with Chart Nodes

In this blog post we will create DiagramNode instances that render a chart. The charts get resized according to the size of the node. We will use two MindFusion libraries for JavaScript – Charting and Diagramming. You can run the sample online from this link:

I. Project Setup

We will use a web page that will hold the HTML Canvas element that we need in order to render the diagram:

<div style="width: 100%; height: 100%; overflow: scroll;">
    <canvas id="diagram" width="2100" height="2100" style="background:#f0f0f0;">
        This page requires a browser that supports HTML 5 Canvas element.
    </canvas>
</div>

We give the diagram’s Canavs big width and height and we also provide an id. The id is important because we will need to access the Canvas from code.

We add the scripts that we need in order to use the Charting and Diagramming libraries:

<script src="Scripts/MindFusion.Common.js" type="text/javascript"></script>
<script src="Scripts/MindFusion.Diagramming.js" type="text/javascript"></script>
<script src="Scripts/MindFusion.Charting.js" type="text/javascript"></script>

We add the references at the end of the web page, just before the closing BODY tag. We also need to add a reference to a JavaScript file that will hold the code for our sample. We name it “PieNode.js”.

II. The Diagram

In the code-behind file we create a diagram instance. We use the DOMContentLoaded event to initialize our diagram:

document.addEventListener("DOMContentLoaded", function ()
{
// create a Diagram component that wraps the "diagram" canvas
diagram = MindFusion.Diagramming.Diagram.create(document.getElementById("diagram"));
diagram.setBehavior(MindFusion.Diagramming.Behavior.LinkShapes);
diagram.setLinkHeadShapeSize(2);
diagram.setBounds(new Rect(0, 0, 2000, 2000));

// draw a pie when the user creates a node
diagram.addEventListener(Events.nodeCreated, onNodeCreated);

});

The Behavior enumeration lists various modes of behavior for the diagram. We choose Behavior.LinkShapes, which creates nodes, when the mouse is dragged
over an empty area and connects the nodes if the mouse is dragged from an existing node. We set tbe bounds of the diagram to a big Rect which guarantees that the user can draw nodes anywhere on the visible area. When the user draws towards the edge of the browser, the diagram control expands automatically.

Finally, we add an event handler for the nodeCreated event.

//nodeCreated event handler
function onNodeCreated(sender, args)
{
	var node = args.getNode();
	
	var nBounds = node.getBounds ();
	var topLeftCoord = diagram.docToClient(nBounds.topLeft());
	var bottomRightCoord = diagram.docToClient(nBounds.bottomRight());
	.......................................................
}

At first we get the node that was created. Then we need to get its actual size, for which we use the docToClient method that converts between diagram and browser measure units. We get the two coordinates of the node’s bounding rectangle.

We create then a Canvas, which takes the size of the node’s rectangle:

............................................
.....................................................
var pieChartCanvas = document.createElement('canvas');
pieChartCanvas.width = bottomRightCoord.x - topLeftCoord.x;
pieChartCanvas.height = bottomRightCoord.y - topLeftCoord.y;

We then add this temp canvas to the body of the web page and call a method “createPie” where we draw the pie chart. Once the chart is drawn we get the URL of the image and set is to the node with the setImageLocation method. We remove the Canvas from the tree with the elements because we want to use for the next node.

//create a temporary Canvas for the pie chart
//to draw itself upon
document.body.appendChild(pieChartCanvas);
createPie(pieChartCanvas);
var pieImageLocation = pieChartCanvas.toDataURL();
node.setImageLocation(pieImageLocation);
document.body.removeChild(pieChartCanvas);

III. The Chart

We create a pie chart in the Canvas provided to the createPie method:

//draw a pie chart on the provided canvas
function createPie(pieChartCanvas)
{
	var pieChart = new Controls.PieChart(pieChartCanvas);
	pieChart.startAngle = 45;			
	pieChart.showLegend = false;
	pieChart.title = "Sales";
	pieChart.titleMargin = new Charting.Margins(0, 10, 0, 0);
	pieChart.chartPadding = 3;
...........................

We set some appearance properties to make the chart look the way we want – change the start angle of the pie, add a title and title margin, hide the legend. Then we create a PieSeries which holds the data and the labels of the pie. We assign the PieSeries to the series property of the pie chart:

// create sample data
var values = new Collections.List([20.00, 30.00, 15.00, 40.00]);
pieChart.series = new Charting.PieSeries(
	values,
	new Collections.List(["20", "30", "15", "40"]),
null);

We style the chart with an instance of the PerElementSeriesStyle class, which colors all elements of a Series with the consequtive Brush and stroke from its brushes and strokes collections. Then we adjust the dataLabelsFontSize to match the size of the canvas. We make the labels be drawn with a white brush using the dataLabelsBrush property. Finally we call draw to render the pie.

var brushes = new Collections.List(
		[
			new Drawing.Brush("#0455BF"),
			new Drawing.Brush("#033E8C"),
			new Drawing.Brush("#F24405"),
			new Drawing.Brush("#F21905")
		]);

	var seriesBrushes = new Collections.List();
	seriesBrushes.add(brushes);

	var strokes = new Collections.List(
		[
			new Drawing.Brush("#c0c0c0")
		]);

	var seriesStrokes = new Collections.List();
	seriesStrokes.add(strokes);

	pieChart.plot.seriesStyle = new Charting.PerElementSeriesStyle(seriesBrushes, seriesStrokes);
	pieChart.theme.highlightStroke = new Drawing.Brush("#000063");
	pieChart.theme.dataLabelsFontSize = pieChartCanvas.height/20;
	pieChart.theme.dataLabelsBrush = new Drawing.Brush("#FFFFFF");

	pieChart.draw();

And with that the sample is ready. You can download the source code together with all MindFusion JavaScript libraries used from:

http://mindfusion.eu/samples/javascript/diagram/PieNodes.zip

About Diagramming for JavaScript: 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 and 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 https://mindfusion.eu/javascript-diagram.html.

About Charting for JavaScript: MindFusion library for interactive charts and gauges. It supports all common chart types including 3D bar charts. Charts can have a grid, a legend, unlimited number of axes and series. Scroll, zoom and pan are supported out of the box. You can easily create your own chart series by implementing the Series interface.
The gauges library is part of Charting for JavaScript. It supports oval and linear gauge with several types of labels and ticks. Various samples show you how the implement the gauges to create and customize all popular gauge types: car dashboard, clock, thermometer, compass etc. Learn more about Charting and Gauges for JavaScript at https://mindfusion.eu/javascript-chart.html.