@kerusiweb/core 2.3.0 → 3.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 +22 -22
- package/README.md +74 -68
- package/dist/kerusi/index.d.ts +4 -3
- package/dist/kerusi/index.d.ts.map +1 -1
- package/dist/kerusi/index.js +4 -3
- package/dist/kerusi/index.js.map +1 -1
- package/dist/kerusi/kerusi-geometry.d.ts +47 -0
- package/dist/kerusi/kerusi-geometry.d.ts.map +1 -0
- package/dist/kerusi/kerusi-geometry.js +111 -0
- package/dist/kerusi/kerusi-geometry.js.map +1 -0
- package/dist/kerusi/kerusi-map.model.d.ts +121 -68
- package/dist/kerusi/kerusi-map.model.d.ts.map +1 -1
- package/dist/kerusi/kerusi-map.model.js +6 -2
- package/dist/kerusi/kerusi-map.model.js.map +1 -1
- package/dist/kerusi/kerusi-rows.d.ts +2 -2
- package/dist/kerusi/kerusi-rows.js +2 -2
- package/dist/kerusi/kerusi-validator.d.ts +18 -9
- package/dist/kerusi/kerusi-validator.d.ts.map +1 -1
- package/dist/kerusi/kerusi-validator.js +301 -122
- package/dist/kerusi/kerusi-validator.js.map +1 -1
- package/dist/render/build-render-model.d.ts +8 -4
- package/dist/render/build-render-model.d.ts.map +1 -1
- package/dist/render/build-render-model.js +147 -45
- package/dist/render/build-render-model.js.map +1 -1
- package/dist/render/index.d.ts +1 -1
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +1 -1
- package/dist/render/index.js.map +1 -1
- package/dist/render/map-layout.d.ts +92 -0
- package/dist/render/map-layout.d.ts.map +1 -0
- package/dist/render/map-layout.js +93 -0
- package/dist/render/map-layout.js.map +1 -0
- package/dist/render/navigation-order.d.ts +20 -10
- package/dist/render/navigation-order.d.ts.map +1 -1
- package/dist/render/navigation-order.js +72 -57
- package/dist/render/navigation-order.js.map +1 -1
- package/dist/render/render-model.d.ts +48 -26
- package/dist/render/render-model.d.ts.map +1 -1
- package/dist/render/seat-shapes.d.ts +3 -3
- package/dist/render/seat-shapes.js +3 -3
- package/dist/view/index.d.ts +6 -2
- package/dist/view/index.d.ts.map +1 -1
- package/dist/view/index.js +6 -2
- package/dist/view/index.js.map +1 -1
- package/dist/view/rtl.d.ts +1 -1
- package/dist/view/rtl.js +1 -1
- package/dist/view/seat-aria.d.ts +6 -0
- package/dist/view/seat-aria.d.ts.map +1 -1
- package/dist/view/seat-aria.js +8 -0
- package/dist/view/seat-aria.js.map +1 -1
- package/dist/view/seat-card-placement.d.ts +60 -0
- package/dist/view/seat-card-placement.d.ts.map +1 -0
- package/dist/view/seat-card-placement.js +94 -0
- package/dist/view/seat-card-placement.js.map +1 -0
- package/dist/view/seat-card.d.ts +83 -0
- package/dist/view/seat-card.d.ts.map +1 -0
- package/dist/view/seat-card.js +68 -0
- package/dist/view/seat-card.js.map +1 -0
- package/dist/view/seat-glyph.d.ts +1 -1
- package/dist/view/seat-glyph.d.ts.map +1 -1
- package/dist/view/seat-hover.d.ts +90 -0
- package/dist/view/seat-hover.d.ts.map +1 -0
- package/dist/view/seat-hover.js +205 -0
- package/dist/view/seat-hover.js.map +1 -0
- package/dist/view/viewport.d.ts +35 -7
- package/dist/view/viewport.d.ts.map +1 -1
- package/dist/view/viewport.js +56 -7
- package/dist/view/viewport.js.map +1 -1
- package/package.json +42 -42
- package/dist/kerusi/kerusi-layout-mode.d.ts +0 -58
- package/dist/kerusi/kerusi-layout-mode.d.ts.map +0 -1
- package/dist/kerusi/kerusi-layout-mode.js +0 -117
- package/dist/kerusi/kerusi-layout-mode.js.map +0 -1
- package/dist/render/section-layout.d.ts +0 -66
- package/dist/render/section-layout.d.ts.map +0 -1
- package/dist/render/section-layout.js +0 -186
- package/dist/render/section-layout.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2015-2026 Arsyad "Shad Ahm" Ahmad
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
22
|
-
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-2026 Arsyad "Shad Ahm" Ahmad
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -1,68 +1,74 @@
|
|
|
1
|
-
# @kerusiweb/core
|
|
2
|
-
|
|
3
|
-
Framework-agnostic core for the **[Kerusi Seat Map & Availability
|
|
4
|
-
Format](https://github.com/ShadAhm/kerusi)**: the document types, a conformance
|
|
5
|
-
validator, and the render model and geometry a seat-map renderer consumes.
|
|
6
|
-
|
|
7
|
-
Pure TypeScript. No Angular, no React, no RxJS, no DOM, so it runs in a
|
|
8
|
-
browser, in a build step, or on a server.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @kerusiweb/core
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
For a UI on top of it, add the binding for your framework:
|
|
15
|
-
[`@kerusiweb/angular`](https://www.npmjs.com/package/@kerusiweb/angular) or
|
|
16
|
-
[`@kerusiweb/react`](https://www.npmjs.com/package/@kerusiweb/react). Both
|
|
17
|
-
expose the same surface and emit the same SVG.
|
|
18
|
-
|
|
19
|
-
## What's in it
|
|
20
|
-
|
|
21
|
-
**`kerusi/`: the format.** `KerusiMap`, `KerusiState`, `KerusiSession`, `Seat`,
|
|
22
|
-
`Section`, `Money` and friends, plus the logic the standard defines over them:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
import { validateDocumentSet, errorsOf, resolveSeatPrice, expireHolds } from '@kerusiweb/core';
|
|
26
|
-
|
|
27
|
-
const violations = validateDocumentSet({ map, state, session });
|
|
28
|
-
if (errorsOf(violations).length) throw new Error('non-conformant documents');
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**`render/`: the resolved view and its geometry.** `buildRenderModel()` merges
|
|
32
|
-
a state onto a map and resolves prices, locale, row order
|
|
33
|
-
`RenderMap`; `
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
(`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
# @kerusiweb/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic core for the **[Kerusi Seat Map & Availability
|
|
4
|
+
Format](https://github.com/ShadAhm/kerusi)**: the document types, a conformance
|
|
5
|
+
validator, and the render model and geometry a seat-map renderer consumes.
|
|
6
|
+
|
|
7
|
+
Pure TypeScript. No Angular, no React, no RxJS, no DOM, so it runs in a
|
|
8
|
+
browser, in a build step, or on a server.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @kerusiweb/core
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
For a UI on top of it, add the binding for your framework:
|
|
15
|
+
[`@kerusiweb/angular`](https://www.npmjs.com/package/@kerusiweb/angular) or
|
|
16
|
+
[`@kerusiweb/react`](https://www.npmjs.com/package/@kerusiweb/react). Both
|
|
17
|
+
expose the same surface and emit the same SVG.
|
|
18
|
+
|
|
19
|
+
## What's in it
|
|
20
|
+
|
|
21
|
+
**`kerusi/`: the format.** `KerusiMap`, `KerusiState`, `KerusiSession`, `Seat`,
|
|
22
|
+
`Section`, `Money` and friends, plus the logic the standard defines over them:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { validateDocumentSet, errorsOf, resolveSeatPrice, expireHolds } from '@kerusiweb/core';
|
|
26
|
+
|
|
27
|
+
const violations = validateDocumentSet({ map, state, session });
|
|
28
|
+
if (errorsOf(violations).length) throw new Error('non-conformant documents');
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**`render/`: the resolved view and its geometry.** `buildRenderModel()` merges
|
|
32
|
+
a state onto a map and resolves prices, locale, row order, seat sizes and
|
|
33
|
+
section bounds into a `RenderMap`; `computeMapLayout()` places every seat and
|
|
34
|
+
element on the map's canvas, exactly where the document puts it, mirroring the
|
|
35
|
+
whole canvas for a right-to-left locale; `seatBodyPath()` and friends return
|
|
36
|
+
SVG path `d` strings.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { buildRenderModel, computeMapLayout, seatBodyPath } from '@kerusiweb/core';
|
|
40
|
+
|
|
41
|
+
const model = buildRenderModel(map, state);
|
|
42
|
+
const layout = computeMapLayout(model, { rtl: false });
|
|
43
|
+
// layout.width / layout.height → the canvas: the map's one viewBox
|
|
44
|
+
// layout.sections[0].seats[0] → { seat, x, y, width, height, centerX, centerY, ... }
|
|
45
|
+
const { x, y, width, height } = layout.sections[0].seats[0];
|
|
46
|
+
const d = seatBodyPath(x, y, width, height); // → 'M4 8 …', ready for <path d>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**`view/`: presentation policy, still framework-free.** The colour system
|
|
50
|
+
(`DEFAULT_KERUSI_COLORS`, `seatFill`, `readableOn`), the ARIA strings
|
|
51
|
+
(`seatAriaLabel`, `disallowedAnnouncement`), the selection rules
|
|
52
|
+
(`toggleSeatSelection`, `summarizeSelection`, `DisallowedReason`), and the rules
|
|
53
|
+
behind seat hover and seat cards: `reduceSeatHover()` (the pointer-type filter,
|
|
54
|
+
the pause during a pan or zoom, the open and close delays) and `placeSeatCard()`
|
|
55
|
+
(side, position and arrow offset, with flip and clamp), both pure, plus the
|
|
56
|
+
`SeatClick` and `KerusiSeatCardContext` types.
|
|
57
|
+
|
|
58
|
+
## Server-side use
|
|
59
|
+
|
|
60
|
+
Core is `"type": "module"` and its emitted imports carry explicit extensions, so
|
|
61
|
+
it loads under plain Node ESM with no bundler:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
import { validateDocumentSet } from '@kerusiweb/core';
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Contributing
|
|
68
|
+
|
|
69
|
+
See [docs/architecture.md](../../docs/architecture.md) for what belongs here and
|
|
70
|
+
what belongs in a framework binding.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
MIT © Arsyad "Shad Ahm" Ahmad
|
package/dist/kerusi/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Kerusi Seat Map & Availability Format support.
|
|
3
3
|
*
|
|
4
|
-
* The document types, a conformance validator,
|
|
5
|
-
*
|
|
4
|
+
* The document types, a conformance validator, the canvas geometry the
|
|
5
|
+
* standard defines (adjacency, row guides, seat size), and the price, locale
|
|
6
|
+
* and row-order resolution the renderer is built on. Everything here is pure —
|
|
6
7
|
* no framework import — so it can be used server-side or in a build step.
|
|
7
8
|
*
|
|
8
9
|
* See docs/kerusi.md and the full standard for details.
|
|
@@ -10,7 +11,7 @@
|
|
|
10
11
|
export * from './kerusi-map.model.js';
|
|
11
12
|
export * from './kerusi-state.model.js';
|
|
12
13
|
export * from './kerusi-violation.js';
|
|
13
|
-
export
|
|
14
|
+
export { areNeighbours, guidePoint, isOnGuide, seatSizeOf } from './kerusi-geometry.js';
|
|
14
15
|
export * from './kerusi-rows.js';
|
|
15
16
|
export * from './kerusi-locale.js';
|
|
16
17
|
export * from './kerusi-price.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kerusi/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kerusi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACxF,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
|
package/dist/kerusi/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Kerusi Seat Map & Availability Format support.
|
|
3
3
|
*
|
|
4
|
-
* The document types, a conformance validator,
|
|
5
|
-
*
|
|
4
|
+
* The document types, a conformance validator, the canvas geometry the
|
|
5
|
+
* standard defines (adjacency, row guides, seat size), and the price, locale
|
|
6
|
+
* and row-order resolution the renderer is built on. Everything here is pure —
|
|
6
7
|
* no framework import — so it can be used server-side or in a build step.
|
|
7
8
|
*
|
|
8
9
|
* See docs/kerusi.md and the full standard for details.
|
|
@@ -10,7 +11,7 @@
|
|
|
10
11
|
export * from './kerusi-map.model.js';
|
|
11
12
|
export * from './kerusi-state.model.js';
|
|
12
13
|
export * from './kerusi-violation.js';
|
|
13
|
-
export
|
|
14
|
+
export { areNeighbours, guidePoint, isOnGuide, seatSizeOf } from './kerusi-geometry.js';
|
|
14
15
|
export * from './kerusi-rows.js';
|
|
15
16
|
export * from './kerusi-locale.js';
|
|
16
17
|
export * from './kerusi-price.js';
|
package/dist/kerusi/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/kerusi/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/kerusi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACxF,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { KerusiMap, Point, RowShape, Seat, Section } from './kerusi-map.model.js';
|
|
2
|
+
/**
|
|
3
|
+
* The seat size that applies within a section (§4.5): the section's own
|
|
4
|
+
* `seatSize` when it declares one, the map's otherwise. `undefined` only for a
|
|
5
|
+
* document missing both, which the validator rejects.
|
|
6
|
+
*/
|
|
7
|
+
export declare function seatSizeOf(map: Pick<KerusiMap, 'seatSize'>, section?: Pick<Section, 'seatSize'>): number | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Whether two seats of the SAME section are neighbours (§4.3.5): same row, and
|
|
10
|
+
* cols that differ by exactly 1. Nothing else implies adjacency — not distance,
|
|
11
|
+
* not labels, not array order. Seats in different sections never are, so the
|
|
12
|
+
* caller must only pass seats from one section.
|
|
13
|
+
*/
|
|
14
|
+
export declare function areNeighbours(a: Pick<Seat, 'row' | 'col'>, b: Pick<Seat, 'row' | 'col'>): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The guide point of column `col` on a row shape (§4.2.3). `null` when the
|
|
17
|
+
* column lies outside the shape's `cols` range, or the shape is not one the
|
|
18
|
+
* standard defines.
|
|
19
|
+
*
|
|
20
|
+
* Only editors need this. A renderer draws each seat at its own `x`/`y` and
|
|
21
|
+
* never consults a row shape.
|
|
22
|
+
*/
|
|
23
|
+
export declare function guidePoint(shape: RowShape, col: number): Point | null;
|
|
24
|
+
/**
|
|
25
|
+
* Whether a seat lies on its guide (§4.2.3): within `seatSize / 4` of its guide
|
|
26
|
+
* point. Editors use this to decide which seats to move when a guide changes;
|
|
27
|
+
* renderers never do.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isOnGuide(seat: Pick<Seat, 'col' | 'x' | 'y'>, shape: RowShape, seatSize: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* A seat's footprint (§4.5): a square of side `size` centred on `x`/`y`, turned
|
|
32
|
+
* by `theta` radians.
|
|
33
|
+
*/
|
|
34
|
+
export interface Footprint {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
size: number;
|
|
38
|
+
theta: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function footprintOf(seat: Pick<Seat, 'x' | 'y' | 'rotation'>, size: number): Footprint;
|
|
41
|
+
/**
|
|
42
|
+
* Whether two footprints overlap (§4.3.1), by the separating axis theorem over
|
|
43
|
+
* the edge normals of both squares. Footprints that only touch, as neighbouring
|
|
44
|
+
* seats placed exactly one seat size apart do, don't overlap.
|
|
45
|
+
*/
|
|
46
|
+
export declare function footprintsOverlap(p: Footprint, q: Footprint): boolean;
|
|
47
|
+
//# sourceMappingURL=kerusi-geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kerusi-geometry.d.ts","sourceRoot":"","sources":["../../src/kerusi/kerusi-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAelF;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,GAClC,MAAM,GAAG,SAAS,CAKpB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,OAAO,CAQjG;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAgCrE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC,EACnC,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAST;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAE7F;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAcrE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas geometry the standard defines over a map (§4.2.3, §4.3.1, §4.3.5,
|
|
3
|
+
* §4.5), with the same semantics as the reference validator's
|
|
4
|
+
* `schema/semantic-rules.mjs`. Reimplemented rather than imported so core keeps
|
|
5
|
+
* no runtime dependencies.
|
|
6
|
+
*/
|
|
7
|
+
const isNum = (v) => typeof v === 'number' && Number.isFinite(v);
|
|
8
|
+
const isInteger = (v) => Number.isInteger(v);
|
|
9
|
+
const rad = (degrees) => (degrees * Math.PI) / 180;
|
|
10
|
+
/**
|
|
11
|
+
* The seat size that applies within a section (§4.5): the section's own
|
|
12
|
+
* `seatSize` when it declares one, the map's otherwise. `undefined` only for a
|
|
13
|
+
* document missing both, which the validator rejects.
|
|
14
|
+
*/
|
|
15
|
+
export function seatSizeOf(map, section) {
|
|
16
|
+
if (isNum(section?.seatSize)) {
|
|
17
|
+
return section.seatSize;
|
|
18
|
+
}
|
|
19
|
+
return isNum(map?.seatSize) ? map.seatSize : undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether two seats of the SAME section are neighbours (§4.3.5): same row, and
|
|
23
|
+
* cols that differ by exactly 1. Nothing else implies adjacency — not distance,
|
|
24
|
+
* not labels, not array order. Seats in different sections never are, so the
|
|
25
|
+
* caller must only pass seats from one section.
|
|
26
|
+
*/
|
|
27
|
+
export function areNeighbours(a, b) {
|
|
28
|
+
if (a.row === undefined || b.row === undefined || a.row !== b.row) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (!Number.isInteger(a.col) || !Number.isInteger(b.col)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return Math.abs(a.col - b.col) === 1;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The guide point of column `col` on a row shape (§4.2.3). `null` when the
|
|
38
|
+
* column lies outside the shape's `cols` range, or the shape is not one the
|
|
39
|
+
* standard defines.
|
|
40
|
+
*
|
|
41
|
+
* Only editors need this. A renderer draws each seat at its own `x`/`y` and
|
|
42
|
+
* never consults a row shape.
|
|
43
|
+
*/
|
|
44
|
+
export function guidePoint(shape, col) {
|
|
45
|
+
const g = 'line' in shape
|
|
46
|
+
? shape.line
|
|
47
|
+
: 'arc' in shape
|
|
48
|
+
? shape.arc
|
|
49
|
+
: 'circle' in shape
|
|
50
|
+
? shape.circle
|
|
51
|
+
: undefined;
|
|
52
|
+
if (!g) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const [a, b] = Array.isArray(g.cols) ? g.cols : [];
|
|
56
|
+
if (!isInteger(col) || !isInteger(a) || !isInteger(b) || col < a || col > b) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const t = a === b ? 0 : (col - a) / (b - a);
|
|
60
|
+
const onCircle = (center, radius, degrees) => [
|
|
61
|
+
center[0] + radius * Math.cos(rad(degrees)),
|
|
62
|
+
center[1] + radius * Math.sin(rad(degrees)),
|
|
63
|
+
];
|
|
64
|
+
if ('line' in shape) {
|
|
65
|
+
const { from, to } = shape.line;
|
|
66
|
+
return [from[0] + (to[0] - from[0]) * t, from[1] + (to[1] - from[1]) * t];
|
|
67
|
+
}
|
|
68
|
+
if ('arc' in shape) {
|
|
69
|
+
const { center, radius, start, sweep } = shape.arc;
|
|
70
|
+
return onCircle(center, radius, start + sweep * t);
|
|
71
|
+
}
|
|
72
|
+
const { center, radius, start } = shape.circle;
|
|
73
|
+
return onCircle(center, radius, start + (360 * (col - a)) / (b - a + 1));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether a seat lies on its guide (§4.2.3): within `seatSize / 4` of its guide
|
|
77
|
+
* point. Editors use this to decide which seats to move when a guide changes;
|
|
78
|
+
* renderers never do.
|
|
79
|
+
*/
|
|
80
|
+
export function isOnGuide(seat, shape, seatSize) {
|
|
81
|
+
if (seat.col === undefined) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const point = guidePoint(shape, seat.col);
|
|
85
|
+
if (!point || !isNum(seat.x) || !isNum(seat.y)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return Math.hypot(seat.x - point[0], seat.y - point[1]) <= seatSize / 4;
|
|
89
|
+
}
|
|
90
|
+
export function footprintOf(seat, size) {
|
|
91
|
+
return { x: seat.x, y: seat.y, size, theta: rad(isNum(seat.rotation) ? seat.rotation : 0) };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Whether two footprints overlap (§4.3.1), by the separating axis theorem over
|
|
95
|
+
* the edge normals of both squares. Footprints that only touch, as neighbouring
|
|
96
|
+
* seats placed exactly one seat size apart do, don't overlap.
|
|
97
|
+
*/
|
|
98
|
+
export function footprintsOverlap(p, q) {
|
|
99
|
+
const dx = q.x - p.x;
|
|
100
|
+
const dy = q.y - p.y;
|
|
101
|
+
const tolerance = 1e-9 * Math.max(p.size, q.size);
|
|
102
|
+
const reach = (f, axis) => (f.size / 2) * (Math.abs(Math.cos(f.theta - axis)) + Math.abs(Math.sin(f.theta - axis)));
|
|
103
|
+
for (const axis of [p.theta, p.theta + Math.PI / 2, q.theta, q.theta + Math.PI / 2]) {
|
|
104
|
+
const gap = Math.abs(dx * Math.cos(axis) + dy * Math.sin(axis));
|
|
105
|
+
if (gap >= reach(p, axis) + reach(q, axis) - tolerance) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=kerusi-geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kerusi-geometry.js","sourceRoot":"","sources":["../../src/kerusi/kerusi-geometry.ts"],"names":[],"mappings":"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"}
|