2.0.0 • Published 6 years ago

crowded-google-map v2.0.0

Weekly downloads
3
License
Apache License 2....
Repository
github
Last release
6 years ago

Crowded Google Map - because sometimes it gets crowded

Display a lot of POIs on Google Map without sacrificing UX

Demo

Prerequisites

Before initializing the crowded google map, make sure you have loaded Google Maps API.

Read how to do it at https://developers.google.com/maps/documentation/javascript/tutorial

Basic usage

new CrowdedGoogleMap({
  container: document.querySelector(".google-map"),
  googleMapsConfig: {
    center: { lat: -34.397, lng: 150.644 },
    zoom: 10
  },
  markersData: new Promise(resolve =>
    resolve([
      {
        first_name: "Michael",
        last_name: "Scott",
        position: { lat: 34.210973, lng: -118.436232 }
      },
      {
        first_name: "Kevin",
        last_name: "Malone",
        position: { lat: -25.363, lng: 131.044 }
      }
    ])
  )
});

Advanced Usage

const defaultClusterStyle = {
  textColor: "white",
  textSize: 12,
  height: 50,
  width: 50
};

new CrowdedGoogleMap({
  container: document.querySelector(".google-map"),
  googleMapsConfig: {
    center: { lat: -34.397, lng: 150.644 },
    zoom: 10,
    mapTypeId: "satellite"
  },
  markersData: fetch("/api/getmarkers.json", {
    credentials: "same-origin"
  }).then(res => resolve(res.json())),
  parseMarkerData: marker => {
    return Object.assign({}, marker, {
      name: `${marker.first_name} ${marker.last_name}`,
      href: `http://google.com/?q=${marker.first_name}+${marker.last_name}`,
      icon: {
        url: `http://my.cdn.com/images/gmap/${marker.type}-icon.svg`,
        size: new google.maps.Size(24, 24),
        origin: new google.maps.Point(0, 0),
        anchor: new google.maps.Point(0, 24)
      }
    });
  },
  infoWindowConfig: marker => {
    return {
      content: `<a href="${marker.href}">${marker.name}</a>`,
      maxWidth: 640
    };
  },
  clustererConfig: {
    styles: [
      Object.assign({}, defaultClusterStyle, {
        url: `http://my.cdn.com/images/gmap/small.png`
      }),
      Object.assign({}, defaultClusterStyle, {
        url: `http://my.cdn.com/images/gmap/big.png`
      })
    ]
  }
});

Options

container

Type: DOM Element

Example:

document.querySelector(".google-map");

googleMapsConfig

Type: Object

Example:

{
  zoom: 6,
  center: { lat: -34.397, lng: 150.644 },
  mapTypeId: "satellite"
}

Config that will be passed to Google Maps constructor. You can use everything that Google Maps supports (ie. styling).

Read more about google maps api options at https://developers.google.com/maps/documentation/javascript/3.exp/reference

clustererConfig

Type: Object

Example:

{
  gridSize: 30,
  maxZoom: 12
}

Object that will extend/override default clusterer config that can be found in src/config.

Read more about supported options at https://www.npmjs.com/package/node-js-marker-clusterer

spiderifyConfig

Type: Object

Example:

{
  circleFootSeparation: 30,
  nearbyDistance: 60
}

Object that will extend/override default spiderify config that can be found in src/config.

Read more about supported options at https://www.npmjs.com/package/overlapping-marker-spiderfier

markersData

Type: Promise (resolving to an array of objects)

Example:

fetch("/api/getmarkers.json", {
  credentials: "same-origin"
}).then(res => resolve(res.json()));

Collection of objects that will be used on the map. They will be parsed later on if you pass parseMarkerData.

parseMarkerData

Type: Function

Example:

const parseMarkerData = marker => {
  return Object.assign({}, marker, {
    // Take whatever has been passed as marker, extend using object passed below
    name: `${marker.first_name} ${marker.last_name}`,
    href: `https://google.com/?q=${marker.first_name}+${marker.last_name}`,
    icon: {
      url: `https://my.cdn.com/images/gmap/${marker.type}-icon.svg`,
      size: new google.maps.Size(24, 24),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(0, 24)
    }
  });
};

Function that will be run on each marker (using .map) object before turning it into google map marker. Make sure this function returns proper objects/structure/data to use in later life cycles (ie. creation of google markers, info windows)

infoWindowConfig

Type: Function

Example:

const infoWindowConfig = marker => {
  return {
    content: `<a href="${marker.href}">${marker.name}</a>`,
    maxWidth: 640
  };
};

Configuration of infoWindow based on currently created marker. Content key is required by Google.

Read more about infoWindows

Dependencies

This script includes two depencenies to handle crowded maps:

Performance tips

If your markers are served by the API (which often is the case), start downloading them as soon as possible. For example, you might want to use XHR to start downloading them in the <head>. The benefits depend on weight/speed of loading other blocking assets, so your milage may vary. In my tests I have observed 2-2.5 seconds boost by starting request as a first request on the site.

window.mapMarkers = new Promise(function(resolve) {
  return fetch("/getMarkers.json", { credentials: "same-origin" }).then(
    function(res) {
      return resolve(res.json());
    }
  );
});

Having this set up you can pass window.mapMarkers as markersData to the map constructor - it will initialize as much as possible without the markers, then continue when they arrive.

Testing

Run npm test to open test page with (hopefully) working example.

Troubleshooting

My map isn't showing up at all

Remember to provide some kind of css to make sure the map has height. You can even do that inline.

<div data-crowded-google-map="container" style="height: 700px"></div>

My clusters are missing icons

Make sure you pass styles with proper urls to graphic icons. See Advanced Usage example.

Known bugs

Uncaught TypeError: Cannot read property 'fromLatLngToDivPixel' of undefined in oms.js. Everything works, if you have any idea why it throws error anyway please help me fix it :)