@thilakbhat/heatmap-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +471 -0
  3. package/dist/calendar.d.ts +40 -0
  4. package/dist/calendar.d.ts.map +1 -0
  5. package/dist/calendar.js +136 -0
  6. package/dist/calendar.js.map +1 -0
  7. package/dist/colors.d.ts +112 -0
  8. package/dist/colors.d.ts.map +1 -0
  9. package/dist/colors.js +186 -0
  10. package/dist/colors.js.map +1 -0
  11. package/dist/grid.d.ts +26 -0
  12. package/dist/grid.d.ts.map +1 -0
  13. package/dist/grid.js +102 -0
  14. package/dist/grid.js.map +1 -0
  15. package/dist/heatmap.d.ts +4 -0
  16. package/dist/heatmap.d.ts.map +1 -0
  17. package/dist/heatmap.js +134 -0
  18. package/dist/heatmap.js.map +1 -0
  19. package/dist/heatmap3d-patterns.d.ts +19 -0
  20. package/dist/heatmap3d-patterns.d.ts.map +1 -0
  21. package/dist/heatmap3d-patterns.js +57 -0
  22. package/dist/heatmap3d-patterns.js.map +1 -0
  23. package/dist/heatmap3d-scene.d.ts +49 -0
  24. package/dist/heatmap3d-scene.d.ts.map +1 -0
  25. package/dist/heatmap3d-scene.js +104 -0
  26. package/dist/heatmap3d-scene.js.map +1 -0
  27. package/dist/heatmap3d-visuals.d.ts +30 -0
  28. package/dist/heatmap3d-visuals.d.ts.map +1 -0
  29. package/dist/heatmap3d-visuals.js +50 -0
  30. package/dist/heatmap3d-visuals.js.map +1 -0
  31. package/dist/heatmap3d.d.ts +6 -0
  32. package/dist/heatmap3d.d.ts.map +1 -0
  33. package/dist/heatmap3d.js +268 -0
  34. package/dist/heatmap3d.js.map +1 -0
  35. package/dist/index.d.ts +11 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +11 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/projection3d.d.ts +29 -0
  40. package/dist/projection3d.d.ts.map +1 -0
  41. package/dist/projection3d.js +55 -0
  42. package/dist/projection3d.js.map +1 -0
  43. package/dist/scale.d.ts +21 -0
  44. package/dist/scale.d.ts.map +1 -0
  45. package/dist/scale.js +61 -0
  46. package/dist/scale.js.map +1 -0
  47. package/dist/shapes.d.ts +13 -0
  48. package/dist/shapes.d.ts.map +1 -0
  49. package/dist/shapes.js +63 -0
  50. package/dist/shapes.js.map +1 -0
  51. package/dist/static-svg.d.ts +45 -0
  52. package/dist/static-svg.d.ts.map +1 -0
  53. package/dist/static-svg.js +177 -0
  54. package/dist/static-svg.js.map +1 -0
  55. package/dist/types.d.ts +151 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -0
  59. package/docs/cover.png +0 -0
  60. package/docs/playground-2d.png +0 -0
  61. package/docs/playground-3d.png +0 -0
  62. package/package.json +61 -0
  63. package/src/styles.css +385 -0
package/dist/shapes.js ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Shape geometry. Rounded, square and circle are corner radii; the rest are
3
+ * clip paths, which keeps every shape a single element that can still carry a
4
+ * background, an outline and a transition.
5
+ */
6
+ const CLIP_PATHS = {
7
+ diamond: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)",
8
+ hexagon: "polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)",
9
+ plus: "polygon(35% 0%, 65% 0%, 65% 35%, 100% 35%, 100% 65%, 65% 65%, " +
10
+ "65% 100%, 35% 100%, 35% 65%, 0% 65%, 0% 35%, 35% 35%)",
11
+ };
12
+ const RADII = {
13
+ rounded: "22%",
14
+ square: "0",
15
+ circle: "50%",
16
+ bar: "2px",
17
+ ring: "50%",
18
+ };
19
+ /** Hexagons tile only when alternate rows are offset by half a column. */
20
+ export function rowOffset(shape, row, columnWidth) {
21
+ return shape === "hexagon" && row % 2 === 1 ? columnWidth / 2 : 0;
22
+ }
23
+ /** Hexagon rows interlock, so they sit closer together than their box height. */
24
+ export function rowSpacing(shape, cellSize, gap) {
25
+ return shape === "hexagon" ? cellSize * 0.75 + gap : cellSize + gap;
26
+ }
27
+ export function shapeStyle(shape, radius) {
28
+ const style = {};
29
+ const clipPath = CLIP_PATHS[shape];
30
+ if (clipPath)
31
+ style.clipPath = clipPath;
32
+ if (radius !== undefined) {
33
+ style.borderRadius = typeof radius === "number" ? radius + "px" : radius;
34
+ }
35
+ else if (RADII[shape]) {
36
+ style.borderRadius = RADII[shape];
37
+ }
38
+ return style;
39
+ }
40
+ /**
41
+ * `bar` grows from the bottom and `ring` thickens inward, so both express
42
+ * intensity through geometry and need the level to draw themselves.
43
+ */
44
+ export function fillStyle(shape, level, levels, color, cellSize) {
45
+ const intensity = levels > 0 ? level / levels : 0;
46
+ if (shape === "bar") {
47
+ return {
48
+ height: Math.max(2, Math.round(cellSize * Math.max(intensity, 0.08))) + "px",
49
+ alignSelf: "end",
50
+ background: color,
51
+ };
52
+ }
53
+ if (shape === "ring") {
54
+ const thickness = Math.max(1, Math.round((cellSize / 2) * Math.max(intensity, 0.18)));
55
+ return {
56
+ background: "transparent",
57
+ border: thickness + "px solid " + color,
58
+ boxSizing: "border-box",
59
+ };
60
+ }
61
+ return { background: color };
62
+ }
63
+ //# sourceMappingURL=shapes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shapes.js","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,GAA0C;IACxD,OAAO,EAAE,6CAA6C;IACtD,OAAO,EAAE,+DAA+D;IACxE,IAAI,EACF,gEAAgE;QAChE,uDAAuD;CAC1D,CAAC;AAEF,MAAM,KAAK,GAA0C;IACnD,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,KAAK;IACb,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,KAAmB,EAAE,GAAW,EAAE,WAAmB;IAC7E,OAAO,KAAK,KAAK,SAAS,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,QAAgB,EAAE,GAAW;IAC3E,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAmB,EACnB,MAAmC;IAEnC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,QAAQ;QAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAExC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,CAAC,YAAY,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3E,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CACvB,KAAmB,EACnB,KAAa,EACb,MAAc,EACd,KAAa,EACb,QAAgB;IAEhB,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAElD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI;YAC5E,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,KAAK;SAClB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACtF,OAAO;YACL,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,KAAK;YACvC,SAAS,EAAE,YAAY;SACxB,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { Heatmap3DAnimation, Heatmap3DBlockStyle, Heatmap3DFace, Heatmap3DFaceColor, Heatmap3DMaterial, Heatmap3DPattern, Heatmap3DShape, Heatmap3DThemeName, HeatmapScale, HeatmapValues, ResolvedCell } from "./types.js";
2
+ export type Heatmap3DSvgLabel = string | number;
3
+ /** Options for an accessible, non-interactive SVG snapshot of a 3D heatmap. */
4
+ export type Heatmap3DSvgOptions = {
5
+ rows: number;
6
+ columns: number;
7
+ values?: HeatmapValues;
8
+ scale?: HeatmapScale;
9
+ levels?: number;
10
+ thresholds?: readonly number[];
11
+ shape?: Heatmap3DShape;
12
+ blockStyle?: Heatmap3DBlockStyle;
13
+ cellSize?: number;
14
+ gap?: number;
15
+ maxHeight?: number;
16
+ heightDomain?: readonly [number, number];
17
+ yaw?: number;
18
+ pitch?: number;
19
+ zoom?: number;
20
+ colors?: readonly string[];
21
+ emptyColor?: string;
22
+ unknownOpacity?: number;
23
+ theme?: Heatmap3DThemeName;
24
+ material?: Heatmap3DMaterial;
25
+ patterns?: Partial<Record<Heatmap3DFace, readonly Heatmap3DPattern[]>>;
26
+ faceColor?: Heatmap3DFaceColor;
27
+ animation?: Heatmap3DAnimation;
28
+ isSlotHidden?: (row: number, column: number) => boolean;
29
+ rowLabels?: readonly Heatmap3DSvgLabel[];
30
+ columnLabels?: readonly {
31
+ column: number;
32
+ text: Heatmap3DSvgLabel;
33
+ }[];
34
+ cellLabel?: (cell: ResolvedCell) => string;
35
+ showLegend?: boolean;
36
+ ariaLabel?: string;
37
+ className?: string;
38
+ };
39
+ /**
40
+ * Render the same scene model as `Heatmap3D` without React or a DOM. The
41
+ * result is suitable for a README, email, GitHub image, SSR response, or a
42
+ * cached asset generated by a scheduled job.
43
+ */
44
+ export declare function renderHeatmap3DSvg({ rows, columns, values, scale, levels: levelsProp, thresholds, shape, blockStyle, cellSize, gap, maxHeight: maxHeightProp, heightDomain, yaw, pitch, zoom, colors, emptyColor, unknownOpacity, theme: themeProp, material, patterns, faceColor, animation, isSlotHidden, rowLabels, columnLabels, cellLabel, showLegend, ariaLabel, className, }: Heatmap3DSvgOptions): string;
45
+ //# sourceMappingURL=static-svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-svg.d.ts","sourceRoot":"","sources":["../src/static-svg.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EAEnB,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD,+EAA+E;AAC/E,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACvE,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACxD,SAAS,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACzC,YAAY,CAAC,EAAE,SAAS;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,iBAAiB,CAAA;KAAE,EAAE,CAAC;IACtE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA6HF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,KAAgB,EAChB,MAAM,EAAE,UAAU,EAClB,UAAU,EACV,KAAmB,EACnB,UAAoB,EACpB,QAAa,EACb,GAAO,EACP,SAAS,EAAE,aAAmB,EAC9B,YAAY,EACZ,GAAG,EACH,KAAK,EACL,IAAI,EACJ,MAAM,EACN,UAAU,EACV,cAAoB,EACpB,KAAK,EAAE,SAAS,EAChB,QAAkB,EAClB,QAAQ,EACR,SAAS,EACT,SAAkB,EAClB,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAkB,EAClB,SAAS,EACT,SAAS,GACV,EAAE,mBAAmB,GAAG,MAAM,CA+E9B"}
@@ -0,0 +1,177 @@
1
+ import { resolve3DTheme } from "./colors.js";
2
+ import { buildCells } from "./grid.js";
3
+ import { buildHeatmap3DScene, cameraDirection, point, rectangle } from "./heatmap3d-scene.js";
4
+ import { patternPath } from "./heatmap3d-patterns.js";
5
+ import { normalizeCamera, polygonPath, projectPoint, resolveHeightDomain } from "./projection3d.js";
6
+ import { heatmap3DLegendColors, resolveHeatmap3DPattern, resolveHeatmap3DVisual } from "./heatmap3d-visuals.js";
7
+ const finitePositive = (value, fallback) => Number.isFinite(value) ? Math.max(0, value) : fallback;
8
+ function escapeXml(value) {
9
+ return String(value)
10
+ .replace(/&/g, "&amp;")
11
+ .replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;")
13
+ .replace(/"/g, "&quot;")
14
+ .replace(/'/g, "&apos;");
15
+ }
16
+ function number(value) {
17
+ return Number.isFinite(value) ? value.toFixed(3).replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1") : "0";
18
+ }
19
+ function labelWidth(value, minimum, factor) {
20
+ return typeof value === "string" ? Math.max(minimum, value.length * factor) : minimum;
21
+ }
22
+ function formatValue(value) {
23
+ return new Intl.NumberFormat(undefined, {
24
+ notation: Math.abs(value) >= 10000 ? "compact" : "standard",
25
+ maximumFractionDigits: 1,
26
+ }).format(value);
27
+ }
28
+ function surfaceMarkup(face, camera, visual) {
29
+ const path = polygonPath(face.points, camera);
30
+ const pattern = visual.patternId(face.face);
31
+ const fill = visual.faceColor(face.face);
32
+ const base = pattern
33
+ ? `<path d="${path}" fill="${escapeXml(fill)}" class="heatmap3d__surface heatmap3d__surface-base" data-face="${face.face}" pointer-events="none"/>`
34
+ : "";
35
+ const surface = `<path d="${path}" fill="${pattern ? `url(#${escapeXml(pattern)})` : escapeXml(fill)}" class="heatmap3d__surface" data-face="${face.face}" data-material="${pattern ? "pattern" : "solid"}/>`;
36
+ const shade = `<path d="${path}" fill="${face.shade >= 0 ? "#fff" : "#071b19"}" opacity="${number(Math.abs(face.shade))}" pointer-events="none"/>`;
37
+ const windows = (face.windows ?? []).map((window, index) => `<path d="${polygonPath(window, camera)}" class="heatmap3d__window" opacity="${index % 5 === 0 ? 0.2 : index % 3 === 0 ? 0.65 : 0.42}" pointer-events="none"/>`).join("");
38
+ return `<g>${base}${surface}${shade}${windows}</g>`;
39
+ }
40
+ function cellMarkup(entry, motionIndex, camera, options, cellLabel, unknownOpacity = 0.5) {
41
+ const { cell, geometry, height } = entry;
42
+ const visual = resolveHeatmap3DVisual({ cell, options });
43
+ const label = cellLabel?.(cell) ?? `Row ${cell.row + 1}, column ${cell.column + 1}: ${cell.known ? cell.value : "no data"}`;
44
+ const body = !cell.known
45
+ ? `<path d="${polygonPath(geometry.footprint, camera)}" fill="transparent" class="heatmap3d__unknown" opacity="${number(unknownOpacity)}"/>`
46
+ : [
47
+ ...geometry.faces.map((face) => surfaceMarkup(face, camera, visual)),
48
+ geometry.roof ? `<path d="${polygonPath(geometry.roof, camera)}" class="heatmap3d__roof"/>` : "",
49
+ ...geometry.studs.flatMap((faces) => faces.map((face) => surfaceMarkup(face, camera, visual))),
50
+ ].join("");
51
+ return `<g class="heatmap3d__cell" data-row="${cell.row}" data-column="${cell.column}" data-known="${cell.known ? "true" : "false"}" data-value="${number(cell.value)}" data-height="${number(height)}" data-level="${cell.level}" data-material="${options.material}" style="--heatmap3d-index:${motionIndex}" role="img" aria-label="${escapeXml(label)}"><title>${escapeXml(label)}</title>${body}</g>`;
52
+ }
53
+ function sceneBounds({ geometry, width, depth, size, maxHeight, camera, rows, columns, step, rowLabels, columnLabels, }) {
54
+ const facing = cameraDirection(camera);
55
+ const rowEdge = facing.x > 0.001 ? 1 : -1;
56
+ const columnEdge = facing.y >= 0 ? 1 : -1;
57
+ const rowOutward = rowEdge * Math.cos(camera.yaw * Math.PI / 180);
58
+ const rowAnchor = Math.abs(rowOutward) < 0.3 ? "middle" : rowOutward > 0 ? "start" : "end";
59
+ const rowLabelPosition = (index) => projectPoint(point(rowEdge * (width / 2 + size), index * step + size / 2 - depth / 2, 0), camera);
60
+ const columnLabelPosition = (column) => projectPoint(point(column * step + size / 2 - width / 2, columnEdge * (depth / 2 + size), 0), camera);
61
+ const axisCorner = point((Math.cos(camera.yaw * Math.PI / 180) >= 0 ? -1 : 1) * (width / 2 + size), (facing.x >= 0 ? 1 : -1) * (depth / 2 + size), 0);
62
+ const points = rectangle(0, 0, width + size, depth + size, -5);
63
+ for (const entry of geometry)
64
+ for (const footprintPoint of entry.geometry.footprint)
65
+ points.push({ ...footprintPoint, z: entry.height });
66
+ points.push(axisCorner, { ...axisCorner, z: maxHeight });
67
+ const projected = points.map((value) => projectPoint(value, camera));
68
+ rowLabels?.slice(0, rows).forEach((text, index) => {
69
+ const position = rowLabelPosition(index);
70
+ const widthOfLabel = labelWidth(text, 24, 4.5);
71
+ projected.push({ ...position, x: position.x + (rowAnchor === "end" ? -widthOfLabel : widthOfLabel), y: position.y + 10 });
72
+ });
73
+ columnLabels?.forEach((entry) => {
74
+ if (entry.column < 0 || entry.column >= columns)
75
+ return;
76
+ const position = columnLabelPosition(entry.column);
77
+ const halfWidth = labelWidth(entry.text, 15, 2.25);
78
+ projected.push({ ...position, x: position.x - halfWidth, y: position.y + 16 }, { ...position, x: position.x + halfWidth, y: position.y + 16 });
79
+ });
80
+ const extents = projected.reduce((range, value) => ({
81
+ minX: Math.min(range.minX, value.x), maxX: Math.max(range.maxX, value.x),
82
+ minY: Math.min(range.minY, value.y), maxY: Math.max(range.maxY, value.y),
83
+ }), { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity });
84
+ const minX = extents.minX - 20;
85
+ const maxX = extents.maxX + 12;
86
+ const minY = extents.minY - 15;
87
+ const maxY = extents.maxY + 15;
88
+ return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };
89
+ }
90
+ function gridPath(a, b, camera) {
91
+ const start = projectPoint(a, camera);
92
+ const end = projectPoint(b, camera);
93
+ return `M${number(start.x)},${number(start.y)} L${number(end.x)},${number(end.y)}`;
94
+ }
95
+ /**
96
+ * Render the same scene model as `Heatmap3D` without React or a DOM. The
97
+ * result is suitable for a README, email, GitHub image, SSR response, or a
98
+ * cached asset generated by a scheduled job.
99
+ */
100
+ export function renderHeatmap3DSvg({ rows, columns, values, scale = "linear", levels: levelsProp, thresholds, shape = "rectangle", blockStyle = "solid", cellSize = 13, gap = 3, maxHeight: maxHeightProp = 100, heightDomain, yaw, pitch, zoom, colors, emptyColor, unknownOpacity = 0.5, theme: themeProp, material = "solid", patterns, faceColor, animation = "none", isSlotHidden, rowLabels, columnLabels, cellLabel, showLegend = false, ariaLabel, className, }) {
101
+ const size = Math.max(1, finitePositive(cellSize, 13));
102
+ const gutter = finitePositive(gap, 3);
103
+ const maxHeight = finitePositive(maxHeightProp, 100);
104
+ const theme = themeProp ?? "color";
105
+ const levels = Math.max(1, levelsProp ?? colors?.length ?? 4);
106
+ const themeEmptyColor = emptyColor ?? resolve3DTheme(theme).emptyColor;
107
+ const camera = normalizeCamera({ yaw, pitch, zoom });
108
+ const { cells, total, unknownCount } = buildCells({ rows, columns, values, scale, levels, thresholds, isSlotHidden });
109
+ const domain = resolveHeightDomain(cells, heightDomain);
110
+ const step = size + gutter;
111
+ const width = Math.max(size, columns * step - gutter);
112
+ const depth = Math.max(size, rows * step - gutter);
113
+ const geometry = buildHeatmap3DScene({ cells, cellSize: size, gap: gutter, width, depth, domain, maxHeight, shape, blockStyle, camera });
114
+ const bounds = sceneBounds({ geometry, width, depth, size, maxHeight, camera, rows, columns, step, rowLabels, columnLabels });
115
+ const sceneCenterX = bounds.x + bounds.width / 2;
116
+ const sceneCenterY = bounds.y + bounds.height / 2;
117
+ const visualOptions = {
118
+ theme,
119
+ material,
120
+ colors,
121
+ emptyColor: themeEmptyColor,
122
+ patterns,
123
+ faceColor,
124
+ levels,
125
+ columns,
126
+ patternPrefix: "heatmap3d-static-pattern",
127
+ };
128
+ const patternDefinitions = material === "pattern"
129
+ ? ["top", "left", "right"].flatMap((face) => Array.from({ length: levels }, (_, index) => {
130
+ const pattern = resolveHeatmap3DPattern({ face, level: index + 1, options: visualOptions });
131
+ return { face, level: index + 1, pattern };
132
+ }))
133
+ : [];
134
+ const facing = cameraDirection(camera);
135
+ const rowEdge = facing.x > 0.001 ? 1 : -1;
136
+ const columnEdge = facing.y >= 0 ? 1 : -1;
137
+ const rowOutward = rowEdge * Math.cos(camera.yaw * Math.PI / 180);
138
+ const rowAnchor = Math.abs(rowOutward) < 0.3 ? "middle" : rowOutward > 0 ? "start" : "end";
139
+ const rowLabelPosition = (index) => projectPoint(point(rowEdge * (width / 2 + size), index * step + size / 2 - depth / 2, 0), camera);
140
+ const columnLabelPosition = (column) => projectPoint(point(column * step + size / 2 - width / 2, columnEdge * (depth / 2 + size), 0), camera);
141
+ const axisCorner = point((Math.cos(camera.yaw * Math.PI / 180) >= 0 ? -1 : 1) * (width / 2 + size), (facing.x >= 0 ? 1 : -1) * (depth / 2 + size), 0);
142
+ const axisBottom = projectPoint(axisCorner, camera);
143
+ const axisTop = projectPoint({ ...axisCorner, z: maxHeight }, camera);
144
+ const floor = rectangle(0, 0, width + size, depth + size, -1);
145
+ const label = ariaLabel ?? `3D heatmap, ${rows} by ${columns}, height represents value${unknownCount > 0 ? `, ${unknownCount} slots with no data` : ""}`;
146
+ const preset = resolve3DTheme(theme);
147
+ const staticStyle = `<style>.heatmap3d__floor-edge{fill:${preset.floorEdge}}.heatmap3d__floor-surface{fill:${preset.floor};stroke:${preset.floorEdge};stroke-width:.7}.heatmap3d__grid-line{fill:none;stroke:${preset.grid};stroke-width:.45;opacity:.7}.heatmap3d__contact-shadow{fill:#111b2b;opacity:.13}.heatmap3d__surface{stroke:#ffffff30;stroke-width:.3;stroke-linejoin:round}.heatmap3d__surface-base{stroke:none}.heatmap3d__window{fill:${preset.window}}.heatmap3d__roof{fill:#07101b;fill-opacity:.11;stroke:#ffffff70;stroke-width:.45;stroke-linejoin:round}.heatmap3d__unknown{stroke:${preset.ink};stroke-width:.7;stroke-dasharray:2 1.8}.heatmap3d__axis line{stroke:${preset.ink};stroke-width:.6;opacity:.65}.heatmap3d__axis text,.heatmap3d__labels text,.heatmap3d__static-legend text{fill:${preset.ink};font-family:sans-serif;font-size:8px}.heatmap3d__static-legend text{font-size:8px}${animation === "grow" ? `@keyframes heatmap3d-grow{from{opacity:0;transform:translateY(4px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes heatmap3d-reduced-fade{from{opacity:.45}to{opacity:1}}.heatmap3d__scene[data-animation="grow"] .heatmap3d__cell[data-known="true"]{animation:heatmap3d-grow 240ms cubic-bezier(.23,1,.32,1) both;animation-delay:calc(min(var(--heatmap3d-index,0),32) * 26ms);transform-box:fill-box;transform-origin:center bottom}@media (prefers-reduced-motion:reduce){.heatmap3d__scene[data-animation="grow"] .heatmap3d__cell[data-known="true"]{animation:heatmap3d-reduced-fade 160ms ease-out both;animation-delay:0ms;transform:none}}` : ""}</style>`;
148
+ const patternMarkup = patternDefinitions.length > 0
149
+ ? `<defs>${patternDefinitions.map(({ face, level, pattern }) => {
150
+ const id = `heatmap3d-static-pattern-${face}-${level}`;
151
+ return `<pattern id="${id}" patternUnits="userSpaceOnUse" patternContentUnits="userSpaceOnUse" width="${pattern.width}" height="${pattern.bitmap.length}"><rect width="${pattern.width}" height="${pattern.bitmap.length}" fill="${escapeXml(pattern.background)}"/><path d="${patternPath(pattern)}" fill="${escapeXml(pattern.foreground)}"/></pattern>`;
152
+ }).join("")}</defs>`
153
+ : "";
154
+ const axisTicks = [0, 0.5, 1].map((fraction) => {
155
+ const tick = projectPoint({ ...axisCorner, z: maxHeight * fraction }, camera);
156
+ const value = domain[0] + (domain[1] - domain[0]) * fraction;
157
+ return `<g><line x1="${number(tick.x - 3)}" x2="${number(tick.x + 3)}" y1="${number(tick.y)}" y2="${number(tick.y)}"/><text x="${number(tick.x - 7)}" y="${number(tick.y + 3)}" text-anchor="end">${escapeXml(formatValue(value))}</text></g>`;
158
+ }).join("");
159
+ const floorMarkup = `<g class="heatmap3d__floor" aria-hidden="true"><path d="${polygonPath(floor.map((value) => ({ ...value, z: -5 })), camera)}" class="heatmap3d__floor-edge"/><path d="${polygonPath(floor, camera)}" class="heatmap3d__floor-surface"/>${Array.from({ length: Math.max(0, columns + 1) }, (_, index) => `<path d="${gridPath(point(index * step - width / 2 - gutter / 2, -depth / 2 - size / 2, -0.5), point(index * step - width / 2 - gutter / 2, depth / 2 + size / 2, -0.5), camera)}" class="heatmap3d__grid-line"/>`).join("")}${Array.from({ length: Math.max(0, rows + 1) }, (_, index) => `<path d="${gridPath(point(-width / 2 - size / 2, index * step - depth / 2 - gutter / 2, -0.5), point(width / 2 + size / 2, index * step - depth / 2 - gutter / 2, -0.5), camera)}" class="heatmap3d__grid-line"/>`).join("")}${geometry.filter((entry) => entry.height > 0).map((entry) => `<path d="${polygonPath(entry.geometry.footprint.map((value) => ({ ...value, x: value.x + size * 0.13, y: value.y + size * 0.13, z: -0.1 })), camera)}" class="heatmap3d__contact-shadow"/>`).join("")}</g>`;
160
+ const labelsMarkup = `<g class="heatmap3d__labels" aria-hidden="true">${rowLabels?.slice(0, rows).map((text, index) => {
161
+ const position = rowLabelPosition(index);
162
+ return `<text x="${number(position.x)}" y="${number(position.y + 3)}" text-anchor="${rowAnchor}">${escapeXml(text)}</text>`;
163
+ }).join("") ?? ""}${columnLabels?.map((entry) => {
164
+ if (entry.column < 0 || entry.column >= columns)
165
+ return "";
166
+ const position = columnLabelPosition(entry.column);
167
+ return `<text x="${number(position.x)}" y="${number(position.y + 10)}" text-anchor="middle">${escapeXml(entry.text)}</text>`;
168
+ }).join("") ?? ""}</g>`;
169
+ const classNames = ["heatmap", "heatmap3d", "heatmap3d__scene", className].filter(Boolean).join(" ");
170
+ const cellsMarkup = geometry.map((entry, motionIndex) => cellMarkup(entry, motionIndex, camera, visualOptions, cellLabel, unknownOpacity)).join("");
171
+ const legendColors = heatmap3DLegendColors(visualOptions);
172
+ const legendMarkup = showLegend && legendColors.length > 0
173
+ ? `<g class="heatmap3d__static-legend" aria-label="Legend"><text x="${number(bounds.x + 4)}" y="${number(bounds.y + bounds.height - 4)}">less</text>${legendColors.map((color, index) => `<rect x="${number(bounds.x + 25 + index * 9)}" y="${number(bounds.y + bounds.height - 11)}" width="7" height="7" rx="1" fill="${escapeXml(color)}"/>`).join("")}<text x="${number(bounds.x + 25 + legendColors.length * 9 + 2)}" y="${number(bounds.y + bounds.height - 4)}">more</text></g>`
174
+ : "";
175
+ return `<svg xmlns="http://www.w3.org/2000/svg" class="${escapeXml(classNames)}" viewBox="${number(bounds.x)} ${number(bounds.y)} ${number(bounds.width)} ${number(bounds.height)}" preserveAspectRatio="xMidYMid meet" style="display:block;width:100%;height:auto" role="img" aria-label="${escapeXml(label)}" data-total="${number(total)}" data-shape="${shape}" data-block-style="${blockStyle}" data-heatmap3d-theme="${theme}" data-material="${material}" data-animation="${animation}" data-interactive="false">${staticStyle}${patternMarkup}<g transform="translate(${number(sceneCenterX)} ${number(sceneCenterY)}) scale(${number(camera.zoom)}) translate(${-number(sceneCenterX)} ${-number(sceneCenterY)})">${floorMarkup}<g class="heatmap3d__axis" aria-hidden="true"><line x1="${number(axisBottom.x)}" y1="${number(axisBottom.y)}" x2="${number(axisTop.x)}" y2="${number(axisTop.y)}"/>${axisTicks}</g>${cellsMarkup}${labelsMarkup}${legendMarkup}</g></svg>`;
176
+ }
177
+ //# sourceMappingURL=static-svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-svg.js","sourceRoot":"","sources":["../src/static-svg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ import type { CSSProperties, HTMLAttributes, ReactNode } from "react";
2
+ /**
3
+ * A dense grid. `null` marks a slot with no data, which is not the same as a
4
+ * slot whose value is zero.
5
+ */
6
+ export type HeatmapMatrix = ReadonlyArray<ReadonlyArray<number | null>>;
7
+ /** A sparse cell. Anything not listed is treated as having no data. */
8
+ export type HeatmapCell = {
9
+ row: number;
10
+ column: number;
11
+ value: number;
12
+ /** false when the slot is covered by no data at all. Defaults to true. */
13
+ known?: boolean;
14
+ /** Passed back untouched to `tooltip` and `cellLabel`. */
15
+ meta?: unknown;
16
+ };
17
+ export type HeatmapValues = HeatmapMatrix | ReadonlyArray<HeatmapCell>;
18
+ /** A cell after normalisation, shading and layout. */
19
+ export type ResolvedCell = {
20
+ row: number;
21
+ column: number;
22
+ value: number;
23
+ known: boolean;
24
+ /** 0 for empty, then 1..levels. */
25
+ level: number;
26
+ meta: unknown;
27
+ };
28
+ export type HeatmapShape = "rounded" | "square" | "circle" | "diamond" | "hexagon" | "plus" | "bar" | "ring";
29
+ /**
30
+ * How intensity is conveyed. Colour alone is invisible to roughly one reader
31
+ * in twelve, so "size" and "both" exist to encode it redundantly.
32
+ */
33
+ export type HeatmapEncoding = "color" | "size" | "both";
34
+ export type HeatmapScale = "quantile" | "linear" | "log" | ((value: number, values: readonly number[]) => number);
35
+ export type HeatmapLegendLabels = {
36
+ less?: ReactNode;
37
+ more?: ReactNode;
38
+ unknown?: ReactNode;
39
+ };
40
+ export type HeatmapProps = Omit<HTMLAttributes<HTMLDivElement>, "values"> & {
41
+ rows: number;
42
+ columns: number;
43
+ values?: HeatmapValues;
44
+ /** Shade bands. "linear" is the default and cuts at even fractions of the
45
+ * largest value, the behaviour readers know from GitHub. "quantile" ranks the
46
+ * active values instead, which suits heavy-tailed data. */
47
+ scale?: HeatmapScale;
48
+ /** Number of shade bands. Defaults to the length of `colors`, else 4. */
49
+ levels?: number;
50
+ /** Explicit band ceilings, ascending. Skips `scale` entirely. */
51
+ thresholds?: readonly number[];
52
+ shape?: HeatmapShape;
53
+ encode?: HeatmapEncoding;
54
+ cellSize?: number;
55
+ gap?: number;
56
+ /** Overrides the shape's own corner rounding. */
57
+ radius?: number | string;
58
+ /** The ramp, palest first. */
59
+ colors?: readonly string[];
60
+ /** A slot with a known value of zero. */
61
+ emptyColor?: string;
62
+ /** Opacity applied to slots with no data. */
63
+ unknownOpacity?: number;
64
+ /** Smallest fraction of the slot a "size"-encoded cell may shrink to. */
65
+ minScale?: number;
66
+ /**
67
+ * Hides slots that do not exist, as opposed to slots with no data. A
68
+ * calendar's final column is partial, and a month view is ragged at both
69
+ * ends; those slots should not be drawn at all.
70
+ */
71
+ isSlotHidden?: (row: number, column: number) => boolean;
72
+ rowLabels?: ReadonlyArray<ReactNode>;
73
+ columnLabels?: ReadonlyArray<{
74
+ column: number;
75
+ text: ReactNode;
76
+ }>;
77
+ tooltip?: (cell: ResolvedCell) => ReactNode;
78
+ /** Optional visual content centred inside a cell. Pair with `cellLabel` for accessible text. */
79
+ cellContent?: (cell: ResolvedCell) => ReactNode;
80
+ /** Per-cell accessible name. Cells are unlabelled, and unfocusable, without it. */
81
+ cellLabel?: (cell: ResolvedCell) => string;
82
+ onCellClick?: (cell: ResolvedCell) => void;
83
+ showLegend?: boolean;
84
+ legendLabels?: HeatmapLegendLabels;
85
+ ariaLabel?: string;
86
+ style?: CSSProperties;
87
+ };
88
+ export type Heatmap3DShape = "rectangle" | "circle" | "bar";
89
+ export type Heatmap3DBlockStyle = "solid" | "lego" | "building";
90
+ export type Heatmap3DCamera = {
91
+ yaw: number;
92
+ pitch: number;
93
+ zoom: number;
94
+ };
95
+ /** `side` is a convenient alias for patterns; geometry reports left/right. */
96
+ export type Heatmap3DFace = "top" | "side" | "left" | "right";
97
+ export type Heatmap3DThemeName = "color" | "night" | "seasonal" | "rainbow";
98
+ export type Heatmap3DMaterial = "solid" | "pattern";
99
+ export type Heatmap3DAnimation = "none" | "grow";
100
+ /**
101
+ * An SVG bitmap row. Numbers are read from the most-significant bit; strings
102
+ * may be binary ("0101") or hexadecimal ("0x5"). The row count is the
103
+ * pattern height, so a compact pattern needs no separate height prop.
104
+ */
105
+ export type Heatmap3DPattern = {
106
+ width: number;
107
+ bitmap: readonly (number | string)[];
108
+ background?: string;
109
+ foreground?: string;
110
+ };
111
+ export type Heatmap3DFaceColorArgs = {
112
+ cell: ResolvedCell;
113
+ face: Heatmap3DFace;
114
+ color: string;
115
+ level: number;
116
+ theme: Heatmap3DThemeName;
117
+ };
118
+ /** Override the default top/side material treatment for a cell. */
119
+ export type Heatmap3DFaceColor = (args: Heatmap3DFaceColorArgs) => string;
120
+ /** Heights encode actual values linearly, independently of the colour bands. */
121
+ export type Heatmap3DProps = Omit<HeatmapProps, "shape" | "encode" | "radius" | "minScale" | "cellContent"> & {
122
+ shape?: Heatmap3DShape;
123
+ blockStyle?: Heatmap3DBlockStyle;
124
+ /** Surface treatment. `color` defers to `colors`; the rest set their own. */
125
+ theme?: Heatmap3DThemeName;
126
+ /** Solid fills or reusable SVG bitmap fills. */
127
+ material?: Heatmap3DMaterial;
128
+ /** Per-face bitmap rows, indexed by level. Missing entries use a built-in pattern. */
129
+ patterns?: Partial<Record<Heatmap3DFace, readonly Heatmap3DPattern[]>>;
130
+ /** Resolve a concrete fill separately for top and visible side faces. */
131
+ faceColor?: Heatmap3DFaceColor;
132
+ /** Opt-in entrance motion. The reduced-motion variant is supplied by the stylesheet. */
133
+ animation?: Heatmap3DAnimation;
134
+ /** Maximum elevation in grid units. Defaults to 100. */
135
+ maxHeight?: number;
136
+ /** Defaults to [0, largest positive value]. Values outside the domain clamp.
137
+ * Negative values remain labelled but are drawn flat at the zero plane. */
138
+ heightDomain?: readonly [number, number];
139
+ /** Horizontal orbit in degrees. Defaults to -35. */
140
+ yaw?: number;
141
+ /** Elevation in degrees, clamped to 15–75. Defaults to 38. */
142
+ pitch?: number;
143
+ /** Magnification, clamped to 0.55–2. Defaults to 1. */
144
+ zoom?: number;
145
+ onCameraChange?: (camera: Heatmap3DCamera) => void;
146
+ /** Drag to orbit; focus the chart and use arrows to rotate, +/- to zoom. */
147
+ interactive?: boolean;
148
+ /** Displays zoom and reset buttons. Defaults to true. */
149
+ showControls?: boolean;
150
+ };
151
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/docs/cover.png ADDED
Binary file
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@thilakbhat/heatmap-ui",
3
+ "version": "0.1.0",
4
+ "description": "A headless heatmap toolkit for React. Any grid, eight cell shapes, a 3D SVG mode, and full control of colour, size and layout.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./static-svg": {
17
+ "types": "./dist/static-svg.d.ts",
18
+ "import": "./dist/static-svg.js",
19
+ "default": "./dist/static-svg.js"
20
+ },
21
+ "./styles.css": "./src/styles.css",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "src/styles.css",
27
+ "README.md",
28
+ "LICENSE",
29
+ "docs/cover.png",
30
+ "docs/playground-2d.png",
31
+ "docs/playground-3d.png"
32
+ ],
33
+ "sideEffects": ["**/*.css"],
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.build.json",
36
+ "typecheck": "tsc -p tsconfig.build.json --noEmit",
37
+ "pretest": "npm run build",
38
+ "test": "node --test",
39
+ "prepublishOnly": "npm run build"
40
+ },
41
+ "peerDependencies": {
42
+ "react": ">=18.2.0",
43
+ "react-dom": ">=18.2.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/react": "^19.0.0",
47
+ "@types/react-dom": "^19.0.0",
48
+ "typescript": "^5.0.0"
49
+ },
50
+ "repository": { "type": "git", "url": "git+https://github.com/tb962/heatmap-ui.git" },
51
+ "homepage": "https://tb962.github.io/heatmap-ui/",
52
+ "bugs": { "url": "https://github.com/tb962/heatmap-ui/issues" },
53
+ "author": "tb962",
54
+ "keywords": [
55
+ "heatmap", "react", "calendar-heatmap", "contribution-graph", "punchcard",
56
+ "hexbin", "data-visualization", "grid", "accessible", "headless",
57
+ "3d", "isometric", "svg", "themeable", "quantile"
58
+ ],
59
+ "engines": { "node": ">=20" },
60
+ "publishConfig": { "access": "public" }
61
+ }