Chart Scaling
iXMaps provides several complementary mechanisms for controlling how symbols and charts are sized. Understanding how they interact helps you get the right visual density at every zoom level.
The three sizing levers
| Lever | Scope | Where | Effect |
|---|---|---|---|
normalSizeScale |
Map | .options() |
Reference map scale denominator — sets the zoom level at which symbols appear at their “nominal” size |
normalsizevalue |
Layer | .style() |
Reference data value that maps to nominal size — higher value = smaller symbols |
scale |
Layer | .style() |
Direct multiplier applied on top of everything else |
They multiply together. A symbol’s screen size is approximately:
screen size ∝ (data value / normalsizevalue) * scale * f(currentZoom / normalSizeScale)
normalSizeScale — the zoom anchor
Set in .options(). Tells iXMaps: “at this map scale denominator, render symbols at their nominal size.”
| Zoom level | Approximate normalSizeScale |
|---|---|
| 4 (continent) | "30000000" |
| 5 (large country) | "15000000" |
| 6 (country, e.g. Italy) | "8000000" |
| 8 (region) | "2000000" |
| 10 (province) | "500000" |
| 12 (city) | "100000" |
| 14 (district) | "25000" |
.options({
objectscaling: "dynamic",
normalSizeScale: "8000000", // zoom 6 = nominal size
})normalSizeScale below ~10 000
Very small values (e.g. "1") invert the scaling and produce wildly oversized or invisible symbols at all zoom levels. Always use a geographically meaningful scale denominator.
normalsizevalue — the data anchor
Set in .style(). Declares: “a data value equal to normalsizevalue renders at the nominal symbol size.”
Higher value → smaller symbols (because most real data values fall below it).
// If your data has values up to 10 000 000:
.style({ normalsizevalue: "5000000" }) // median-ish value → medium bubbles
// If your values are small (0–100):
.style({ normalsizevalue: "50" }) // smaller reference → larger bubblesscale — direct multiplier
The simplest lever. Applied after everything else. Start at 1 and adjust:
.style({ scale: 0.5 }) // half size
.style({ scale: 2.0 }) // double size
.style({ scale: 0.32 }) // recommended with |GLOW (glow halo adds apparent size)sizepow — power curve
Controls how aggressively size contrasts between large and small data values.
Formula:
Adjusted Size = BaseSize × (dataValue ^ (1/sizePow)) / (maxValue ^ (1/sizePow))
Effect of different values:
sizepow |
Curve | Use case |
|---|---|---|
1 |
Linear — size directly proportional to value | Equal-weight comparison |
2 (default) |
Square root — dampens extremes | Most bubble/symbol maps |
0.5 |
Quadratic — amplifies large values | When you want large values to dominate |
3 |
Cubic root — strongly dampens extremes | Very wide value ranges |
10 |
Near-logarithmic — almost equal visual size for all values | Revenue, orders-of-magnitude data |
Defaults set automatically by type modifier:
| Type modifier | Auto sizepow |
|---|---|
LINEAR / SIZEP1 |
1 |
SIZEP1H |
1.5 |
SIZEP3 / SIZEVOLUME |
3 |
SIZELOG |
10 |
| (none of the above) | 2 |
.style({ sizepow: 2 }) // default — square root
.style({ sizepow: 0.5 }) // amplify large values
.style({ sizepow: 10 }) // near-logarithmicdynamicScalePow — zoom rate
Controls how quickly symbols grow or shrink as the user zooms. The default is 3 (cubic root), which provides smooth transitions without extreme size changes.
Formula: DynamicScale = (1 / scaleRatio) ^ (1 / dynamicScalePow)
.options({
objectscaling: "dynamic",
normalSizeScale: "8000000",
dynamicScalePow: "3" // default — cubic root, smooth transitions
// dynamicScalePow: "1.8" // more aggressive growth on zoom-in (dense datasets)
})Higher values produce faster growth when zooming in. For dense point datasets where you want symbols to spread out noticeably on zoom, use "1.8". For sparse data where continuity matters more, keep the default "3".
Urban trees preset
A reliable starting point for street-level zoom (zoom 14–16) with species bubbles and |GLOW:
.options({
objectscaling: "dynamic",
normalSizeScale: "5000" // street scale
})
.style({
normalsizevalue: "220", // diameter in cm — controls relative sizing
scale: 0.32, // reduce glow halo size
fillopacity: 0.8,
showdata: "true"
})
.type("CHART|BUBBLE|CATEGORICAL|GLOW")Scale-dependent visibility
Hide a layer when the map is too zoomed out or too zoomed in:
.style({
chartupper: "1:5000", // hide when denominator > 5000 (zoomed out)
chartlower: "1:500" // hide when denominator < 500 (zoomed in)
})Background boxes can also appear/disappear by scale:
.style({
boxupper: "1:250000" // box visible only at denominator ≤ 250 000
})Runtime size adjustments
Change size interactively after the map loads:
// Set scale to 2x:
myMap.then(api => api.changeThemeStyle("layerName", "scale:2.0", "set"));
// Shrink by 10 %:
myMap.then(api => api.changeThemeStyle("layerName", "scale:0.9", "factor"));
// Grow grid cells by 10 %:
myMap.then(api => api.changeThemeStyle("layerName", "gridwidthpx:1.1", "factor"));