@fusion.dev/helix-headless 0.190.0 → 0.192.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.
- package/api.json +1 -1
- package/custom-elements.json +47 -36
- package/dist/spatial-heatmap/projection.d.ts +28 -18
- package/dist/spatial-heatmap/projection.js +79 -51
- package/dist/spatial-heatmap/root/spatial-heatmap-root.d.ts +26 -17
- package/dist/spatial-heatmap/root/spatial-heatmap-root.js +32 -21
- package/dist/spatial-scatter-chart/root/spatial-scatter-chart-root.d.ts +1 -1
- package/dist/spatial-surface-chart/root/spatial-surface-chart-root.d.ts +1 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +24 -14
- package/types/vue.d.ts +1 -1
package/custom-elements.json
CHANGED
|
@@ -152188,9 +152188,16 @@
|
|
|
152188
152188
|
"type": {
|
|
152189
152189
|
"text": "number"
|
|
152190
152190
|
}
|
|
152191
|
+
},
|
|
152192
|
+
{
|
|
152193
|
+
"name": "camera",
|
|
152194
|
+
"default": "ISOMETRIC",
|
|
152195
|
+
"type": {
|
|
152196
|
+
"text": "Camera"
|
|
152197
|
+
}
|
|
152191
152198
|
}
|
|
152192
152199
|
],
|
|
152193
|
-
"description": "Every reading as a prism, filling down each column of `rows` and then\nacross, as the flat heatmap does
|
|
152200
|
+
"description": "Every reading as a prism, filling down each column of `rows` and then\nacross, as the flat heatmap does, seen from `camera`.\n\n**Columns run down to the right and rows down to the left, from the\nisometric camera, so there the order of the readings is the order to paint\nthem in.** A prism can only cover the neighbors behind it, which are the one\nbefore it in its column and the one in the same row of the column before,\nand both come earlier in the table. Turned, the order comes from how near\nthe camera each prism stands, which is `order`.\n\n`footprint` is how much of its cell a prism covers along each edge, so `1`\nleaves no gap between neighbors."
|
|
152194
152201
|
}
|
|
152195
152202
|
],
|
|
152196
152203
|
"exports": [
|
|
@@ -152250,7 +152257,7 @@
|
|
|
152250
152257
|
"declarations": [
|
|
152251
152258
|
{
|
|
152252
152259
|
"kind": "class",
|
|
152253
|
-
"description": "The same strip as `Heatmap`, seen from above at an angle. Each reading is a\nprism: its top face takes the cell's tone, and its height repeats the value,\nmeasured from zero against the highest reading in the table. `rows=\"7\"`\nmakes a contribution graph, with each week a column running down to the\nright.\n\n**The height says what the tone says.** Read the exact value from the tooltip\nor the table, and compare readings by tone. A tall reading at the front can\nhide a short one behind it, so the newest column stands at the front, where\nnothing covers it.\n\n**Everything else is `Heatmap`.** The table named by `for`, the tones and\nthresholds, the keys, the tooltip, the overview, `selection-mode`, and the\nevents all work as they do there. The class extends the headless heatmap,\nand its own entry point carries the drawing, so a page using only `Heatmap`\nloads none of it.\n\n**It was `helix-isometric-heatmap` until 0.
|
|
152260
|
+
"description": "The same strip as `Heatmap`, seen from above at an angle. Each reading is a\nprism: its top face takes the cell's tone, and its height repeats the value,\nmeasured from zero against the highest reading in the table. `rows=\"7\"`\nmakes a contribution graph, with each week a column running down to the\nright.\n\n**The height says what the tone says.** Read the exact value from the tooltip\nor the table, and compare readings by tone. A tall reading at the front can\nhide a short one behind it, so the newest column stands at the front, where\nnothing covers it.\n\n**Everything else is `Heatmap`.** The table named by `for`, the tones and\nthresholds, the keys, the tooltip, the overview, `selection-mode`, and the\nevents all work as they do there. The class extends the headless heatmap,\nand its own entry point carries the drawing, so a page using only `Heatmap`\nloads none of it.\n\n**It was `helix-isometric-heatmap` until 0.190.0**, and\n`helix-headless-isometric-heatmap` in the headless tier. The old tags are\ngone, and so are the `--isometric-heatmap-*` hooks, which are\n`--spatial-heatmap-*`, and the words key, which is `helix-spatial-heatmap`.\nThe two shade hooks now take a step of lightness, such as `0.07`, where they\ntook a percentage mixed toward black. Every attribute, part, and event kept\nits name.\n\n**`flat` lays every prism down** at no height, which leaves the tones on a\nplane at the same angle.\n\n**The prisms stand on a slab**, the `base`, which reaches a little past the\ngrid, so the relief reads as one object. The `start` and `end` slots name\nthe two ends of the front edge, which is the strip's first and last column:\nthe component writes where those corners are on the `footer`, and a\nstylesheet stands each label at its corner. A renderer tells the chart where\nit draws those corners, so the labels stand at them there too, and follow\nthem as the view turns.\n\n**`gap` and `min-cell` set the smallest cell.** The drawing scales as a\nwhole, so a wider box draws larger cells and the gap grows with them. A box\ntoo narrow for every column at `min-cell` draws the newest that fit.\n\n**The drawing is SVG and holds still.** It scales with its box through its\n`viewBox`, needs no WebGL, and has no motion to pause. Shift with an arrow\nturns it a step, or tilts it, from the isometric view it starts at.\n**Under `selection-mode`, the prisms are painted back to front for the\nview, and the grid's rows and cells stand beside them in the table's\norder**, holding no drawing of their own, so a turned view paints\ncorrectly and a screen reader still reads the grid in order.\n\n**A renderer can draw it in 3D instead.** Put a box for it in the\n`renderer` slot, and `connectSpatialHeatmap` from `@fusion.dev/helix-plot`\ndraws the prisms in it with three.js, lit, in the same tones, in a view\nthat drags round and zooms. The chart publishes its readings in `field`,\nand its own drawing stays under the renderer's, unseen, where a screen\nreader and the keys still reach it. Shift with an arrow turns the view,\nexcept under `selection-mode=\"multiple\"`, where it selects.\n\n**Keyboard.** The keys are `Heatmap`'s. Down moves to the next reading in a\ncolumn, drawn down to the left, and Right to the same reading in the next\ncolumn, drawn down to the right.\n\n| Key | What it does |\n|---|---|\n| Tab | Moves focus to the strip and shows the first cell. |\n| Down, Up | Moves to the next or the previous cell. |\n| Right, Left | Moves a column on or back, a week with `rows=\"7\"`. On a right-to-left page, Left moves on. |\n| Home, End | Moves to the first or the last cell. |\n| Page Down, Page Up | Moves a month on or back where the rows carry dates, and four columns otherwise. |\n| Enter, Space | Presses the cell, which sends `helix-reading-press`, and selects it or lets it go under `selection-mode`. |\n| Shift with an arrow, Home, End, Page Up or Page Down | Selects every cell from the last one pressed to where the key went, under `selection-mode=\"multiple\"`. |\n| Shift with an arrow | Turns the view a step, or a renderer's where one is connected, except under `selection-mode=\"multiple\"`. |\n| Escape | Puts the cell's tooltip away. |",
|
|
152254
152261
|
"name": "HelixHeadlessSpatialHeatmap",
|
|
152255
152262
|
"cssProperties": [
|
|
152256
152263
|
{
|
|
@@ -152408,7 +152415,7 @@
|
|
|
152408
152415
|
"name": "base-top"
|
|
152409
152416
|
},
|
|
152410
152417
|
{
|
|
152411
|
-
"description": "One reading: a group holding
|
|
152418
|
+
"description": "One reading drawn as a prism: a group holding the faces the view shows. Under `selection-mode` it is the picture of a grid cell, hidden from screen readers.",
|
|
152412
152419
|
"name": "cell",
|
|
152413
152420
|
"inheritedFrom": {
|
|
152414
152421
|
"name": "HelixHeadlessHeatmap",
|
|
@@ -152420,15 +152427,15 @@
|
|
|
152420
152427
|
"name": "drawing"
|
|
152421
152428
|
},
|
|
152422
152429
|
{
|
|
152423
|
-
"description": "The
|
|
152430
|
+
"description": "The side of a prism facing the light more: from the isometric view, the side toward the next row, drawn at its lower left. Left out where the view shows no side.",
|
|
152424
152431
|
"name": "left-face"
|
|
152425
152432
|
},
|
|
152426
152433
|
{
|
|
152427
|
-
"description": "The
|
|
152434
|
+
"description": "The side of a prism facing the light less: from the isometric view, the side toward the next column, drawn at its lower right. Left out where the view shows one side or none.",
|
|
152428
152435
|
"name": "right-face"
|
|
152429
152436
|
},
|
|
152430
152437
|
{
|
|
152431
|
-
"description": "A column of
|
|
152438
|
+
"description": "A column of the strip, which a grid reads as a row, under `selection-mode`. It holds the column's grid cells, which draw nothing: the prisms are painted apart, in the order the view needs.",
|
|
152432
152439
|
"name": "row",
|
|
152433
152440
|
"inheritedFrom": {
|
|
152434
152441
|
"name": "HelixHeadlessHeatmap",
|
|
@@ -152794,6 +152801,16 @@
|
|
|
152794
152801
|
"default": "undefined",
|
|
152795
152802
|
"description": "The prisms drawn on the last render, which the tooltip is placed against."
|
|
152796
152803
|
},
|
|
152804
|
+
{
|
|
152805
|
+
"kind": "field",
|
|
152806
|
+
"name": "camera",
|
|
152807
|
+
"type": {
|
|
152808
|
+
"text": "Camera"
|
|
152809
|
+
},
|
|
152810
|
+
"privacy": "private",
|
|
152811
|
+
"default": "ISOMETRIC",
|
|
152812
|
+
"description": "Where the chart's own drawing is seen from, which Shift with an arrow turns."
|
|
152813
|
+
},
|
|
152797
152814
|
{
|
|
152798
152815
|
"kind": "field",
|
|
152799
152816
|
"name": "rendered",
|
|
@@ -152944,7 +152961,7 @@
|
|
|
152944
152961
|
"name": "onTurnKeydown",
|
|
152945
152962
|
"privacy": "private",
|
|
152946
152963
|
"readonly": true,
|
|
152947
|
-
"description": "Shift with an arrow turns
|
|
152964
|
+
"description": "Shift with an arrow turns the view, the chart's own drawing or a\nrenderer's, and moves no reading, except under\n`selection-mode=\"multiple\"`, where it selects a range."
|
|
152948
152965
|
},
|
|
152949
152966
|
{
|
|
152950
152967
|
"kind": "field",
|
|
@@ -152982,27 +152999,9 @@
|
|
|
152982
152999
|
},
|
|
152983
153000
|
"parameters": [
|
|
152984
153001
|
{
|
|
152985
|
-
"name": "
|
|
152986
|
-
"type": {
|
|
152987
|
-
"text": "number"
|
|
152988
|
-
}
|
|
152989
|
-
},
|
|
152990
|
-
{
|
|
152991
|
-
"name": "top",
|
|
152992
|
-
"type": {
|
|
152993
|
-
"text": "string"
|
|
152994
|
-
}
|
|
152995
|
-
},
|
|
152996
|
-
{
|
|
152997
|
-
"name": "left",
|
|
152998
|
-
"type": {
|
|
152999
|
-
"text": "string"
|
|
153000
|
-
}
|
|
153001
|
-
},
|
|
153002
|
-
{
|
|
153003
|
-
"name": "right",
|
|
153002
|
+
"name": "prism",
|
|
153004
153003
|
"type": {
|
|
153005
|
-
"text": "
|
|
153004
|
+
"text": "Prism"
|
|
153006
153005
|
}
|
|
153007
153006
|
},
|
|
153008
153007
|
{
|
|
@@ -153030,7 +153029,7 @@
|
|
|
153030
153029
|
}
|
|
153031
153030
|
}
|
|
153032
153031
|
],
|
|
153033
|
-
"description": "One reading as a prism. The sides come first, so the top face is painted\nover the edge they share with it
|
|
153032
|
+
"description": "One reading as a prism. The sides come first, so the top face is painted\nover the edge they share with it, and a side the view does not show is\nleft out. Under `selection-mode` it is the picture of a grid cell, hidden\nfrom a screen reader, which reads the cell itself."
|
|
153034
153033
|
},
|
|
153035
153034
|
{
|
|
153036
153035
|
"kind": "method",
|
|
@@ -153072,7 +153071,7 @@
|
|
|
153072
153071
|
},
|
|
153073
153072
|
{
|
|
153074
153073
|
"kind": "method",
|
|
153075
|
-
"name": "
|
|
153074
|
+
"name": "renderGridRows",
|
|
153076
153075
|
"privacy": "private",
|
|
153077
153076
|
"return": {
|
|
153078
153077
|
"type": {
|
|
@@ -153081,13 +153080,25 @@
|
|
|
153081
153080
|
},
|
|
153082
153081
|
"parameters": [
|
|
153083
153082
|
{
|
|
153084
|
-
"name": "
|
|
153083
|
+
"name": "count",
|
|
153085
153084
|
"type": {
|
|
153086
|
-
"text": "
|
|
153085
|
+
"text": "number"
|
|
153086
|
+
}
|
|
153087
|
+
},
|
|
153088
|
+
{
|
|
153089
|
+
"name": "keys",
|
|
153090
|
+
"type": {
|
|
153091
|
+
"text": "readonly string[]"
|
|
153092
|
+
}
|
|
153093
|
+
},
|
|
153094
|
+
{
|
|
153095
|
+
"name": "chosen",
|
|
153096
|
+
"type": {
|
|
153097
|
+
"text": "ReadonlySet<string>"
|
|
153087
153098
|
}
|
|
153088
153099
|
}
|
|
153089
153100
|
],
|
|
153090
|
-
"description": "The
|
|
153101
|
+
"description": "The grid's rows, one for each column of the strip, and its cells in the\ntable's order, each named by its row and saying whether it is selected,\nas the flat strip's cell is. They hold no drawing: the prisms are painted\napart, in the order the view needs."
|
|
153091
153102
|
},
|
|
153092
153103
|
{
|
|
153093
153104
|
"kind": "method",
|
|
@@ -154943,7 +154954,7 @@
|
|
|
154943
154954
|
"summary": "A heatmap drawn as a relief, where each reading stands as tall as its value.",
|
|
154944
154955
|
"helix": {
|
|
154945
154956
|
"category": "charts",
|
|
154946
|
-
"since": "0.
|
|
154957
|
+
"since": "0.190.0",
|
|
154947
154958
|
"status": "experimental",
|
|
154948
154959
|
"documentation": "https://fusion.dev/helix/components/spatial-heatmap",
|
|
154949
154960
|
"aliases": [
|
|
@@ -156531,7 +156542,7 @@
|
|
|
156531
156542
|
"summary": "A chart that plots each row as a point in three dimensions, for data with three measures.",
|
|
156532
156543
|
"helix": {
|
|
156533
156544
|
"category": "charts",
|
|
156534
|
-
"since": "0.
|
|
156545
|
+
"since": "0.190.0",
|
|
156535
156546
|
"status": "experimental",
|
|
156536
156547
|
"documentation": "https://fusion.dev/helix/components/spatial-scatter-chart",
|
|
156537
156548
|
"aliases": [
|
|
@@ -158437,7 +158448,7 @@
|
|
|
158437
158448
|
"summary": "A chart that draws a height over a grid as a surface in three dimensions, for a measure that varies over two others.",
|
|
158438
158449
|
"helix": {
|
|
158439
158450
|
"category": "charts",
|
|
158440
|
-
"since": "0.
|
|
158451
|
+
"since": "0.190.0",
|
|
158441
158452
|
"status": "experimental",
|
|
158442
158453
|
"documentation": "https://fusion.dev/helix/components/spatial-surface-chart",
|
|
158443
158454
|
"aliases": [
|
|
@@ -209045,6 +209056,6 @@
|
|
|
209045
209056
|
],
|
|
209046
209057
|
"helix": {
|
|
209047
209058
|
"package": "@fusion.dev/helix-headless",
|
|
209048
|
-
"version": "0.
|
|
209059
|
+
"version": "0.192.0"
|
|
209049
209060
|
}
|
|
209050
209061
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Where each reading of a spatial heatmap stands,
|
|
2
|
+
* Where each reading of a spatial heatmap stands, seen from a camera that turns and tilts, as SVG path data.
|
|
3
3
|
*
|
|
4
4
|
* Kept apart from the element because it is arithmetic a picture hides: a face
|
|
5
5
|
* drawn in the wrong order is covered by the prism it should cover, and a
|
|
@@ -10,30 +10,35 @@
|
|
|
10
10
|
* the `viewBox` and a server can write it with no width to measure.
|
|
11
11
|
*
|
|
12
12
|
* **The projection is the one every spatial drawing shares**, `helix-core`'s,
|
|
13
|
-
* seen from the isometric camera. What is here is the
|
|
14
|
-
* its columns and rows run, its prisms,
|
|
13
|
+
* seen from the isometric camera until the reader turns it. What is here is the
|
|
14
|
+
* heatmap's own: which way its columns and rows run, its prisms, the slab
|
|
15
|
+
* under them, and the order to paint them in.
|
|
15
16
|
*/
|
|
16
|
-
import { type PagePoint } from '@fusion.dev/helix-core';
|
|
17
|
+
import { type Camera, type PagePoint } from '@fusion.dev/helix-core';
|
|
17
18
|
/** How far across the page one step along either axis goes: the cosine of 30 degrees. */
|
|
18
19
|
export declare const ACROSS: number;
|
|
19
20
|
/** A point on the page, in cells. */
|
|
20
21
|
export type Point = PagePoint;
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* One reading drawn as a prism: the faces the camera sees, as path data. From
|
|
24
|
+
* the isometric camera, the lighter side is the one toward the next row,
|
|
25
|
+
* drawn at the lower left, and the darker the one toward the next column.
|
|
26
|
+
*/
|
|
22
27
|
export interface Prism {
|
|
23
28
|
/** The reading's place among those drawn. */
|
|
24
29
|
index: number;
|
|
25
|
-
/** The
|
|
30
|
+
/** The side facing the light more, or `''` where the camera sees no side. */
|
|
26
31
|
left: string;
|
|
27
32
|
/** The middle of the top face, which is where the tooltip points. */
|
|
28
33
|
peak: Point;
|
|
29
|
-
/** The
|
|
34
|
+
/** The side facing it less, or `''` where the camera sees one side or none. */
|
|
30
35
|
right: string;
|
|
31
36
|
/** The face the reading's tone is painted on. */
|
|
32
37
|
top: string;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
|
-
* The slab the prisms stand on: its top, which is the floor, and
|
|
36
|
-
* sides
|
|
40
|
+
* The slab the prisms stand on: its top, which is the floor, and the two
|
|
41
|
+
* sides the camera sees, lighter first, as path data.
|
|
37
42
|
*/
|
|
38
43
|
export interface Base {
|
|
39
44
|
left: string;
|
|
@@ -60,7 +65,12 @@ export interface Relief {
|
|
|
60
65
|
end: Point;
|
|
61
66
|
start: Point;
|
|
62
67
|
} | undefined;
|
|
63
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* The prisms' places in `prisms`, back to front, the order to paint them
|
|
70
|
+
* in. From the isometric camera it is the order of the readings.
|
|
71
|
+
*/
|
|
72
|
+
order: number[];
|
|
73
|
+
/** In the order of the readings. */
|
|
64
74
|
prisms: Prism[];
|
|
65
75
|
}
|
|
66
76
|
/** How far the slab reaches past the grid on every side, in cells. */
|
|
@@ -81,16 +91,16 @@ export declare const heightsOf: (values: readonly (number | undefined)[], highes
|
|
|
81
91
|
export declare const highestOf: (values: readonly (number | undefined)[]) => number;
|
|
82
92
|
/**
|
|
83
93
|
* Every reading as a prism, filling down each column of `rows` and then
|
|
84
|
-
* across, as the flat heatmap does
|
|
94
|
+
* across, as the flat heatmap does, seen from `camera`.
|
|
85
95
|
*
|
|
86
|
-
* **Columns run down to the right and rows down to the left,
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
96
|
+
* **Columns run down to the right and rows down to the left, from the
|
|
97
|
+
* isometric camera, so there the order of the readings is the order to paint
|
|
98
|
+
* them in.** A prism can only cover the neighbors behind it, which are the one
|
|
99
|
+
* before it in its column and the one in the same row of the column before,
|
|
100
|
+
* and both come earlier in the table. Turned, the order comes from how near
|
|
101
|
+
* the camera each prism stands, which is `order`.
|
|
92
102
|
*
|
|
93
103
|
* `footprint` is how much of its cell a prism covers along each edge, so `1`
|
|
94
104
|
* leaves no gap between neighbors.
|
|
95
105
|
*/
|
|
96
|
-
export declare const reliefOf: (heights: readonly number[], rows: number, footprint: number) => Relief;
|
|
106
|
+
export declare const reliefOf: (heights: readonly number[], rows: number, footprint: number, camera?: Camera) => Relief;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISOMETRIC, pathData, projectionOf } from '@fusion.dev/helix-core';
|
|
1
|
+
import { depthOrder, ISOMETRIC, pathData, projectionOf, solid, } from '@fusion.dev/helix-core';
|
|
2
2
|
export const ACROSS = Math.sqrt(3) / 2;
|
|
3
3
|
export const MARGIN = 0.3;
|
|
4
4
|
export const THICKNESS = 0.25;
|
|
@@ -6,69 +6,97 @@ export const heightsOf = (values, highest, tallest) => values.map((value) => hig
|
|
|
6
6
|
? (Math.min(value, highest) / highest) * tallest
|
|
7
7
|
: 0);
|
|
8
8
|
export const highestOf = (values) => values.reduce((high, value) => (value !== undefined && value > high ? value : high), 0);
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
9
|
+
const floor = (column, row) => ({ x: column, y: -row });
|
|
10
|
+
const boxFaces = (projection, low, high, bottom, top) => {
|
|
11
|
+
const at = (x, y, z) => projection.at(x, y, z);
|
|
12
|
+
const corners = [
|
|
13
|
+
[low.x, low.y],
|
|
14
|
+
[high.x, low.y],
|
|
15
|
+
[high.x, high.y],
|
|
16
|
+
[low.x, high.y],
|
|
17
|
+
];
|
|
18
|
+
const outward = [
|
|
19
|
+
[0, -1],
|
|
20
|
+
[1, 0],
|
|
21
|
+
[0, 1],
|
|
22
|
+
[-1, 0],
|
|
23
|
+
];
|
|
24
|
+
const sides = [];
|
|
25
|
+
corners.forEach(([x, y], index) => {
|
|
26
|
+
const [nx, ny] = outward[index];
|
|
27
|
+
if (nx * projection.toward[0] + ny * projection.toward[1] <= 1e-6) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const [x2, y2] = corners[(index + 1) % 4];
|
|
31
|
+
sides.push({
|
|
32
|
+
d: pathData([at(x, y, top), at(x2, y2, top), at(x2, y2, bottom), at(x, y, bottom)]),
|
|
33
|
+
light: nx * projection.across[0] + ny * projection.across[1],
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
sides.sort((one, other) => one.light - other.light);
|
|
37
|
+
const points = corners.flatMap(([x, y]) => [at(x, y, top), at(x, y, bottom)]);
|
|
38
|
+
return {
|
|
39
|
+
points,
|
|
40
|
+
sides: sides.map((side) => side.d),
|
|
41
|
+
top: pathData(corners.map(([x, y]) => at(x, y, top))),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export const reliefOf = (heights, rows, footprint, camera = ISOMETRIC) => {
|
|
45
|
+
const projection = projectionOf(camera);
|
|
13
46
|
const count = Math.max(1, Math.floor(rows) || 1);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let top = Number.POSITIVE_INFINITY;
|
|
18
|
-
let bottom = Number.NEGATIVE_INFINITY;
|
|
19
|
-
const prisms = heights.map((height, index) => {
|
|
47
|
+
const width = Math.min(1, Math.max(0, footprint));
|
|
48
|
+
const points = [];
|
|
49
|
+
const places = heights.map((height, index) => {
|
|
20
50
|
const column = Math.floor(index / count);
|
|
21
51
|
const row = index % count;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
bottom = Math.max(bottom, frontFloor.y);
|
|
52
|
+
return { height, index, ...floor(column + 0.5, row + 0.5) };
|
|
53
|
+
});
|
|
54
|
+
const prisms = places.map(({ height, index, x, y }) => {
|
|
55
|
+
const drawn = solid(projection, 'block', x, y, width, height);
|
|
56
|
+
const sides = drawn.faces.slice(0, -1).sort((one, other) => one.darken - other.darken);
|
|
57
|
+
const half = width / 2;
|
|
58
|
+
for (const corner of [
|
|
59
|
+
[x - half, y - half],
|
|
60
|
+
[x + half, y - half],
|
|
61
|
+
[x + half, y + half],
|
|
62
|
+
[x - half, y + half],
|
|
63
|
+
]) {
|
|
64
|
+
points.push(projection.at(corner[0], corner[1], 0), projection.at(corner[0], corner[1], height));
|
|
65
|
+
}
|
|
37
66
|
return {
|
|
38
67
|
index,
|
|
39
|
-
left:
|
|
40
|
-
peak:
|
|
41
|
-
right:
|
|
42
|
-
top:
|
|
68
|
+
left: sides[0]?.d ?? '',
|
|
69
|
+
peak: drawn.peak,
|
|
70
|
+
right: sides[1]?.d ?? '',
|
|
71
|
+
top: drawn.faces.at(-1)?.d ?? '',
|
|
43
72
|
};
|
|
44
73
|
});
|
|
45
74
|
if (prisms.length === 0) {
|
|
46
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
base: undefined,
|
|
77
|
+
box: { height: 0, width: 0, x: 0, y: 0 },
|
|
78
|
+
corners: undefined,
|
|
79
|
+
order: [],
|
|
80
|
+
prisms,
|
|
81
|
+
};
|
|
47
82
|
}
|
|
48
83
|
const columns = Math.ceil(heights.length / count);
|
|
49
84
|
const deep = Math.min(count, heights.length);
|
|
50
|
-
const [
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const frontFoot = at(last, far, -THICKNESS);
|
|
58
|
-
const downFoot = at(first, far, -THICKNESS);
|
|
59
|
-
const base = {
|
|
60
|
-
left: path([down, front, frontFoot, downFoot]),
|
|
61
|
-
right: path([front, across, acrossFoot, frontFoot]),
|
|
62
|
-
top: path([back, across, front, down]),
|
|
63
|
-
};
|
|
64
|
-
left = Math.min(left, downFoot.x);
|
|
65
|
-
right = Math.max(right, acrossFoot.x);
|
|
66
|
-
top = Math.min(top, back.y);
|
|
67
|
-
bottom = Math.max(bottom, frontFoot.y);
|
|
85
|
+
const [low, high] = [floor(-MARGIN, deep + MARGIN), floor(columns + MARGIN, -MARGIN)];
|
|
86
|
+
const slab = boxFaces(projection, low, high, -THICKNESS, 0);
|
|
87
|
+
const base = { left: slab.sides[0] ?? '', right: slab.sides[1] ?? '', top: slab.top };
|
|
88
|
+
points.push(...slab.points);
|
|
89
|
+
const xs = points.map((point) => point.x);
|
|
90
|
+
const ys = points.map((point) => point.y);
|
|
91
|
+
const [left, top] = [Math.min(...xs), Math.min(...ys)];
|
|
68
92
|
return {
|
|
69
93
|
base,
|
|
70
|
-
box: { height:
|
|
71
|
-
corners: {
|
|
94
|
+
box: { height: Math.max(...ys) - top, width: Math.max(...xs) - left, x: left, y: top },
|
|
95
|
+
corners: {
|
|
96
|
+
end: projection.at(columns + MARGIN, -(deep + MARGIN), -THICKNESS),
|
|
97
|
+
start: projection.at(-MARGIN, -(deep + MARGIN), -THICKNESS),
|
|
98
|
+
},
|
|
99
|
+
order: depthOrder(projection, places).map((place) => place.index),
|
|
72
100
|
prisms,
|
|
73
101
|
};
|
|
74
102
|
};
|
|
@@ -22,7 +22,7 @@ import { HelixHeadlessHeatmap } from '../../heatmap/root/heatmap-root.js';
|
|
|
22
22
|
* and its own entry point carries the drawing, so a page using only `Heatmap`
|
|
23
23
|
* loads none of it.
|
|
24
24
|
*
|
|
25
|
-
* **It was `helix-isometric-heatmap` until 0.
|
|
25
|
+
* **It was `helix-isometric-heatmap` until 0.190.0**, and
|
|
26
26
|
* `helix-headless-isometric-heatmap` in the headless tier. The old tags are
|
|
27
27
|
* gone, and so are the `--isometric-heatmap-*` hooks, which are
|
|
28
28
|
* `--spatial-heatmap-*`, and the words key, which is `helix-spatial-heatmap`.
|
|
@@ -46,7 +46,12 @@ import { HelixHeadlessHeatmap } from '../../heatmap/root/heatmap-root.js';
|
|
|
46
46
|
* too narrow for every column at `min-cell` draws the newest that fit.
|
|
47
47
|
*
|
|
48
48
|
* **The drawing is SVG and holds still.** It scales with its box through its
|
|
49
|
-
* `viewBox`, needs no WebGL, and has no motion to pause.
|
|
49
|
+
* `viewBox`, needs no WebGL, and has no motion to pause. Shift with an arrow
|
|
50
|
+
* turns it a step, or tilts it, from the isometric view it starts at.
|
|
51
|
+
* **Under `selection-mode`, the prisms are painted back to front for the
|
|
52
|
+
* view, and the grid's rows and cells stand beside them in the table's
|
|
53
|
+
* order**, holding no drawing of their own, so a turned view paints
|
|
54
|
+
* correctly and a screen reader still reads the grid in order.
|
|
50
55
|
*
|
|
51
56
|
* **A renderer can draw it in 3D instead.** Put a box for it in the
|
|
52
57
|
* `renderer` slot, and `connectSpatialHeatmap` from `@fusion.dev/helix-plot`
|
|
@@ -69,10 +74,10 @@ import { HelixHeadlessHeatmap } from '../../heatmap/root/heatmap-root.js';
|
|
|
69
74
|
* | Page Down, Page Up | Moves a month on or back where the rows carry dates, and four columns otherwise. |
|
|
70
75
|
* | Enter, Space | Presses the cell, which sends `helix-reading-press`, and selects it or lets it go under `selection-mode`. |
|
|
71
76
|
* | Shift with an arrow, Home, End, Page Up or Page Down | Selects every cell from the last one pressed to where the key went, under `selection-mode="multiple"`. |
|
|
72
|
-
* | Shift with an arrow | Turns a renderer's
|
|
77
|
+
* | Shift with an arrow | Turns the view a step, or a renderer's where one is connected, except under `selection-mode="multiple"`. |
|
|
73
78
|
* | Escape | Puts the cell's tooltip away. |
|
|
74
79
|
*
|
|
75
|
-
* @since 0.
|
|
80
|
+
* @since 0.190.0
|
|
76
81
|
* @status experimental
|
|
77
82
|
* @category charts
|
|
78
83
|
* @aliases Isometric heatmap, Isometric chart, 3D heatmap, Relief chart, Isometric contribution graph
|
|
@@ -87,11 +92,11 @@ import { HelixHeadlessHeatmap } from '../../heatmap/root/heatmap-root.js';
|
|
|
87
92
|
* @csspart base-left - The slab's side toward the viewer at the lower left, under the strip's last row.
|
|
88
93
|
* @csspart base-right - The slab's side toward the viewer at the lower right, under the newest column.
|
|
89
94
|
* @csspart base-top - The slab's top, which is the floor the prisms stand on.
|
|
90
|
-
* @csspart cell - One reading: a group holding
|
|
95
|
+
* @csspart cell - One reading drawn as a prism: a group holding the faces the view shows. Under `selection-mode` it is the picture of a grid cell, hidden from screen readers.
|
|
91
96
|
* @csspart drawing - The SVG every prism is drawn in. It is mirrored on a right-to-left page.
|
|
92
|
-
* @csspart left-face - The
|
|
93
|
-
* @csspart right-face - The
|
|
94
|
-
* @csspart row - A column of
|
|
97
|
+
* @csspart left-face - The side of a prism facing the light more: from the isometric view, the side toward the next row, drawn at its lower left. Left out where the view shows no side.
|
|
98
|
+
* @csspart right-face - The side of a prism facing the light less: from the isometric view, the side toward the next column, drawn at its lower right. Left out where the view shows one side or none.
|
|
99
|
+
* @csspart row - A column of the strip, which a grid reads as a row, under `selection-mode`. It holds the column's grid cells, which draw nothing: the prisms are painted apart, in the order the view needs.
|
|
95
100
|
* @csspart strip - The box the drawing fills, which takes focus to be read by key. It is named by the host's `aria-labelledby` or `aria-label`, then by `label`, then by the caption of the table.
|
|
96
101
|
* @csspart top-face - The top of a prism, which carries the reading's tone.
|
|
97
102
|
*
|
|
@@ -122,6 +127,8 @@ export declare class HelixHeadlessSpatialHeatmap extends HelixHeadlessHeatmap {
|
|
|
122
127
|
relief: number;
|
|
123
128
|
/** The prisms drawn on the last render, which the tooltip is placed against. */
|
|
124
129
|
private shown;
|
|
130
|
+
/** Where the chart's own drawing is seen from, which Shift with an arrow turns. */
|
|
131
|
+
private camera;
|
|
125
132
|
/** Whether a renderer has drawn the relief, which its own drawing then stays under. */
|
|
126
133
|
private rendered;
|
|
127
134
|
/** Where the renderer draws the reading, which the tooltip points at. */
|
|
@@ -187,8 +194,9 @@ export declare class HelixHeadlessSpatialHeatmap extends HelixHeadlessHeatmap {
|
|
|
187
194
|
} | undefined): void;
|
|
188
195
|
protected updated(changed: PropertyValues): void;
|
|
189
196
|
/**
|
|
190
|
-
* Shift with an arrow turns
|
|
191
|
-
*
|
|
197
|
+
* Shift with an arrow turns the view, the chart's own drawing or a
|
|
198
|
+
* renderer's, and moves no reading, except under
|
|
199
|
+
* `selection-mode="multiple"`, where it selects a range.
|
|
192
200
|
*/
|
|
193
201
|
private readonly onTurnKeydown;
|
|
194
202
|
/**
|
|
@@ -204,10 +212,9 @@ export declare class HelixHeadlessSpatialHeatmap extends HelixHeadlessHeatmap {
|
|
|
204
212
|
protected render(): TemplateResult;
|
|
205
213
|
/**
|
|
206
214
|
* One reading as a prism. The sides come first, so the top face is painted
|
|
207
|
-
* over the edge they share with it
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* table and saying whether it is selected, as the flat strip's cell is.
|
|
215
|
+
* over the edge they share with it, and a side the view does not show is
|
|
216
|
+
* left out. Under `selection-mode` it is the picture of a grid cell, hidden
|
|
217
|
+
* from a screen reader, which reads the cell itself.
|
|
211
218
|
*/
|
|
212
219
|
private renderPrism;
|
|
213
220
|
/**
|
|
@@ -222,10 +229,12 @@ export declare class HelixHeadlessSpatialHeatmap extends HelixHeadlessHeatmap {
|
|
|
222
229
|
*/
|
|
223
230
|
private cornersStyle;
|
|
224
231
|
/**
|
|
225
|
-
* The
|
|
226
|
-
*
|
|
232
|
+
* The grid's rows, one for each column of the strip, and its cells in the
|
|
233
|
+
* table's order, each named by its row and saying whether it is selected,
|
|
234
|
+
* as the flat strip's cell is. They hold no drawing: the prisms are painted
|
|
235
|
+
* apart, in the order the view needs.
|
|
227
236
|
*/
|
|
228
|
-
private
|
|
237
|
+
private renderGridRows;
|
|
229
238
|
/**
|
|
230
239
|
* The bubble over the top face of the reading the pointer or the keys rest
|
|
231
240
|
* on, placed as a share of the drawing, which the strip's box matches.
|