API Reference

iXMaps API reference: the Map constructor, map and layer chain methods, filters and the runtime API, with required patterns and examples.

Complete reference for the iXMaps JavaScript API.


Map constructor

ixmaps.Map(elementId, options)

Creates a new map instance. Always assign the result to a const — a discarded instance silently breaks all subsequent calls.

const myMap = ixmaps.Map("map", {
    mapType: "VT_TONER_LITE",
    mode:    "info",
    legend:  "closed",
    tools:   true
});

Parameters:

Parameter Type Description
elementId string ID of the HTML <div> that will contain the map
options object Map configuration (see below)

Options:

Option Type Default Description
mapType string "VT_TONER_LITE" Basemap style — see Map Setup
mapProjection string (web Mercator) Projection — "lambert", "equalearth", "orthographic", etc.
mode string "pan" "info" enables tooltips on hover; "pan" pan/zoom only
legend string "closed" "open" or "closed" initial legend panel state
tools boolean false Show the map toolbar (zoom buttons, search)
projectionParams object — Albers-only: custom standard parallels / center

Returns: a MapBuilder instance — chainable.


Map chain methods

The map builder supports a fluent API. Call these methods immediately after ixmaps.Map().

.view(config)

Set the initial center and zoom.

// Standard (Mercator / tile-based):
.view({ center: { lat: 42.5, lng: 12.5 }, zoom: 6 })

// Projection maps (MUST use array form):
.view([42.5, 12.5], 6)
Zoom Coverage
1–3 world / continent
4–6 country
7–10 region / state
11–14 city
15–18 street / building

.options(opts)

Configure rendering and behaviour.

.options({
    objectscaling:   "dynamic",   // symbols scale with zoom
    normalSizeScale: "8000000",   // ⚠️ REQUIRED with objectscaling
    basemapopacity:  0.6,
    flushChartDraw:  1000000      // 1 000 000 = instant (no animation)
})
Option Type Description
objectscaling string "dynamic" — symbols grow/shrink with zoom
normalSizeScale string Required with objectscaling. Map scale denominator at which charts render at their nominal size. Zoom 6 ≈ "8000000", zoom 12 ≈ "100000"
dynamicScalePow string Exponent for zoom scaling. "1.8" recommended for dense point sets
featurescaling string "true" — scale individual features relative to each other
basemapopacity number Opacity of basemap tiles. 0 = invisible, 1 = fully opaque
flushChartDraw number Rendering batch size. 1000000 = instant, 1 = animated one-by-one
flushPaintShape number Set to 1000000 for large polygon datasets (municipalities) to prevent render hangs
zoomAnimation boolean Smooth zoom transitions. false = snap

.on(events, handler)

Subscribe to map events. Multiple space-separated event names are accepted; names are case-insensitive.

myMap
    .on("ready",     () => hideSpinner())
    .on("layerdraw", e => console.log("drawn:", e.id))
    .on("click",     e => showDetail(e.id))
    .on("mouseover", e => highlight(e.id))
    .on("mouseout",  () => clearHighlight())
    .on("zoomend moveend", () => updateStats());

View events — handler receives { nZoom, zoomChanged, panChanged, frozenDynamic, szMap }:

Event Fires when
zoomend Zoom changed
moveend Map panned without a zoom change
viewchange / zoompan Any zoom or pan (fires on every engine notification)
NoteZoom wins over pan

A combined zoom-and-pan fires only zoomend, never moveend too. Subscribe to "zoomend moveend" (or viewchange) to catch every view change.

Item (feature) events — handler receives { type, szId, id, theme, szMap }:

Event Fires when
mouseover / itemover Pointer enters a feature
mouseout / itemout Pointer leaves a feature
click / itemclick Feature clicked
Payload key Content
szId Full compound SVG id: "themeId::itemKey"
theme Theme/layer name — the part before ::
id Item key — the part after :: (use this to look up the data record)

Clicks on the map background are filtered out — item handlers only fire on real features.

Lifecycle events — handler receives { type, szMap }:

Event Fires when
ready / mapready SVG engine fully loaded
resize Map container was resized

Layer events — handler receives { type, id, szMap } where id = theme/layer id:

Event Fires when
layerdraw / drawtheme A layer finishes drawing
layeradd / newtheme A layer is created
layerremove / removetheme A layer is removed
NoteMultiple maps on one page

View-event listeners registered on a named map instance only receive events from that map (szMap is matched). Errors thrown inside your handlers are caught and silently ignored — they never break the map engine.

.off(events, handler)

Remove handlers previously registered with .on(). Same event names and aliases; the handler reference must be the same function object that was registered:

const onZoom = e => updateStats(e.nZoom);
myMap.then(api => {
    api.on("zoomend", onZoom);
    // later:
    api.off("zoomend", onZoom);
});

Layer chain

Every data layer uses the same method chain:

myMap.layer("layerName")
    .data({...})       // ① data source
    .binding({...})    // ② field mapping   ← required
    .filter("...")     // ③ optional filter
    .type("...")        // ④ visualization type
    .style({...})      // ⑤ style properties
    .meta({...})       // ⑥ tooltip / metadata
    .title("...")       // ⑦ legend label
    .define()          // ⑧ register (required — must close every chain)

.data(config) — data source

Inline JSON:

.data({ obj: myArray, type: "json" })
.data({ obj: myArray, type: "json", cache: "true" })  // reuse for multiple layers

External file:

.data({ url: "https://example.com/data.csv",  type: "csv" })
.data({ url: "https://example.com/geo.topojson", type: "topojson" })

Supported type values: "json" · "jsonl" · "csv" · "geojson" · "topojson" · "parquet" · "geoparquet" · "geopackage" / "gpck" · "flatgeobuf" / "fgb" · "geobuf" / "pbf"

Multi-source loading (Data.provider):

var loadData = function(themeObj, options) {
    Data.provider()
        .addSource("https://example.com/2022.csv.gz", "csv")
        .addSource("https://example.com/2023.csv.gz", "csv")
        .load(function(dataA) {
            dataA[0].append(dataA[1]);
            options.type = "dbtable";
            ixmaps.setExternalData(dataA[0], options);
        });
};

myMap.layer("events")
    .data({ name: "themeDataObj", query: loadData.toString(), cache: "true" })
    // ...
ImportantSelf-contained function required

The function passed to query: is serialised with .toString(). It cannot reference outer-scope variables — make everything self-contained inside the function body.


.binding(config) ⚠️ Required

Maps data fields to map properties.

Point data (CSV / JSON with lat/lon columns):

.binding({ geo: "lat|lon",   value: "fieldname", title: "label" })
.binding({ geo: "geometry",  value: "fieldname", title: "label" })  // GeoJSON Point geometry

GeoJSON / TopoJSON with join:

.binding({ geo: "geometry", id: "CNTR_ID", title: "NAME_ENGL" })

Choropleth overlay (joins to FEATURE base by id):

.binding({ lookup: "csv_code_col", value: "metric" })
// "lookup" field must match the "id" field of the FEATURE base

Multi-value (sparklines, stacked bars, flows):

.binding({ geo: "lat|lon", value: "val2020|val2021|val2022|val2023" })

With size driven by a separate field (categorical color + numeric size):

.binding({ geo: "lat|lon", value: "category", title: "name", size: "numericField" })

Time series:

.binding({ geo: "lat|lon", value: "metric", title: "name", timefield: "year" })
Key Purpose
geo Coordinates: "lat\|lon" for columns, "geometry" for GeoJSON geometry
position Alias for geo — both are accepted; use one consistently
geo2 Destination coordinates for flow maps (CHART\|VECTOR\|BEZIER): "to_lat\|to_lon"
id Feature identifier for later joins (FEATURE base layers)
lookup Join key on the data side (must match id in the geometry)
value Field(s) to visualise — pipe-separated for multi-value
title Display name in tooltips
size Independent size field when using CATEGORICAL with numeric sizing
alpha Field for dynamic opacity (DOPACITYMAX / DOPACITYMINMAX)
timefield Time field for animated / time-slider maps

Flow map (origin → destination):

.binding({ geo: "from_lat|from_lon", geo2: "to_lat|to_lon", value: "volume", title: "from_name" })

.filter(expression) — optional

Filter rows before visualisation.

.filter('WHERE country == "IT"')
.filter('WHERE year == 2024')
.filter('WHERE value > 100 AND category in (A,B,C)')
WarningString quoting in filters

Use double quotes for string values — single quotes are not string delimiters and produce no matches. Use AND / OR not && / ||.


.type(vizType) — visualization type

The type string is composed by piping modifiers with |. See Visualization Types & Modifiers for the full reference.

Quick reference:

Type string Renders
"FEATURE" Polygon or line boundaries only
"CHOROPLETH\|QUANTILE" Colour-coded polygons joined to a FEATURE base
"CHART\|DOT" Uniform dots at coordinates
"CHART\|BUBBLE\|SIZE\|VALUES" Sized bubbles with value labels
"CHART\|BUBBLE\|CATEGORICAL" Bubbles coloured by category
"CHART\|PIE" Pie charts at coordinates
"CHART\|BAR\|STACKED" Stacked / grouped bar charts
"CHART\|SYMBOL\|PLOT\|LINES" Sparklines (time-series curves)
"CHART\|VECTOR\|BEZIER\|POINTER" Flow arrows

.style(props) — visual properties

See Style Properties for the complete reference. Minimum required for any layer:

.style({ showdata: "true" })  // ⚠️ required — missing this = nothing renders

.meta(config) — tooltip and metadata

.meta({ tooltip: "{{name}}: {{value}}" })
.meta({ name: "myLayer", tooltip: "{{theme.item.chart}}{{theme.item.data}}" })
Key Purpose
tooltip Mustache template for the hover tooltip
name Theme name — required for changeThemeStyle, hideTheme, showTheme

Tooltip placeholders:

Syntax Result
{{fieldname}} iXMaps-formatted value
{{raw.fieldname}} Raw unformatted value — bypasses all iXMaps formatting
{{theme.item.chart}} Built-in chart SVG for this item
{{theme.item.data}} Built-in data table for this item

Runtime API

Access the live map instance through myMap.then():

myMap.then(function(api) {
    // api is the live iXMaps map object
    api.changeThemeStyle("layerName", "filter:WHERE year == 2024", "set");
    api.removeTheme("prevTheme");
    api.setBasemapOpacity(0.3, "absolute");
});

api.changeThemeStyle(name, styleString, mode)

Modify a style property on a live layer and trigger re-render.

myMap.then(api => {
    api.changeThemeStyle("cities", "filter:WHERE pop > 500000", "set");
    api.changeThemeStyle("cities", "filter", "remove");          // clear filter
    api.changeThemeStyle("cities", "scale:1.2", "set");
    api.changeThemeStyle("cities", "gridwidthpx:1.1", "factor"); // multiply by 1.1
});
Mode Effect
"set" Replace the property value
"remove" Delete the property entirely
"factor" Multiply the current numeric value by the given value
"add" / "delta" Add the given value to the current numeric value
"pow" Raise the current numeric value to the given power (not for scale)
"set\|silent" Set without the “… processing …” message (silent, fast and direct are equivalent) — the theme is still redrawn

factor, add/delta and pow apply to numeric properties (scale, opacity, fillopacity, valuescale, linewidth, gridwidthpx, normalsizevalue, maxcharts, …); any other property is simply set. scale acts as a resize factor on the drawn charts: "scale:0" is ignored and leaves the theme unchanged.

All themes at once

Pass null as the theme name to change every theme on the map except FEATURE themes (base geometries are left alone) — no meta.name needed:

myMap.then(api => api.changeThemeStyle(null, "scale:1.5", "set"));

// the global form, as used by chart-size sliders
// (the leading null is the map; two identical leading arguments are shifted)
ixmaps.changeThemeStyle(null, null, "scale:" + slider.value, "set");

This is the usual way to wire a single “chart size” slider that resizes all chart themes together.

ImportantRequires name in .meta()

changeThemeStyle with a theme name finds the theme by the name key in .meta(). Without it, the call silently has no effect. (The null form above needs no name.)

api.removeTheme(name)

Remove a layer by its meta.name. Use this before redefining an overlay to prevent stacking:

let ACTIVE = null;

function showYear(year) {
    const themeName = "year-" + year;
    const prev = ACTIVE;
    myMap.then(api => {
        if (prev) { try { api.removeTheme(prev); } catch(e) {} }
        myMap.layer("countries")
            .data({ obj: yearData[year], type: "json" })
            .binding({ geo: "lat|lon", value: "metric" })
            .type("CHART|BUBBLE|SIZE|VALUES")
            .style({ colorscheme: ["#0066cc"], showdata: "true" })
            .meta({ name: themeName, tooltip: "{{name}}: {{metric}}" })
            .define();
        ACTIVE = themeName;
    });
}

ixmaps.hideTheme(name) / ixmaps.showTheme(name)

Toggle layer visibility by meta.name. For initially hidden layers, use visible: false in .style():

myMap.layer("overlay")
    .style({ ..., visible: false })
    .meta({ name: "overlay" })
    .define();

// Later:
ixmaps.showTheme("overlay");
ixmaps.hideTheme("overlay");

// Checkbox toggle:
// <input type="checkbox" onchange="this.checked ? ixmaps.showTheme('overlay') : ixmaps.hideTheme('overlay')">

ixmaps.getZoom() / ixmaps.getCenter()

Global helpers — call directly without .then():

const z = ixmaps.getZoom();
const c = ixmaps.getCenter();  // { lat, lng }

api.getBounds()

Returns a flat 4-element array [swLat, swLng, neLat, neLng]:

myMap.then(function(m) {
    const bounds = m.getBounds();
    if (!bounds || bounds.length !== 4) return;
    const [swLat, swLng, neLat, neLng] = bounds;
});

Projections

Set mapProjection in the constructor ("mercator", "lambert", "equalearth", "winkel", "albers", "orthographic"); omit it for the default Web Mercator / Leaflet tile setup. For projection maps, use the array form .view([lat, lng], zoom) and set mapType to a background color ("#0a1929", "white", "dark") — do not use CSS background on #map.

The full projection table with aliases, per-projection examples and the three map contexts: Map Setup.


Geometry sources (quick reference)

World countries (GISCO):

.data({ url: "https://gisco-services.ec.europa.eu/distribution/v2/countries/topojson/CNTR_RG_60M_2020_4326.json", type: "topojson" })
.binding({ geo: "geometry", id: "CNTR_ID", title: "NAME_ENGL" })
// Scales: 60M (world) · 20M · 10M · 3M · 1M (country)
// ⚠️ Join field is CNTR_ID, NOT CNTR_CODE

Italy municipalities (ISTAT 2024-compatible):

.data({ url: "https://raw.githubusercontent.com/gjrichter/geo/0153a0e14da5dae877b8c94d6deb11f210d4660a/italy/boundaries/italy_istat_municipalities_4326_500m.topojson", type: "topojson" })
.binding({ geo: "geometry", id: "com_istat_code_num", title: "name" })
// com_istat_code_num = integer 28001 (use for joins with ISTAT CSVs)
// com_istat_code     = zero-padded string "028001"
// ⚠️ Add flushPaintShape: 1000000 to .options() for all ~8000 polygons

Germany LAU municipalities:

.data({ url: "https://cdn.jsdelivr.net/gh/gjrichter/geo@028b3fe/lau/germany_lau_2021_4326.topojson", type: "topojson" })
.binding({ geo: "geometry", id: "LAU_ID", title: "LAU_NAME" })

NUTS1–3 (Eurostat):

.data({ url: "https://gisco-services.ec.europa.eu/distribution/v2/nuts/topojson/NUTS_RG_60M_2021_4326_LEVL_1.json", type: "topojson" })
.binding({ geo: "geometry", id: "NUTS_ID", title: "NUTS_NAME" })
// For a single country: .filter('WHERE CNTR_CODE == "DE"')