We’re always interested to hear how you’re using the Maps APIs, so let us know if you’ve got something cool to show by tagging +Google Maps API on your posts (or comment right here!). For technical questions that aren’t answered in the developer documentation, check out the Google Maps developer community on Stack Overflow. Don’t forget to tell us what you’d like to see in the next release using the Google Maps API issue tracker.
Posted by Daniel Schramm, Associate Product Manager, Google Maps Mobile APIs
The MapView has two child views. The DOM element for a custom overlay actually needs to reside inside the markup generated by Google Maps, but the overlay is an Ember.View so the MapOverlayView is actually rendered as a sibling of the MapCanvas and then moved into the correct spot later.
Keep the overlay centered while panning
The default behavior for a custom overlay is to re-calculate the styles when the map is panned, but to build an overlay that stays centered on the map, the overlay should only be drawn once and then pan with the map.
Creating the overlay
Finally, once the overlay has been created and rendered, resolve a promise letting the application know the map is ready.
Final Thoughts
This project was extremely fun and was successful due to the collaboration between design and development. The Google Maps API gave us the creative freedom to completely customize the map, while Custom Overlays really pulled the experience together.
Posted by Monica Tran, Google Maps API Marketing
Adam and Abby Putinski are a husband and wife design/dev team located in San Francisco. Learn more about their work at abbyputinski.com
Thanks to BigQuery, running complex correlations over billions or trillions of attributes is surprisingly easy. But don’t forget if your data does have some spatial component, a quick mapping visual can add some great context to your results.
Posted by Josh Livni Maps Developer Relations Team
We represent the overlay items with a protocol having two methods: updateWithPanoramaView and draw. The updateWithPanoramaView method updates an item’s screen location geometry, while draw draws it to the current graphics context.
We store all items to be drawn in a collection, update their positions based on the panorama position, and draw the collection in our view’s standard drawRect method.
If we want to make sure these items are drawn in a certain order that might change based on the data, we can add z-indexes to them and then sort the collection by z-index after we update them and before drawing.
II. Syncing the Overlay with the Panorama
To make sure this overlay view stays updated as the panorama moves beneath it, we can update the view’s data in an implementation of GMSPanoramaViewDelegate’sdidMoveCamera method. We can use a CADisplayLink to ensure the overlay view is redrawn at regular intervals, and use a flag to make sure it is only redrawn when necessary.
Optimization
CoreGraphics can be a bottleneck. [UIBezierPath strokePath] and [NSString drawAtPoint] are expensive as you can see by profiling with Instruments. For performance intensive applications, an alternative is to use OpenGL. Avoiding overdraw is always a good idea, so the first optimization, if needed, is to carefully examine what is being drawn to the screen, and draw only what is necessary.
III. Mapping data to the panorama view
The GMSProjection class has a pointForCoordinate method that returns the screen pixel location for a coordinate on the Map. This is useful for overlaying elements on top of a GMSMapView, and is used in the Sun Surveyor Map View to draw text related to sun and moon paths on top of the Map.
GMSPanoramaView has a similar method, pointForOrientation. This method allows us to query the panorama for a screen pixel location given a GMSOrientation (bearing and pitch tuple) relative to the panorama location, where the camera is stationed, at ground level. This is useful to make sure an item we overlay onto the view remains in the same location relative to the scene, even as the camera moves and the view shifts.
Because the camera has a Field of View that determines what is visible on the screen, some orientations are not visible (such as behind the camera position). pointForOrientation helpfully returns NAN (not a number) for such orientations, so we know the given orientation is not visible.
With sun path data already expressed in terms of orientation relative to the ground level of the viewer, drawing corresponding paths with screen pixel locations is easy. We map our data with pointForOrientation, and draw what is visible by checking the result for NAN.
The sample project uses a panorama of Sydney, Australia, looking west, with a sun path for 12/20/2013.
Bonus: altering the Field of View
Version 1.4.1 of the SDK added support for changing the GMSPanoramaCamera’s field of view (FOV). The field of view determines how much of the scene is visible on a device screen, as well as how much distortion around the edges of the view is present. Smaller values for FOV are the equivalent of having a telephoto lens on a real camera: it brings distant objects closer.
The Street View panorama viewer in the Google Maps SDK for iOS is an example of a great API. The GMSPanoramaView class is simple to understand and use. In the course of a weekend, I was able to deliver a fun, interactive and highly requested feature to Sun Surveyor’s iOS users. I can’t wait to see what people are able to do with this new Street View Panorama feature in my app, and I look forward to seeing all the other implementations that others develop!
Stonehenge, as seen from a Street View panorama in Sun Surveyor
Posted by Monica Tran, Google Maps API
Sun Surveyor visualizes the sun and moon in a variety of ways for photographers, filmmakers, solar industry professionals, architects, homebuyers, gardeners, and anyone needing to predict or understand the movement of the sun and moon.
Adam Ratana is a Carnegie Mellon University graduate living in, and loving, Pittsburgh, PA. He produces dance music as a member of Pittsburgh Track Authority, enjoys photography, traveling with his wife, and writing fun software in his free time. Adam also enjoys attending the Pittsburgh Cocoaheads chapter meetings.
You’ll notice that we’re not including the actual fragment in the layout - we add the Fragment at runtime, because we don’t want to pay the cost of the fragment transaction and add all the markers on the map, unless the user requests it.
You’ll also notice a bit of a hack at the bottom of the layout. In testing, we found that the MapFragment would leave a black box artifact on the screen on certain devices when the user opened our sliding menu navigation. Adding a simple FrameLayout “above” the map seems to fix the problem.
Extending SupportMapFragment makes it much easier to separate the map display logic from our Activity and list fragment. Our SupportMapFragment (and its inner classes) is responsible for:
Adding markers representing each available hotel
Customizing the GoogleMap UI options
Centering and animating the map to show the added markers
Showing an info window when a marker is clicked
Launching an Intent to display more details when an info window is clicked
Next up, we’ll talk about how we add markers to the map and keep memory usage down.
Managing Markers
One of the challenges in migrating from v1 to v2 of the Google Maps Android API was figuring out the best way to know which hotel’s info to display when a marker is tapped. To solve this, we place each <Marker, Hotel> pair in a HashMap when adding the markers to the Google Map. Later, we can use this HashMap to look up a marker's corresponding hotel info.
The code snippets below illustrate how we do it.
This HashMap allows us to look up the selected hotel in our InfoWindowAdapter, enabling us to display more information about it.
We place quite a few markers on the map for hotel results and each marker can have a different custom image. It's really easy to run out of memory and we were getting quite a few OutOfMemoryExceptions early in development. To manage memory more effectively, we made sure we didn't create a new new Bitmap and BitmapDescriptor for every marker placed on the map. We also ensured that the resources were recycled after we were done with them.
When the user taps a marker, we want to show more information; that’s where info windows come in handy.
Introducing Info Windows
Aside from simply viewing the location of all available hotels on a map, users are typically interested in the name and price of the hotel. The architecture for implementing this information window changed considerably from version 1 to version 2 of the Google Maps Android API.
Before: Info windows in the Google Maps Android API v1
When using v1 of the Google Maps Android API, our app displayed more detailed hotel information in a custom info view when the user tapped on a hotel marker. That custom view displayed the hotel name and price, and triggered a custom animation when the view was added to the screen. This animation made it appear that the view was growing from inside the pin on the map.
We achieved this effect by setting the LayoutParams to MapView.LayoutParams.BOTTOM_CENTER and MapView.LayoutParams.MODE_MAP, which centered the bottom of the custom view on top of the tapped hotel marker.
With the introduction of the Google Maps Android API v2, MapView.LayoutParams.MODE_MAP was removed, so we explored alternative treatments to show the hotel information when the user clicks on a result. For our purposes, the best alternative was to use the new info window interface.
After: Info windows in the Google Maps Android API v2
Creating an InfoWindowAdapter is pretty straightforward. The API provides two ways to populate the info window; either by supplying the contents of the info window (shown in the default window stylec) or creating a full View. Because we wanted to have a custom window background, loaded from a 9-patch, we opted to build a complete View for the info window by overriding the getInfoContents() method to return null, and by returning a custom View from getInfoWindow().
Here’s a sample of our code:
We could further simplify this code by having our HotelView take a Hotel model as a parameter in the constructor.
A caveat with info windows is that even though they are populated by the returned View, the info window is not treated like a *live* View object. The system will call the view’s draw() method only once, then use that cached rendering as the user continues to interact with the map. Our existing animation didn’t work in the Google Maps Android API v2, but we decided to be consistent with the platform and remove the animation rather than try to hack around this limitation.
We <3 Google Maps Android API v2
Upgrading from version 1 to version 2 of the Google Maps Android API was virtually painless and fun to do! The introduction of MapFragment helped us separate the map display logic from the rest of the code and made code reuse much easier. Using custom info views was very straightforward with the new info window interface. We look forward to adding even more Google Map features to our app.
Posted by Monica Tran, Maps Developer Marketing
Monika Szymanski is a Lead Engineer on the Android team at Orbitz, where she works on apps that are friendly, fast, and easy to use. In her free time, she enjoys outdoors, running, red wine, and anything chocolate.
Mike Kelley is a Software Engineer at Orbitz, where he works on Android travel tools to help people travel smarter. He's a Michigan grad, transportation and technology enthusiast and craft beer buff. Some of Mike's ideas and projects live online at theelfismike.com.
Orbitz Worldwide (NYSE: OWW) is a leading global online travel company that uses innovative technology to enable leisure and business travelers to search for, plan and book a broad range of travel products and services including airline tickets, hotels, car rentals, cruises, and vacation packages. Orbitz Worldwide owns a portfolio of consumer brands that includes Orbitz, CheapTickets, ebookers, and HotelClub. Also within the Orbitz Worldwide family, Orbitz Partner Network delivers private label travel solutions to a broad range of partners including many of the world's largest airlines, and Orbitz for Business delivers managed corporate travel solutions for corporations.