Draw a map in a WPF application
Recently, a production need arose - to display on the form a map of Russia, with details of the regions. In this case, you need:
The quality requirement is easily achievable using vector graphics. And then I got the idea to use WPF - but what, draw a picture in Expression Blend, thereby obtaining a set of WPF controls. The rest - to add "interactive" - a matter of technology.
So, the very first thing that needed to be done was to get the image itself. Our country is large, which, of course, is beautiful, but there was no desire to draw so many elements ourselves. This was not required - a great example of a map of Russia was found in Wikimedia :
This is exactly what you need! One point is an SVG file. It was necessary to somehow convert it to XAML. As a result of a search, I came across a XamlTune kit, which has a console utility with the speaking name svg2xaml. She did her job well, and soon I got a canvas with many nested Path elements, which depicts our country. The resulting XAML is as follows:
Obviously, several copies of the canvas are used to draw the borders of the state and subjects.
The thing is small - it remains to display the card on the screen. It would seem that everything is very simple - put the canvas on the form and enjoy. That's how it is, only you can notice its very solid dimensions: Width = "1091.99" Height = "630.119". How to scale it? If you replace the canvas with the Grid, for example, when changing the size of the form, all parts of the map “move apart”. To avoid this, use the Viewbox control. Place it on the form as follows:
It is worth noting here that I put the canvas with the map in the resources with the key “svg2”. The canvas will be compressed while maintaining the proportions to the current dimensions of the ViewBox container. At the same time, the absolute coordinates within the canvas will remain valid, and the layout of the map will not “go”. Now it is possible to set the mouse click handler in the style, for example, like this:
T.O. a click handler will be set for all Path elements. Well, etc.- in the style you can define triggers, set properties, thereby ensuring the necessary appearance and behavior: further actions depend on your tasks and imagination. For example, you can highlight the boundaries of the region when you hover the mouse, or highlight the background when an event occurs, etc.
I needed an interactive map, i.e. so that you can work with its individual parts, including accepting user input. If this is not required, you can use the canvas with the map as a VisualBrush. You can do this, for example, like this:
To preserve the original aspect ratio of the canvas with the map, the Uniform value was set for the Stretch property of the brush. Of course, in the case of using VisualBrush we will get a gain in speed - less CPU resources and RAM will be required. In confirmation of this - the data from the profiler from the Visual Studio 2010 suite (the blue line of the graph indicates the CPU load):
1) Option with VisualBrush (allocation of managed memory ~ 11.36Mb):
2) Option with ViewBox (allocation of managed memory ~ 14, 83Mb):
Therefore, if user input processing is not needed, the VisualBrush approach is preferable.
So, it’s quite simple and quick to solve the problem of working with a geographical map. It is in such situations that you begin to understand the full power of WPF technology. Not the most trivial task - getting an interactive and “rubber” (ie resilient to resizing) card - came down to using the utility and “screwing” the styles. Very indicative, in my opinion.
Sample Source
- depending on various conditions, change the appearance of the map areas;
- the card should “perceive” user input and respond to it;
- you need to have good quality “picture cards” regardless of the resolution of the monitor.
The quality requirement is easily achievable using vector graphics. And then I got the idea to use WPF - but what, draw a picture in Expression Blend, thereby obtaining a set of WPF controls. The rest - to add "interactive" - a matter of technology.
So, the very first thing that needed to be done was to get the image itself. Our country is large, which, of course, is beautiful, but there was no desire to draw so many elements ourselves. This was not required - a great example of a map of Russia was found in Wikimedia :
This is exactly what you need! One point is an SVG file. It was necessary to somehow convert it to XAML. As a result of a search, I came across a XamlTune kit, which has a console utility with the speaking name svg2xaml. She did her job well, and soon I got a canvas with many nested Path elements, which depicts our country. The resulting XAML is as follows:
Obviously, several copies of the canvas are used to draw the borders of the state and subjects.
The thing is small - it remains to display the card on the screen. It would seem that everything is very simple - put the canvas on the form and enjoy. That's how it is, only you can notice its very solid dimensions: Width = "1091.99" Height = "630.119". How to scale it? If you replace the canvas with the Grid, for example, when changing the size of the form, all parts of the map “move apart”. To avoid this, use the Viewbox control. Place it on the form as follows:
It is worth noting here that I put the canvas with the map in the resources with the key “svg2”. The canvas will be compressed while maintaining the proportions to the current dimensions of the ViewBox container. At the same time, the absolute coordinates within the canvas will remain valid, and the layout of the map will not “go”. Now it is possible to set the mouse click handler in the style, for example, like this:
T.O. a click handler will be set for all Path elements. Well, etc.- in the style you can define triggers, set properties, thereby ensuring the necessary appearance and behavior: further actions depend on your tasks and imagination. For example, you can highlight the boundaries of the region when you hover the mouse, or highlight the background when an event occurs, etc.
I needed an interactive map, i.e. so that you can work with its individual parts, including accepting user input. If this is not required, you can use the canvas with the map as a VisualBrush. You can do this, for example, like this:
To preserve the original aspect ratio of the canvas with the map, the Uniform value was set for the Stretch property of the brush. Of course, in the case of using VisualBrush we will get a gain in speed - less CPU resources and RAM will be required. In confirmation of this - the data from the profiler from the Visual Studio 2010 suite (the blue line of the graph indicates the CPU load):
1) Option with VisualBrush (allocation of managed memory ~ 11.36Mb):
2) Option with ViewBox (allocation of managed memory ~ 14, 83Mb):
Therefore, if user input processing is not needed, the VisualBrush approach is preferable.
So, it’s quite simple and quick to solve the problem of working with a geographical map. It is in such situations that you begin to understand the full power of WPF technology. Not the most trivial task - getting an interactive and “rubber” (ie resilient to resizing) card - came down to using the utility and “screwing” the styles. Very indicative, in my opinion.
Sample Source