# crowded-google-map

> Display a lot of POIs on Google Map without sacrificing UX

Latest version **2.0.0** (published 2018-01-13) · Apache License 2.0 license · 0 weekly downloads

## Install

```sh
npm install crowded-google-map
pnpm add crowded-google-map
yarn add crowded-google-map
bun add crowded-google-map
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.0.0 |
| Published | 2018-01-13 |
| First published | 2018-01-09 |
| Weekly downloads | 0 |
| License | Apache License 2.0 |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 3 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | pavelloz@gmail.com |
| Maintainers | pavelloz |

## Links

- npm: https://www.npmjs.com/package/crowded-google-map
- Repository: https://github.com/pavelloz/crowded-google-map
- Homepage: https://github.com/pavelloz/crowded-google-map#readme
- Issues: https://github.com/pavelloz/crowded-google-map/issues
- npm.io page: https://npm.io/package/crowded-google-map

## Dependencies (3)

- [object-assign-deep](https://npm.io/package/object-assign-deep.md) ^0.3.1
- [node-js-marker-clusterer](https://npm.io/package/node-js-marker-clusterer.md) ^1.0.0
- [overlapping-marker-spiderfier](https://npm.io/package/overlapping-marker-spiderfier.md) ^1.1.4

## Recent versions

- 2.0.0 (latest) — 2018-01-13
- 1.1.1 — 2018-01-10
- 1.1.0 — 2018-01-10
- 1.0.1 — 2018-01-09
- 1.0.0 — 2018-01-09

## README

# Crowded Google Map - because sometimes it gets crowded

Display a lot of POIs on Google Map without sacrificing UX

![Demo](https://cdn.rawgit.com/pavelloz/crowded-google-map/demo/demo.gif)

## 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

```js
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

```js
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:

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

### googleMapsConfig

Type: Object

Example:

```js
{
  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:

```js
{
  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:

```js
{
  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:

```js
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:

```js
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:

```js
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](https://developers.google.com/maps/documentation/javascript/infowindows)

## Dependencies

This script includes two depencenies to handle crowded maps:

* [node-js-marker-clusterer](https://www.npmjs.com/package/node-js-marker-clusterer) - Joins markers that are close by to prevent overlapping
* [overlapping-marker-spiderfier](https://www.npmjs.com/package/overlapping-marker-spiderfier) - Allows user to spread pins that are very close together (after zooming in, where clustering is no longer available) see them better

## 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.

```js
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.

```html
<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 :)

---
_Source: https://npm.io/package/crowded-google-map · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
