Skip to contentSkip to author details

"Zooming" into a map element using element coordinates

 development  javascript  GIS  DevExtreme  DevExpress  Mapping

I am still working on a map at work and I needed to be able to zoom into a map element when a user clicks on it. Originally, I was using the dxVectorMap.zoomLevel() method, but I realized that calculating the zoom level was harder than I thought.

Note: I covered the basics of working with the dxVectorMap in a previous post titled Working with Geographical data using Dev Extreme dxVectorMap

I then noticed that each map element has a coordinates() method that you can call that will return an array of points for the boundaries of the element. It uses those points to draw the boundary lines on the map.

So, I decided to write a simple two-dimensional loop to calculate the minimum and maximum latitude and longitude points on the element.

The way this works is that you loop through each point to find the largest latitude, the smallest latitude, the largest longitude, and the smallest longitude in the array and use these to build your bounds array.

Here is a simplified image to help describe the process:

Map boundary calculation demonstration

In the picture above, all of the red colored points ([50,1],[90,20], [1,60], and [52,95]) are the max and min values for their latitude and longitude. In this simple example, there are only four points that make up the boundaries.

The remaining points are unimportant as they are within the boundary of the other four major points.

Our goal in the code is to locate the extreme edges (the red points in our picture). To do this, we have to do some comparisons during our iteration of the array of 2D points. As I loop through the array of point arrays, there will be a massive number of points for this shape. We need to have 4 variables to keep up with our min and max values (min latitude, max latitude, min longitude, and max longitude). As we loop through the array, we'll check to see if the new value is higher than our highest and lower than our lowest values and store them accordingly.

Here is the code:

 var _cerkit = {  
    getElementBounds: function (elementCoordinates) {
        // loop through the element coordinates and find the bounds for the eastern-, western-, southern-, and northern-most points
        // return them as the bounds (can be used to set the viewport) and zoom level

        // prep the min and max values (with opposite values so we can compare min and max properly)
        var minLongitude = 180;
        var maxLongitude = -180;
        var minLatitude = 90;
        var maxLatitude = -90;

        for (var i = 0; i < elementCoordinates.length; i++) {
            for (var j = 0; j < elementCoordinates[i].length; j++) {

                // retrieve the latitude and longitude from the element points array
                var lng = elementCoordinates[i][j][0];
                var lat = elementCoordinates[i][j][1];

                if (lng > maxLongitude) {
                    maxLongitude = lng;
                } else if (lng < minLongitude) {
                    minLongitude = lng;
                }

                if (lat > maxLatitude) {
                    maxLatitude = lat
                } else if (lat < minLatitude) {
                    minLatitude = lat;
                }
            }
        }

        // return bounds (with adjustments for borders)
        return [(minLongitude - 0.05), (maxLatitude + 0.05), (maxLongitude  + 0.05), (minLatitude - 0.05)];
    }
};

After running this code on the shape represented by the picture above, our boundaries will be (dxVectorMap coordinates are ordered [longitude,latitude]):

min latitude = 1
min longitude = 1
max latitude = 95
max longitude = 90

So, our bounds would be (arranged according to the requirements of dxVectorMap, which are longitude first):

Order:

[minLongitude, maxLatitude, maxLongitude, minLatitude]

Example map

var sampleImageBounds = [[1,1],[1,90],[95,1],[95,90]];

Also, I adjusted each of the values by 0.05 to allow for space between the edges of the map element and the boundary. 0.05 is an arbitrary number that I picked that works well with my map at my zoom level. You may need to adjust this value according to the zoom level and boundary needs of your map.

Then, simply pass this array to a call to viewport() on the dxVectorMap widget:

$("mapContainer").dxVectorMap("instance").viewport(_cerkit.getElementBounds(selectedDistrict.coordinates()));

See the dxVectorMap documentation for more information on using coordinates() and viewport().