Image maps are a pure-HTML way to hyperlink different parts of an image to different destination. Add in a free jQuery plugin and image maps render beautifully on all types of devices. Read this tutorial to learn how to create image maps. F5 — reload the page and display the form for loading image. Ctrl+S — save map params in localStorage. Drawing mode (rectangle/circle/polygon) ENTER — stop polygon drawing (or click on first helper). ESC — cancel drawing of a new area. SHIFT — square drawing in case of a rectangle and right angle drawing in case of a polygon. DELETE — remove a selected area.
Note
MapControl and map services requite a maps authentication key called a MapServiceToken. For more info about getting and setting a maps authentication key, see Request a maps authentication key.
Overlay third-party or custom tiled images on a map by using tile sources. Use tile sources to overlay specialized information such as weather data, population data, or seismic data; or use tile sources to replace the default map entirely.
Tip To learn more about using maps in your app, download the Universal Windows Platform (UWP) map sample on Github.
Tiled image overview
Map services such as Nokia Maps and Bing Maps cut maps into square tiles for quick retrieval and display. These tiles are 256 pixels by 256 pixels in size, and are pre-rendered at multiple levels of detail. Many third-party services also provide map-based data that's cut into tiles. Use tile sources to retrieve third-party tiles, or to create your own custom tiles, and overlay them on the map displayed in the MapControl.
Important When you use tile sources, you don't have to write code to request or to position individual tiles. The MapControl requests tiles as it needs them. Each request specifies the X and Y coordinates and the zoom level for the individual tile. You simply specify the format of the Uri or filename to use to retrieve the tiles in the UriFormatString property. That is, you insert replaceable parameters in the base Uri or filename to indicate where to pass the X and Y coordinates and the zoom level for each tile.
Here's an example of the UriFormatString property for an HttpMapTileDataSource that shows the replaceable parameters for the X and Y coordinates and the zoom level.
(The X and Y coordinates represent the location of the individual tile within the map of the world at the specified level of detail. The tile numbering system starts from {0, 0} in the upper left corner of the map. For example, the tile at {1, 2} is in the second column of the third row of the grid of tiles.)
For more info about the tile system used by mapping services, see Bing Maps Tile System.
Overlay tiles from a tile source
Overlay tiled images from a tile source on a map by using the MapTileDataSource.
Instantiate one of the three tile data source classes that inherit from MapTileDataSource.
Configure the UriFormatString to use to request the tiles by inserting replaceable parameters in the base Uri or filename.
The following example instantiates an HttpMapTileDataSource. This example specifies the value of the UriFormatString in the constructor of the HttpMapTileDataSource.
Instantiate and configure a MapTileSource. Specify the MapTileDataSource that you configured in the previous step as the DataSource of the MapTileSource.
The following example specifies the DataSource in the constructor of the MapTileSource.
You can restrict the conditions in which the tiles are displayed by using properties of the MapTileSource.
- Display tiles only within a specific geographic area by providing a value for the Bounds property.
- Display tiles only at certain levels of detail by providing a value for the ZoomLevelRange property.
Optionally, configure other properties of the MapTileSource that affect the loading or the display of the tiles, such as Layer, AllowOverstretch, IsRetryEnabled, and IsTransparencyEnabled.
Add the MapTileSource to the TileSources collection of the MapControl.
Overlay tiles from a web service
Overlay tiled images retrieved from a web service by using the HttpMapTileDataSource.
Instantiate an HttpMapTileDataSource.
Specify the format of the Uri that the web service expects as the value of the UriFormatString property. To create this value, insert replaceable parameters in the base Uri. For example, in the following code sample, the value of the UriFormatString is:
The web service has to support a Uri that contains the replaceable parameters {x}, {y}, and {zoomlevel}. Most web services (for example, Nokia, Bing, and Google) support Uris in this format. If the web service requires additional arguments that aren't available with the UriFormatString property, then you have to create a custom Uri. Create and return a custom Uri by handling the UriRequested event. For more info, see the Provide a custom URI section later in this topic.
Then, follow the remaining steps described previously in the Tiled image overview.
The following example overlays tiles from a fictitious web service on a map of North America. The value of the UriFormatString is specified in the constructor of the HttpMapTileDataSource. In this example, tiles are only displayed within the geographic boundaries specified by the optional Bounds property.
Overlay tiles from local storage
Overlay tiled images stored as files in local storage by using the LocalMapTileDataSource. Typically, you package and distribute these files with your app.
Instantiate a LocalMapTileDataSource.
Specify the format of the file names as the value of the UriFormatString property. To create this value, insert replaceable parameters in the base filename. For example, in the following code sample, the value of the UriFormatString is:
If the format of the file names requires additional arguments that aren't available with the UriFormatString property, then you have to create a custom Uri. Create and return a custom Uri by handling the UriRequested event. For more info, see the Provide a custom URI section later in this topic.
Then, follow the remaining steps described previously in the Tiled image overview.
You can use the following protocols and locations to load tiles from local storage:
Uri | More info |
---|---|
ms-appx:/// | Points to the root of the app's installation folder. |
This is the location referenced by the Package.InstalledLocation property. | |
ms-appdata:///local | Points to the root of the app's local storage. |
This is the location referenced by the ApplicationData.LocalFolder property. | |
ms-appdata:///temp | Points to the app's temp folder. |
This is the location referenced by the ApplicationData.TemporaryFolder property. |
The following example loads tiles that are stored as files in the app's installation folder by using the ms-appx:///
protocol. The value for the UriFormatString is specified in the constructor of the LocalMapTileDataSource. In this example, tiles are only displayed when the zoom level of the map is within the range specified by the optional ZoomLevelRange property.
Provide a custom URI
If the replaceable parameters available with the UriFormatString property of the HttpMapTileDataSource or the UriFormatString property of the LocalMapTileDataSource aren't sufficient to retrieve your tiles, then you have to create a custom Uri. Create and return a custom Uri by providing a custom handler for the UriRequested event. The UriRequested event is raised for each individual tile.
- In your custom handler for the UriRequested event, combine the required custom arguments with the X, Y, and ZoomLevel properties of the MapTileUriRequestedEventArgs to create the custom Uri.
- Return the custom Uri in the Uri property of the MapTileUriRequest, which is contained in the Request property of the MapTileUriRequestedEventArgs.
The following example shows how to provide a custom Uri by creating a custom handler for the UriRequested event. It also shows how to implement the deferral pattern if you have to do something asynchronously to create the custom Uri.
Overlay tiles from a custom source
Overlay custom tiles by using the CustomMapTileDataSource. Create tiles programmatically in memory on the fly, or write your own code to load existing tiles from another source.
To create or load custom tiles, provide a custom handler for the BitmapRequested event. The BitmapRequested event is raised for each individual tile.
- In your custom handler for the BitmapRequested event, combine the required custom arguments with the X, Y, and ZoomLevel properties of the MapTileBitmapRequestedEventArgs to create or retrieve a custom tile.
- Return the custom tile in the PixelData property of the MapTileBitmapRequest, which is contained in the Request property of the MapTileBitmapRequestedEventArgs. The PixelData property is of type IRandomAccessStreamReference.
The following example shows how to provide custom tiles by creating a custom handler for the BitmapRequested event. This example creates identical red tiles that are partially opaque. The example ignores the X, Y, and ZoomLevel properties of the MapTileBitmapRequestedEventArgs. Although this is not a real world example, the example demonstrates how you can create in-memory custom tiles on the fly. The example also shows how to implement the deferral pattern if you have to do something asynchronously to create the custom tiles.
Replace the default map
To replace the default map entirely with third-party or custom tiles:
- Specify MapTileLayer.BackgroundReplacement as the value of the Layer property of the MapTileSource.
- Specify MapStyle.None as the value of the Style property of the MapControl.
Related topics
Creating Responsive Image Maps
December 31, 2017Working on a browser, I constantly get to research and play with new, cutting-edge features. It can be a ton of fun to picture what the future of the web will look like and what new technologies we need to create to get there. But one of my passions is looking back at where the web has come from, to think about how older features can exist in today's world (and vice-versa). Whether it be making ServiceWorker powered websites work in IE 5, or client side applications work in Mosiac 2 browsers have done a phenomenal job of giving developers the ability to give rich backwards compatibility to their applications and sites. A lot of the time, if you code to standards, things just sort-of... work. This backwards compatibility has created the web where you can layer up offline strategies from a service worker, falling back to appcache, and further still to an HTA (if you are a sadist). However, the reason I still have a job is because a number of features from yesteryear simply were not created in a way that makes them of practical use for today's web, despite how useful their concepts may be. There have been countless examples of browsers trying something early on, and eventually getting it right (or at least better). Other times, there was a great feature back in the day, that simply doesn't have a modern analog. One of the biggest examples of this, is the humble image map.
Primer
In case you are unfamiliar, image maps are awesome! The idea is that you can define regions of an image that, when clicked, does different things. At least it did eventually.
The Stone Ages
The earliest concept of an image map was proposed by Tony Sanders back in 1996, and was first shipped in Mosiac 1.1. It was a lot less feature filled than future versions, however. Back then, rather than defining a shape client side like in the above example, every click just sent the coordinates of the pixel relative to the image back up to the server.
To get it to work, you would just take any image
add the ismap
attribute to it, and wrap it in an <a>
nchor tag like so.
and that was it! So when you click on the upper right left corner of the image the server gets a request at cgi-bin/smile.map.html?0,0
rather than just cgi-bin/smile.map.html
.
Now all you need to do to set the proper mood is slap together a perl script to process those coordinates, play with a tomagochi and walk in the snow, uphill, both ways.
Not too long after ismap
was created, browsers began to support clientside imagemaps.
Medieval Maps
The idea of having to bounce back between the client, the server, and back to the client to do a what is basically just a link navigation is kind of a bummer. You are doubling the number of server trips for something that could probably be fully expressed in the page's original html. Coupling that with the speed of the internet 20 years ago, and you have a you can see how much of a perf problem image maps could be. So in HTML 3.2, we gained the ability to define the click regions for an image map on the client side. Gone are the days where you had to wrap an image in an anchor tag, now you get new semantic elements!
If you have ever written SVG, you may get recognize some of the syntax. The idea is that you create a <map>
element, and inside of it you write some <area>
tags that create the regions over the image. Sort of like absolutely positioning anchor tags over an image, but more flexible, because you are not limited to rectangles. You can use circles, as well as polygons. That means that you can create extremely detailed outlines of items in an image in order to create a rich, client side, javascript free experience for users that can work in browsers older than a lot of our readers. Pretty neat!
an aside...
One of the reasons I first got really into image maps is my background in ecommerce. Back in the day, I worked at Urban Outfitters and a very common request from management was to have an image on the site, and have our users be able to click on any of the stuff in the image and take them to the page to buy that thing. Seems like a perfect fit for image maps, right? Thats what my buddy Jack Keller and I thought when we started to code the thing up. But quickly we realized a problem you may have already noticed. If you haven't, check out how you define the coordinates.
Those numbers inside the coords
section are pixels. It means that the rectangle starts at 0,0 (the top left of the image), and extends to the right 120 pixels, and down 250 pixels. Makes perfect sense in a world where every website was hard coded 640 x 480, but when you live in the 21st century, we needed to be coding responsive websites rather than hardcoding exact coordinates into the design.
So, I told my coworkers it wasn't possible, and we retreated1. We ended up putting absolute positioned anchor tags over an <img>
, and pouting about it. Image maps felt so close to being the right thing, it was just not quite there. But it is a problem that always stuck in my craw. In the back of my head I never stopped trying to figure out how to get responsive image maps working.
Thank god for Estelle
Years later, I was catching up on the blogs that I follow, when something caught my eye. This was a time when browsers still lacked support for the <picture>
element or srcset
, and as a result there was not a way to load different sized images for different sized devices in an accessible way - at least that was the common thought. Estelle Weyl, however, had discovered a way to achieve just that using SVG. She dubbed it the 'Clown Car' technique, and essentially the idea is that you use SVG's ability to embed CSS to include a @media
query that will change the image that the user sees based on the window's screen size. It was a incredibly clever solution to the problem, but once we had actual support for responsive images (e.g. srcset
) there wasn't really a reason to use it anymore. Or so I thought.
Responsive Image Maps
The thing that makes the clown car technique so cool is that it is powered by SVG. SVG is extremely flexible, and as a result, we are able to leverage it to create an image map-like thing that is actually useful in todays responsive world.
As we covered before, image maps use exact pixels for coordinates. As a result, we aren't able to salvage them to use for our modern implementation. But we take the spirit of what they were used to achieve, and pair it with Estelle's clown car example, and get something great.
Here is what you need to get a basic version working
See the Pen Responsive Image Map by patrick kettner (@patrickkettner) on CodePen.
It works! Try resizing your window, or just collapsing or opening the codepen tabs up above. No matter what the size of the image, the <path>
s have scaled properly and give us the desired effect. Hopefully how it works is pretty self evident by looking over the code, but I will cover some of the more potentially esoteric portions of it.
viewBox
Right off the bat, the <svg> tag has the viewBox
attribute on it. This is a part of the SVG Coordinates system, which Sara Soueidan covers wonderfully here. I wouldn't dare attempt to summarize Sara's work (you are doing yourself a disservice if you haven't read it), suffice to say that it helps maintain the aspect ratio of the images we load inside of our image map.
path { fill: transparent }
Each of the clickable areas in our image map are inside of <path>
tags. By default, their fill
(sort of like an SVG version of background-color
) is black. Since we want our users to actually be able to see what they are clicking on, we make it transparent
xlink:href
While we do use an <a>
tag (becuase it works in both SVG and HTML documents), we need to go back in time to gross XML documents to support the ability to actually link to something with our links. You can read a bit more about them here, but essentially you just need to include xlink:
before your href
s.
Making it Accessible
As excited as I was after stumbling onto this, I noticed a number of potential improvements that could be made. For our second version, we introduce a number of accessibility related changes
See the Pen A11Y Responsive Image Map by patrick kettner (@patrickkettner) on CodePen.
so what did we change?
Pointing out links
Traditional image maps show the pointing-finger cursor whenever you are hovering over a link. By default, our SVG based version does not. This is easily remedied by setting the cursor
CSS property.
Using <g>roups, setting <title>s
One thing I love using with traditional <a>
tags is that if you set a title
attribute, you will get a tooltip with the title whenever you hover over any of those links. We can replicate this by using the <title>
tag in our SVG code, but in order to do so we need to create a group. If you look over the above code, you will see that the <path>
s have been wrapped in <g>
tags. That way we can place a <title>
inside each of the <g>
s.
More svelt outlines
For our keyboard-navigating friends, the outline
CSS property is an essential way to show where the keyboards current focus is. outline
s are always rectangular. Normally this is fine, since div
s are as well. But since we have complex polygons, we can create highlights that hug the curves of our elements exactly. By setting a semi-opaque fill
for a focused path, we can hide the built in outline
while still allowing for the current focus to be clear to our user.
Doing this yourself
Hopefully how the code actually works has made a decent amount of sense. The next challange is to create all of the complex polygons for all of the different clickable areas. I go over how to do so in the video below, but the TL;DW is outlined in the text below
So how do you create these SVGs yourself? Once you have an image, open it up in Illustrator (or Inkscape if you prefer a free program). Both Illustrator and Inkscape are vector editing programs that we will use to trace the shapes of the image.
Using the pen tool, you can start to create a new shape on a new layer. Just outline each item you want to be a region, making sure to create a new layer for each region you want to be seperate.
Once that is complete, we can save our file as an SVG. Since we don't want to embed the image inside of it, make sure to delete the layer containing the image we have been tracing over.Now that we have our SVG file, it would be a great idea to compress the file. There is undoubtedly some reduction possible. I highly recommend SVGOMG, an online SVG minifier.After that - thats about it! Now you just need to wrap each of the <path>
s in a <g>
tags to add our title, and <a>
tags to get it to link to stuff.
Aboutresponsive Image Map Creator Template
And thats it! You can now create responsive image maps using inline SVG.
In conclusion...
How To Make Images Responsive
The web has a long, and storied history. And having been built by mortals, it is filled with false starts, dead ends, and vestigial tails. But we can learn a lot about the right way to move forward when we examine the problems we have had in the past. Image maps are a really fun problem to solve, but there are lots more out there to do as well. What else did the old web have that the modern one lacks?
Please do reach out to me on twitter or email with comments and corrections.