@mappedin/marker-cluster
TypeScript icon, indicating that this package has built-in type declarations

6.0.1-beta.51 • Public • Published

@mappedin/marker-cluster

An extension for Mappedin JS that allows clustering markers together.

Usage

Installation

With NPM:

npm install @mappedin/marker-cluster

With Yarn:

yarn add @mappedin/marker-cluster

Getting Started

import { show3dMap, Marker } from '@mappedin/mappedin-js';
import { MarkerCluster, ClusterFn } from `@mappedin/marker-clustering`;

const mapView = await show3dMap(...);

/**
 * Add Markers to the map like normal, keeping track of markers that should be clustered.
 */
const markers: Marker[] = []
mapData.getByType('space').forEach(space => {
    const marker = mapView.Markers.add(space, `<div>${space.name}</div>`, {
        rank: 'always-visible', // Markers should have rank: 'always-visible' for the best effect
    });
    markers.push(marker);
});

/**
 * Define a cluster function of type ClusterFn that returns a special Marker.
 */
const clusterFn: ClusterFn = ({ center, markers }) => {
    return mapView.Markers.add(center, `<div>${markers.length}</div>`, {
        rank: 'always-visible', // Cluster markers should also be always-visible
    });
};

/**
 * Create a new MarkerCluster from the MapView and a cluster function, then add all Markers that
 * should be considered for clustering.
 */
const cluster = new MarkerCluster(mapView, clusterFn);
for (const [marker] of markerProperties) {
    cluster.add(marker);
}

/**
 * Dispose the MarkerCluster when it is no longer needed.
 */
cluster.destroy();

Options

type MarkerClusterOptions<Algorithm extends IClusterAlgorithm = ScreenDistanceClustering> = Partial<{
	/**
	 * The floor the clustered marker is on. If unspecified, the floor of the first added marker will be used.
	 */
	floor: Floor | null;
	/**
	 * The minimum number of markers in a cluster.
	 *
	 * @default 2
	 */
	minSize: number;
	/**
	 * The debounce time in milliseconds for computing clusters when the camera is moving. If set to 0, the clusters will
	 * be computed on every camera frame. This could lead to performance issues if there are a lot of markers.
	 *
	 * @default 50
	 */
	debounce: number;
	/**
	 * Whether the original markers should be hidden when clustered together.
	 *
	 * @default true
	 */
	hideClusteredMarkers: boolean;
	/**
	 * A custom algorithm to use for clustering.
	 *
	 * @default ScreenDistanceClustering
	 */
	algorithm: Algorithm;
	/**
	 * Options for the algorithm.
	 */
	algorithmOptions: OptionsOf<Algorithm>;
}

Default Algorithm

/**
 * The default algorithm used by MarkerCluster is the built-in ScreenDistanceClustering algorithm. When run, this algorithm will cluster markers whose anchor coordinates are within a certain number of pixels on screen.
 */
import { ScreenDistanceClustering } from '@mappedin/marker-cluster';

Default Algorithm Options

export type ScreenDistanceClusteringOptions = Partial<{
	/**
	 * The distance in pixels that a marker should be from another marker to be considered part of the same cluster.
	 */
	threshold: number;
}>;

Custom Algorithm

import { MarkeCluster, IClusterAlgorithm } from '@mappedin/marker-cluster';

/**
 * Custom options can be passed to IClusterAlgorithm for stronger typing.
 */
type CustomClusteringOptions = {
	threshold: number;
};

/**
 * Define a custom clustering algorithm that implements IClusterAlgorithm.
 */
class CustomClustering implements IClusterAlgorithm<CustomClusteringOptions> {
	/**
	 * A custom algorithm should probably be constructed with the MapView, but it is not necessary.
	 */
	constructor(mapView: MapView) {}
	/**
	 * setOptions() is called immediately after the custom algorithm is instantiated with the value passed to "MarkerClusteringOptions.algorithmOptions". This happens in the MarkerCluster constructor.
	 */
	setOptions(options: CustomClusteringOptions): void {}
	/**
	 * load() is called whenever the debounce period elapses between Camera moves. It gets passed an array of all markers that were added to the MarkerCluster.
	 */
	load(markers: Marker[]): void {}
	/**
	 * getClusters() is called whenever MarkerCluster wants to update the rendered clusters. This usually happens immediately after load() is called.
	 */
	getClusters(): Marker[][] {}
	/**
	 * destroy() is called when "MarkerCluster.destroy()" is called. Any resources that the ClusteringAlgorithm is holding onto can be freed up here.
	 */
	destroy(): void {}
}

/**
 * Create a new MarkerCluster with the custom algorithm.
 */
const cluster = new MarkerCluster(mapView, clusterFn, {
	algorithm: new CustomAlgorithm(mapView),
	algorithmOptions: { threshold: 100 },
});

PointRBush

import { PointRBush } from '@mappedin/marker-cluster';

/**
 * PointRBush is a utility class that extends the rbush package to work with { x, y } points. It can be used to help build custom clustering algorithms, but it is not necessary.
 */
const rbush = new PointRBush();

/**
 * Insert, load, remove, or clear points the same as rbush.
 */
const points = [
	{ x: 1, y: 2 },
	{ x: 3, y: 4 },
	{ x: 5, y: 6 },
];
rbush.insert(points[0]);
rbush.load([points[1], points[2]]);
rbush.remove(points[0]);
rbush.clear();

/**
 * Search for points with a box the same as rbush.
 */
const results = rbush.search({ minX: 0, maxX: 5, minY: 0, maxY: 5 });

/**
 * Peek at an item in the tree. This can be useful when generating clusters by removing any already clustered points and retrieving a remaining point that still needs to be clustered.
 */
const item = rbush.peek();

/**
 * Check if a point is in the tree. This can be useful for optimizations if previous clusters are cached between updates.
 */
const exists = rbush.has({ x: 1, y: 2 });

/**
 * Retrieve points from the tree. This can be useful for optimizations if previous clusters are cached between updates.
 */
const found = rbushl.find(point => point.x > 2);

Readme

Keywords

none

Package Sidebar

Install

npm i @mappedin/marker-cluster

Weekly Downloads

25

Version

6.0.1-beta.51

License

SEE LICENSE IN LICENSE.txt

Unpacked Size

52.6 kB

Total Files

5

Last publish

Collaborators

  • mappedin-ops
  • mappedin-engineering