nx_chartlay_lib.nx
buildroot/runtime/nx_chartlay_lib.nx
about
nx_chartlay_lib.nx -- THE ONE chart-layout ruler for every SVG chart the compare emitters draw (datavis DV1, 2026-09-15).
Domain-fit scales with nice ticks, integer linear scaling, a colour-blind-safe categorical palette (Okabe-Ito, the
house accent in slot 0), text-width estimates, greedy collision-free label placement with leader lines, and the
READABILITY CRITIC (label-label, label-mark and mark-mark overlaps, off-canvas labels, data spread) so a render
GRADES ITSELF before it ships and prints the grade beside the picture. Born of the operator's 2026-09-15 junk verdict
on the position map: five marks in one corner of a fixed 0..1000 canvas, labels overlapping and clipped at the right
edge, a cube nobody could read. Pure integer arithmetic, struct-free, so the laptop toolchain proves it too.
The field's practice this encodes (Datawrapper, Observable Plot, Vega-Lite: 4..7 gridlines, axes fit to the data with
a breathing pad, direct labels that never collide, one palette that survives colour-vision deficiency) is the ORACLE;
nothing here links, forks or shells any of them -- they stay outside the build path as liar-killers and benchmarks.
license_tier: ORIGINAL
dependencies 2 imports · 3 importers
imports: nx_syscalls.nxnx_uiq_color.nx
imported by: nx_cdmap_referee_lib.nxnx_chartlay_gate.nxnx_swcompare_lib.nx
structs
| none |
consts
| 15 | const CL_PERMIL: i64 = 1000 |
| 16 | const CL_I64_BYTES: i64 = 8 |
| 17 | const CL_TWO: i64 = 2 |
| 18 | const CL_TICKS_MAX: i64 = 7 // the most ticks an axis wants: pick the smallest nice step that needs no more |
| 19 | const CL_PAD_PERMIL: i64 = 120 // breathing pad each side of the data span, permil of the span |
| 20 | const CL_PAD_MIN: i64 = 20 // ...never less than this many permil, so a tight cluster still breathes |
| 21 | const CL_STEP_N: i64 = 9 |
| 22 | const CL_STEP_10: i64 = 10 |
| 23 | const CL_STEP_20: i64 = 20 |
| 24 | const CL_STEP_25: i64 = 25 |
| 25 | const CL_STEP_50: i64 = 50 |
| 26 | const CL_STEP_100: i64 = 100 |
| 27 | const CL_STEP_200: i64 = 200 |
| 28 | const CL_STEP_250: i64 = 250 |
| 29 | const CL_STEP_500: i64 = 500 |
| 30 | const CL_STEP_1000: i64 = 1000 |
| 31 | const CL_S0: i64 = 0 |
| 32 | const CL_S1: i64 = 1 |
| 33 | const CL_S2: i64 = 2 |
| 34 | const CL_S3: i64 = 3 |
| 35 | const CL_S4: i64 = 4 |
| 36 | const CL_S5: i64 = 5 |
| 37 | const CL_S6: i64 = 6 |
| 38 | const CL_S7: i64 = 7 |
| 39 | const CL_DOM_W: i64 = 3 // a domain record: lo, hi, step |
| 40 | const CL_D_LO: i64 = 0 |
| 41 | const CL_D_HI: i64 = 1 |
| 42 | const CL_D_STEP: i64 = 2 |
| 43 | const CL_TEXT_W_PERMIL: i64 = 560 // mean glyph advance of a sans face at 1 em (digits and lower case read 0.50..0.61 em) |
| 44 | const CL_LINE_H_PERMIL: i64 = 1250 // a one-line label box is 1.25 em tall |
| 45 | const CL_GAP: i64 = 6 // px between a mark's edge and its label box |
| 46 | const CL_LEAD_MULT: i64 = 3 // a leader-line candidate sits CL_GAP * this from the mark |
| 47 | const CL_CAND_N: i64 = 8 |
| 48 | const CL_CAND_RIGHT: i64 = 0 |
| 49 | const CL_CAND_LEFT: i64 = 1 |
| 50 | const CL_CAND_ABOVE: i64 = 2 |
| 51 | const CL_CAND_BELOW: i64 = 3 |
| 52 | const CL_CAND_RU: i64 = 4 // right-up with a leader |
| 53 | const CL_CAND_LU: i64 = 5 |
| 54 | const CL_CAND_RD: i64 = 6 |
| 55 | const CL_CAND_LD: i64 = 7 |
| 56 | const CL_CAND_LEADER_FROM: i64 = 4 // candidates at or past this index need a leader line |
| 57 | const CL_CRIT_W: i64 = 6 |
| 58 | const CL_C_LL: i64 = 0 // label-label overlapping pairs |
| 59 | const CL_C_LM: i64 = 1 // label-over-mark overlaps |
| 60 | const CL_C_OFF: i64 = 2 // labels outside the canvas |
| 61 | const CL_C_MM: i64 = 3 // mark-mark overlapping pairs (a property of the data, reported never hidden) |
| 62 | const CL_C_SPREAD: i64 = 4 // permil of the plot the data bounding box spans, mean of the two axes |
| 63 | const CL_C_DEFECTS: i64 = 5 // LL + LM + OFF: what a reader cannot read |
| 64 | const CL_PAL_N: i64 = 8 |
| 65 | const CL_PAL_ACCENT: i64 = 0 |
| 66 | const CL_PAL_RIVALS: i64 = 7 |
| 261 | const CL_RESEAT_N: i64 = 5 |
| 293 | const CL_CT_W: i64 = 5 |
| 294 | const CL_CT_SMALL: i64 = 0 // floor x100 for text below the large tier |
| 295 | const CL_CT_LARGE: i64 = 1 // floor x100 for large text |
| 296 | const CL_CT_LARGE_PX: i64 = 2 // regular text at or past this px is large |
| 297 | const CL_CT_LARGE_BOLD_PX: i64 = 3 // bold text at or past this px is large |
| 298 | const CL_CT_LOADED: i64 = 4 // 0 defaults (no conf) / 1 conf read / 2 conf names an unimplemented algorithm (defaults, announced) |
| 299 | const CL_CT_DEFAULT_SMALL: i64 = 450 |
| 300 | const CL_CT_DEFAULT_LARGE: i64 = 300 |
| 301 | const CL_CT_DEFAULT_LARGE_PX: i64 = 18 |
| 302 | const CL_CT_DEFAULT_LARGE_BOLD_PX: i64 = 14 |
| 303 | const CL_CT_ALGORITHM: *u8 = "wcag2-ratio" |
| 304 | const CL_CT_UNKNOWN_ALG: i64 = 2 |
| 305 | const CL_CT_CH_PIPE: i64 = 124 |
| 306 | const CL_CT_CH_NL: i64 = 10 |
| 307 | const CL_CT_CH_0: i64 = 48 |
| 308 | const CL_CT_CH_9: i64 = 57 |
| 309 | const CL_CT_BASE10: i64 = 10 |
functions
| 68 | func chl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } // chl_, not cl_: nx_catalog_lib owns cl_slen in the emitter's closure |
| 69 | func cl_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } |
| 70 | func cl_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } |
| 71 | func cl_step_at(i: i64) -> i64 called by 1: cl_nice_step |
| 83 | func cl_nice_step(span: i64) -> i64 |
| 88 | func cl_floor_to(v: i64, step: i64) -> i64 { return v - (v % step) } called by 1: cl_domain |
| 89 | func cl_ceil_to(v: i64, step: i64) -> i64 { let r: i64 = v % step; if r == 0 { return v } return v + step - r } called by 1: cl_domain |
| 92 | func cl_domain(vmin: i64, vmax: i64, dom: *i64) -> i64 |
| 113 | func cl_tick(dom: *i64, i: i64) -> i64 { return dom[CL_D_LO] + i * dom[CL_D_STEP] } called by 1: main |
| 114 | func cl_ticks(dom: *i64) -> i64 { return (dom[CL_D_HI] - dom[CL_D_LO]) / dom[CL_D_STEP] + 1 } called by 1: main |
| 116 | func cl_scale(v: i64, lo: i64, hi: i64, p0: i64, p1: i64) -> i64 { if hi == lo { return p0 } return p0 + (v - lo) * (p1 - p0) / (hi - lo) } |
| 117 | func cl_scale_dom(v: i64, dom: *i64, p0: i64, p1: i64) -> i64 { return cl_scale(v, dom[CL_D_LO], dom[CL_D_HI], p0, p1) } |
| 118 | func cl_text_w(nchars: i64, font_px: i64) -> i64 { return nchars * font_px * CL_TEXT_W_PERMIL / CL_PERMIL } |
| 119 | func cl_text_h(font_px: i64) -> i64 { return font_px * CL_LINE_H_PERMIL / CL_PERMIL } |
| 120 | func cl_box_hit(ax: i64, ay: i64, aw: i64, ah: i64, bx: i64, by: i64, bw: i64, bh: i64) -> i64 |
| 127 | func cl_leader(k: i64) -> i64 { if k >= CL_CAND_LEADER_FROM { return 1 } return 0 } called by 1: main |
| 129 | func cl_cand(k: i64, mx: i64, my: i64, mr: i64, lw: i64, lh: i64, xy: *i64) -> i64 |
| 144 | func cl_fits(i: i64, x: i64, y: i64, n: i64, mx: *i64, my: *i64, mr: *i64, lx: *i64, ly: *i64, lw: *i64, lh: *i64, placed: *i64, x0: i64, y0: i64, x1: i64, y1: i64) -> i64 |
| 162 | func cl_place(n: i64, mx: *i64, my: *i64, mr: *i64, lw: *i64, lh: *i64, x0: i64, y0: i64, x1: i64, y1: i64, lx: *i64, ly: *i64, lside: *i64, lres: *i64) -> i64 |
| 170 | func cl_place_from(n: i64, nfixed: i64, mx: *i64, my: *i64, mr: *i64, lw: *i64, lh: *i64, x0: i64, y0: i64, x1: i64, y1: i64, lx: *i64, ly: *i64, lside: *i64, lres: *i64) -> i64 |
| 201 | func cl_critic(n: i64, mx: *i64, my: *i64, mr: *i64, lx: *i64, ly: *i64, lw: *i64, lh: *i64, x0: i64, y0: i64, x1: i64, y1: i64, out: *i64) -> i64 |
| 245 | func cl_palette(i: i64) -> *u8 |
| 262 | func cl_reseat_in(i: i64, n: i64, mx: *i64, my: *i64, mr: *i64, lx: *i64, ly: *i64, lw: *i64, lh: *i64, rx0: i64, ry0: i64, rx1: i64, ry1: i64) -> i64 |
| 310 | func cl_contrast(fr: i64, fg: i64, fb: i64, br: i64, bg: i64, bb: i64) -> i64 { return uiq_ratio100(fr, fg, fb, br, bg, bb) } |
| 312 | func cl_blend(top: i64, under: i64, a_permil: i64) -> i64 { return (top * a_permil + under * (CL_PERMIL - a_permil)) / CL_PERMIL } called by 1: main |
| 313 | func cl_contrast_defaults(ct: *i64) -> i64 called by 1: cl_contrast_conf |
| 321 | func cl_contrast_floor(font_px: i64, bold: i64, ct: *i64) -> i64 called by 1: main |
| 326 | func cl_contrast_ok(x100: i64, floor: i64) -> i64 { if x100 >= floor { return 1 } return 0 } called by 1: main |
| 328 | func cl_ct_field(b: *u8, s: i64, e: i64, f: i64) -> i64 |
| 334 | func cl_ct_field_is(b: *u8, s: i64, e: i64, f: i64, lit: *u8) -> i64 |
| 342 | func cl_ct_field_int(b: *u8, s: i64, e: i64, f: i64) -> i64 |
| 351 | func cl_contrast_conf(path: *u8, ct: *i64) -> i64 |
| 377 | func cl_palette_name(i: i64) -> *u8 |