Working with Geographical data using Dev Extreme dxVectorMap

Currently at work, I am working on creating a map of Alabama that we can use to select and display data for individual counties/school districts and points of interest within those counties.
Update: May 17, 2016: As it turns out, using *.shp
files with dxVectorMap
is much easier than I originally thought. I have updated this post to show a more efficient way of working with the shape files.
Update: May 18, 2016: DevExtreme left a great comment showing a few ways to use shape files with the dxVectorMap control. I had already modified this post to include some of them, but one of them stood out as extremely important. It is possible to use the node command line to convert a shape file to GeoJson. Here is the command to use with the node.js command prompt (using the dx.vectormaputils.node.js
script):
node ./Scripts/dx.vectormaputils.node.js --input ./data/test.shp --json
At first, I started by downloading an SVG map of Alabama (with the counties marked with an id attribute for their name) so I could use it to display data, but after about six or seven hours of failed attempts to get what I wanted, I decided to start fresh. Basically, the svg map was devoid of coordinate data, which I desperately need to match the data in our database to real points on the map.
I am already using the awesome DevExtreme controls in my project, so I thought I would visit the dxVectorMap
control. As it turns out, the dxVectorMap consumes industry standard GeoJson files as well as shape files (you can find shape files at the TIGER site of the US Census Bureau). It comes prepackaged with a few maps already, but there are no maps for the states. So, a quick search of "State counties with GeoJson" brought me to an excellent blog post on How to use US Census visualization with D3.js.
I used the process outlined in the blog post and installed the GISInternals tools (a Windows port of the GDAL tools mentioned in the post). I ran into difficulty trying to convert the 2015 county file (it was for the entire country) with ogr2ogr as there was a formatting issue. However, I ended up downloading the counties shape files directly from the TIGER FTP site for 2010 Census and downloaded the Alabama zip file.
2010 TIGER/LineĀ® Shapefiles: Counties (and equivalent)
Unfortunately, there's a county in Alabama that didn't convert correctly using ogr2ogr
as its boundaries intersect with each other causing an error in the dxVectorMap
control. This is why I decided to use the shape files directly.
I decided to use the vectormaputils
object to convert the shape files for me.
If you're using node, this is how you would do it:
var source = 'shapeSources/world.shp',
options = {
output: 'destinationFolder',
precision: 2,
isJSON: true
};
vectormaputils.processFiles(source, options);
This process is outlined in the DevExtreme docs.
Using dx.vectormaputils.js for shape file conversion on the client browser
After you install DevExtreme, you will have a folder containing all of the JavaScript source files you need to use the controls. They will be installed in the "C:\Program Files (x86)\DevExpress 15.2\DevExtreme\Sources\Lib" folder.
Note: The following process using NuGet to install DevExtreme is only neccessary if you choose not to use the DevExtreme CDN.
I'm creating an ASP.NET MVC + WebApi project using Visual Studio 2015 community edition. Once the project is created, right-click on references and choose 'Manage NuGet packages'. Then, search for DevExtreme and install DevExtreme.Web
. This will add the appropriate scripts to your project. Also, if you're not using the GeoJson file, you'll need to copy the vectormap-utils
folder from the DevExpress install folder to your web application (they are not installed as part of the NuGet install).
Move the *.shp
and *.dbf
files that you downloaded for your state and store them in a folder named Assets
in your project.
Update: Here is the easiest way to consume *.shp
files with the dxVectorMap
. Credit for the code goes to Renato Xavier from a question on the DevExtreme forums.
Here is the Razor file (I am using the @Url.Content()
helper to get a relative path to the Assets
folder).
<!DOCTYPE html>
<html>
<head>
<title>Configure a Vector Map</title>
<meta charset="utf-8" />
<!--[if lt IE 9]>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<!--<![endif]-->
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/globalize/0.1.1/globalize.min.js"></script>
<script type="text/javascript" src="http://cdn3.devexpress.com/jslib/15.2.5/js/dx.chartjs.js"></script>
<script type="text/javascript" src="http://cdn3.devexpress.com/jslib/15.2.5/js/vectormap-utils/dx.vectormaputils.js"></script>
<script type="text/javascript" src="vectorMap.js"></script>
</head>
<body>
<div id="mapContainer" style="height:450px;max-width:750px;margin:0px auto"></div>
</body>
</html>
Then, in your web.config
, add the following static file definitions:
<system.webServer>
<staticContent>
<remove fileExtension=".json" />
<mimeMap fileExtension=".json" mimeType="application/json" />
<!-- MIME types for Geographic shape files (for the map) -->
<remove fileExtension=".shp" />
<remove fileExtension=".dbf" />
<mimeMap fileExtension=".shp" mimeType="application/x-shp" />
<mimeMap fileExtension=".dbf" mimeType="application/x-dbf" />
</staticContent>
</system.webServer>
This will ensure that the shape files are handled correctly by your web server (assuming IIS, if you are running another web server, refer to the documentation on how to set MIME maps for each of the two file extensions):
.shp
-application/x-shp
.dbf
-application/x-dbf
Then, in your vectorMap.js
, simply add a reference to your map shape file (without the file extension):
$(function () {
DevExpress.viz.vectormaputils.parse('@Url.Content("~/Assets/")/YOUR_SHAPE_FILE_NAME_WITHOUT_EXTENSION', { precision: 8 }, function (data) {
$('#mapContainer').dxVectorMap({
layers: [{
type: 'area',
data: data
}]
});
});
});
It's as easy as just referring to the shape files. The dx.vectormaputils
will do the conversion work for you.
Converting the shape file to GeoJson for use with Google Maps Api
Simply put the text of the data in a textarea (from within the handler for the parse
method, assuming the use of jQuery):
$("#ID_OF_TEXTAREA").text(JSON.stringify(data));
This will be a big file, so be patient with your browser...
Then, simply copy the text inside the textarea into a text file and save it as a .json file. Make sure your web server is configured to serve .json files as application/json
in the MIME mappings (see the sample web.config
above for an example of how to do this in a .NET project).
We then set a few properties on the map.
Here is a picture of a sample map (Alabama school districts):
I am using a custom palette for each of the districts. I will cover how to use the custom palette in another post. DevExtreme is very well documented, but some of it is still a bit complex. I am attempting to share with you what I have learned in an effort to add to the conversation.