Interactive maps,
without the weight.

CargoCanvas is a JavaScript library for building fast, mobile-friendly interactive maps. No dependencies, a class-based ES module API, and about 40 kB of gzipped JavaScript.

BSD 2-Clause~40 kB gzippedzero dependenciesESM + UMDby AIQIA

Every map on this page is live and running the real build of the library. Open Source under any of them to see the exact code that produced it — the snippet shown is the very string the demo executes, so it cannot drift out of date. All of them are centred on Curitiba, PR.

Prefer a complete file you can copy wholesale? Every topic below also exists as a standalone example page.

Installation

CargoCanvas ships as an ES module with a UMD fallback, plus one stylesheet.

npm

npm install cargocanvas

Script tag

The UMD build exposes a single global, CargoCanvas:

<link rel="stylesheet" href="/dist/cargo-canvas.css" />
<script src="/dist/cargo-canvas-global.js"></script>

<script>
  const map = new CargoCanvas.CargoMap('map', {center: [-25.4284, -49.2733], zoom: 12});
</script>

The stylesheet filename matters. The default marker icon resolves its image path by looking for a <link> whose href ends in cargo-canvas.css. If you rename or inline the stylesheet, set iconUrl on your icons explicitly.

Quick start

A map needs three things: a container with a height, a view, and a source of tiles.

1. Give the container a height

This is the single most common reason a map renders blank — a <div> with no height is zero pixels tall.

<div id="map" style="height: 400px"></div>

2. Create the map

import {CargoMap, TileLayer, Marker} from 'cargocanvas';
import 'cargocanvas/styles.css';

const map = new CargoMap('map', {
  center: [-25.4284, -49.2733],
  zoom: 12,
});

new TileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; OpenStreetMap contributors',
  maxZoom: 19,
}).addTo(map);

new Marker([-25.4284, -49.2733]).bindPopup('Hello').addTo(map);

There are no factory functions. CargoCanvas is class-based throughout: write new Marker(…), never marker(…). Every class is a named export.

Coordinates

CargoCanvas takes coordinates as [latitude, longitude] — the opposite order from GeoJSON, which uses [longitude, latitude]. The GeoJSON layer handles that conversion for you; everywhere else, latitude comes first.

A map and a tile layer

TileLayer takes a URL template with {z}, {x} and {y} placeholders. Any XYZ raster source works — CargoCanvas is provider-agnostic.

Every snippet below is extracted from the code that produced the map above it. They all share these two constants, declared once at the top of lib/demos.js:

const OSM = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
const OSM_ATTR = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';

Basic map

Drag to pan, scroll to zoom, double-click to zoom in.

Markers, popups and tooltips

bindPopup opens on click; bindTooltip opens on hover. Both accept a string, an HTMLElement, or a function returning either.

Three markers, three presentations

Default icon with a popup, default icon with a tooltip, and a custom DivIcon.

Vector layers

Paths share a common styling vocabulary: color, weight, opacity, fill, fillColor, fillOpacity. Note that Circle takes a radius in metres, while CircleMarker takes it in pixels.

Circle, polygon, polyline, rectangle

Click any shape for its popup. Zoom out — the circle scales with the map, in metres.

GeoJSON

The GeoJSON layer accepts a Feature, a FeatureCollection or a raw geometry. Three hooks cover almost everything: style for paths, pointToLayer to decide what a Point becomes, and onEachFeature to wire up interactions.

Styled FeatureCollection

Points become CircleMarkers sized by a property; the polygon is styled by its kind.

Controls

The zoom and attribution controls are added automatically — disable them with the zoomControl: false and attributionControl: false map options. Others you add yourself.

Layer switcher and scale bar

Switch base layers with the control at the top right; toggle the coverage overlay.

ControlPurpose
ZoomControlZoom in / out buttons. Added by default.
AttributionControlData attribution line. Added by default.
LayersControlSwitch base layers, toggle overlays.
ScaleControlMetric / imperial scale bar.
ControlBase class — extend it for your own.

Canvas renderer

By default every path is an SVG element. That is convenient but does not scale — a few thousand DOM nodes will stutter. Pass a shared Canvas renderer and the same paths are drawn into a single <canvas>.

2,000 circle markers

Rendered to one canvas element. Pan and zoom stay smooth.

You can also set renderer once as a map option so every path inherits it, rather than passing it to each layer.

Events

Every class extends Evented, so on, once, off and fire are available everywhere — on the map, on layers, on controls.

Click to place, click again to remove

Mouse events carry a latlng; zoom events carry the new view.

EventFired whenPayload
click / dblclickPointer click on the map or a layerlatlng, containerPoint
pointerover / pointerout / pointermovePointer enters, leaves or moves over the targetlatlng, containerPoint
moveendPanning finishes
zoomendZooming finishes
layeradd / layerremoveA layer enters or leaves the maplayer
resizeThe container is resizedoldSize, newSize

API surface

Everything below is a named export of the cargocanvas module. Detailed per-option documentation lives in the source, as comment blocks next to each class.

Map

  • CargoMap
  • Map (alias)

Tile layers

  • TileLayer
  • WMSTileLayer
  • GridLayer

Markers

  • Marker
  • Icon
  • DefaultIcon
  • DivIcon

Vector

  • Path
  • Polyline
  • Polygon
  • Rectangle
  • Circle
  • CircleMarker

Renderers

  • Renderer
  • SVG
  • Canvas

Overlays

  • ImageOverlay
  • VideoOverlay
  • SVGOverlay
  • BlanketOverlay

Grouping

  • Layer
  • LayerGroup
  • FeatureGroup
  • GeoJSON

UI

  • Popup
  • Tooltip
  • DivOverlay

Controls

  • Control
  • ZoomControl
  • AttributionControl
  • LayersControl
  • ScaleControl

Geometry

  • LatLng
  • LatLngBounds
  • Point
  • Bounds
  • Transformation
  • LineUtil / PolyUtil

Projection

  • CRS
  • EarthCRS
  • EPSG3857
  • EPSG3395
  • EPSG4326
  • SimpleCRS
  • Projection

Core

  • Class
  • Evented
  • Handler
  • Browser
  • Util
  • DomUtil / DomEvent
  • Draggable
  • PosAnimation

Map handlers

  • DragHandler
  • ScrollWheelZoomHandler
  • DoubleClickZoomHandler
  • BoxZoomHandler
  • KeyboardHandler
  • PinchZoomHandler
  • TapHoldHandler

Extending a class

include adds methods to an existing class; mergeOptions adds default options; addInitHook runs code at construction. This is how the built-in controls attach themselves to the map, and how plugins should attach themselves too.

import {Marker, CargoMap} from 'cargocanvas';

Marker.include({
  flash() {
    this.getElement().animate(
      [{opacity: 1}, {opacity: 0.2}, {opacity: 1}],
      {duration: 600},
    );
    return this;
  },
});

CargoMap.mergeOptions({myPluginEnabled: true});

CargoMap.addInitHook(function () {
  if (this.options.myPluginEnabled) { /* … */ }
});

License

CargoCanvas is released under the BSD 2-Clause License. You may use it commercially, modify it, and ship it inside closed-source products, with no fee and no obligation to open-source your own code.

When you redistribute it you must retain the copyright notice and the disclaimer in source distributions, and reproduce them in the documentation or other materials of binary distributions. The bundles in dist/ already carry them in their banner comment, so shipping those unmodified satisfies the requirement.