Frameworks • iOS, macOS • 57:14
MapKit JS brings Apple Maps to your website. See how MapKit JS provides map rendering that is optimized for various browsers and devices, and supports native gestures such as pinch-to-zoom, two-finger rotate, and more. Learn how to add annotations and overlays, and how to use JavaScript interfaces to Apple Maps services such as Search and Directions to deliver an amazing map experience on your website.
Speakers: Vicki Murley, Julien Quint, Melody Kelly
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Hi, everyone.
[ Applause ]
I'm Vicki Murley and I'm the Engineering Manager for the MapKit JS Team. This is Session 212, Introducing MapKit JS. So, when iPhone came out more than ten years ago, it really changed the game, and it introduced us all to what we now kind of know as this app ecosystem. And it's funny to think about, because for so many of us, apps are such an integral part of our daily lives, but before there were apps, there were websites.
If your company was founded before iPhone, your whole company may have started as a website, and even today, if you have an app, you might be using a website to reach a larger audience or even just a different audience of people. So, lots of developers out there, just like you, have a website and an app. And the WWDC site is a great example. We have this site and there's an accompanying app, which you're probably using to find your way around the conference center, as you're on the go, here this week.
So, at Apple, we've been really lucky that we have been able to show Apple Maps on our own websites for a little while now. This is a page on the WWDC site, which is showing you other events around the convention center. If you've ever used Find My iPhone of iCloud.com, you've seen Apple Maps on a website. And if you've ever searched for a retail store, again, an example of Apple Maps on a website. So, most of you out there are probably used to using MapKit inside your apps, and today, we're making MapKit JS available to you for your websites.
[ Applause ]
So, this week at WWDC, we're making a MapKit JS Beta available, and this is the same library that we have been using on our production websites. Every web mapping library out there, has a free tier of usage. Like some number of requests that you get for free, and MapKit JS Beta is no different.
So, you -- as part of the MapKit JS Beta, you're getting 250,000 map initializations, and 25,000 service requests. That includes geocoding, search, search auto-complete, and directions. And often these free usage tiers are specified over some period of time, like per year, per month, per week. For the MapKit JS Beta, we're making this amount of free usage available to you per day.
[ Applause ]
So, that's a good amount. And -- but if you need more for your particular use case or your business, you can contact us. There's a form online. Just fill it out and submit it, and we will receive that request. To use MapKit JS, you need a key, and you can get that by signing into your developer account, and go to the Certificates, ID's, and Profiles Panel. And you can get a key there, just like you would for any other service in your developer account. There's a limited number of keys available for the MapKit JS Beta, so I suggest you go and get one as soon as possible.
Once you get a key and start using MapKit JS, I mean, I'm biased because I work on it, but I think there's a lot of things that you're going to really like about it. The first thing is, it lets you unify on one map provider, for both your app and your website. So, we've noticed lots of you are using Apple Maps inside your apps. Now, you'll be able to use Apple Maps everywhere.
The MapKit JS APIs, are really inspired by the APIs that you're already using inside native MapKit, but they're using conventions that are familiar to web developers. So, they should be easy for you to adapt. Also, MapKit JS really brings the Apple Maps experience to web pages. It's localized and in 32 languages with full right to left support. It's accessible via keyboard access and with voiceover. It has the beautiful cartography that we all know and love in Apple Maps. And it has support for native gestures like Pinch to Zoom, Two-Finger Rotation, and also Shift, and Two Finger Scroll to zoom in.
It also uses something that's called Adaptive Rendering Modes. So, what that means is, there's a couple different modes in which the map can be rendered. The first is Client-Side Rendering, and this is a full WebGL engine that is rendering the map on the client. And this allows us to do lots of things, like these very, smooth transitions as users pinch to zoom or shift two-finger scroll to zoom in. You'll see the labels fading in and out as we transition between zoom levels, just like on native.
Also, Client-Side Rendering gives us full control over the labels on the map. So, we can enable features such as Rotation, where I'm rotating the map with two-fingers, but the labels are staying horizontal as I rotate. Finally, with CSR, we have the marker style annotations that you're used to seeing on iOS.
And the title of this annotation is My Marker. If I select this annotation, the subtitle will appear, but it would overlap that label that is beneath it. So, with Client-Side Rendering, and full control over the labels, we can just collide that label out and remove it so that the labels on the map never overlap the text for your annotations.
And even as users are zooming in and out, and the map labels are changing all over the place, the map labels are never going to overlap your annotation labels. In fact, if you have a draggable annotation and the user is picking it up and moving it all over the map, labels are never going to overlap your annotation labels.
So, this is one of the rendering modes, Client-Side Rendering. But web code can run anywhere, and not all devices are created equal. So, for those times when your users may be running on a low performance configuration, maybe an old device, we have a different mode that we call Labels Only Client-Side Rendering. And what this is, it's a grid of image tiles that show the base map, with a layer of WebGL labels over the top of it. So, we can still give as many users as possible these great features like rotation and label collisions, in a high-performance way.
In your users' configuration does not support WebGL at all, they get something that we call Server-Side Rendering, which is a grid of tiles, tile images, and in this case, the labels are actually part of the image. So, adaptive rendering modes are pretty cool because there is an ideal mode for every client configuration out there.
And we choose the best mode for your user automatically. So, you don't have to decide whether to use the WebGL version, or the tile version, or whatever. We run a quick test and give that user the best mode for their configuration. In our experience so far, most users are getting Client-Side Rendering or Labels Only Client-Side Rendering. So, that's a quick introduction to MapKit JS. And now, to tell you more about using the API, I'm going to hand it off to Julien Quint.
[ Applause ]
Thank you, Vicki. Let's get down to the technical details of using MapKit JS for your website. We will see how to set up a map. We will see how to navigate an annotate this map so that you can show your own data. And finally, we'll see how to enable rich interactions with additional services.
To set up your map, you need to go through these four steps. First step is to import MapKit JS. Here you see a script tag that you can add somewhere on your page. And the URL of the MapKit JS script includes a version number. We follow the semantic versioning system where the first number is the major version number, which is updated if breaking changes are introduced.
The second number is a minor version number, so when bugs are fixed, when new features are added or when performance improvements take place, we update this number. And finally, for urgent patches, we update the patch number. You can specify and X instead of a specific number for the minor or the patch version, and we recommend that you use this Version 5.0.X to get started so that you will get urgent bug fixes on our first public release.
In order to be able to show a map on your website, you will need to tell your page -- to tell MapKit where to show that map. So, in order to do that, you can use an HTML element that will be the container for your map. So, in this case, I'm using a development which is usually a very good candidate for that. I give it an ID so that I can refer back to it easily.
And one thing that is very important is to set its size, because the map doesn't have a size of its own, so it will just use the size of the elements that it is part of. So, if you have a development that I represented here with a gray background, a map will be shown inside that element. If your element size changes, then your map size will change as well.
So, I have set up an element for my map. The next step is to initialize MapKit JS. So, we just saw that you need a key to be able to use MapKit JS, and in initializing MapKit, you get your authorization callback so that you will be able to use the services that MapKit JS provides.
And most importantly, to show the actual map on your websites. And the last point is to create a map object, here using the Map Constructor from MapKit. I give it the idea of the container where the map will show. And this is what happens. We have a map showing on our sites.
This is the different map. We didn't pass any other parameters, so it will show a different region and the different control. You can see the controls in the corners. You can see the Compass for rotation. The Zoom control. The Map Type Control on the top, etcetera. This was a pretty large area, but if you're on a page where you want to show only a very small map, these controls can use a lot of valuable space, so by default, when your map size is below a certain width or height, we will toggle these controls off automatically.
On touch devices, the situation is a little bit different. We don't really need to show the -- some of the controls like the Zoom or the Compass, because we have gestures to change the rotation of the map or to zoom in. So again, we don't really need to use up that space by showing these controls, and we turn them off by default.
Note that the Apple logo and the legal text are always present. These are the difference for the controls, but you can also set these control visibilities yourself. Some controls are so-called Adaptive Controls. This includes the Compass and the Scale. This means that depending on the platform, they will behave in a slightly different manner.
So, on iOS, the Compass control is not shown by default, but if the map rotates, then we will show it indicate where North is pointing. And the Scale is an indicator of the units of distance on your map. And we show it only when the user is zooming in and out.
So, here, we can see the -- when we have zooming and rotation, we can see the Compass appear and disappear in the bottom right corner. And the Scale appear and disappear in the top left corner. Of course, we can also select these controls to be always visible or always hidden. The rest of the controls have a binary state, so they can be hidden or set to be visible by setting a Boolean property.
In this example, we show the controls that do not show by default on desktop, such as the User Location Control which appears in the bottom right of the window. Here, I've selected it. So now, the user location is tracked, and you can see the user location in the center of the map. And the Scale is shown at the top let, because I marked it to Always Visible.
We can go further in configuring these controls. In order to match better the color scheme of your page, you can set the tint of the map. And this changes the color of the user controls. So, you can see, for instance, the -- all of the controls of the map. You can see the user control is now highlighted in red because I set this tint color to a red color. You can use any CSS color value here.
The MapKit will use your [inaudible] language configuration, so that it will adapt itself to the language that your user expects. You can also set that language into the initialization code or you can even set it on the fly using the language property. So here, I've set it to Japanese so that I'm sure -- so that I can show the map, as well as the controls in Japanese. So, you can see the North indicator for instance in the Compass has been replaced, and the units are not in -- using the metric system which is more traditional in Japan, than using miles or years.
If you set your language to a right to left language, such as Hebrew in this example, or Arabic, the controls are also mirrored to match your users' expectations. So, the controls are the way -- are some of the ways that your users can interact with the map, but again, also in turn directly. As I said, we can use touch events on touch enabled device. On this stuff, you can use the Track Pad for some of the gestures, and you can also use the mouse to click and pan the map, or double-tap for instance, to zoom in on the map.
You can also disable these interactions directly, by setting the Zoom Enabled, Scroll Enabled, or Rotate Enabled property to be false. So, for instance, in the case where you have this very small map as I showed earlier, you might want to make sure that the user doesn't accidentally move the map around to be sure that it always shows the right area. And you would set these properties to false, which would make the map static. Now, that we know how to set up the map on our page, we want to make sure that we show some interesting content.
So, we can do that by navigating around the world to show a specific area, but also to annotate the map to call attention to the region that we are showing. We'll see how to set the center in the region, how to add annotations to the map to mark locations, and how to cover the -- some areas of the map with overlays. So, starting with the center and the region of the map, again, this is the default map. And it shows the default region, which is zooming out at the minimum possible level. And centering the map on, zero, zero, latitude and longitude.
You probably want to show a more specific area of the world. So, for this example, I want to focus on Rio de Janeiro in Brazil. And to do that, I will set the center of my map to the coordinate of Rio de Janeiro. So, you can see on the right, that the map center has moved to show Rio at is center. But setting the center of the map does not change the scale. So, at this scale, we are always still not very much in focus because we can see all of South America, for instance. So, let's zoom in a little bit.
And in order to do that, I will set a region. So, a coordinate region is made up of a center, which is represented by these dots at the center of the map, as well as a latitude and longitude span. So here, I have represented the region as this dotted box.
But we will not that the map -- the region that is set ultimately on your map, will be bigger than the region that you asked for because we need to make sure that it fits entirely within the bounds that you have set for your map. So, in this case, I need to add some padding, north and south of the region to be able to show the -- all of the region that was specified. So, in terms of putting the MapKit JS framework -- the center is set to a MapKit coordinator object which is a latitude and longitude pair.
In the Coordinate Region, to set the region of the map, is an object that contains two member, a center which is also a coordinate and a coordinate span which is a latitude delta and a longitude delta there. How did I come up with the region or with the coordinates that I showed you in these screen shots? There are many ways to decide on regions and coordinates. You can look them up on Wikipedia and help put them in your code. You could get them from some database that has some geographical information. But one way that you can also get this information, is to use MapKit Services that includes Geocoding and Search.
So, Geocoding lets you look at a place and will return your coordinate in a region. So, in these previous examples, I used the geocoding from MapKit JS to look at the coordinate in the region for Rio de Janeiro and this is what I set on my map. You can also use search to search for places. And it will return not only the coordinates of these places, but also bounding region that you can set on your map, to make sure that it encloses all of the results.
Another way to quickly set a region on your map that is very convenient, is a method called Show Items. We will see now how to add annotations and overlays on your map, and by calling Show Items, we will make sure that we have a region that encloses these items so that they are all visible to your user. I will note that region changes may be animated, so that you can provide a nice animation. Or you can set the region instantly.
Because these things, changing the regions, changing the center, etcetera, can be done from your code but can also be done by the user as a result of interactions you want to be able to react to these interactions. And we -- and the Map Object allows you to listen to user events such as region changes, when they begin, when they end, since they can be animated. And also, when gestures such as coding, zooming, rotations begin and end.
We follow the model of DOM Event Handling, so you will have the familiar method such as Add Event Listener and Remove Event Listener, the name of the event, and you get past an event object with the parameters of the event. So, for instance, if I wanted to refresh my map with some new information every time the user has mapped to a different area, I can listen to region change and events, and that will let me know that the map has settled to a new place, and I can now use the region of that map to compute which information I wanted to show at this stage.
Now, that we know how to set up a map, let's add some our own information on it. And we can do that with annotations and overlay. We'll start with annotations. And MapKit JS provides three kinds of annotations. The first one, you've had a quick peek at it, which is the Marker Annotation. You can customize annotations further than the -- what the marker annotation provides by using images, or even DOM Elements that will have completely customizable appearance.
The marker annotations are the most useful annotations that MapKit JS provide as they also have lots of rich interaction built-in. And there's lots of styling options. So, they are analogous to the marker annotations that that you may have seen already on iOS. They have a built-in animation for selection and deselection. And they automatically collide out the underlying map labels as we've seen before. So here, when I select my annotation, the label for the exit of the station is hidden to make room for the subtitle.
Marker annotations -- the appearance of marker annotation also adapts itself automatically to the rendering mode that has been selected by MapKit JS for your map. So, we've seen that if we have Client-Side Rendering Mode or Label Only Client-Side Rendering Mode, we are able to hide labels, so we can display the title and the subtitle of your annotations on the map. And this is what is shown on the left-hand side.
If you have Server-Side Rendering, the labels are built into tiles and we cannot hide them. So, if you see the map on the right-hand side, we see that we have many more labels because none of them have been hidden. So, in order to be able to show our annotations legibly, we only show the annotation balloon and the labels are not shown on the map.
We can still see the title and the subtitle of these annotations when we select them by using a callout bubble as in this example. And custom annotations, will also make use of these callout bubble to show the title and subtitle. Finally, the market annotations provide a lot of standing options.
So, this is the default for market annotation. You create an annotation with a coordinate and some properties such as title and subtitle, and this is the basic default rendering. You have glyph image which is a pin shown in the balloon, and it comes up with a red color.
You can change that color to any CSS color value. So, here, I've used a green color for my balloon. You can also change the color of the glyph. So, the glyph can only have one color. So, in this case, I switched from the default white to a yellow color.
You can change the image of the glyph. So, from the default pin that is provided by MapKit JS, to any raster image that you can provide. So, in this case, I've provided this image. You can give several sources for your images for different pixel ratios. When the annotation is selected, it becomes bigger, so you have more room to show more details in your glyph. So, in this case, we can also specify a selected glyph image, which is different from the original one.
Finally, instead of an image, you can change the glyph by using some text. We recommend that you stick to very, short strings such as one to three characters, and in this case, I'm just using the Letter M. When the glyph text and the glyph image are both specified, then the glyph text is shown.
So, now that we know how to display marker annotations, we can go crazy and put a lot of annotations on our map. So, this is the result of doing searches for cafes and bars in Paris. And I've styled them slightly differently to distinguish them from one another. But the problem is that there is a very dense number of annotations in the same area.
Fortunately, we have two ways in MapKit JS to deal with this sort of clutter. The first one is to set a display priority property on annotations. What this means is that when two annotations collide, the annotation with the highest display property, which is a number, will collide out the annotation with the lowest display priority.
So, in this case, we can see that many annotations have been collided out. When you zoom in and out, these collisions run again, so that zooming in for instance, will let you discover more annotations. And when they have the same display priority, we will use the one that appears at the bottom of the screen as the more -- as the one with the highest priority. Another way to deal with clutter, is to use clustering instead of these display priorities.
So, in this case, when two annotations that have the same clustering identifier, which is a property that can be set on marker annotations, and is a simple string, when two annotations that collide and have the same clustering identifier, they are replaced by a single annotation that will represent both of them, or more than two of them of course if more than two annotations collide.
So, in this case, we see that some of the annotations can be shown by themselves because they have no neighbor, but in the dense areas in the center, we have clustered several annotations together. When a cluster is created, we use a marker annotation to represent it and we use the glyph to show how many annotations are in the cluster. You can also change the behavior -- not the behavior, the appearance of your clusters, by specifying a new style or a new kind of annotation. And now, we'll do a small demo to show these annotations in action.
So, in this demo, which should appear here -- in this demo, we will use a map and the data that we will display is Bigfoot Sightings that Have Occurred in this Area. So, after this session, or maybe this weekend when you are done with the conference, you can maybe go explore the woods of Northern California and see if you can find Bigfoot. I have created a map which I have initialized in the manner that I've displayed in the previous slides.
And what I have done, is I have gathered a list of Bigfoot annotations -- of Bigfoot sightings, sorry, including the location, the year in which they occurred, and some other information. So, what I will want to do is I will want to use these annotations, show them on the map, with marker annotation. So, let me start by creating a function to translate a sighting object which has all these properties, into a marker annotation.
So, when I get a sighting, I want the coordinate of the sighting to be used as the coordinate of my marker annotation. And these sightings have several other properties, such as the year of the sighting, which I will display in the title. This comes from a database put together by the Bigfoot Field Researchers Organization.
So, I will show the idea so that if you are interested in more details about that sighting, you can go look at that database and find even more information. And finally, I'm ready to create a marker annotation with that coordinate and these options that I've created. So, now that I know how to set up a marker annotation for a sighting, I will get the sightings that I've prepared.
And with this list of sightings, I will create an annotation for each of them. I will then make sure that my sightings are shown on the map. My annotations are shown on the map. And I will use the Show Items method, which is very convenient because not only it ensures that the items are visible, but also that they are added to the map.
And since I'm doing a webpage, I can also add some extra information on my page such as how many sightings there were in this area. So, let me make sure that I save and by reloading, I now see a map with 60 sightings on it. So, all of these annotations are sightings and we run into the problem that I've just highlighted which is that in this park area, I can see lots of sightings happening, and they all overlap each other. And even as I zoom in, I can see that there's still lots of clutter, so I will clean that up using the Display Priority Property on Annotations.
So, in order to choose a display priority, what I will use is I will use a very important property of the sightings which is whether they were clear sightings. So, if someone really, really saw bigfoot, or maybe they just heard it or saw some traces of it. So, I have this clear flag which I will use to set my display priority.
Display priorities a number and these priorities can be pretty arbitrary. So, we provide predefined values, such as required, meaning that your annotation must always be shown on the map, but also, high and low display priority. So, when the sighting is clear, I will set a high display priority. When it's not, I will set a low display priority.
And finally, I will also encode that information as the color of my annotation so that the users can understand better why an annotation was shown or now. So, when it's brown, it's a clear annotation and when it's great, it was not so clear. So, let's see the difference that this makes.
So, now you can see that the map is much cleaner because all of the collisions have been a result. You can see that some of the annotations are brown. So, these are the clear sightings. These are probably the ones that are the most interesting ones to visit first.
But you can also see that if I zoom in on the map, then new sightings are being revealed. So, your users can explore the map and find out about where they can hope to see Bigfoot. I will conclude by this demo, by adding, another piece of information to my map. I will change the glyph to be either an icon of Bigfoot which I've prepared.
So, this is a simple PNG image which I will use for the clear sightings, and in case the sighting is not so clear, I will make that more explicit by setting the glyph text to be a question mark. And now, what I can see, is that these questionable sightings are a question mark. And the Bigfoot sightings that are really clear, have the Bigfoot icon. So, this includes the first demo. Thank you.
[ Applause ]
So, in this demo, we show how to create marker annotations from JavaScript objects, how to set the display priority of annotations to unclutter our map, and how to style these annotations with colored glyph image, glyph text, so that we can translate the information that we have onto the map.
Sometimes, market annotation is very convenient, but may not be exactly what you want to use on your map. For instance, if you want to use the logo of your company and it has more than one color, then you cannot choose a glyph image because it's restricted to just one color. Sometimes the shape of the annotation is not really the one that you are going for, so in this case, you may provide images to represent your annotations instead. So, in this case, I have the small sticker look to mark places where -- which I have visited recently.
So, I can use a raster image for these annotations. The title and subtitle are shown in a callout bubble, just like in Server-Side Rendering for marker annotations. And to create an image annotation, this is very similar to a marker annotation, but with the additional property that much be provided which is the URL for the images. And here, you can see two different URLs for two different pixel ratios.
Another way that I could represent a notation is using the classic pin example. And pins usually come up in many different colors. And the problem is that if I want to provide a lot of different colors, I will need to provide a lot of different images. And this can quickly become unmanageable. So instead, what I can do is I can use a custom annotation. And in this case, instead of an image, I will use any DOM Element to represent my annotation.
And these elements are created on demand for your annotations. So, let's see an example. Here, if I wanted to do just some color for any pin that shows up on my map, then I will create an annotation with a coordinate [inaudible]. And a third parameter which is a function that we will return a DOM Element for that annotation.
So, in this case, I will use a Canvas Element. I create a Canvas Element. I get .Context. I drew a pin image in that Canvas. I changed the head of the pin to the color that I want, and I returned to Canvas. And this is the Canvas that is shown on the map for this annotation.
So, these were the three kinds of annotations that you could use. But sometimes you want to show more than just a single location or a set of single locations. Sometimes you want to call -- to show complete areas on your map. And to do that, we have overlays and we have -- we provide three different kinds of overlays. And here are some examples of how you could use them.
With a circle overlay, you can show all of the distances -- or the distances from a point. With a polyline overlay, we can show a route between two points. And you can highlight geographical areas such as a state, the boundaries of a country or a city, etcetera, using a polygon overlay.
So, here is an example of a circle overlay. So, now I'm in Brussels and I've centered my map on the Manneken Pis. And this is right in the center of the city and this is a very nice place to walk around. So, by using concentric circles around my location of increasing radius, I can see walking distances.
So, here I've created overlays with their coordinates, and the second parameter that you need to give to a circle overlay, is a radius expressed in meter. So here, every overlay has a radius starting from 400 meters, increasing by 400 meters. So, 400, 800, etcetera. So, I can see in the right, that there is a museum for comic strip art. That sounds interesting. And it looks like it could be between 1200 and then 1600 meters. So, about 10 to 15 minutes' walk. One important thing that I can do with overlays, is I can also style them.
So here, to represent this style of overlay, I can use a MapKit Style Object, which has several properties such as the line width, the line depth, the stroke color which again, can be any CSS color. By default, circle overlays are filled with blue color, but in this case, I want them to be transparent. So, I set the field color to be null.
I have decided that I want to go visit this comic strip museum, and MapKit JS as we will show, has services that can give you walking and driving directions between two points. So, in this case, I've asked for directions from where I was, the Manneken Pis, to where I want to go.
I receive as a result, a route which I represent on this map using a polyline overlay. And a polyline overlay is a list of points. So, these are all coordinates linked to each other. I can style them by setting the Stroke Opacity for instance, or a thick line width to make sure that it shows up on my map.
And the last example is a polygon overlay. This is very useful to do for instance data visualization. And here I have a map of the United States where every state is an overlay of its own. A polygon overlay is defined again by a list of points, but this -- in this case, the shape is closed and filled.
You can even specify lists of lists of points to -- for more complex scenarios. So, for instance, if you have enclaves and exclaves, which is often the case with real geographical areas. Annotations and overlays can also have an extra piece of information added to them, which is this data property.
So, in this example, I want to show the population of every state of the United States. I can show it as a color, which gives me a rough idea of the population. But I can also add some additional data so that if the user selects one of the overlays, so in this case, the State of Texas, I can show that the actual population is over 20 million people. And overlays are selectable just like annotations.
To show overlays such as the route that I showed you or to show all of the states, we need a lot of data, we need a lot of points, so for the states, we had thousands and thousands of points. So, a convenient way to get that data into your program, is to use GeoJSON Import. So, if you have a GeoJSON data file, then you can import it automatically using MapKit JS. Annotations and overlays are created.
So, in this example, this was a different data file, which contained a lot of UFO sightings. And this is just a detail of the map. So, you can see there are lots of these sightings. And all of these annotations and overlays are created automatically and can of course be customized using some delegate methods.
Finally, these -- since these annotations and these overlays can be selected by users, you want to listen to events from them, as well as you could from the map. So, you can listen to selection and the selection events. And we've also seen earlier that annotations could be dragged, so you can listen to dragging events. And again, this uses the Add Event Listener Method.
So, for instance, you can use Add Event Listener to listen to select events from the map, which will tell you when an annotation or an overlay has been selected. And we will see an example of that in the demo. The next section is Enabling Rich Interactions with Services, and for this section, I will give the mic to Melody.
[ Applause ]
MapKit JS provides you with access to three services, Geocoding, Search, and Directions. I'll step through examples of each of those, but before that, I'll tell you what they have in common. You can use the services in a similar way, with four easy steps. You first create the service object, then you specify the request parameters and options, then you make the request, and finally, handle the asynchronous response via a callback function. So first, let's talk about the Geocoder.
Here's an example of how you can use the Geocoder, and it has two methods: Lookup and Reverse Lookup. So, this is if have you an address or a place, and you want to find the coordinate, or if you have the opposite. You have a coordinate and you want to find the address.
So, the first step is to create your object, which you can optionally provide at Gets User Location parameter. This will allow you to provide more context to the geocoder. This is useful in the case where there are places with the same name in multiple locations. For example, if you're using the geocoder here, you'll be most likely to return Brisbane, California instead of Brisbane, Australia. Next, you build the requests. Here, we're using this convention center. And then you can handle the response. As we mentioned before, the geocoder can easily be used to place marker annotations. So, here we're adding a marker annotation to the map.
And then here we have an example of the reverse lookup where we have a coordinate, and we want to find the address for the place. So, that's the geocoder. Next up we have service context. So, as I mentioned before, you can provide a Gets User Location parameter, but you can also provide coordinate and region to search. This is useful to provide the most relevant results to your user. So, that's where places are in multiple locations with the same name, or you can provide your search results, closer to the user.
Here's an example of how you can use the Search Service. It's an example for finding coffee nearby the user. So first, you create your service object. Then you build your request using query like coffee. You can also do something more specific like a specific name of a coffee shop that you have.
And then you can handle the results, which can easily be displayed using annotation since sometimes you return multiple results. And you can use the coordinate as well as the title to populate the fields of annotation. And then finally, we simultaneously add and display the annotations using the Map Show Items method.
So, this is useful if you have your full query that you want to send in the request, but if you have a Search Bar that you want to respond to user input, you can use the Search Autocomplete Method. With Search Autocomplete, you can provide a partial query to the user - to the service, and then save your user some keystrokes by providing suggestions which you can then use to complete a search.
And the last service is directions. Similarly, to the other services, you create your directions object. You can choose to provide a language which will then return the route steps in that provided language. If you don't provide a language, the language provided to the MapKit initialization function will be used. And if that's not provided, the browser's preferred language will be used.
Then you build your request using two required fields: the origin and the destination. These can be coordinates, addresses, or places. By default, the transportation type is by automobile. You can switch this using the transport enum to walking directions. We won't keep that, because that's a really far way to walk, but we will use Request Alternate Routes. You can use this to provide multiple options to your users. This way we can display different routes instead of the default of one optimal route.
And then finally, you can display your results on the map. Here we have polyline overlays as you've seen earlier. And you also get a set of route steps as well as the distance and the travel time. So, those are the services. Now, that you're more familiar with them, Julien will come back up for a demo.
[ Applause ]
Thank you, Melody. So, we will pick up where we left off and we will continue building our Bigfoot Finder. And there's one things that's really missing from this finder, is that even though it can tell us where we are, and it can tell us where Bigfoot is, it doesn't yet tell us how to get there. So, I'm going to add some directions from All Current Location, which is the McEnery Convention Center, to these Bigfoot locations. I will use the MapKit JS direction services to do that. I will use polyline overlays to draw them.
But the first thing I need to do is I need to make sure that the user - I need to find a way so that the user can tell me which one of these sightings they want to see. So, well, this one is selected, so that's probably the one that the user wants to see, right? So, this is what we will do. We will use the Select Event Listener from the map to listen to annotation selections from the user.
And when an annotation is selected, that means they might be interested in knowing how to see that specific location. So, we will request a route and draw it so that they can see how to get there. And then finally, we will let them also select one of the routes from the options that are returned by Direction Services and display more information about each of these routes. So, let's start by setting up our Event Listener.
So, we listen to the select events from the map, which tells us when an annotation or an overlay is selected. So, this is the property of the event, object that I received. And if annotation has a value, then that means that this annotation was just selected. So, there is only one annotation overlay selected at a time, in MapKit. So, there is no ambiguity here. This is the one that we want to go to. So, I will show routes to that annotation.
Showing our route means drawing it on the map. So, let's set up a polyline overlay to draw a route on the map. So, first off, I will start by defining a style that I will use for all my routes, setting some opacity and some line width to make sure that the route stands out. The default color is blue, which is fine for the moment, so that's what we will use.
And just like we did a function that created annotations on demand for citing objects, here we'll create overlays on demand for routes. So, a route that is returned by the MapKit JS Direction Service, contains a lot of information including a path which is a list of steps that you can take to go from A to B. And each list of steps, itself contains a list of points.
And if you remember to create a polyline overlay, I want a list of points. So, now that I have a list of - list of points, I will reduce it to a single list so that I will put all of - the path steps one after the other. This is the list of points that I want to create my polyline overlay. This is the style that I just defined above, that I want my overlay to show up as.
And later, I will let the user select this overlay to see more information. So, I will keep around all of the route object, in the Data Properties so that I can display the distance of the estimated travel time. I know how to draw these overlays, so now I know - I need to request them from the service. So, here we go.
This is a little bit longer but not so bad. I first need to create a directions object. I will just use the current language for the directions. So, the default is fine. So now, when I'm requesting a route to a specific annotation or rather, routes to a specific annotation, I will clean up my map first because maybe I've shown routes to a different place before. So, if I query the other list property of my map, it tells me which overlays are currently added to the map, and I can remove them by using the Remove Overlays Method. So, now I have a clean map, and I can display new routes.
I'm building my request for the origin. I will hot code this place, the McEnery Convention Center. Again, I could put coordinates for instance, instead, but this is much more convenience. For the destination, I will use coordinate because I have them. They are the coordinate of the annotation that was given as a parameter.
And I want to show all of the possible - not all of the possible but the several possible routes to this point. So, I make sure that My Request Alternate Routes Property's set to true. Now, that my request has been created, I can execute it on the Direction Services using the Route Method.
Things can go wrong when you do these kind of queries. So, we must make sure that we have a way to handle errors when they occur. So, in this case, I will fall back to show a default route that I've created and it's just a straight line. So, if we see a straight line, then we know we're in trouble.
But let's focus, let's be positive and focus on the cases where the request succeeds, and in this case, I will have a list of routes and I will create a new polyline overlay for every one of them. I will use my trusty Show Items Method on the map to add these routes and make sure that they are being shown by setting the region to enclose the routes. And let me introduce a couple more options in that method.
The first one is Animate, because I wanted to make sure that there is a smooth animation from the current region of the map to the one where the routes are shown. And finally, I will also add some padding so that I can keep some of the context and not constrict the region too much around the routes.
So, I'm now ready to request routes from the - this convention center to an annotation. So, let's select this one again. And now that my annotation has been selected, the request has been made. I see that I have three different results. So, they share a part of the route, but then they diverge in the end. And they start from our current location, the convention center.
So, I think this is right. Yes, that looks right. I have got three results. So now, I might be interested in knowing more about what's the difference in travel time or distance. So, I can use selection to do that. But if I select a route, the only thing that happens is that my annotation has been deselected because there is only one selection at a time. The problem here is that there is no default behavior for overlays being selected. So, let's implement our own. What we will do is we will highlight these overlays and then display their information on the side bar.
So, in order to highlight these overlays, I will create a new style for highlighting overlays. So, let's put it here, along with my old style. So, this style will keep the same opacity. We will make the line figure and we will make it purple so that it stands out from the other ones.
But now, we need to apply this style to my overlay once it's selected. Fortunately, I already have an event handler for selections. And up to that point, we were only interested in listening to annotation being selected. But now we will just add a new -- we will add plans to this function. Oops. So now, if annotation is selected, I still do the same thing that I was doing, but if an overlay's selected, I will change its style to be the selected route style that I've just defined, so that it is highlighted. So, let's see this in action.
We can use a different one. I'm feeling lucky. And now, we can see that we can select the routes to - from the list of routes that have - that has been provided. I haven't implemented showing the data yet. Let's see if I select another route. What happens is that there is nothing happening by default when an overlay's selected, but there is nothing happening by default when an overlay is deselected. So, I have to implement that part of the behavior as well. So, in this case, I will add a new event listener for deselect events. So, when an overlay is deselected, then I will switch its style to the default one.
So, this should fix my issue. So, let's try again. I have a route here. And if I select again, I do the same place because here we have two overlays on top of each other. This will select the other overlay. And the deselection event handler is working, so, my previous highlighting has disappeared, and now, the new selection is shown correctly. So, this seems to be working pretty well. Here is another example.
So again, I can select these routes. But now I want to know more about them. I want to know what are the driving directions, how long it takes to use one of the routes versus another, etc. So, this is very simple to do because all of the - everything that I need is already in place. I have saved data on my overlays, and I have Event List now for Selection and Deselection. So, when the overlay's selected, I will show the data in the sidebar.
So, this is just classic. Now, we are really into web development land where we have a bunch of the time we went to -- format it into some HTML, so I won't go over the details. But the detail that we have is the one that is associated with the overlay. And it gets shown when the overlay's selected. And I will not make the same mistake about this this selection, so I will directly hide the data when the overlay's deselected so that I don't have several routes appearing at once.
So, let's try again. Let's go back. I like this example. So again, I will select this route. And now that the route is selected, we can see on the right-hand side that we have some additional information. This is a quick name for the route. So, this is the route that goes from Mount Hamilton Road. It's 70 kilometers long and under ideal driving conditions, it should take me an hour and 32 minutes to reach there. And here are all the steps that I can follow to get to my destination.
I could see what this one looks like. It's actually longer in distance but it should get me there faster. So, there we are. We have built a Bigfoot Finder and -- that lets us select where we want to go and tells us where we are going to go.
[ Applause ]
Thank you. Quick recap. We've seen how to react to user events. So, in this case, selection and deselection. We've got driving directions from the MapKit JS Service. We've used polyline overlays to render these driving directions. And we've added our own behavior for the selection of overlays since there is no specific behavior provided by default.
So, there is plenty more to talk about MapKit JS, but we only have one hour. So, I will stop here. But I hope that we have made a good case for MapKit JS, delivering a top-notch map experience for the web. That it lets you unify on a single map provider with a familiar and flexible API. So, if you have on your team people who have used the native MapKit API, this would feel right at home, because the same concepts apply. And web developers will be happy to see that the APIs are also tailored to match JavaScript.
So, I will remind you that you need the MapKit JS Key to be able to use MapKit JS. So, please go to the developer portal, get your key, and try it out today. If you want to know more about MapKit JS, you can find the documentation and sample code at this URL.
And if you want to know more about this session, you have this URL for the session itself. We have accompanying video that will take you step-by-step through getting and using a MapKit JS Key. And finally, we have labs happening on Wednesday morning and Friday morning, so you can come to talk to the whole MapKit JS team to ask us questions about MapKit JS. Thank you very much.
[ Applause ]