Arenarium Maps

Introduction

@arenarium/maps is a high performance TypeScript library designed for applications that need to display a large number of complex markers without cluttering the map. Its purpose is to simplify visualizing and searching map related information.
To use the library, you will need an access token. First go to the sign in page and sign in to your account. After signing in, go to the dashboard and create a new token.

Installation

To install the arenarium/maps library for MapLibre using npm, run the following command in your project directory:
bash
npm install @arenarium/maps @arenarium/maps-integration-maplibre maplibre-gl

Setup

To initialize the library, first add a container element to your HTML where the map will be rendered.
app.html
<div id="map"></div>
Import the MapManager and the required css from the main library.
app.ts
import { MapManager } from '@arenarium/maps'; import '@arenarium/maps/style.css';
Next, use the MaplibreProvider class which requires a maplibregl.Map class, a maplibregl.Marker class and a maplibregl.MapOptions object. Use the MaplibreProvider instance, along with the token key, to initialize the map manager.
app.ts
import { MaplibreProvider } from '@arenarium/maps-integration-maplibre'; import maplibregl from 'maplibre-gl'; import 'maplibre-gl/dist/maplibre-gl.css'; // Create a maplibre provider instance const maplibreProvider = new MaplibreProvider(maplibregl.Map, maplibregl.Marker, { container: 'map', // Other maplibre options... }); // Initialize the map manager with the provider const mapManager = await MapManager.create('YOUR_TOKEN_KEY', maplibreProvider); // Access the maplibre instance for direct map interactions const mapLibreMap = maplibreProvider.getMap();
Map features like rotation or tilting are disabled in order for the plugin to work correctly.
You can change the map's visual appearance by setting a predefined dark or light theme:
app.ts
import { MaplibreDarkStyle, MaplibreLightStyle } from '@arenarium/maps-integration-maplibre'; mapLibreMap.setStyle(MaplibreDarkStyle); // or MaplibreLightStyle
Alternatively, you can apply a custom map style by providing a URL to a JSON file that adheres to the MapLibre Style Specification. You can also override specific color properties within a custom style.
app.ts
mapLibreMap.setStyle('https://tiles.openfreemap.org/styles/liberty.json');

Markers

A marker consists of a pin, a tooltip and an optional popup:
  • The pin is an element that should convey the marker's location and basic information like an icon or a color.
  • The tooltip is an element that should provide additional information that needs to be readable — it could be a small or large amount of information depending on the application.
  • The popup is an element that is displayed when the user clicks on the marker. It should contain additional information that is not necessary or too large for a tooltip.
Markers toggle between the pin and the tooltip elements as the user zooms in. The pin is displayed when there is no room for the tooltip. When the user zooms in and more space is available, more tooltips are displayed. Which tooltips are displayed first is determined primarily by the ranking of the markers — the higher the rank, the sooner the tooltip is displayed.
To add markers to the map, you first need to define an array of MapMarkerData objects. Provide the base marker data and the configuration for the tooltip, pin and popup. The configurations have body callbacks which should return a HTMLElement.
Use the updateMarkers method on the map manager to update the map with new markers. If some of the provided markers already exist on the map with the same id, it will be assumed that the data is the same (width, height, body...). This approach is designed for continuous updates of map markers.
When updating the markers, you can let the library try to automatically measure the sizes of the provided elements, or use the dimensions property to manually set the sizes. Using it will also slightly improve loading performance when working with a large number of complex elements.
app.ts
import { type MapMarkerProperties } from '@arenarium/maps'; const count = 100; const radius = 10; const lat = 39.8283; const lng = -98.5795; // Create markers const markers: MapMarkerProperties[] = []; for (let i = 0; i < count; i++) { const id = i.toString(); markers.push({ // A unique identifier for the marker id: id, // The rank of the marker, used for prioritization rank: i, // The latitude of the marker's location lat: lat + (Math.random() - 0.5) * radius, // The longitude of the marker's location lng: lng + (Math.random() - 0.5) * radius, // The tooltip configuration of the marker (required) tooltip: { // Callback function that returns the HTMLElement object for the tooltip body element: getTooltipElement(id), // (Optional) The desired dimensions of the marker's tooltip area dimensions: { height: 32 + (i % 16), width: 64 + (i % 16), padding: 6 }, // (Optional) The tooltip-specific style style: { background: '#ffffff', filter: 'drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3))', radius: 8 } // (Optional) The tooltip initialze callback, called when visible for the first time // initialize: async (id, element) => { } }, // (Optional) The pin configuration of the marker pin: { // (Optional) Callback function that returns the HTMLElement object for the pin body element: getPinElement(), // (Optional) The desired dimensions of the marker's pin area dimensions: { radius: 8, stroke: 1 }, // (Optional) The pin-specific colors style: { background: '#008800', stroke: '#000000' } // (Optional) The pin initialze callback, called when visible for the first time // initialize: async (id, element) => { } }, // (Optional) The popup configuration of the marker popup: { // Callback function that returns the HTMLElement object for the popup body element: getPopupElement(id), // (Optional) The desired dimensions of the marker's popup area dimensions: { height: 96 + (i % 16), width: 128 + (i % 16), padding: 6 }, // (Optional) The popup-specific colors style: { background: '#ffffff', filter: 'drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3))', radius: 8 } // (Optional) The popup initialze callback, called when visible for the first time // initialize: async (id, element) => { } } }); } mapManager.updateMarkers(markers);
The tooltip and popup body dimensions must abide by the following rules:
  • The width, height and radius of the body must be greater than zero.
  • The padding must be less than a fourth of the minimum of the width or height of the body.
The following are body callback functions for the current demo. Use them to return the HTMLElement object for the tooltip, pin and popup. You can create them manually or by using a specific frontend library such as React, Vue, Svelte, or any other library that supports creating and manipulating DOM elements.
app.ts
const getTooltipElement = (id: string) => { const element = document.createElement('div'); element.style = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: #000000; font-family: Outfit, sans-serif;'; element.innerHTML = 'Tooltip ' + id; return element; }; const getPinElement = () => { const element = document.createElement('div'); element.style = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; border-radius: 50%;'; return element; }; const getPopupElement = (id: string) => { const element = document.createElement('div'); element.style = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: #000000; font-family: Outfit, sans-serif;'; element.innerHTML = 'Popup ' + id; return element; };
To remove all markers from the map, use the removeMarkers method:
app.ts
mapManager.removeMarkers();
To manually toggle the popup of a marker, use the showPopup and hidePopup methods:
app.ts
mapManager.showPopup(id); mapManager.hidePopup();

Configuration

MapConfiguration allows you to customize various aspects of the map and marker behavior when initializing the MapManager. You can control settings such as pin fading, popup panning, event handlers and more.
To use, simply pass your configuration object when creating the map:
app.ts
const mapConfiguration = { // (Optional) pin: { // Values for pin fadeout effect. They define how much the pin fades per zoom level fadeout: { scale: 0.1, opacity: 0.15 color: 0.2 }, // Zoom level delta in which the pin will remain visible depth: 3 }, // (Optional) popup: { // Whether to pan the map when the popup is opened pan: true }, // (Optional) events: { error: (message, err) => { console.error('Map error:', message, err); } } // And more... }; const mapManager = await MapManager.create('YOUR_TOKEN_KEY', mapProvider, mapConfiguration);
Refer to the MapConfiguration schema for all available options and further customize your map experience.

Usage

Usage is proportional to the number of marker updates. Every time you update map markers, some computation is required to calculate the optimal position of the markers. The compute is provided by an API endpoint which is used by the library internally.
Usage pricing is scales per million marker updates per month.
Usage does not increase on cache hits. For example if you use the same markers on your map multiple times, subsequent compute requests will hit the cache and the usage is not increased. The cache is invalidated after a certain time.