Tooltips & Interaction
Interactivity in iXMaps has three layers: tooltips shown on hover, events your code can subscribe to, and runtime changes to live themes. This guide collects all three.
Enabling tooltips
The map’s mode option controls whether the feature layer responds to the mouse. It is not fixed at construction time — it can be changed at any point:
const myMap = ixmaps.Map("map", {
mapType: "VT_TONER_LITE",
mode: "info" // hover shows tooltips immediately
});mode: "info"— the feature layer stays interactive. Hovering over an SVG object bound to a theme shows its tooltip right away.mode: "pan"(the default) — the base map handles panning and zooming; the feature layer normally ignores the mouse. A single click briefly runs the same processing as"info"mode for that instant — if a themed feature is under the pointer, its tooltip appears — then the map switches back to"pan"automatically once the pointer moves on.
Change the mode at runtime with ixmaps.setMode("info" | "pan") (or ixmaps.toggleInputMode() to flip between the two), or let users switch it themselves via the built-in mode button — pass tools: true (or toolbutton: true) to the constructor to show it.
A plain FEATURE layer with no theme bound to it falls back to an auto-generated field list instead of a custom tooltip — a holdover from ixMaps’ original QGIS-tiled-SVG generator, which baked tooltips directly into the SVG.
The tooltip template
The tooltip content is a Mustache template set per layer in .meta():
.meta({ tooltip: "<b>{{name}}</b><br>Population: {{pop}}" })Any data field of the layer can be used as a placeholder. HTML is allowed.
Placeholders
| Syntax | Result |
|---|---|
{{fieldname}} |
iXMaps-formatted value (numbers get thousand separators) |
{{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 |
{{theme.item.data}}requiresshowdata: "true"in.style()— without it the data table renders empty (the layer itself still draws).- Field names are case-sensitive, and GeoJSON properties are addressed directly:
{NAME}, not{properties.NAME}.
raw.
Numeric identifiers (postal codes, ISTAT codes, IDs) get thousand-separator formatting like any number — 28001 renders as 28.001. Use {{raw.fieldname}} for identifier fields.
Extra fields in the data table
{{theme.item.data}} shows the layer’s bound fields. To include additional columns, list them in datafields:
.style({ showdata: "true", datafields: ["region", "year", "source"] })Combining chart and data
A common pattern for rich tooltips — the item’s chart plus its data table:
.meta({ tooltip: "{{theme.item.chart}}{{theme.item.data}}" })Styling the tooltip
The tooltip is a regular HTML element with id tooltip — style it with CSS. On dark basemaps the default text color can be invisible:
#tooltip { color: #e8eaf6 !important; }
#tooltip * { color: #e8eaf6 !important; }iXMaps owns the element ids tooltip, loading-div and contextmenu. Never use them for your own page elements — see Troubleshooting.
Reacting to map events
Subscribe with .on() — on the map builder or on the live API. Multiple space-separated event names are accepted; names are case-insensitive:
myMap
.on("mouseover", e => highlight(e.id)) // e.theme = layer, e.id = item key
.on("mouseout", () => clearHighlight())
.on("click", e => showDetail(e.id))
.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) |
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 |
theme and id are the two halves of the compound SVG id "themeId::itemKey", and id is what you use to look up the data record. Clicks on the map background are filtered out.
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 } (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 |
See the API Reference for .off() and notes on multiple maps on one page.
Hooking into framework functions
Besides .on(), the framework calls a set of plain functions named htmlgui_on... at various points, and picks them up if you define them on ixmaps yourself — there’s no registration call, you just assign the function:
ixmaps.htmlgui_onItemClick = function (evt, szId) {
console.log("clicked:", szId);
return true; // suppress the built-in info popup
};Safe hooks — these have no built-in behavior of their own; the engine calls them defensively (wrapped in try/catch) purely as an opt-in extension point:
| Function | Called when | Arguments | Return value |
|---|---|---|---|
htmlgui_onItemClick(evt, szId) |
a feature is clicked, before the built-in info popup | event, compound id | truthy → suppresses the built-in click/info-popup handling |
htmlgui_onItemOver(evt, szId, shape) |
a feature is hovered, before the built-in tooltip/info | event, compound id, SVG node | truthy → suppresses the built-in hover handling |
htmlgui_onTooltipDisplay(evt, szText) |
right before a tooltip is shown | event, resolved tooltip text | return value replaces the tooltip text |
htmlgui_onTooltipDelete() |
a tooltip is being removed | — | truthy → also clears the current highlight/selection list |
htmlgui_onInfoTitle(szTitle, dataRow) |
building an info-popup title | current title, theme data row | return value replaces the title |
htmlgui_onInfoDisplayExtend(svgDoc, szObjId) |
building an info popup | SVG document, object id | return an SVG group node to append it into the popup |
htmlgui_onSelection(szId) |
a selection finishes | selection theme id | truthy → suppresses the default “show info” behavior |
htmlgui_onInitThemes() |
the theme engine (re)initializes | — | — |
htmlgui_onNewTheme(szId) |
a layer/theme is created | theme id | — (see also .on("layeradd")) |
htmlgui_onDrawTheme(szId) |
a layer/theme finishes drawing | theme id | — (see also .on("layerdraw")) |
htmlgui_onRemoveTheme(szId) |
a layer/theme is removed | theme id | — (see also .on("layerremove")) |
htmlgui_onErrorTheme(szTheme) |
a theme’s data couldn’t be loaded | theme/table name | — |
htmlgui_onWindowResize() |
after the browser window resize handler runs | — | — |
htmlgui_onStoryLoaded(szUrl, target) |
a story-mode page finishes loading | url, target element | — |
htmlgui_onHideStoryTool() |
the story tool panel is hidden | — | — |
ixmaps.parentApi.htmlgui_onProjectLoaded(project) |
a project JSON finishes loading, in the parent page of an embedded map | parsed project object | — |
Another script — a plugin, a previous <script> block, the framework itself — may already have assigned one of these hooks. Save the previous function and call it from your own, so you extend it instead of silently replacing it:
var __oldOnItemClick = ixmaps.htmlgui_onItemClick;
ixmaps.htmlgui_onItemClick = function (evt, szId) {
var fSuppress = __oldOnItemClick ? __oldOnItemClick.apply(this, arguments) : false;
// ... your own code ...
return fSuppress; // preserve whatever the previous hook decided
};This is exactly how the framework itself wraps htmlgui_onMapResize internally (htmlgui_flat.js) to also dispatch the .on("resize") event without breaking whatever the map init already assigned.
Internal engine functions — these already carry real default behavior (map init, resize, tool switching), so overriding them means replacing that behavior, not just adding to it. Several are now better reached through .on() instead:
| Function | Default behavior | Prefer instead |
|---|---|---|
htmlgui_onMapInit(mapwindow) |
sets up the embedded-SVG handle, sizes the map | — |
htmlgui_onMapReady(mapwindow) |
clears the loading state, shows the map | .on("ready") |
htmlgui_onMapError() |
hides the loading indicator, falls back to ready-handling | — |
htmlgui_onMapResize() |
re-syncs the HTML/SVG map box after a resize | .on("resize") |
htmlgui_onMapTool(szMode) |
reconfigures mouse-event sharing for the new pan/info/zoom tool | — |
htmlgui_onSVGPointerIdle() |
releases SVG event handling back to the base map — internal plumbing, not really an authoring hook | — |
htmlgui_onZoomAndPan(nZoomScale) |
low-level zoom/pan signal | .on("viewchange") |
Runtime theme changes
React to user input by changing live themes through myMap.then(). All of these require a name in the layer’s .meta():
Filter a theme:
myMap.then(api => {
api.changeThemeStyle("cities", 'filter:WHERE pop > 500000', "set");
// and back:
api.changeThemeStyle("cities", "filter", "remove");
});Toggle a layer with a checkbox:
myMap.layer("overlay")
.style({ /* ... */, visible: false }) // starts hidden
.meta({ name: "overlay" })
.define();<input type="checkbox"
onchange="this.checked ? ixmaps.showTheme('overlay') : ixmaps.hideTheme('overlay')">Swap the visualization (remove-then-define) — see Examples § Swappable themes for the full pattern.
For changeThemeStyle modes (set, remove, factor, set|silent) and the rest of the runtime API, see the API Reference.