Topics to cover
- Referencing JavaScript and CSS resources
- Using access key/token
- Understanding the pixel coordinate systems
- Handling events
- Comparable classes with examples (Bing/Mapbox)
- Map/Map
- Switching map view types or base layers
- Location/LatLng
- LocationRect/LatLngBounds
- Point/Point
- Pushpin/Marker
- PushpinOptions/Icon
- Polygon/Polygon, MultiPolygon
- Color/<Path options>
- Infobox/Popup
- EntityCollection/LayerGroup, FeatureGroup, GeoJson
- GeoLocationProvider/map.locate(), CircleMarker
- TileLayer/TileLayer
- Concluding remarks
Referencing JavaScript and CSS resources
Bing
Apparently according to this page, in order to draw complex shapes such as a multipolygon, we also need to load its “Microsoft.Maps.AdvancedShapes” API using the “loadModule” method, as shown below, after the above JavaScript reference. You can click here and here to find more info about the “AdvancedShapes” module. In our app we definitely draw lots of complex shapes such as multipolygons, so we needed to include this line of code for sure. That’s it. That’s all we need for loading Bing map resources.
Mapbox
Mapbox only lets you load the resources by https. It also requires you to explicitly load the CSS, as shown below:
But other than that, that’s it. No need to load anything else for complex shapes like we had to do for Bing. Notice that the API version number (v2.1.5) is included in the reference.
Using access key/token
Bing
To create a Bing map app, you will need to create a developer account on the Bing Maps Account Center. When you have an account, you will be able to create a Bing map key that you can use in your map app. This key is required. I won’t go over the instructions for doing that here. You can find the info on how to do that here.
Your Bing map key is embedded in the “credentials” prop of the “MapOptions” object, which is passed into the constructor for a “Map” object, as shown below:
Mapbox
With Mapbox you also will need to create an account with them, and then you will be issued an access token that’s required to create Mapbox apps. You can find more info about that here.
Mapbox account access token is used like below before you can create your first map object:
Understanding the pixel coordinate systems
I want to spend a little bit of time talking about this topic b/c it actually caused me quite a bit of confusion for a couple of days. You might run into this issue too some day if you are not aware of the differences.
We have an algorithm that calculates where to display a popup on mouseover on a certain layer to ensure the popup is always shown at an ideal location on the map. In order to figure out where to display a popup on the map, we basically have to do 5 steps:
- Get the lat and long of a point on the map
- Convert the lat and long to pixel location
- Do some math with the pixel location
- Convert the new pixel location back to lat and long
- Display the popup based on the new lat and long
After I thought I had completely migrated the API over for displaying popups, I was expecting everything to just work. But that wasn’t the case. I checked and double-checked the algorithm and the math. All was good. I was scratching my head for a couple of days…and then finally it dawned on me: the centers of the pixel coordinate systems in the 2 APIs were NOT the same! I was not expecting this at all. I just assumed they would all be using the same pixel coordinate system. Man was I wrong. I will definitely check this first next time I work with a different mapping API.
Bing
In Bing Map, apparently the (0,0) of the pixel coordinate system defaults to the center of the map view displayed on the screen, which is the “PixelReference.viewport” enumeration discussed on this page. In this configuration, to the right of the center is positive X values, and below the center is positive Y values. So a point on the map in the NE quadrant would have a positive X value, and a negative Y value.
So when I’m doing conversion using “Map.tryLocationToPixel” or “Map.tryPixelToLocation” and not specifying the “PixelReference” param, it defaults to “PixelReference.viewport”.
Mapbox
On the contrast, in Mapbox, the (0,0) of the pixel coordinate system is at the upper left corner of the map view. I’m not sure if this is a configurable option or not. To the right of the center is positive X values and below the center is positive Y values. So no visible point on a Mapbox map would have negative X or Y values.
So now you understand what caused the confusion. Without changing our algorithm used to calculate the popup position in our app, I just had to tweak the math a little in order to achieve the same result using Mapbox API.
Handling events
Very soon into the project I noticed there’s a pretty big difference in the event handling APIs between Bing and Mapbox. I just want to say a few words about it here in a general sense, so that you will become aware of it. Even though they are different, event handling in both APIs is fairly easy to catch on. You should be able to easily identify events in Bing and find an equivalent way to do it in Mapbox for the most part.
Bing
The Bing map API has the “Events” object whose methods you can call directly to add/remove an event handler on pretty much any object, as shown below:
Mapbox
In Mapbox, there are a set of methods shared between event-powered classes such as “Map” or “Marker”. The set of methods include “on”, “once”, “off”, “fire”. Here’s an example to add an event handler to a “Map” object on “click” event:
Comparable classes with examples
The Map/Map classes (Bing/Mapbox)
For both Bing map and Mapbox, the Map class is the central class of each API. It’s used to create a map object on a web page and all other objects displayed on the map will be added to the map object.
Bing
Creation API:
Map(<HTMLElement> element, <MapOptions | ViewOptions> optionsObject?)
Example:
Note that the “mapTypeId” enumeration prop of the “viewOptions” object in the example above is used to define the type of map view displayed. It can be aerial, auto, birdseye, road, etc. There are no comparable type for this in Mapbox, but this is accomplished in Mapbox using different tile layers. This is the same for the “labelOverlay” prop. I’ll give an example of how to switch map view types in both APIs shortly.
Mapbox
Creation API:
L.mapbox.map(<string> htmlElementId, <string> mapId? | url? | <object> tilejsonObject?, <object> optionsObject?)
or
L.map(<HTMLElement | string> id, <Map options> options?)
Example:
Note that in Mapbox’s Map object creation API, there’s not a way to define the initial bounds like it does in Bing map. Thus the code example above has to initialize the map’s initial bounds in 2 steps by calling “map.fitBounds” method.
Switching map view types or base layers
Earlier we talked about Mapbox’s Map object creation API doesn’t have a way to set an initial map view type like it does in Bing. But in Mapbox we can accomplish this using different tile layers.
Bing
Mapbox
Location/LatLng classes
Represents the lat and long of a geographical point on a map.
Bing
Creation API:
Location(<number> latitude, <number> longitude, <number> altitude?, <AltitudeReference> altitudeRef?)
Example:
Mapbox
Creation API:
L.latLng(<Number> latitude,<Number> longitude,<Number> altitude?)
Example:
LocationRect/LatLngBounds classes
Represents a geographical rectangle on a map.
Bing
Creation API:
LocationRect(<Location> center, <number> width, <number> height)
or use static methods:
LocationRect.fromCorners(<Location> northwest, <Location> southeast);
LocationRect.fromEdges(<number> north, <number> west, <number> south, <number> east, <number> altitude, <AltitudeReference> altitudeRef);
LocationRect.fromLocations(list of locations/array)
Example:
Mapbox
Creation API:
L.latLngBounds(<LatLng> southWest,<LatLng> northEast )
or
L.latLngBounds(<LatLng[]> latlngsArray )
Example:
Point/Point classes
Represents a point on a map with x and y coordinates in pixels. (Different from Location/LatLng)
Bing
Creation API:
Point(<number> x, <number> y);
Example:
Mapbox
Creation API:
L.point(<Number> x, <Number> y,<Boolean> round?)
Example:
Pushpin/Marker classes
Represents a pushpin/marker object on a map.
Bing
Creation API:
Pushpin(<Location> location, <PushpinOptions> optionsObj?)
Example:
Mapbox
Creation API:
L.marker(<LatLng> latlng,<Marker options> options?)
Example:
Related: PushpinOptions/Icon classes
Infobox/Popup classes
Represents an info box/popup for a pin/marker on a map.
Bing
Creation API:
Infobox(<Location> location, <InfoboxOptions> optionsObject)
Example:
Mapbox
Creation API:
L.popup(<Popup options> options?,<ILayer> source?)
Example:
Polygon/Polygon, MultiPolygon classes
Represents a polygon or multipolygon on a map.
Bing
Creation API:
Polygon(<Location[]> locations, <PolygonOptions> optionsObject)
or
Polygon(<Location[][]> arraysOfLocations, <PolygonOptions> optionsObject) for both polygon and complex polygons.
More info about complex polygons can be found here.
Example:
Mapbox
Creation API:
L.polygon(<LatLng[]> latlngs,<Polyline options> options? )
or
L.polygon(<LatLng[][]> latlngs,<Polyline options> options? )
L.multiPolygon(<LatLng[][]> latlngs,<Polyline options> options? )
Example:
Related: Color, EntitiyCollection/Polyline, Path classes
Color class/<Path options> object
Represents color values to use on an object on a map.
Bing
Creation API:
Color(<number> alpha, <number> red, <number> green, <number> blue);
Example:
Mapbox
Creation API:
N/A, not a class
Example:
EntityCollection/LayerGroup, FeatureGroup, GeoJson classes
In Bing map, an EntityCollection object is used to contain a collection of entities, which can be of type: Infobox, Polygon, Polyline, Pushpin, TileLayer or EntityCollection itself. It allows us to treat a collection of entities such as pushpins as a whole, and add that to a map in one call. Also, a “map” object by default has an “entities” prop that’s an EntityCollection type. Any qualifying entity such as a Pushpin object can be added to the map by using “map.entities.push(pushpin)”.
In Mapbox, there’s not an obvious match for this class. The most comparable classes I can find for EntityCollection in Bing are LayerGroup, FeatureGroup, and GeoJson. GeoJson extends FeatureGroup, which extends LayerGroup. But in this project, it turned out that the LayerGroup class was sufficient for OUR needs. The LayerGroup class also allows us to treat an array of objects such as markers as a whole, and then add that to a map in one call.
Bing
Creation API:
EntityCollection(<EntityCollectionOptions> optionsObject)
Example:
Mapbox
Creation API:
L.layerGroup( <ILayer[]> layers? )
L.featureGroup( <ILayer[]> layers? )
L.geoJson( <Object> geojson?,<GeoJSON options> | <Path options> options? )
Example:
GeoLocationProvider class/map.locate(), CircleMarker class
These are the classes/methods used to obtain and display the user’s current location using W3C GeoLocation API. In Bing map, there’s the GeoLocationProvider class dedicated to this. In Mapbox, there’s not a dedicated class, but simply the “locate()” method on the “map” object. Once the location is found, we can use the Mapbox CircleMarker class to draw a circle at the found location. Whereas in Bing map, we can just use the “addAccuracyCircle()” method of the GeoLocationProvider class to draw a circle.
Bing
Creation API:
GeoLocationProvider(<Map> map)
Methods:
getCurrentPosition(<PositionOptions> options)
addAccuracyCircle(<Location> center, <number> radiusInMeters, <number> segments, <PositionCircleOptions> options)
Example:
Mapbox
Creation API:
N/A
Methods:
locate(<Locate options> options? )
L.circleMarker(<LatLng> latlng,<Path options> options? )
Example:
TileLayer/TileLayer classes
Represents (raster) tile layers on a map. We can use this to load custom tile images on our map.
Bing
Creation API:
TileLayer(<TileLayerOptions> options)
Example:
Mapbox
Creation API:
L.tileLayer(<String> urlTemplate, <TileLayer options> options?)
or
L.mapbox.tileLayer(<string> mapboxMapId | url | <object> tileJson, <TileLayer options> options?)
Example:
Custom wrapper for TileLayer
Concluding remarks
I have to say that I’ve enjoyed working with both APIs, except the fact that Bing map licensing costs more and it had an issue with loading custom tiles. I think both APIs are well designed and fairly pleasant to work with.
As you can probably tell from looking over the API differences, the Bing map API was designed to have a more traditional OOP look and feel like C# and Java, since everything starts with a class. Mapbox/Leaflet, on the other hand, has a good mix of OOP and functional programming flavor to it, as evidenced by code like this: marker.setRadius(200).addTo(map). So if you are more of an traditional OOP type of developer, then you will probably prefer working with Bing map. If you have been working with JavaScript for a while, then you might find Mapbox/Leaflet to be more natural to you.
Well, that’s it for now. Even though this is NOT a comprehensive list of comparable classes between Bing and Mapbox, I believe I’ve covered quite a few of the prominent API classes commonly used in mapping. I hope you’ve found this blog post series helpful on learning about both mapping APIs, and giving you a head start if you were to move from Bing to Mapbox some day.