Sync Zooming and Panning across Multiple Charts

Sync Zooming and Panning across Multiple Charts in ASP.NET MVC

With CanvasJS, you can easily sync zooming and panning across multiple charts in your ASP.NET MVC Application.
In this tutorial, we will cover how to sync multiple charts. It works for all chart types with axes.

If you haven’t already, please refer to this tutorial for step by step instruction of adding charts to your ASP.Net MVC Application. We recommend that you download the Sample Visual Studio Project and try it on your own to understand the API better.


Download ASP.Net MVC Chart Samples

Here are the steps:

Step 1:

We will update the controller to generate the dataPoints randomly and pass them to the charts.

using ASPNET_MVC_Samples.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ASPNET_MVC_Samples.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {

	double count = 50, y1 = 10, y2 = 20;
	
            Random random = new Random(DateTime.Now.Millisecond);
            
	List<DataPoint> dataPoints1; // for chart 1
            List<DataPoint> dataPoints2; // for chart 2
            
            dataPoints1 = new List<DataPoint>();
            dataPoints2 = new List<DataPoint>();

            for (int i = 0; i < count; i++)
            {
                y1 = y1 + (random.Next(0, 20) - 10);
                y2 = y2 + (random.Next(0, 20) - 10);

                dataPoints1.Add(new DataPoint(i, y1));
                dataPoints2.Add(new DataPoint(i, y2));
            }

            ViewBag.DataPoints1 = JsonConvert.SerializeObject(dataPoints1);

            ViewBag.DataPoints2 = JsonConvert.SerializeObject(dataPoints2);

            return View();
        }
    }
}

Step 2:

We will add two charts in the View which accept dataPoints from the controller.

<div id="chartContainer1" style="height: 360px; width: 100%;"></div>
<div id="chartContainer2" style="height: 360px; width: 100%;"></div>

<script type="text/javascript">

    window.onload = function () {
       
        //--------------- Chart 1 ---------------//
        var chart1 = new CanvasJS.Chart("chartContainer1", {
            zoomEnabled: true,
            zoomType: "x", // change it to "xy" to enable zooming on both axes
            title: {
                text: "Chart1 - Try Zooming / Panning"
            },
            data: [{
                type: "line",

                dataPoints: @Html.Raw(ViewBag.DataPoints1),
            }],
            rangeChanged: syncHandler
        });
        chart1.render();

       
       //--------------- Chart 2 ---------------//
        var chart2 = new CanvasJS.Chart("chartContainer2", {
            zoomEnabled: true,
            zoomType: "x", // change it to "xy" to enable zooming on both axes
            title: {
                text: "Chart2 - Try Zooming / Panning"
            },
            data: [{
                type: "line",

                dataPoints: @Html.Raw(ViewBag.DataPoints2),
            }],
            rangeChanged: syncHandler
        });

        chart2.render();

    };
</script>

Please refer to zoomEnabled, zoomType and rangeChanged to know more about them. In the above example, zoomType is set to “x”, set it to “xy” to enable zooming on both axes.

NOTE: We will write a syncHandler method (passed to rangeChanged property) in the next step to handle syncing across multiple charts.

Step 3:

The syncHandler method to handle syncing of both axis X and axis Y across the charts.This is a generic method which works for any number of charts – you can use it in your own application as well.

var charts = [chart1, chart2]; // add all charts (with axes) to be synced

function syncHandler(e) {

    for (var i = 0; i < charts.length; i++) {
        var chart = charts[i];

        if (!chart.options.axisX) 
	    chart.options.axisX = {};
        
        if (!chart.options.axisY) 
            chart.options.axisY = {};

        if (e.trigger === "reset") {
            
            chart.options.axisX.viewportMinimum = chart.options.axisX.viewportMaximum = null;
            chart.options.axisY.viewportMinimum = chart.options.axisY.viewportMaximum = null;
	    
            chart.render();
	
        } else if (chart !== e.chart) {
            
            chart.options.axisX.viewportMinimum = e.axisX.viewportMinimum;
            chart.options.axisX.viewportMaximum = e.axisX.viewportMaximum;
            
            chart.options.axisY.viewportMinimum = e.axisY.viewportMinimum;
            chart.options.axisY.viewportMaximum = e.axisY.viewportMaximum;

            chart.render();

        }
    }
}

Please refer to axisX.viewportMinimum,axisX.viewportMaximum, axisY.viewportMinimum and axisY.viewportMaximum to know more about them.

Finalising

To summarize, in order to sync zooming and panning across multiple charts, we can create and pass method which handles the syncing, and pass it to rangeChanged property of the chart.


@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="http://canvasjs.com/assets/script/canvasjs.min.js"></script>
</head>
<body>
    <h1>Synching Multiple Charts</h1>
    <div id="chartContainer1" style="height: 360px; width: 100%;"></div>
    <div id="chartContainer2" style="height: 360px; width: 100%;"></div>
    <script type="text/javascript">
       window.onload = function () {
            //-------- Chart 1 ---------------
            var chart1 = new CanvasJS.Chart("chartContainer1", {
                zoomEnabled: true,
                zoomType: "x", // change it to "xy" to enable zooming on both axes
                title: {
                    text: "Chart1 - Try Zooming / Panning"
                },
                data: [{
                    type: "line",

                    dataPoints: @Html.Raw(ViewBag.DataPoints1),
                }],
                rangeChanged: syncHandler
            });
            chart1.render();

            //-------- Chart 2 ---------------
            var chart2 = new CanvasJS.Chart("chartContainer2", {
                zoomEnabled: true,
                zoomType: "x", // change it to "xy" to enable zooming on both axes
                title: {
                    text: "Chart2 - Try Zooming / Panning"
                },
                data: [{
                    type: "line",

                    dataPoints: @Html.Raw(ViewBag.DataPoints2),
                }],
                rangeChanged: syncHandler
            });

            chart2.render();

            //--------------------Sync Chart-------------------
            var charts = [chart1, chart2]; // add all charts (with axes) to be synced

            function syncHandler(e) {

                for (var i = 0; i < charts.length; i++) {
                    var chart = charts[i];

                    if (!chart.options.axisX) chart.options.axisX = {};
                    if (!chart.options.axisY) chart.options.axisY = {};

                    if (e.trigger === "reset") {

                        chart.options.axisX.viewportMinimum = chart.options.axisX.viewportMaximum = null;
                        chart.options.axisY.viewportMinimum = chart.options.axisY.viewportMaximum = null;
                        chart.render();
                    } else if (chart !== e.chart) {

                        chart.options.axisX.viewportMinimum = e.axisX.viewportMinimum;
                        chart.options.axisX.viewportMaximum = e.axisX.viewportMaximum;

                        chart.options.axisY.viewportMinimum = e.axisY.viewportMinimum;
                        chart.options.axisY.viewportMaximum = e.axisY.viewportMaximum;
                        chart.render();
                    }

                }
            }
        };
    </script>
</body>
</html>			
using ASPNET_MVC_Samples.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ASPNET_MVC_Samples.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {

            double count = 50, y1 = 10, y2 = 20;

            Random random = new Random(DateTime.Now.Millisecond);

            List<DataPoint> dataPoints1; // for chart 1
            List<DataPoint> dataPoints2; // for chart 2

            dataPoints1 = new List<DataPoint>();
            dataPoints2 = new List<DataPoint>();

            for (int i = 0; i < count; i++)
            {
                y1 = y1 + (random.Next(0, 20) - 10);
                y2 = y2 + (random.Next(0, 20) - 10);

                dataPoints1.Add(new DataPoint(i, y1));
                dataPoints2.Add(new DataPoint(i, y2));
            }

            ViewBag.DataPoints1 = JsonConvert.SerializeObject(dataPoints1);

            ViewBag.DataPoints2 = JsonConvert.SerializeObject(dataPoints2);

            return View();
        }
    }
}			
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;
 
namespace ASPNET_MVC_Samples.Models
{
	//DataContract for Serializing Data - required to serve in JSON format
	[DataContract]
	public class DataPoint
	{
		public DataPoint(double x, double y)
		{
			this.X = x;
			this.Y = y;
		}
 
	//Explicitly setting the name to be used while serializing to JSON.
	[DataMember(Name = "x")]
	public Nullable<double> X = null;
 
	//Explicitly setting the name to be used while serializing to JSON.
	[DataMember(Name = "y")]
	public Nullable<double> Y = null;		
	}
}			


In order to provide better support,we have closed the comments and switched completely to our Forums.
If you have any questions, please feel free to ask in our forums.