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 full-size slide

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

    View full-size slide

  3. Visualisation Tools
    Making Data Interesting

    View full-size slide

  4. 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 full-size slide

  5. 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 full-size slide

  6. Maps of Lots of Pins

    View full-size slide

  7. Heatmap Layer

    View full-size slide

  8. GeoJSON Data Layer

    View full-size slide

  9. TopoJSON -> GeoJSON

    View full-size slide

  10. Fusion Tables

    View full-size slide

  11. Cluster Markers

    View full-size slide

  12. Spider Markers
    Spider Markers

    View full-size slide

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

    View full-size slide

  14. Heatmaps
    Can you handle the heat?

    View full-size slide


  15. 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 full-size slide

  16. 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 full-size slide

  17. 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 full-size slide

  18. 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 full-size slide

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

    View full-size slide

  20. GeoJSON
    Geometry on maps

    View full-size slide

  21. 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 full-size slide

  22. 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 full-size slide

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

    View full-size slide

  24. 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 full-size slide

  25. Live Example

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. 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 full-size slide

  29. 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 full-size slide

  30. Live Example
    Live Example

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  33. 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 full-size slide

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

    View full-size slide

  35. 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 full-size slide

  36. goo.gl/1XXOoc

    View full-size slide

  37. goo.gl/I3O9Oa

    View full-size slide

  38. snazzymaps.com

    View full-size slide

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

    View full-size slide

  40. http://smartypins.withgoogle.com/

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  43. http://nyctaxi.herokuapp.com/

    View full-size slide

  44. http://nyctaxi.herokuapp.com/

    View full-size slide

  45. http://xkcd.com/1110/

    View full-size slide

  46. Things to think about
    Watch out for some pitfalls

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  49. 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 full-size slide

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

    View full-size slide

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

    View full-size slide