Neil Patrick's Mansion

    mappy

    1.0.0 • Public • Published

    MAPPY

    Gitter

    WARNING: This library is under heavy development and should be considered ALPHA We don't recommend using in production at this time.

    Build Status

    Creating a map using mappy

    • Clone this repo
    • npm install
    • Rename dist/example-config.js to config.js
    • Customise properties of the config object (see 'Config in detail') in config.js
    • npm run build
    • use resulting dist/bundle.js and dist/bundle.min.js files

    Developing mappy

    • run npm run build:dev to produce a non minified map bundle file
    • and/or run npm run build:prod to produce a minified map bundle file.

    Installation

    You can use this project to build various javascript map bundles from config.

    Quickstart

    • clone the repo
    • npm install
    • npm run build
    • use resulting dist/bundle.js and dist/bundle.min.js files

    Config in detail

    Configuration is a javascript object with three properties: map, layers and key

    key

    Defines the map key (optional)

    dataSources

    Defines the data sources that the layers can use. There are currently 3 options

    • longPoll for refreshing the data from a URL on an interval
    • singlePoll to only load the data from a URL once
    • local to not load any data automatically. Layer data can be added via map.pushToDataService(dataSourceName, geojsonData)

    Data source definitions should be in format:

    {
      dataSources: [
        {
          name: 'my-api',
          type: 'longPoll' // longPoll, singlePoll, local
          refresh: 10000   // Interval to refresh the data from the endpoint, only required for longPoll
          request: { // for longPoll or singlePoll
            url: '/path/to/some/geojson/endpoint'
            // other options for xhr module (https://github.com/Raynos/xhr) can be passed in here e.g. headers: {}
          }
        }
      ]
    }
     
    layers

    Defines an array of layers to plot on the map. Currently types geojson and click are supported.

    • Type geojson can be used to render a geojson feature collection on the map
    • Type click can be used to wire up user clicks to external services
    Geojson layers

    The main way that layers are loaded into mappy is via geojson. A geojson layer can be added defining a layer of type = geojson in the layers array of the config object

    {
      layers: [
        {
          name: 'my-first-layer',
          type: 'geojson',
          dataSource: 'my-api'
        }
      ]
    }

    Assuming that valid geojson was returned, a layer of data should be plotted on the map.

    Geojson layer relationships

    If you have multiple layers defined for your map and you would like some layers to react to user interactions on another layer you can define pub/sub like relationships between layers.

    On one layer we specify that any user actions of the specified type(s) performed on the layer should be 'notified' to any other interested layers

    {
      name: 'my-first-layer',
      type: 'geojson',
      notifies: ['click'],
      //...
    }

    Then, on another layer we specify that we are interested in any user clicks on 'my-first-layer', registering a handler like so:

    {
      name: 'my-second-layer',
      type: 'geojson',
      listens: [
        {
          listensTo: 'my-first-layer',
          type: 'click',
          handler: function (feature, map) {
            map.hideGeojsonLayer('my-second-layer')
          }
        }
      ],
      //...
    }

    the registered handler function gets passed the feature that the user clicked on as the first parameter and the map object as the second

    map

    Defines details about the map such as tilelayers

    assets

    Templates for popups are defined as string properties in the config object. You can also optionally define a templateFunction property that accepts a template string and data object. If the templateFunction property is not present Handlebars will be used as the templating engine

    CSS for your templates must be included separately.

    More information

    See dist/example-config.js for existing features

    External API

    Currently this API is fluid and should be considered unstable, though we will attempt to adhere to semver guidelines during ongoing development

    When creating an instance of Mappy from config, the return value is an object with a defined interface

    Current API:

    showGeojsonLayer('layerName')
    hideGeojsonLayer('layerName')
     
    stopDataService('dataServiceName')
    startDataService('dataServiceName')
     
    pushToDataService('dataSourceName', geojsonData)

    Example:

    // Will create map and load data from defined data sources
    var map = window.Mappy.create(config);
     
    map.hideGeojsonLayer('layerName') // assuming there was a layer called 'layerName' defined in config
     
    // Example of how to add data manually using a local data source (or can overwrite data for any data source type)
    $.getJSON(url).done(function (geojson) {
      pushToDataService('local-example', geojson)
    })

    Development

    To work on the project:

    • clone the repo
    • npm install
    • run npm test to start the test runner
    • In another terminal run npm run start:dev to serve the dist dir, bundle files and watch for file changes. Visit localhost:3000 to see the map

    Ongoing development notes

    Client

    • store user preferences (basemap/layers on)
    • make use of config as much as possible
    • possiblity to have many maps generated from different geojson based data sets
    • backend should be able to push updates
    • default layer, on by default layers

    Server

    • possibility to send updates to the client
    • adaptors for feeds to node service which can then diff for changes and send server sent events (sse's) to connected clients

    Testing

    • Set up automated cross-browser testing

    Browser Compatibility

    WIP, see 'Ongoing development notes' above Manually tested in:

    • IE 9, 10, 11
    • Chrome 39
    • Firefox 33
    • Safari 8

    Config details

    Map

    {
      domElementId: 'map',
      key: {
        domElementId: 'key',
        title: 'My map key'
      },
      tileLayers: {
        base-tiles: {
          url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
          attribution: '',
          maxZoom: 18,
          time: {
            on: '8:00',
            off: '11:00'
          },
          //any other leaflet tile layer options eg.
          zIndex: 100,
          opacity: 0.5
        }
      },
      bounds: [
        [-43.577988,172.515934],
        [-43.461397,172.749529]
      ],
      mapOptions: {
        maxZoom: 19
      }
    }

    Layers

    [
        {
            name: 'Major Roadworks',
            description: 'This is layer 1',
            styles: {
                popup: {
                    css: 'myPopupCssFile.css',
                    template: 'myTemplate.html'
                },
                layer: {
                    general: { // Roughly following leaflet dsl
                        stroke: true,
                        weight: 5
                    },
                    properties: {
                        weighting: {
                            2: {
                                stroke: true
                            },
                            5: {
                                stroke: false
                            }
                        },
                        lane: {
                            left: {
                                colour: 'green'
                            },
                            *: {
                                colour: 'black'
                            }
                        }
                    }
                },
                icon: {
                  general: {
                    iconUrl: '/icons/leaf-green.png',
                    shadowUrl: '/icons/leaf-shadow.png',
                    iconSize: [38, 95],
                    shadowSize: [50, 64],
                    iconAnchor: [22, 94],
                    shadowAnchor: [4, 62],
                    popupAnchor: [-3, -76]
                  },
                  properties: {
                    highway: {
                      traffic_signals: {
                        iconUrl: '/icons/leaf-red.png'
                      },
                      crossing: {
                        iconUrl: '/icons/leaf-orange.png'
                      }
                    }
                  },
                  "cluster": {
                    "showCoverageOnHover": false
                  }
                }
            },
            sortOrder: 1, // used to order layers, higher numbers brought to front
            startVisible: true // whether to display the layer on map load
            defaultLayerType: false || 'default', // false would mean this layer is off if the zoom level is outside
                                                    // the levels defined in the 'zoom' config
                                                    // 'default', 'heatmap', 'cluster', etc
            zoom: [
                {
                    min: 4,
                    max: 8,
                    type: 'heatmap'
                },
                {
                    min: 9,
                    max: 16,
                    type: 'cluster'
                }
            ],
            dataSource: 'name-of-defined-dataSource'
        }
    ]

    Icon config for layer styles

    The keys in 'general' and 'properties' basically follow the leaflet dsl for the Icon class, allowing you to change the icon and its positioning as required.

    In the 'general' section if you specify a type: 'divIcon' then the DivIcon class is used instead, allowing you to specify the html for the icon. This template will be compiled via Handlebars, so you can interpolate properties from the feature that the marker icon is related to, similar to popups.

    NOTE: DivIcon does not have a iconUrl option, so you'll need to add any images using CSS (likely background: url...)

    Key

    You can either use the default, or define custom html to render the layer key template. Custom templates are parsed through the handlebars templating engine, refer to the handlebar docs for further details.

    // default
    {
      domElementId: 'key', // The dom element used to render the key.
      title: 'My map key',
      layers: [
        {
          name: 'layer1',
          description: 'My Layer',
          checked: true
        }
      ]
    }
     
    // custom template
    {
      domElementId: 'key', // The dom element used to render the key.
      title: 'My map key',
      template: '<ul class="items"><ul/>', // Handlebars template used to render the key wrapper.
      itemTemplate: '<li><label for="{{key}}">{{#if text}}<span>{{text}}</span>{{/if}}<input type="checkbox" id="{{key}}" {{#if checked}}checked="checked"{{/if}}></label></li>', // Handlebars template used to render the key items.
      listWrapperClass: '.items', // Dom element in 'template' key wrapper used to render the key items.
      layers: [
        {
          name: 'layer1',
          description: 'My Layer',
          checked: true,
          templateData: { // optional data to pass through to the 'itemTemplate'
            example1: 'test' // can be referenced thrigh the 'itemTemplate' with 'templateData.example1'
          }
        }
      ]
    }
     

    Clustering

    Enable clustering on a layer by setting the "cluster" property on layer icon config to 'true', alternatively you can pass through options to override the default cluster settings. You can refer to the Leaflet.markercluster module documentation for configuration options.

    Possible values

    To enable clustering

    cluster: true //default options
    cluster: { ... } //overide default options

    The following will disable clustering

    cluster: false
    cluster: null
    cluster: undefined
    

    If you specify an icon it will override iconCreateFunction to create the icon with the given config. If showClusterCount is also truthy then it will render div's instead, with the cluster count inside. See the example below, with css to show an image AND cluster count.

    Note: If you want to use clustering with the default styling you will need to include the default marker clusterer stylesheet. eg.

    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.Default.css" />

    Clustering example

    {
      layers: [
        {
          name: 'layer1',
          ...
          styles: {
            icon: {
              cluster: {
                showCoverageOnHover: false,
                icon: {
                  showClusterCount: true, // if false, specify normal icon options e.g. iconUrl
                  iconClass: 'leafy-background',
                  iconSize: [38, 95],
                  iconAnchor: [22, 94],
                  popupAnchor: [-3, -76]
                }
              }
            }
          }
        }
      ]
    }

    with CSS for the cluster count icon

    .leaflet-div-icon {
      background-color: transparent;
      border: none;
    }
    .leafy-background {
      background-image: url(/icons/leaf-green.png);
      width: 100%;
      height: 100%;
    }
    .leafy-background .cluster-count {
      text-align: center;
      padding-top: 15px;
    }

    Google

    To generate a Google tile base layer specify the 'google' type on the map property tileLayers config. Include the Google javascript api to your project html <script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script>. You can also specify a 'mapType' to display (see the Google API for different map types). This will default to ROADMAP.

    var config = {
      map: {
        domElementId: 'map',
        tileLayers: {
          base-tiles: {
            type: 'google',
            maxZoom: 18,
            zIndex: 10,
            mapType: 'SATELLITE'
          }
        },
        bounds: [
          [-43.577988,172.515934],
          [-43.461397,172.749529]
        ]
      }
    }

    Install

    npm i mappy

    DownloadsWeekly Downloads

    39

    Version

    1.0.0

    License

    MIT

    Last publish

    Collaborators

    • digitalsadhu
    • coder_stu
    • matt-in-a-hat