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 factor
"set\|silent" Set without triggering a redraw
ImportantRequires name in .meta()

changeThemeStyle finds themes by the name key in .meta(). Without it, the call silently has no effect.

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"')