@graview/layout 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.
- package/LICENSE +96 -0
- package/README.md +20 -0
- package/dist/band.d.ts +103 -0
- package/dist/band.d.ts.map +1 -0
- package/dist/band.js +344 -0
- package/dist/band.js.map +1 -0
- package/dist/city.d.ts +161 -0
- package/dist/city.d.ts.map +1 -0
- package/dist/city.js +319 -0
- package/dist/city.js.map +1 -0
- package/dist/ids.d.ts +79 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +115 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolate.d.ts +27 -0
- package/dist/interpolate.d.ts.map +1 -0
- package/dist/interpolate.js +217 -0
- package/dist/interpolate.js.map +1 -0
- package/dist/label-fit.d.ts +115 -0
- package/dist/label-fit.d.ts.map +1 -0
- package/dist/label-fit.js +162 -0
- package/dist/label-fit.js.map +1 -0
- package/dist/layout.d.ts +99 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +1391 -0
- package/dist/layout.js.map +1 -0
- package/dist/rank.d.ts +35 -0
- package/dist/rank.d.ts.map +1 -0
- package/dist/rank.js +84 -0
- package/dist/rank.js.map +1 -0
- package/dist/related.d.ts +42 -0
- package/dist/related.d.ts.map +1 -0
- package/dist/related.js +207 -0
- package/dist/related.js.map +1 -0
- package/dist/types.d.ts +404 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/view-state.d.ts +189 -0
- package/dist/view-state.d.ts.map +1 -0
- package/dist/view-state.js +350 -0
- package/dist/view-state.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A NAME THAT FITS THE THING IT NAMES.
|
|
3
|
+
*
|
|
4
|
+
* Every drawn surface in this framework eventually has to write a word
|
|
5
|
+
* inside a shape — a district, a region on a plan, a band on a calendar —
|
|
6
|
+
* and every one of them starts by centring the text at one size and hoping.
|
|
7
|
+
* That works for as long as the names are short, which is for as long as a
|
|
8
|
+
* person is typing them.
|
|
9
|
+
*
|
|
10
|
+
* A product asked a model to survey a garden and got seven areas back
|
|
11
|
+
* called things like "Pea-gravel corner with river-rock border, log seats
|
|
12
|
+
* and a fire bowl". The map drew each at one size across the middle of its
|
|
13
|
+
* shape: three ran off the canvas, two were struck through by a
|
|
14
|
+
* neighbour's outline, and nothing failed — every test passed, the
|
|
15
|
+
* accessibility tree was perfect, and the picture said "rick patio with
|
|
16
|
+
* gravel joints". Agent-authored labels are not an edge case; they are the
|
|
17
|
+
* normal case for anything with an intelligence provider in it.
|
|
18
|
+
*
|
|
19
|
+
* So this is the arithmetic, apart from any drawing, where it can be
|
|
20
|
+
* tested: how much room a shape actually has, and what of a name will fit
|
|
21
|
+
* in it. Nothing here knows what a zone is.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* How wide a shape is AT A HEIGHT — not its bounding box.
|
|
25
|
+
*
|
|
26
|
+
* The shapes that overflow worst are the long thin ones, whose box is
|
|
27
|
+
* generous exactly where the shape is not. So this is a scanline: cross the
|
|
28
|
+
* polygon with a horizontal line and take the widest run that is genuinely
|
|
29
|
+
* inside it. For an L, a crescent or an hourglass waist that is much less
|
|
30
|
+
* than the box, which is the point.
|
|
31
|
+
*/
|
|
32
|
+
export function spanAt(outline, y) {
|
|
33
|
+
const crossings = [];
|
|
34
|
+
for (let i = 0; i < outline.length; i += 1) {
|
|
35
|
+
const a = outline[i];
|
|
36
|
+
const b = outline[(i + 1) % outline.length];
|
|
37
|
+
if (a.y === b.y)
|
|
38
|
+
continue;
|
|
39
|
+
const low = Math.min(a.y, b.y);
|
|
40
|
+
const high = Math.max(a.y, b.y);
|
|
41
|
+
if (y < low || y >= high)
|
|
42
|
+
continue;
|
|
43
|
+
crossings.push(a.x + ((y - a.y) / (b.y - a.y)) * (b.x - a.x));
|
|
44
|
+
}
|
|
45
|
+
crossings.sort((p, q) => p - q);
|
|
46
|
+
let best = { x0: 0, x1: 0 };
|
|
47
|
+
/* Pairs, not neighbours: odd gaps are inside the shape, even ones are not. */
|
|
48
|
+
for (let i = 0; i + 1 < crossings.length; i += 2) {
|
|
49
|
+
const run = { x0: crossings[i], x1: crossings[i + 1] };
|
|
50
|
+
if (run.x1 - run.x0 > best.x1 - best.x0)
|
|
51
|
+
best = run;
|
|
52
|
+
}
|
|
53
|
+
return best;
|
|
54
|
+
}
|
|
55
|
+
/** The corner-to-corner extent, for the vertical room a label has. */
|
|
56
|
+
export function boxOf(outline) {
|
|
57
|
+
let top = Infinity;
|
|
58
|
+
let bottom = -Infinity;
|
|
59
|
+
for (const point of outline) {
|
|
60
|
+
if (point.y < top)
|
|
61
|
+
top = point.y;
|
|
62
|
+
if (point.y > bottom)
|
|
63
|
+
bottom = point.y;
|
|
64
|
+
}
|
|
65
|
+
return { top, bottom };
|
|
66
|
+
}
|
|
67
|
+
/** How much a shape covers, by the shoelace. For ordering, not for display. */
|
|
68
|
+
export function areaOf(outline) {
|
|
69
|
+
let twice = 0;
|
|
70
|
+
for (let i = 0; i < outline.length; i += 1) {
|
|
71
|
+
const a = outline[i];
|
|
72
|
+
const b = outline[(i + 1) % outline.length];
|
|
73
|
+
twice += a.x * b.y - b.x * a.y;
|
|
74
|
+
}
|
|
75
|
+
return Math.abs(twice) / 2;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The area-weighted centroid, which is NOT the mean of the corners.
|
|
79
|
+
*
|
|
80
|
+
* An L-shaped region with six corners has four of them bunched at one end,
|
|
81
|
+
* and averaging drags the label off the shape entirely — onto the
|
|
82
|
+
* neighbour, where it reads as that neighbour's name. The fallback keeps a
|
|
83
|
+
* degenerate shape from producing a NaN that silently removes the label.
|
|
84
|
+
*/
|
|
85
|
+
export function centroidOf(outline) {
|
|
86
|
+
let twiceArea = 0;
|
|
87
|
+
let x = 0;
|
|
88
|
+
let y = 0;
|
|
89
|
+
for (let i = 0; i < outline.length; i += 1) {
|
|
90
|
+
const a = outline[i];
|
|
91
|
+
const b = outline[(i + 1) % outline.length];
|
|
92
|
+
const cross = a.x * b.y - b.x * a.y;
|
|
93
|
+
twiceArea += cross;
|
|
94
|
+
x += (a.x + b.x) * cross;
|
|
95
|
+
y += (a.y + b.y) * cross;
|
|
96
|
+
}
|
|
97
|
+
if (Math.abs(twiceArea) < 1e-9) {
|
|
98
|
+
const mean = outline.reduce((acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }), { x: 0, y: 0 });
|
|
99
|
+
return { x: mean.x / outline.length, y: mean.y / outline.length };
|
|
100
|
+
}
|
|
101
|
+
return { x: x / (3 * twiceArea), y: y / (3 * twiceArea) };
|
|
102
|
+
}
|
|
103
|
+
const ADVANCE = 0.58;
|
|
104
|
+
export const estimateWidth = (text, fontSize) => text.length * fontSize * ADVANCE;
|
|
105
|
+
/**
|
|
106
|
+
* A name that fits, or no name at all.
|
|
107
|
+
*
|
|
108
|
+
* In order: the whole thing on one line; the whole thing broken at the space
|
|
109
|
+
* nearest the middle, which is what a person lettering a plan does; the same
|
|
110
|
+
* shrunk, down to the floor; and then cut, with an ellipsis, so the shape is
|
|
111
|
+
* at least identified.
|
|
112
|
+
*
|
|
113
|
+
* A shape too small for four characters gets NOTHING. A two-letter stub over
|
|
114
|
+
* a flower bed is worse than a clean shape, because it reads as somebody
|
|
115
|
+
* else's label clipped — and `whole: false` is how the caller knows to say
|
|
116
|
+
* the name somewhere a person can still read it.
|
|
117
|
+
*/
|
|
118
|
+
export function fitLabel(text, options) {
|
|
119
|
+
const { room, height, size: base, floor, measure = estimateWidth, lines: most = 2 } = options;
|
|
120
|
+
const fits = (lines, size) => lines.every((line) => measure(line, size) <= room) && lines.length * size * 1.15 <= height;
|
|
121
|
+
if (fits([text], base))
|
|
122
|
+
return { lines: [text], fontSize: base, whole: true };
|
|
123
|
+
const words = text.split(/\s+/);
|
|
124
|
+
if (most > 1 && words.length > 1) {
|
|
125
|
+
/* The break nearest the middle by CHARACTER, not by word count: "The
|
|
126
|
+
long south-facing bed" breaks after "long", not after "south-facing". */
|
|
127
|
+
let at = 1;
|
|
128
|
+
let bestGap = Infinity;
|
|
129
|
+
let run = 0;
|
|
130
|
+
for (let i = 0; i < words.length - 1; i += 1) {
|
|
131
|
+
run += words[i].length + 1;
|
|
132
|
+
const gap = Math.abs(run - text.length / 2);
|
|
133
|
+
if (gap < bestGap) {
|
|
134
|
+
bestGap = gap;
|
|
135
|
+
at = i + 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const two = [words.slice(0, at).join(" "), words.slice(at).join(" ")];
|
|
139
|
+
if (fits(two, base))
|
|
140
|
+
return { lines: two, fontSize: base, whole: true };
|
|
141
|
+
for (let size = base; size >= floor; size -= base * 0.06) {
|
|
142
|
+
if (fits(two, size))
|
|
143
|
+
return { lines: two, fontSize: size, whole: true };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (let size = base; size >= floor; size -= base * 0.06) {
|
|
147
|
+
if (fits([text], size))
|
|
148
|
+
return { lines: [text], fontSize: size, whole: true };
|
|
149
|
+
}
|
|
150
|
+
/* Cut, at the floor, on a word boundary where there is one. */
|
|
151
|
+
const perCharacter = measure(text, floor) / Math.max(1, text.length);
|
|
152
|
+
const fitsAt = Math.floor(room / perCharacter) - 1;
|
|
153
|
+
if (fitsAt < 4 || floor * 1.15 > height)
|
|
154
|
+
return null;
|
|
155
|
+
const cut = text.slice(0, fitsAt);
|
|
156
|
+
const space = cut.lastIndexOf(" ");
|
|
157
|
+
const kept = space > 3 ? cut.slice(0, space) : cut;
|
|
158
|
+
return { lines: [`${kept}…`], fontSize: floor, whole: false };
|
|
159
|
+
}
|
|
160
|
+
/** Whether two boxes touch. The whole of collision avoidance, in one line. */
|
|
161
|
+
export const overlaps = (a, b) => a.x0 < b.x1 && b.x0 < a.x1 && a.y0 < b.y1 && b.y0 < a.y1;
|
|
162
|
+
//# sourceMappingURL=label-fit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label-fit.js","sourceRoot":"","sources":["../src/label-fit.ts"],"names":[],"mappings":"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"}
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type AnySchema, type GraphReader, type NodeOfSchema } from "@graview/core";
|
|
2
|
+
import { type Layout, type LayoutOptions, type Plane } from "./types.js";
|
|
3
|
+
import type { ViewState } from "./view-state.js";
|
|
4
|
+
/**
|
|
5
|
+
* A billboard cut to its picture is never shorter than this, in the lens's
|
|
6
|
+
* own pixels. An empty lens — a header over no rows yet — measured to a
|
|
7
|
+
* strip one line tall, which read as a label, not a screen; at this height
|
|
8
|
+
* the room under the header is visibly an empty screen.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* HOW FAR A BILLBOARD MAY BE MOVED FROM ITS OWN PLOT, in city cells.
|
|
12
|
+
*
|
|
13
|
+
* Cells rather than pixels so the same pin holds at every zoom: a board
|
|
14
|
+
* nudged two cells north is two cells north whether the city is flown close
|
|
15
|
+
* or seen whole. Two is about a village's width — enough to shift a board
|
|
16
|
+
* off whatever it was covering, not enough for it to read as a picture of
|
|
17
|
+
* somewhere else.
|
|
18
|
+
*/
|
|
19
|
+
export declare const SCREEN_LEASH_CELLS = 2;
|
|
20
|
+
export declare const THUMB_ONE: {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
export declare const THUMB_TWO: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
export declare function marqueeHeightFor(titles: readonly string[], cardWidth: number): number;
|
|
29
|
+
/**
|
|
30
|
+
* Where everything sits, as a pure function of (focus, relation, graph),
|
|
31
|
+
* overlaid with user pins.
|
|
32
|
+
*
|
|
33
|
+
* Same graph and same view always produce the same picture — that is what
|
|
34
|
+
* lets spatial memory survive, and what lets any two states be interpolated
|
|
35
|
+
* into an animated transition.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* AN OPENED DISTRICT'S ROSTER, in arithmetic both sides share.
|
|
39
|
+
*
|
|
40
|
+
* The layout reserved 96 pixels under an opened district's nameplate and
|
|
41
|
+
* the view listed sixteen members in 250 — so a dealership's Vehicles,
|
|
42
|
+
* opened at the bottom of the city, ran its list off the scene and over the
|
|
43
|
+
* district beside it. The layout now reserves the rows it will be asked to
|
|
44
|
+
* hold, the view lists the rows it was given (`openedRows`), and the rest
|
|
45
|
+
* are counted.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ROSTER_ROW = 27;
|
|
48
|
+
/** The most rows a roster is given: past it the district is gone into. */
|
|
49
|
+
export declare const ROSTER_MOST = 8;
|
|
50
|
+
export declare const rosterRows: (count: number) => number;
|
|
51
|
+
export declare const rosterHeight: (rows: number) => number;
|
|
52
|
+
export declare function layout<S extends AnySchema>(graph: GraphReader<NodeOfSchema<S>>, schema: S, state: ViewState, options?: LayoutOptions): Layout;
|
|
53
|
+
/** Which plane a node ended up on, or null if it is not in the layout. */
|
|
54
|
+
export declare function planeOf(result: Layout, id: string): Plane | null;
|
|
55
|
+
/**
|
|
56
|
+
* THE PAN, APPLIED AFTER THE FACT — the same answer, without the arithmetic.
|
|
57
|
+
*
|
|
58
|
+
* The pan is baked into every card's coordinates at layout time, and that is
|
|
59
|
+
* right: it is what lets two layouts be interpolated into motion, and it is
|
|
60
|
+
* why connectors, the frame planner and both renderers get panning without
|
|
61
|
+
* any of them learning about it.
|
|
62
|
+
*
|
|
63
|
+
* But it is applied at the END of a function that has already decided
|
|
64
|
+
* everything else — communities, plots, band packing, the drive-in's own
|
|
65
|
+
* sizing loop — and a drag changes nothing but the pan. Running all of that
|
|
66
|
+
* again per pointer move cost rota's city 169 dropped frames and ten
|
|
67
|
+
* seconds of blocked main thread in a two-second drag.
|
|
68
|
+
*
|
|
69
|
+
* So the pan comes out: lay the world out once at rest, and translate it.
|
|
70
|
+
* The result is the same object `layout` would have returned — held to that
|
|
71
|
+
* by `the-pan-is-a-translation` — and the caller can hold the expensive half
|
|
72
|
+
* still while a hand is moving.
|
|
73
|
+
*
|
|
74
|
+
* The city's own origin and extent are unpanned by definition (the ground
|
|
75
|
+
* rides `city.pan`), so only the cards, the lines between them and the
|
|
76
|
+
* recorded pan move.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* A CARD UNDER THE HAND, moved without laying the world out again.
|
|
80
|
+
*
|
|
81
|
+
* A pin only overrides where one card is; everything else about the stop —
|
|
82
|
+
* the band's grouping, the bundles, the districts — is what it was. Laying
|
|
83
|
+
* it all out again on every pointer move put a full `layout()` and a full
|
|
84
|
+
* bundle of every edge in every frame of a drag (docs/scale.md). This moves
|
|
85
|
+
* the held card to the pin (unpanned, as a pin is stored) and re-aims the
|
|
86
|
+
* lines that touch it. `null` when it cannot say the same thing a full
|
|
87
|
+
* layout would — a drive-in's screen, whose pin places it differently —
|
|
88
|
+
* and the caller lays it out with the pin instead. On release the pin goes
|
|
89
|
+
* into the view and the full layout runs once.
|
|
90
|
+
*/
|
|
91
|
+
export declare function holdLayout(placed: Layout, id: string, at: {
|
|
92
|
+
x: number;
|
|
93
|
+
y: number;
|
|
94
|
+
}): Layout | null;
|
|
95
|
+
export declare function panLayout(placed: Layout, pan: {
|
|
96
|
+
x: number;
|
|
97
|
+
y: number;
|
|
98
|
+
}): Layout;
|
|
99
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACtG,OAAO,EAGL,KAAK,MAAM,EAEX,KAAK,aAAa,EAClB,KAAK,KAAK,EACX,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAsCjD;;;;;GAKG;AACH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAyBpC,eAAO,MAAM,SAAS;;;CAA6B,CAAC;AACpD,eAAO,MAAM,SAAS;;;CAA4B,CAAC;AAGnD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMrF;AA6CD;;;;;;;GAOG;AACH;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,0EAA0E;AAC1E,eAAO,MAAM,WAAW,IAAI,CAAC;AAK7B,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAAmD,CAAC;AAC/F,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAA2C,CAAC;AAExF,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EACxC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EACnC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CA+uCR;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAEhE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAiBlG;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAc/E"}
|