Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Not just a red pin anymore: Making Maps Beautiful

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

Steven Gray

November 15, 2014
Tweet

More Decks by Steven Gray

Other Decks in Programming

Transcript

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

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. A brief history of Google Maps
    2005 - 2014: Nine years of online maps

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. Visualisation Tools
    Making Data Interesting

    View Slide

  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

    View Slide

  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

    View Slide

  14. Maps of Lots of Pins

    View Slide

  15. Heatmap Layer

    View Slide

  16. GeoJSON Data Layer

    View Slide

  17. TopoJSON -> GeoJSON

    View Slide

  18. View Slide

  19. Symbols

    View Slide

  20. Symbols

    View Slide

  21. Symbols

    View Slide

  22. Symbols

    View Slide

  23. Fusion Tables

    View Slide

  24. Cluster Markers

    View Slide

  25. Spider Markers
    Spider Markers

    View Slide

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

    View Slide

  27. Heatmaps
    Can you handle the heat?

    View Slide


  28. src=“https://maps.googleapis.com/maps/api/js?sensor=true&key={key}”>


    index.html

    src=“https://maps.googleapis.com/maps/api/js?sensor=true&libraries=visualization”>


    View Slide

  29. View Slide

  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

    View Slide

  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

    View Slide

  32. View Slide

  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);

    View Slide

  34. View Slide

  35. index.html
    heatmap.set('radius', 20);
    var
    data: heatmapData
    });
    heatmap.setMap(map);

    View Slide

  36. View Slide

  37. GeoJSON
    Geometry on maps

    View Slide

  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 ], . . .

    View Slide

  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');

    View Slide

  40. index.html
    map.data.setStyle(function(feature) {
    var lineColor, strokeOp;
    lineColor = 'gray';
    strokeOp = 0.5;
    return {
    strokeColor: lineColor,
    strokeOpacity: opacity,
    strokeWeight: 3
    };
    });

    View Slide

  41. View Slide

  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 = "" + event.feature.getProperty('lines')[0].name + "";
    });

    View Slide

  43. Live Example

    View Slide

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

    View Slide

  45. Adding Custom Geometry
    Quick example of adding custom shapes to maps

    View Slide

  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}))
    }

    View Slide

  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);

    View Slide

  48. Live Example
    Live Example

    View Slide

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

    View Slide

  50. index.html
    var mapOptions = {
    center: {lat: 51.5, lng: 0},
    zoom: 10
    });
    var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

    View Slide

  51. View Slide

  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}]}]

    View Slide

  53. index.html
    var
    center: {lat:
    zoom:
    styles: grayStyles
    });
    var
    styles: grayStyles

    View Slide

  54. View Slide

  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"}]}]

    View Slide

  56. View Slide

  57. goo.gl/1XXOoc

    View Slide

  58. goo.gl/I3O9Oa

    View Slide

  59. snazzymaps.com

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. View Slide

  67. View Slide

  68. http://xkcd.com/1110/

    View Slide

  69. Things to think about
    Watch out for some pitfalls

    View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. View Slide

  75. Data visualisations can lie!
    Easier than you think!

    View Slide

  76. Heatmap -

    View Slide

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

    View Slide

  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

    View Slide

  79. Find out more!
    Examples in Presentation
    github.com/sjg
    Chrome Earth View Extension
    goo.gl/UoStWY

    View Slide

  80. +StevenGray
    Thank you!
    #makemapsbeautiful
    [email protected]
    www.stevenjamesgray.com
    @frogo

    View Slide