Build better maps with MapWrapper

All About MapWrapper

Published on Oct 22, 2019

What is MapWrapper?

MapWrapper is a JavaScript library that abstracts some of the complexity of other client JavaScript mapping libraries, such as Google Maps API or OpenLayers. Clients of MapWrapper can use one unified interface and easily switch out the underlying map provider. MapWrapper also provides some amenities such as better information windows (“info windows”), and simplified initialization of markers.

Why MapWrapper?

The prime use case (and the reason we wrote MapWrapper) is when you want to work with multiple different map providers -- for example, if you wanted to test out how different map vendors look and feel and respond to mouse events, you could use MapWrapper and initialize your page by including different scripts and setting different parameters.

Our particular use case was more unusual: our geocoding comparison page shows maps from four different providers. Why? The larger map providers generally have terms of service restrictions that prohibit their API clients from displaying their geocoding results on other providers’ maps. This is a problem since it is easiest to compare results graphically on a map (we haven’t developed the ability to intuitively discern how far two points are from each other just by looking at latitudinal and longitudinal coordinates). So, we could plot our coordinates alongside Google’s coordinates on Google’s maps, and we could similarly plot our coordinates alongside Mapbox’s coordinates on Mapbox's maps, but we couldn’t have one centralized map that showed coordinates from all geocoding providers.

Our solution was to display four maps alongside each other, showing results from Bing, Google, and Mapbox on their respective maps, as well as plotting the results from the other services that had no such restrictions. We also chose to display our map as the fourth map, allowing users to compare the aesthetics of the four providers. For each map, we wanted users to be able to interact with the maps as they have come to expect from online maps: able to pan by clicking-and-dragging, and able to zoom with the scroll wheel. Since there are four maps, a question naturally arises: when a user interacts with one map (e.g. panning to a different location), what should happen to the other maps? We thought it would be most intuitive for each of the other three maps to be kept in sync with the map that the user interacted with. However, that meant working with three different interfaces, each with their own version of events.

We could have coded up the application logic (such as synchronizing the panning) in the same JavaScript file that also handled the various different events. In the end, we decided to separate the code that is specific to the different mapping APIs in a different layer that we ended up calling... MapWrapper. The abstraction of different APIs in MapWrapper allowed the application JavaScript code to be much simpler: rather than having the event handler of each map iterate through the other maps and check to see if the target map is Bing, Google, or Mapbox, and then issue the corresponding command to update the position, the application code could simply use MapWrapper, streamlining much of the programming logic.

What are some of the other benefits of MapWrapper?

As we developed the geocoding comparison page, we ran into other difficulties that lead to improvements in MapWrapper.

Easier initialization

A frequent map operation is to show several points of interests, whether they be restaurants, houses, or something else. When only one point is shown, it’s easy to center the map on that single point and choose an arbitrary zoom level. When multiple points are shown, it’s still easy to determine the geographic center. However, what zoom level should be used? An arbitrary zoom level might be too zoomed in so that it’s actually possible that none of the markers are visible on the map. Or, if the map is too zoomed out, then points of interest might appear too close to each other. Rather than having the zoom level statically set, it would be ideal for the map library to automatically figure out the closest level of zoom where all points are still visible.

Another optimization (albeit much smaller) is the initialization of markers’ information windows, which can now be done in the map constructor, rather than having a separate loop create a marker, attach an information window, and then add the marker to the map.

var map = new MapWrapper.Map({
    provider: MapWrapper.Provider.OPENLAYERS,
    elementId: "map",
    // MapWrapper will automatically calculate the center and the zoom level for this set of markers
    markers: [{
        position: new MapWrapper.Point({
            latitude: 37.3247,
            longitude: -122.0105
        }),
        // Easy way to initialize info windows; compare to Google Maps API: https://developers.google.com/maps/documentation/javascript/infowindows
        infoWindow: "My favorite place to get a banana flavored dessert"
    }, {
        position: new MapWrapper.Point({
            latitude: 37.349167,
            longitude: -121.893304
        }),
        infoWindow: "I recommend their Banana Double Choco (Banana Crêpe)"
    }],
    tileSource: MapWrapper.TileSource.NETTOOLKIT,
});

Additionally, MapWrapper clients can now specify marker colors without having to find various image URLs. Since MapWrapper Marker objects support hex codes, you can specify your favorite shade of banana yellow (without having to create the marker images).

map.addMarker({
    position: {
        latitude: 38.8892,
        longitude: -77.0523
    },
    // Banana yellow, a bit raw
    color: "#D4FF66",
});

Tooltips

One of our huge frustrations with traditional maps providers centered around tooltips, or information windows (sometimes referred to as “Info Windows”). The major mapping providers allow for information windows to be attached to markers so that users can learn more about a certain point on the map. These popups can generally be triggered in one of two ways:

1. users can click on the marker, after which the information window stays open until the user clicks again to close the window, or

2. users can hover over the marker and the popup automatically closes when the mouse moves to a different part of the map.

In our case, both models were unsatisfactory. Since there could be several different points of interest on our maps, each of which had additional information available in the popup, we felt that requiring the user to click on each point would be too burdensome. At the same time, we wanted to let users interact with the information window, not just click them.

Diving in a little more, the information window had the address that the geocoding service resolved to. That is, after a user submits an address, the geocoding service might normalize or correct the spelling of the user submission or the service might not find an exact address and instead return a less granular address (e.g. missing the street number or perhaps even all of the street details). The address returned by the geocoding service gives important clues as to how well the service thinks it was able to geocode a given address. Since there are several points of interest (several geocoding services), we thought it would be too cumbersome to require the user to click on each marker of interest.

On the other hand, the typical map provider’s model of hiding the information window when the mouse stops hovering over the marker means that users can only use information windows to read information, not interact with it (if the user tries to move the mouse into the information window to click on a link, the window closes). In our case, we wanted users to be able to confirm that a location returned by a geocoding service was correct.

If we went with just the traditional map API where users hover to read from information windows, then users would need to click the marker to trigger content to show up somewhere else on the page, which they would then need to notice before mousing over to click a confirmation button. It made sense for the button to be local to where the user was already looking. This effect could have been achieved with the click-to-open popup model, but then users would need to click several markers to discover information, making the consumption of information cumbersome.

Our solution was to track the movement of the mouse to determine if the user was moving from the marker to the information window (keeping it open) or to some other part of the mapping (closing the popup). It’s a small detail, but figuring out how to track the mouse movement and make that determination took us some time. While our use case might seem very specific, it’s actually widely applicable to online directories that show maps. For example, suppose you have a website that shows restaurants on a map and you have ratings, business hours, and a link to make a reservation. Since there could be many restaurants in view, requiring that the user click on each marker to find out the ratings and business hours could be tedious. On the other hand, if a user decides to make a reservation, it would be nice to not require the user to mouse over to the other side of the page.

Another detail for tooltips occurs when a marker is near the edge of the map. When the user triggers the information window to open, the traditional map libraries would cut off the information window at the map boundaries. Instead, we decided to use smart tooltips that open as a separate HTML element from the map, solving two problems at once: first, if the information window were too close to a map boundary, it would transcend the map boundary and second, if the marker were too close to the edge of the browser window, it would intelligently decide what direction to open to minimize the chance of it being cut off.


Yelp gets both of these details right: their interface allows users to learn more about various listings by hovering over the markers, but still allows users to click inside the information window; Yelp also opens their information windows over the map so that the popups do not get cut off when they are too close to the map boundary. Another site that gets this right is Rent.com.

Yelp information windows
Note that users can mouse into the information window, saving them a click if they wanted to go to the profile listing.

In contrast, VRBO requires you to click on the various markers to see pictures of the different rental properties. VRBO also has tooltips that stay within the map boundaries, but they compensate for that by automatically moving the marker so that the information window will be within the map boundary. Users can see the unobscured information window, but users who are particular about location have a number of extra different mouse operations per listing of interest when browsing through the map: first, they click on the marker to open the information window (which moves the map), then if the user is not interested in that listing, the user would click to close the information window and then click and drag to recenter the map.

VRBO Map and listings
You too can do battle with the VRBO interface as you browse through listings on a map: click, click, click-and-drag. While the map moves the marker so that the information window is within the map boundary, when you drag the map to recenter it, the information window can become obscured.

The consumer version of Google Maps mostly abides by the second model: information windows open on hover, but you can’t mouse over the popups to click on anything, so the windows are read-only. If you wanted to find out more details than what is presented, you need to click on the marker which populates an area on the left, which could be far from the user’s attention. One improvement that Google Maps’ tooltips have over the second model is that the information windows open intelligently such that if the marker is too close to one side, the window will open in the opposite direction. Note, though, that these information windows do not come with Google Maps’ JavaScript client library -- if you want this functionality, you need to build it yourself or find another solution.

Google maps information window

These interactions are difficult to explain in words, but they are nuances that help set the user interactions of one directory apart from another.

Conclusion

We’ve learned a lot as we’ve iterated and improved our geocoding comparison page. When we started, we did not have a clear idea of how we wanted the comparison page to look and feel. An initial idea, for example, was to have a gigantic table that listed distances between points. It’s taken us a long time to get where we are now, but we’re now much more sensitive to the finer points of user interactions on maps. If you opt to use MapWrapper, you get that functionality bundled with tile maps.