Not just a red pin anymore: Making Maps Beautiful

0ae09092606666ea375bdd12052fd77a?s=47 Steven Gray
November 15, 2014

Not just a red pin anymore: Making Maps Beautiful

Talk I gave at Google DevFest London 2014 about using Google Maps Javascript API to visualise large sets of data. Don't just use a red pin. Make Maps Beautiful!

15/11/2014

0ae09092606666ea375bdd12052fd77a?s=128

Steven Gray

November 15, 2014
Tweet

Transcript

  1. Not just a red pin anymore! Making maps Beautiful +StevenGray

  2. None
  3. None
  4. None
  5. A brief history of Google Maps 2005 - 2014: Nine

    years of online maps
  6. None
  7. None
  8. None
  9. None
  10. None
  11. Visualisation Tools Making Data Interesting

  12. Map MapTypeId Controls MapTypeControlStyle ScaleControlStyle ZoomControlStyleControlPosition Overlays Marker MarkerImage MarkerShape

    Symbol SymbolPath Animation InfoWindow Polyline IconSequence Polygon PolyMouseEvent Rectangle Circle GroundOverlay OverlayView MapPanes MapCanvasProjection Services Geocoder GeocoderRequest GeocoderStatus GeocoderResult GeocoderAddressComponent GeocoderGeometry GeocoderLocationType DirectionsRenderer DirectionsService DirectionsRequest TravelMode UnitSystem DirectionsWaypoint DirectionsStatus DirectionsResult DirectionsRoute DirectionsLeg DirectionsStep Distance Duration Time TransitDetails TransitStop TransitLine TransitAgency TransitVehicle ElevationService LocationElevationRequest PathElevationRequest ElevationResult ElevationStatus MaxZoomService M a x Z o o m R e s u l t M a x Z o o m S t a t u s D i s t a n c e M a t r i x S e r v i c e D i s t a n c e M a t r i x R e q u e s t DistanceMatrixResponse DistanceMatrixResponseRow DistanceMatrixResponseElement DistanceMatrixStatus DistanceMatrixElementStatus Map TypesMapType MapTypeRegistry Projection ImageMapType StyledMapType MapTypeStyle MapTypeStyleFeatureType MapTypeStyleElementType MapTypeStyler Layers BicyclingLayer FusionTablesLayer FusionTablesQuery FusionTablesStyle FusionTablesHeatmap FusionTablesMouseEvent FusionTablesCell KmlLayer KmlLayerMetadata KmlLayerStatus KmlMouseEvent KmlFeatureData KmlAuthor TrafficLayer TransitLayer StreetView StreetViewPanorama StreetViewLink StreetViewPov StreetViewPanoramaData StreetViewLocation StreetViewTileData StreetViewService StreetViewStatus Events MapsEventListener event MouseEvent Base LatLng LatLngBounds Point Size MVCObject MVCArray Geometry Library encoding spherical poly AdSense Library AdUnit AdFormat Panoramio Library PanoramioLayer PanoramioFeature PanoramioMouseEvent Places Library Autocomplete ComponentRestrictions PlaceDetailsRequest PlaceGeometry PlaceResult PlaceSearchRequest PlaceSearchPagination PlacesServicePlacesServiceStatus RankBy TextSearchRequest Drawing Library DrawingManager OverlayCompleteEvent OverlayType Weather Library CloudLayer WeatherLayer TemperatureUnit WindSpeedUnit LabelColor WeatherMouseEvent WeatherFeature WeatherConditions WeatherForecast Visualization Library HeatmapLayer WeightedLocation
  13. Map MapTypeId Controls MapTypeControlStyle ScaleControlStyle ZoomControlStyleControlPosition Overlays Marker MarkerImage MarkerShape

    Symbol SymbolPath Animation InfoWindow Polyline IconSequence Polygon PolyMouseEvent Rectangle Circle GroundOverlay OverlayView MapPanes MapCanvasProjection Services Geocoder GeocoderRequest GeocoderStatus GeocoderResult GeocoderAddressComponent GeocoderGeometry GeocoderLocationType DirectionsRenderer DirectionsService DirectionsRequest TravelMode UnitSystem DirectionsWaypoint DirectionsStatus DirectionsResult DirectionsRoute DirectionsLeg DirectionsStep Distance Duration Time TransitDetails TransitStop TransitLine TransitAgency TransitVehicle ElevationService LocationElevationRequest PathElevationRequest ElevationResult ElevationStatus MaxZoomService M a x Z o o m R e s u l t M a x Z o o m S t a t u s D i s t a n c e M a t r i x S e r v i c e D i s t a n c e M a t r i x R e q u e s t DistanceMatrixResponse DistanceMatrixResponseRow DistanceMatrixResponseElement DistanceMatrixStatus DistanceMatrixElementStatus Map TypesMapType MapTypeRegistry Projection ImageMapType StyledMapType MapTypeStyle MapTypeStyleFeatureType MapTypeStyleElementType MapTypeStyler Layers BicyclingLayer FusionTablesLayer FusionTablesQuery FusionTablesStyle FusionTablesHeatmap FusionTablesMouseEvent FusionTablesCell KmlLayer KmlLayerMetadata KmlLayerStatus KmlMouseEvent KmlFeatureData KmlAuthor TrafficLayer TransitLayer StreetView StreetViewPanorama StreetViewLink StreetViewPov StreetViewPanoramaData StreetViewLocation StreetViewTileData StreetViewService StreetViewStatus Events MapsEventListener event MouseEvent Base LatLng LatLngBounds Point Size MVCObject MVCArray Geometry Library encoding spherical poly AdSense Library AdUnit AdFormat Panoramio Library PanoramioLayer PanoramioFeature PanoramioMouseEvent Places Library Autocomplete ComponentRestrictions PlaceDetailsRequest PlaceGeometry PlaceResult PlaceSearchRequest PlaceSearchPagination PlacesServicePlacesServiceStatus RankBy TextSearchRequest Drawing Library DrawingManager OverlayCompleteEvent OverlayType Weather Library CloudLayer WeatherLayer TemperatureUnit WindSpeedUnit LabelColor WeatherMouseEvent WeatherFeature WeatherConditions WeatherForecast Visualization Library HeatmapLayer WeightedLocation HeatMapLayer Visualisation Library Map Overlays Symbol SymbolPath Polygon Circle StyledMapType Geometry WeightedLocation
  14. Maps of Lots of Pins

  15. Heatmap Layer

  16. GeoJSON Data Layer

  17. TopoJSON -> GeoJSON

  18. None
  19. Symbols

  20. Symbols

  21. Symbols

  22. Symbols

  23. Fusion Tables

  24. Cluster Markers

  25. Spider Markers Spider Markers

  26. Spider Markers https://github.com/jawj/ OverlappingMarkerSpiderfier Spider Markers

  27. Heatmaps Can you handle the heat?

  28. <head> <script type="text/javascript" src=“https://maps.googleapis.com/maps/api/js?sensor=true&key={key}”> </script> </head> index.html <head> <script type="text/javascript"

    src=“https://maps.googleapis.com/maps/api/js?sensor=true&libraries=visualization”> </script> </head>
  29. <head <script src </script </head index.html <head> <script type="text/javascript" src=“https://maps.googleapis.com/maps/api/js?sensor=true&libraries=visualization”>

    </script> </head>
  30. var heatmapData = [ new google.maps.LatLng(37.782, -122.447), new google.maps.LatLng(37.782, -122.445),

    new google.maps.LatLng(37.782, -122.443), …. new google.maps.LatLng(37.785, -122.437), new google.maps.LatLng(37.785, -122.435) ]; data.js
  31. var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523); map = new google.maps.Map(document.getElementById('map-canvas'),

    { center: sanFrancisco, zoom: 13, mapTypeId: google.maps.MapTypeId.SATELLITE }); var heatmap = new google.maps.visualization.HeatmapLayer({ data: heatmapData }); heatmap.setMap(map); index.html
  32. None
  33. index.html var gradient = [ 'rgba(0, 255, 255, 0)', 'rgba(0,

    255, 255, 1)', 'rgba(0, 191, 255, 1)', 'rgba(0, 127, 255, 1)', 'rgba(0, 63, 255, 1)', 'rgba(0, 0, 255, 1)', 'rgba(0, 0, 223, 1)', 'rgba(0, 0, 191, 1)', 'rgba(0, 0, 159, 1)', 'rgba(0, 0, 127, 1)', 'rgba(63, 0, 91, 1)', 'rgba(127, 0, 63, 1)', 'rgba(191, 0, 31, 1)', 'rgba(255, 0, 0, 1)' ] heatmap.set('gradient', gradient);
  34. None
  35. index.html heatmap.set('radius', 20); var data: heatmapData }); heatmap.setMap(map);

  36. None
  37. GeoJSON Geometry on maps

  38. tfl_lines.geojson { "type": "FeatureCollection", "crs": { "type": "name", "properties": {

    "name": "urn:ogc:def:crs:OGC: 1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "id": 1, "lines": [ { "name": "Victoria", "network": "Tube", "colour": "#0098D4" } ], "seg_desc": "Victoria" }, "geometry": { "type": "LineString", "coordinates": [ [ -0.1148720, 51.4626062 ], [ -0.1154612, 51.4627201 ], [ -0.1167776, 51.4629816 ], [ -0.121132, 51.4638465 ], [ -0.1215893, 51.463931 ], [ -0.1223392, 51.4641384 ], [ -0.1234773, 51.4645792 ], [ -0.1240446, 51.4648628 ], [ -0.1245532, 51.4652346 ], [ -0.1248932, 51.4655457 ], [ -0.1253925, 51.4661992 ], [ -0.1256804, 51.4668713 ], [ -0.125783, 064019 ], [ -0.1431186, 51.5065574 ], [ -0.1428352, 51.5067094 ], [ -0.1418986, 51.5071603 ], . . .
  39. index.html var mapOptions = { center: {lat: 51.5, lng: 0},

    zoom: 10, mapTypeId: google.maps.MapTypeId.SATELLITE }); var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions); map.data.loadGeoJson('./data/tfl_lines.json');
  40. index.html map.data.setStyle(function(feature) { var lineColor, strokeOp; lineColor = 'gray'; strokeOp

    = 0.5; return { strokeColor: lineColor, strokeOpacity: opacity, strokeWeight: 3 }; });
  41. None
  42. index.html map.data.addListener('mouseover', function(event) { map.data.revertStyle(); var lineColor = event.feature.getProperty('lines')[0].colour; map.data.overrideStyle(event.feature,

    { strokeColor: lineColor, strokeOpacity: 1.0, strokeWeight: 5 }); document.getElementById('data_window').style.display = "initial"; document.getElementById('data_window').innerHTML = "<span style='color: “ +lineColor + "'>" + event.feature.getProperty('lines')[0].name + "</span>"; });
  43. Live Example

  44. index.html // Remove the custom style map.data.addListener('mouseout', function(event) { map.data.revertStyle();

    });
  45. Adding Custom Geometry Quick example of adding custom shapes to

    maps
  46. complex.html google.maps.Polygon.Shape = function(point,r1,r2,r3,r4,rotation,vertexCount,strokeColour,strokeWeight,Strokepacity,fillColour,fillOpacity,opts,tilt) { var rot = -rotation*Math.PI/180; var

    points = []; var latConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat()+0.1,point.lng()))*10; var lngConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat(),point.lng()+0.1))*10; var step = (360/vertexCount)||10; var flop = -1; if (tilt) { var I1=180/vertexCount; } else { var I1=0; } for(var i=I1; i<=360.001+I1; i+=step) { var r1a = flop?r1:r3; var r2a = flop?r2:r4; flop = -1-flop; var y = r1a * Math.cos(i * Math.PI/180); var x = r2a * Math.sin(i * Math.PI/180); var lng = (x*Math.cos(rot)-y*Math.sin(rot))/lngConv; var lat = (y*Math.cos(rot)+x*Math.sin(rot))/latConv; points.push(new google.maps.LatLng(point.lat()+lat,point.lng()+lng)); } return (new google.maps.Polygon({paths: points, strokeColor: strokeColour, strokeWeight: strokeWeight, strokeOpacity: Strokepacity, fillColor: fillColour, fillOpacity: fillOpacity})) }
  47. complex.html // Add a hex to the map var hex

    = google.maps.Polygon.RegularPoly( new google.maps.LatLng(v[1], v[0]),14000,6,90,"#000000",1,1,getRandomColor(),0.5); hex.setMap(map);
  48. Live Example Live Example

  49. Styling Maps Who says Style doesn’t matter?

  50. index.html var mapOptions = { center: {lat: 51.5, lng: 0},

    zoom: 10 }); var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
  51. None
  52. index.html var grayStyles = [{"featureType":"water","elementType":"geometry","stylers":[{"color":"#000000"},{"lightness": 17}]},{"featureType":"landscape","elementType":"geometry","stylers":[{"color":"#000000"},{"lightness":20}]}, {"featureType":"road.highway","elementType":"geometry.fill","stylers":[{"color":"#000000"},{"lightness":17}]}, {"featureType":"road.highway","elementType":"geometry.stroke","stylers":[{"color":"#000000"},{"lightness":29}, {"weight":0.2}]},{"featureType":"road.arterial","elementType":"geometry","stylers":[{"color":"#000000"}, {"lightness":18}]},{"featureType":"road.local","elementType":"geometry","stylers":[{"color":"#000000"},

    {"lightness":16}]},{"featureType":"poi","elementType":"geometry","stylers":[{"color":"#000000"},{"lightness":21}]}, {"elementType":"labels.text.stroke","stylers":[{"visibility":"on"},{"color":"#000000"},{"lightness":16}]}, {"elementType":"labels.text.fill","stylers":[{"saturation":36},{"color":"#000000"},{"lightness":40}]}, {"elementType":"labels.icon","stylers":[{"visibility":"off"}]}, {"featureType":"transit","elementType":"geometry","stylers":[{"color":"#000000"},{"lightness":19}]}, {"featureType":"administrative","elementType":"geometry.fill","stylers":[{"color":"#000000"},{"lightness":20}]}, {"featureType":"administrative","elementType":"geometry.stroke","stylers":[{"color":"#000000"},{"lightness":17}, {"weight":1.2}]}]
  53. index.html var center: {lat: zoom: styles: grayStyles }); var styles:

    grayStyles
  54. None
  55. index.html var mono = [{"featureType":"poi","elementType":"all","stylers":[{"hue":"#000000"},{"saturation":-100}, {"lightness":-100},{"visibility":"off"}]},{"featureType":"poi","elementType":"all","stylers":[{"hue":"#000000"}, {"saturation":-100},{"lightness":-100},{"visibility":"off"}]}, {"featureType":"administrative","elementType":"all","stylers":[{"hue":"#000000"},{"saturation":0}, {"lightness":-100},{"visibility":"off"}]},{"featureType":"road","elementType":"labels","stylers": [{"hue":"#ffffff"},{"saturation":-100},{"lightness":100},{"visibility":"off"}]},

    {"featureType":"water","elementType":"labels","stylers":[{"hue":"#000000"},{"saturation":-100},{"lightness":-100}, {"visibility":"off"}]},{"featureType":"road.local","elementType":"all","stylers":[{"hue":"#ffffff"}, {"saturation":-100},{"lightness":100},{"visibility":"on"}]}, {"featureType":"water","elementType":"geometry","stylers":[{"hue":"#ffffff"},{"saturation":-100},{"lightness":100}, {"visibility":"on"}]},{"featureType":"transit","elementType":"labels","stylers":[{"hue":"#000000"},{"saturation": 0},{"lightness":-100},{"visibility":"off"}]},{"featureType":"landscape","elementType":"labels","stylers": [{"hue":"#000000"},{"saturation":-100},{"lightness":-100},{"visibility":"off"}]}, {"featureType":"road","elementType":"geometry","stylers":[{"hue":"#bbbbbb"},{"saturation":-100},{"lightness":26}, {"visibility":"on"}]},{"featureType":"landscape","elementType":"geometry","stylers":[{"hue":"#dddddd"}, {"saturation":-100},{"lightness":-3},{"visibility":"on"}]}]
  56. None
  57. goo.gl/1XXOoc

  58. goo.gl/I3O9Oa

  59. snazzymaps.com

  60. Bringing it together Good examples of all of these API’s

  61. http://smartypins.withgoogle.com/

  62. https://www.geoguessr.com/world/play

  63. http://www.morethanamap.com/demos/visualization/flights

  64. http://nyctaxi.herokuapp.com/

  65. http://nyctaxi.herokuapp.com/

  66. None
  67. None
  68. http://xkcd.com/1110/

  69. Things to think about Watch out for some pitfalls

  70. None
  71. None
  72. None
  73. None
  74. None
  75. Data visualisations can lie! Easier than you think!

  76. Heatmap -

  77. Just because you have the data, doesn’t mean you should

    map it.
  78. Find out more! Google Maps V3 Style Wizard goo.gl/I3O9Oa Snazzy

    Maps snazzymaps.com Maps API Picker Maps API Picker goo.gl/V9Pfp1
  79. Find out more! Examples in Presentation github.com/sjg Chrome Earth View

    Extension goo.gl/UoStWY
  80. +StevenGray Thank you! #makemapsbeautiful steve@stevenjamesgray.com www.stevenjamesgray.com @frogo