Kirra’s XLSX template system uses fx: prefixed formulas to populate cells with blast data, statistics, graphics, and calculated values. This page is the complete reference for every formula, variable, display code, and render token available.
This is the print template formula engine only. Charge deck formulas and blast-group predicates use different variables and functions — see the Formula Engine hub.
All formulas are entered in XLSX cells with the fx: prefix. Standard Excel formulas (=) are preserved in XLSX output but ignored in PDF output.
Direct values that resolve without iteration. Use them on their own or inside expressions.
| Formula | Description | Example Result |
|---|---|---|
fx:blastName |
User-entered blast name | Shot 42 |
fx:designer |
User-entered designer name | J. Smith |
fx:date |
Current date (dd/mm/yyyy) | 28/03/2026 |
fx:time |
Current time (hh:mm:ss) | 14:30:00 |
fx:datetime |
Current date and time | 28/03/2026, 14:30:00 |
fx:paperSize |
Paper size | A3 |
fx:orientation |
Page orientation | landscape |
fx:printScale |
Calculated print scale | 500 |
fx:holeCount |
Total visible holes | 142 |
fx:drillMetres |
Total drill metres (sum of all hole lengths) | 1927.3 |
fx:totalMass |
Total explosive mass (kg) | 4250.0 |
fx:totalVolume |
Total volume (m3) | 12500.0 |
fx:totalSurfaceArea |
Total surface area (m2) | 8400.0 |
fx:powderFactor |
Overall powder factor (kg/m3) | 0.34 |
fx:entityCount |
Number of entities | 2 |
fx:entityNames |
Comma-separated entity names | Pattern_01, Pattern_02 |
fx:entityName |
First entity name | Pattern_01 |
fx:surfaceCount |
Number of loaded surfaces | 3 |
fx:kadCount |
Number of loaded KAD drawings | 1 |
When multiple entities are loaded, per-entity statistics are available using the entity name as a prefix. Non-alphanumeric characters in entity names are replaced with _.
| Formula Pattern | Description |
|---|---|
fx:Pattern_01_holeCount |
Hole count for entity Pattern_01 |
fx:Pattern_01_drillMetres |
Drill metres for entity Pattern_01 |
fx:Pattern_01_expMass |
Explosive mass for entity Pattern_01 |
fx:Pattern_01_volume |
Volume for entity Pattern_01 |
fx:Pattern_01_surfaceArea |
Surface area for entity Pattern_01 |
fx:Pattern_01_burden |
Burden for entity Pattern_01 |
fx:Pattern_01_spacing |
Spacing for entity Pattern_01 |
fx:Pattern_01_minFiringTime |
Minimum firing time for entity Pattern_01 |
fx:Pattern_01_maxFiringTime |
Maximum firing time for entity Pattern_01 |
Fields that reference individual hole properties. Use with [i] for aggregation, [N] for specific holes, or [++]/[--]/[+>] for auto-incrementing tables.
| Field | Description | Unit |
|---|---|---|
holeID[i] |
Hole ID | text |
entityName[i] |
Entity name per hole | text |
holeLength[i] |
Hole length (collar to toe) | m |
holeDiameter[i] |
Hole diameter | mm |
holeAngle[i] |
Hole angle from vertical (0 = vertical) | deg |
holeBearing[i] |
Hole bearing from north (clockwise) | deg |
benchHeight[i] |
Bench height (collar Z to grade Z, absolute) | m |
burden[i] |
Burden | m |
spacing[i] |
Spacing | m |
subdrillAmount[i] |
Subdrill amount (grade Z to toe Z, deltaZ) | m |
subdrillLength[i] |
Subdrill length (grade XYZ to toe XYZ, vector distance) | m |
holeType[i] |
Hole type (Production, Presplit, Buffer, etc.) | text |
| Field | Description | Unit |
|---|---|---|
startX[i] |
Collar X (easting) | m |
startY[i] |
Collar Y (northing) | m |
startZ[i] |
Collar Z (elevation) | m |
endX[i] |
Toe X (easting) | m |
endY[i] |
Toe Y (northing) | m |
endZ[i] |
Toe Z (elevation) | m |
gradeX[i] |
Grade X (easting) | m |
gradeY[i] |
Grade Y (northing) | m |
gradeZ[i] |
Grade Z (elevation) | m |
| Field | Description | Unit |
|---|---|---|
timingDelay[i] |
Timing delay | ms |
holeTime[i] |
Timing delay (alias) | ms |
fromHoleID[i] |
Connected-from hole ID | text |
connectorCurve[i] |
Connector curve value | number |
rowID[i] |
Row ID | text |
posID[i] |
Position ID | text |
color[i] |
Hole colour hex code | text |
visible[i] |
Hole visibility flag | boolean |
These fields are derived from the loaded charging data (window.loadedCharging), not directly from hole properties.
| Field | Description | Unit |
|---|---|---|
totalMass[i] |
Total explosive mass per hole | kg |
chargeLength[i] |
Total explosive column length per hole | m |
firstChargeTop[i] |
Depth from collar to top of first explosive deck (geometric uncharged zone) | m |
stemLength[i] |
Stemming length (sum of Stemming/StemGel/DrillCuttings deck lengths only) | m |
deckCount[i] |
Total deck count per hole | count |
explosiveDeckCount[i] |
Explosive deck count per hole (COUPLED + DECOUPLED) | count |
primerCount[i] |
Primer count per hole | count |
powderFactor[i] |
Powder factor per hole: mass / (burden x spacing x benchHeight) | kg/m3 |
productName[i] |
Name of the first (primary) explosive product | text |
airLength[i] |
Air deck total length per hole | m |
inertLength[i] |
Total inert deck length per hole (all non-explosive decks) | m |
waterLength[i] |
Water deck total length per hole | m |
spacerCount[i] |
Count of spacer decks per hole | count |
Note:
firstChargeTop[i]andstemLength[i]are different values.
firstChargeTop= depth from collar to top of first explosive (includes air, water, spacers above the charge).stemLength= sum of physical stemming material only (Stemming, StemGel, DrillCuttings deck lengths).
| Field | Description | Unit |
|---|---|---|
measuredMass[i] |
Measured mass | kg |
measuredLength[i] |
Measured length | m |
measuredComment[i] |
Measured comment | text |
Many fields have short aliases and long aliases that resolve to the same hole property. Use whichever is clearest for your template.
| Short Alias | Long Alias | Resolves To |
|---|---|---|
holeLength |
holeLengthCalculated |
holeLengthCalculated |
startX |
startXLocation |
startXLocation |
startY |
startYLocation |
startYLocation |
startZ |
startZLocation |
startZLocation |
endX |
endXLocation |
endXLocation |
endY |
endYLocation |
endYLocation |
endZ |
endZLocation |
endZLocation |
gradeX |
gradeXLocation |
gradeXLocation |
gradeY |
gradeYLocation |
gradeYLocation |
gradeZ |
gradeZLocation |
gradeZLocation |
diameter |
holeDiameter |
holeDiameter |
angle |
holeAngle |
holeAngle |
bearing |
holeBearing |
holeBearing |
timingDelay |
timingDelayMilliseconds |
timingDelayMilliseconds |
holeTime |
timingDelayMilliseconds |
timingDelayMilliseconds |
holeId |
holeID |
holeID |
rowId |
rowID |
rowID |
posId |
posID |
posID |
fromHoleId |
fromHoleID |
fromHoleID |
color |
colorHexDecimal |
colorHexDecimal |
air |
airLength |
Air deck length |
waterDeckLength |
waterLength |
Water deck length |
spacers |
spacerCount |
Spacer deck count |
Access individual holes by position, or auto-iterate through holes for tabular output.
| Syntax | Description | Example |
|---|---|---|
field[N] |
Access the Nth visible hole (1-based index) | fx:holeLength[3] returns the 3rd hole’s length |
field[++] |
Auto-increment per row: row 1 = hole 1, row 2 = hole 2, etc. Blank beyond hole count | fx:holeID[++] |
field[--] |
Auto-decrement per row: row 1 = last hole, row 2 = second-last, etc. | fx:holeID[--] |
field[+>] |
Grid-increment per cell: left-to-right, then top-to-bottom. Auto-paginates across sheets | fx:holeID[+>] |
[N]You can combine [N] with standard Excel cell references to build dynamic index lookups:
="fx:holeID["&$A1&"]"
If cell A1 contains 5, this evaluates to fx:holeID[5], returning the 5th hole’s ID.
[+>]When a [+>] table has more holes than cells, Kirra automatically creates additional pages (sheets) to hold all the data. Each subsequent sheet continues from where the previous one left off.
When [N], [++], or [--] references a hole index beyond the visible hole count, the cell resolves to blank. Entire rows that are completely beyond the hole count are hidden (zero height) in the PDF output.
Use ignore() to prevent a row from being hidden when its index is out of range:
fx:ignore(holeID[++])
Pre-filter which holes are included in [++], [--], and [+>] tables. Place the filter formula in any cell on the same sheet (typically above the table).
| Example | Description |
|---|---|
fx:filter(holeAngle > 0) |
Only angled holes |
fx:filter(holeType == "Production") |
Only Production holes |
fx:filter(holeDiameter >= 200) |
Only holes with diameter >= 200mm |
fx:filter(holeDiameter >= 200 && holeAngle < 15) |
Combined AND condition |
fx:filter(holeType == "Production" \|\| holeType == "Buffer") |
Combined OR condition |
Supported operators: >, <, >=, <=, ==, !=
Logical operators: && (AND), || (OR)
The filter cell itself displays: Filter: <expression> (N holes) showing how many holes passed.
Aggregate across all visible holes using field[i] notation.
| Function | Description | Example | Result |
|---|---|---|---|
sum(field[i]) |
Sum of all values | fx:sum(holeLength[i]) |
1927.35 |
count(field[i]) |
Count of non-null values | fx:count(holeID[i]) |
142 |
avg(field[i]) |
Average (mean) | fx:avg(holeDiameter[i]) |
165.0 |
min(field[i]) |
Minimum value | fx:min(startZ[i]) |
98.2 |
max(field[i]) |
Maximum value | fx:max(startZ[i]) |
143.6 |
median(field[i]) |
Median value | fx:median(holeLength[i]) |
13.5 |
stdev(field[i]) |
Standard deviation (sample) | fx:stdev(holeLength[i]) |
1.23 |
unique(field[i]) |
Count of unique values | fx:unique(holeType[i]) |
3 |
countif(field[i], val) |
Count where field equals val | fx:countif(holeType[i], "Production") |
85 |
sumif(sumF[i], condF[i], val) |
Sum field where condition field equals val | fx:sumif(holeLength[i], holeType[i], "Production") |
1150.5 |
join(field[i], sep) |
Join all values as a string | fx:join(holeID[i], ", ") |
H001, H002, H003... |
uniqueList(field[i], sep) |
Join unique values as a string | fx:uniqueList(entityName[i]) |
Pattern_01, Pattern_02 |
Aggregation results can be used inside other functions:
fx:round(avg(holeLength[i]), 1) → 13.6
fx:"Total: " & sum(holeLength[i]) & "m" → Total: 1927.35m
fx:if(holeCount > 100, "Large", "Small") → Large
Group holes by a field and compute per-group statistics. All return formatted strings.
| Function | Description | Example |
|---|---|---|
sortCount(field[i], sep, limit) |
Count per unique value, sorted by count descending | fx:sortCount(holeType[i], ", ") |
groupCount(field[i], sep, order) |
Group and count. Order: desc (default), asc, alpha |
fx:groupCount(holeType[i], "\n", "desc") |
groupSum(sumF[i], grpF[i], sep) |
Sum a numeric field grouped by another field | fx:groupSum(holeLength[i], entityName[i], "\n") |
groupAvg(valF[i], grpF[i], sep) |
Average grouped by another field | fx:groupAvg(holeDiameter[i], holeType[i], "\n") |
groupMin(valF[i], grpF[i], sep) |
Min grouped by another field | fx:groupMin(holeLength[i], holeType[i], "\n") |
groupMax(valF[i], grpF[i], sep) |
Max grouped by another field | fx:groupMax(startZ[i], holeType[i], "\n") |
groupTable(grpF[i], fmt, sep, order) |
Multi-field per-group format with inline tokens | See below |
groupTable accepts a format string with inline tokens that compute per-group:
| Token | Description |
|---|---|
{key} |
Group key value (e.g. “Production”) |
{count} |
Count of holes in group |
{sum:field} |
Sum of field within group |
{avg:field} |
Average of field within group |
{min:field} |
Minimum of field within group |
{max:field} |
Maximum of field within group |
{median:field} |
Median of field within group |
Example:
fx:groupTable(holeType[i], "{key}: {count} holes, dia={avg:holeDiameter}mm, len={sum:holeLength}m", "\n")
Result:
Production: 85 holes, dia=165.0mm, len=1150.5m
Buffer: 42 holes, dia=127.0mm, len=525.0m
Presplit: 15 holes, dia=89.0mm, len=251.8m
sortCount — quick frequency table:
fx:sortCount(holeType[i], ", ")
→ Production: 85, Buffer: 42, Presplit: 15
groupSum — drill metres per entity:
fx:groupSum(holeLength[i], entityName[i], "\n")
→ Pattern_01: 1234.5
Pattern_02: 692.8
groupAvg with custom separator:
fx:groupAvg(holeDiameter[i], holeType[i], " | ", "alpha")
→ Buffer: 127.0 | Presplit: 89.0 | Production: 165.0
| Function | Description | Example | Result |
|---|---|---|---|
round(value, n) |
Round to n decimals. Negative n rounds to tens/hundreds | fx:round(1927.35, 1) |
1927.4 |
roundup(value, n) |
Round up (ceiling at n decimals) | fx:roundup(1927.31, 1) |
1927.4 |
rounddown(value, n) |
Round down (floor at n decimals) | fx:rounddown(1927.39, 1) |
1927.3 |
ceil(value) |
Ceiling (round up to integer) | fx:ceil(12.1) |
13 |
floor(value) |
Floor (round down to integer) | fx:floor(12.9) |
12 |
abs(value) |
Absolute value | fx:abs(-5) |
5 |
sqrt(value) |
Square root | fx:sqrt(9) |
3 |
pow(base, exp) |
Power | fx:pow(2, 3) |
8 |
pi() |
Pi constant | fx:pi() |
3.14159... |
log(value) |
Natural logarithm (ln) | fx:log(10) |
2.302... |
log10(value) |
Base-10 logarithm | fx:log10(100) |
2 |
min(a, b, ...) |
Minimum of arguments (or array) | fx:min(5, 3, 8) |
3 |
max(a, b, ...) |
Maximum of arguments (or array) | fx:max(5, 3, 8) |
8 |
When n is negative, rounding happens at tens, hundreds, etc.:
fx:round(1927.35, -1) → 1930
fx:round(1927.35, -2) → 1900
| Function | Description | Example | Result |
|---|---|---|---|
& |
String concatenation (converted to + internally) |
fx:"Total: " & holeCount & " holes" |
Total: 142 holes |
upper(text) |
Convert to uppercase | fx:upper("hello") |
HELLO |
lower(text) |
Convert to lowercase | fx:lower("HELLO") |
hello |
trim(text) |
Trim leading/trailing whitespace | fx:trim(entityName) |
Pattern_01 |
left(text, n) |
Left N characters | fx:left("Hello World", 5) |
Hello |
right(text, n) |
Right N characters | fx:right("Hello World", 5) |
World |
mid(text, start, length) |
Substring from start position for length characters | fx:mid("Hello World", 6, 5) |
World |
len(text) |
String length | fx:len("Hello") |
5 |
text(value, fmt) |
Format a number. fmt = "0.00", "0.0", "0" |
fx:text(3.14159, "0.00") |
3.14 |
fixed(value, n) |
Fixed decimal places | fx:fixed(3.14159, 1) |
3.1 |
fx:"Blast: " & blastName & " (" & holeCount & " holes)"
→ Blast: Shot 42 (142 holes)
fx:"PF = " & fixed(powderFactor, 2) & " kg/m³"
→ PF = 0.34 kg/m³
fx:upper(entityName) & " — " & date
→ PATTERN_01 — 28/03/2026
| Function | Description | Example | Result |
|---|---|---|---|
today() |
Today’s date (dd/mm/yyyy locale) | fx:today() |
28/03/2026 |
today(offset) |
Today plus/minus N days | fx:today(-1) |
27/03/2026 |
now() |
Current date and time | fx:now() |
28/03/2026, 14:30:00 |
dateformat(value, fmt, days) |
Format a date, optionally adding days | fx:dateformat(today(), "DDD DD-MM-YY", 1) |
Sun 29-03-26 |
dateformat(fmt) |
Format today’s date (short form) | fx:dateformat("DD/MM/YYYY") |
28/03/2026 |
dateformat(value, format, days) has three parts:
| Part | What it takes |
|---|---|
value |
The date to format: today(), now(), a date written DD/MM/YYYY (with or without a time), a date written YYYY-MM-DD, or "" for now |
format |
The layout, built from the tokens below. Anything that is not a token prints as written |
days |
Optional. Days to add, or subtract with a minus sign, e.g. 1 for tomorrow, -7 for a week ago |
With a single argument, dateformat("DD/MM/YYYY") formats the current date and time, so older templates keep working.
If value is not a date, the cell shows #ERR: not a date.
| Token | Description | Example |
|---|---|---|
YYYY or yyyy |
4-digit year | 2026 |
YY or yy |
2-digit year | 26 |
MMMM |
Month name | March |
MMM |
Short month name | Mar |
MM |
2-digit month (zero-padded) | 03 |
DDDD or dddd |
Day name | Saturday |
DDD or ddd |
Short day name | Sat |
DD or dd |
2-digit day (zero-padded) | 28 |
hh or HH |
2-digit hour (24h, zero-padded) | 14 |
mm |
2-digit minute (zero-padded) | 30 |
ss |
2-digit second (zero-padded) | 00 |
Longer tokens are read first, so DDD is always a day name and never DD followed by a D. Day and month names print in English, whatever language Kirra is set to.
Examples (on Saturday 28 March 2026 at 14:30):
fx:dateformat("YYYY-MM-DD") → 2026-03-28
fx:dateformat("DD/MM/YYYY hh:mm") → 28/03/2026 14:30
fx:dateformat(today(), "DDDD DD MMMM YYYY") → Saturday 28 March 2026
fx:dateformat(today(), "DDD DD-MM-YY", 1) → Sun 29-03-26
fx:dateformat(today(), "DD MMM YYYY", -7) → 21 Mar 2026
fx:dateformat("31/12/2026", "DDDD") → Thursday
| Function | Description | Example | Result |
|---|---|---|---|
if(cond, trueVal, falseVal) |
If condition is true, return trueVal; otherwise falseVal | fx:if(holeCount > 100, "Large", "Small") |
Large |
isnumber(value) |
Returns true if value is a finite number | fx:isnumber(holeCount) |
true |
isblank(value) |
Returns true if value is null, undefined, or empty string | fx:isblank(designer) |
false |
ignore(value) |
Pass-through that prevents row hiding when index is out of range | fx:ignore(holeID[++]) |
value or empty |
fx:if(powderFactor > 0.5, "HIGH", if(powderFactor > 0.3, "OK", "LOW"))
→ OK
Normally, rows with [++] or [+>] that reference holes beyond the hole count are hidden. Wrap in ignore() to keep the row visible with a blank value:
fx:ignore(holeID[++])
| Function | Description | Example | Result |
|---|---|---|---|
connectorList(sep) |
List all connector delay groups with counts, sorted by delay | fx:connectorList(", ") |
25ms x 42, 42ms x 38, 67ms x 12 |
connectorList("\n") |
Same but newline-separated (for multi-line cells) | fx:connectorList("\n") |
One group per line |
connectorCount() |
Total number of connectors | fx:connectorCount() |
92 |
connectorCount(delay) |
Count of connectors with a specific delay (ms) | fx:connectorCount(25) |
42 |
connectorList() groups by delay value, walks each hole’s single fromHoleID, and has
no unit — so on a detonating-cord shot it cannot produce an orderable list. These functions
group by product, count the extra cord feeds and every trunk run, and carry units.
| Function | Description | Example | Result |
|---|---|---|---|
surfaceProductList(sep) |
Surface BOM by product, with units | fx:surfaceProductList(", ") |
5g Detcord: 1240.5m, DRC: 18ea, MSC 25ms: 42ea |
surfaceProductQty(name) |
Quantity of one product (no name = total metres) | fx:surfaceProductQty("DRC") |
18 |
surfaceProductQty(name, allow) |
…plus an allowance | fx:surfaceProductQty("5g Detcord", "+10%") |
1364.6 |
surfaceProductUnit(name) |
m or ea for a product |
fx:surfaceProductUnit("DRC") |
ea |
cordLength() |
Total detonating-cord metres | fx:cordLength() |
1240.5 |
cordLength(allow) |
…plus a waste allowance | fx:cordLength("+10%") |
1364.6 |
harnessLength() |
Total surface-wire metres | fx:harnessLength() |
860.0 |
harnessLength(allow) |
…plus a waste allowance | fx:harnessLength("+10%") |
946.0 |
The waste allowance works on every length — cordLength, harnessLength and
surfaceProductQty all take the same two forms:
| form | meaning | example |
|---|---|---|
"+10%" |
add ten percent | fx:harnessLength("+10%") → 946.0 |
"+10d" |
add ten metres | fx:harnessLength("+10d") → 870.0 |
A negative allowance is honoured too ("-5%"), and the leading + is optional.
It applies only to lengths; asking for a percentage of a connector count would be inventing
connectors, so it is ignored for anything counted ea. An allowance Kirra cannot read
returns the raw figure and logs a warning rather than silently ignoring it — a report that
quietly drops your "+10%" is worse than one that refuses it, because the number still
looks right.
Units. Cord and wire are measured in metres; connectors, downhole detonators, boosters and spacers are counted each; explosives are reported in kilograms. A connector has a tube, but you buy the connector, so it is counted rather than measured.
Whole metres, and whole reels. Metres come back rounded to three decimals at most. Anything coarser is yours to choose, with functions the engine already has:
fx:floor(cordLength()) whole metres, down
fx:ceil(cordLength()) whole metres, up
fx:roundup(cordLength() / 5, 0) * 5 whole 5 m REELS
Cord is bought on a reel — you cannot order 43.2 m — so the last line is the one most plans
want. Change the 5 to your reel length. Kirra deliberately does not round to reels for
you, because reel length varies by supplier and by product.
Trunk runs include the closing leg. A cord loop summed as drawn segments is short by exactly the leg that makes it a loop.
A hole that taps a trunk adds no surface cord. That lead is a downline — a different product family, measured by the depth of its hole.
Metres are raw geometry. Tube is sold on a reel and rounded up to a whole one in practice; apply your own allowance.
Product that Kirra cannot identify is reported under Unassigned rather than dropped — an
absent line would read as “not used”. Set the product on the run in Trunk Properties.
| Function | Description | Example | Result |
|---|---|---|---|
productList(sep) |
List all charged products with total mass, sorted by mass descending | fx:productList(", ") |
ANFO Heavy: 2450.0kg, Emulsion: 1800.5kg |
productMass(name) |
Total mass (kg) of a specific product across all visible holes | fx:productMass("ANFO Heavy") |
2450.0 |
productCount() |
Count of unique product names across all holes | fx:productCount() |
3 |
productCount(name) |
Count of holes that use a specific product | fx:productCount("ANFO Heavy") |
85 |
Pre-built multi-line summaries that group data by entity and hole type.
Two-level grouped summary: entity name then hole type. Shows geometry statistics.
| Parameter | Default | Description |
|---|---|---|
sep |
"\n" |
Line separator |
indent |
" " |
Indent string for nested levels |
Example: fx:blastSummary()
Output:
Blast Name: Pattern_01
Hole Type: Production
Holes: 85
Pattern: B:3.5m x S:4.0m x AvBH:12.0m
Diameter: 165mm
Angle: min:0 deg max:12 deg
Subdrill: min:0.8m max:1.2m
Total Meters: 1150.5m
Hole Type: Buffer
Holes: 42
Pattern: B:2.8m x S:3.2m x AvBH:12.0m
Diameter: 127mm
...
Two-level grouped charging summary: entity name then hole type. Shows charging statistics.
| Parameter | Default | Description |
|---|---|---|
sep |
"\n" |
Line separator |
indent |
" " |
Indent string for nested levels |
Example: fx:chargeSummary()
Output:
Blast Name: Pattern_01
Hole Type: Production
Charged: 85 of 85 holes
Depth to First Charge: avg:3.5m min:3.0m max:4.0m
Charge Length: avg:8.5m min:7.8m max:9.2m
Total Mass: 4250.0 kg (avg:50.0 kg/hole)
Powder Factor: avg:0.34 kg/m³
Products: ANFO Heavy: 2450.0kg, Emulsion: 1800.5kg
Primers: 170 (Pentex 400g x 170)
Render tokens produce graphics (images), not text. The merged cell area in the XLSX determines the image dimensions. Place one render token per merged cell region.
| Formula | Description |
|---|---|
fx:mapView |
Map view with default raster rendering |
fx:mapView(r) |
Raster map (holes, surfaces, images, KADs) |
fx:mapView(r, 300) |
Raster map at 300 DPI (default is 200) |
fx:mapView(v) |
Vector map (crisp scalable lines and text) |
fx:mapView(v, 8) |
Vector map with 8pt label font size |
A number above 50 after the mode is read as the DPI, and a smaller number as a label font size. Ticking Override template DPI setting in the PDF Print dialog replaces the DPI in every map view. See Map View Resolution.
Append display codes after the mode and font/DPI to control exactly what appears on the map. When display codes are specified, only those items are drawn (whitelist mode). When omitted, the current screen display settings are used.
| Formula | Description |
|---|---|
fx:mapView(r, hid, len) |
Raster showing only hole IDs and lengths |
fx:mapView(v, 8, hid, len, tie) |
Vector 8pt with hole IDs, lengths, and connectors |
fx:mapView(r, hid, len, vor.sdb.mm) |
Raster with hole IDs, lengths, and Voronoi SDoB (min-max legend) |
fx:mapView(v, hid, dia, ang, chg) |
Vector with IDs, diameters, angles, and charge columns |
See Display Codes for mapView and legend for the full code list.
| Formula | Description |
|---|---|
fx:northArrow |
North arrow graphic |
fx:scale |
Scale bar + scale text combined |
fx:scaleBar |
Scale bar graphic only |
fx:scaleText |
Scale text only (e.g. 1:500) |
fx:logo |
User logo image |
fx:qrcode |
QR code graphic |
fx:connectorCount |
Connector count table (graphical) |
| Formula | Description |
|---|---|
fx:holeSection("Pattern_01", "H001") |
Single hole charging cross-section |
fx:sectionView("Pattern_01", "H001", "H010") |
Multi-hole bench cross-section between two holes |
Section view arguments can use scalar variables or indexed references:
fx:holeSection(entityName, holeID[1])
fx:sectionView(entityName, holeID[1], holeID[10])
| Formula | Description |
|---|---|
fx:legend(vor.pfd, h) |
Legend for PF Designed, horizontal layout |
fx:legend(vor.sdb.fx, v) |
Legend for SDoB, fixed range, vertical layout |
fx:legend(slp, h) |
Slope angle legend, horizontal |
fx:legend(rel, v) |
Burden relief legend, vertical |
See Legend Codes for all options.
These 3-letter codes control what elements appear on the printed map. Use them as additional arguments in mapView() or as the first argument in legend().
| Code | Display Element | Description |
|---|---|---|
hid |
Hole ID | Hole identifier label |
len |
Hole Length | Hole length value |
dia |
Diameter | Hole diameter value |
ang |
Angle | Hole angle from vertical |
ber |
Bearing | Hole bearing from north |
dip |
Dip | Hole dip (mast angle) |
sub |
Subdrill | Subdrill amount |
typ |
Hole Type | Hole type label |
rap |
Row/Pos ID | Row and Position ID labels |
xlc |
X Coordinate | Collar X (easting) value |
ylc |
Y Coordinate | Collar Y (northing) value |
zlc |
Z Coordinate | Collar Z (elevation) value |
| Code | Display Element | Description |
|---|---|---|
tie |
Connectors | Timing connector lines between holes |
del |
Delay Value | Delay value labels on connectors |
htm |
Initiation Time | Hole initiation (firing) time label |
dtm |
Downhole Timing | Downhole timing display |
fmv |
First Movement | First movement vector display |
| Code | Display Element | Description |
|---|---|---|
chg |
Charges | Charge column display on holes |
hkg |
Mass per Hole | Total mass label per hole |
dkg |
Mass per Deck | Mass label per deck |
| Code | Display Element | Description |
|---|---|---|
mln |
Measured Length | Measured length value |
mms |
Measured Mass | Measured mass value |
mcm |
Measured Comment | Measured comment text |
mwt |
Measured Water | Measured water value |
| Code | Display Element | Description |
|---|---|---|
con |
Contour | Surface contour lines |
slp |
Slope Map | Slope angle overlay |
rel |
Burden Relief | Burden relief overlay |
kpt |
KAD Point ID | KAD drawing point IDs |
Voronoi codes control which metric is displayed when Voronoi cells are rendered. Use as display codes in mapView() or as legend codes in legend().
Each Voronoi code has three variants:
vor.pfd) — uses current screen legend setting.fx suffix (e.g. vor.pfd.fx) — forces fixed-range legend.mm suffix (e.g. vor.pfd.mm) — forces min-max (data-range) legend| Code | Metric | Unit |
|---|---|---|
vor.pfd |
Powder Factor — Designed | kg/m3 |
vor.pfm |
Powder Factor — Measured | kg/m3 |
vor.dms |
Design Mass | kg |
vor.mms |
Measured Mass | kg |
vor.vol |
Cell Volume | m3 |
vor.are |
Cell Area | m2 |
vor.dln |
Design Length | m |
vor.mln |
Measured Length | m |
vor.hft |
Hole Firing Time | ms |
vor.sdb |
Scaled Depth of Burial (SDoB) | m/kg^1/3 |
fx:mapView(r, hid, vor.pfd.fx) → Raster map with hole IDs and PF Designed (fixed legend)
fx:mapView(v, 8, hid, len, vor.sdb.mm) → Vector 8pt, IDs, lengths, SDoB (min-max legend)
fx:legend(vor.pfd.fx, h) → Horizontal PF Designed legend (fixed range)
fx:legend(vor.sdb.mm, v) → Vertical SDoB legend (min-max range)
The legend() render token accepts a display/metric code and an orientation.
Syntax: fx:legend(code, orientation)
| Orientation | Value |
|---|---|
| Horizontal | h (default) |
| Vertical | v |
| Code | Legend Type | Bands |
|---|---|---|
slp or slope |
Slope Angle | 0-5, 5-7, 7-9, 9-12, 12-15, 15-17, 17-20, 20+ degrees |
rel or relief |
Burden Relief | <4, 4-7, 7-10, 10-13, 13-16, 16-19, 19-22, 22-25, 25-30, 30-40, 40+ |
vor.pfd |
PF Designed | Continuous gradient 0 to max |
vor.pfm |
PF Measured | Continuous gradient 0 to max |
vor.dms |
Design Mass | Continuous gradient |
vor.mms |
Measured Mass | Continuous gradient |
vor.vol |
Cell Volume | Continuous gradient |
vor.are |
Cell Area | Continuous gradient |
vor.dln |
Design Length | Continuous gradient |
vor.mln |
Measured Length | Continuous gradient |
vor.hft |
Hole Firing Time | Continuous gradient |
vor.sdb |
SDoB | Continuous gradient |
All Voronoi legend codes support .fx (fixed range) and .mm (min-max range) suffixes.
| Cell | Formula | Result |
|---|---|---|
| B2 | fx:blastName |
Shot 42 |
| B3 | fx:designer |
J. Smith |
| B4 | fx:dateformat("DD/MM/YYYY") |
28/03/2026 |
| B5 | fx:"1:" & printScale |
1:500 |
| B6 | fx:holeCount & " holes" |
142 holes |
| B7 | fx:round(drillMetres, 1) & "m" |
1927.4m |
| B8 | fx:fixed(powderFactor, 2) & " kg/m³" |
0.34 kg/m³ |
| Column A | Column B | Column C | Column D | Column E |
|---|---|---|---|---|
fx:holeID[++] |
fx:round(holeLength[++], 1) |
fx:holeDiameter[++] |
fx:round(startZ[++], 2) |
fx:holeType[++] |
Each row auto-fills with the next hole. Rows beyond the hole count are hidden.
| Cell | Formula | Result |
|---|---|---|
| C10 | fx:sum(holeLength[i]) |
1927.35 |
| C11 | fx:round(avg(holeLength[i]), 1) |
13.6 |
| C12 | fx:min(holeLength[i]) & " - " & max(holeLength[i]) |
11.2 - 16.8 |
| C13 | fx:sortCount(holeType[i], ", ") |
Production: 85, Buffer: 42, Presplit: 15 |
| Cell | Formula | Result |
|---|---|---|
| D10 | fx:round(sum(totalMass[i]), 1) & " kg" |
4250.0 kg |
| D11 | fx:productList("\n") |
ANFO Heavy: 2450.0kg (newline) Emulsion: 1800.5kg |
| D12 | fx:round(avg(firstChargeTop[i]), 1) & "m avg stem" |
3.5m avg stem |
| D13 | fx:connectorList(", ") |
25ms x 42, 42ms x 38 |
A merged cell spanning B15:J45 contains:
fx:mapView(r, hid, len, vor.sdb.mm)
This renders a raster map showing only:
Sheet 1 — Overview map:
fx:mapView(v, 8, hid, tie, del)
Vector map at 8pt font showing hole IDs, connector ties, and delay values.
Sheet 2 — Charging detail:
fx:mapView(r, hid, chg, hkg)
Raster map showing hole IDs, charge columns, and mass per hole.
Sheet 3 — Voronoi analysis:
fx:mapView(r, hid, vor.pfd.fx)
Raster map showing hole IDs and Voronoi PF Designed with fixed-range legend.
fx:filter(holeType == "Production")
Then in the table rows below:
| A | B | C |
|---|---|---|
fx:holeID[++] |
fx:round(holeLength[++], 1) |
fx:round(totalMass[++], 1) |
Only Production holes appear in the table.
fx:groupTable(holeType[i], "{key}: {count} holes, {sum:holeLength}m drilled, avg dia {avg:holeDiameter}mm", "\n")
Result:
Production: 85 holes, 1150.5m drilled, avg dia 165.0mm
Buffer: 42 holes, 525.0m drilled, avg dia 127.0mm
Presplit: 15 holes, 251.8m drilled, avg dia 89.0mm
fx:if(powderFactor > 0.5, "WARNING: High PF", "PF OK: " & fixed(powderFactor, 2) & " kg/m³")
[+>]A 3-column x 10-row grid where each cell holds one hole ID:
| A | B | C |
|---|---|---|
fx:holeID[+>] |
fx:holeID[+>] |
fx:holeID[+>] |
fx:holeID[+>] |
fx:holeID[+>] |
fx:holeID[+>] |
| … | … | … |
Fills left-to-right, top-to-bottom: cell A1 = hole 1, B1 = hole 2, C1 = hole 3, A2 = hole 4, etc. Auto-paginates to additional sheets if there are more holes than cells.