@phin-tech/dottie 0.8.0 → 0.10.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.
@@ -1,5 +1,5 @@
1
1
  import type { Face } from "./metrics.ts";
2
- /** What follows the runtime; DOTTIE_DATA and DOTTIE_OPTIONS are replaced with JSON. Plain ES5, unminified. */
2
+ /** What follows the runtime; DOTTIE_DATA, DOTTIE_OPTIONS and DOTTIE_FONTS are replaced with JSON. Plain ES5, unminified. */
3
3
  export declare const LOADER = ";(function () {\n var data = DOTTIE_DATA, options = DOTTIE_OPTIONS, fonts = DOTTIE_FONTS;\n var script = document.currentScript;\n if (window.Dottie.addFonts) window.Dottie.addFonts(Object.keys(fonts), fonts);\n function attr(el, name, value) { el.setAttribute(name.replace(/[A-Z]/g, function (c) { return \"-\" + c.toLowerCase(); }), value); }\n function mount() {\n var player = document.createElement(\"dottie-player\"), k;\n for (k in options) attr(player, k, options[k]);\n if (script) for (k in script.dataset) if (k !== \"target\") attr(player, k, script.dataset[k]);\n var target = script && script.dataset.target ? document.querySelector(script.dataset.target) : null;\n if (target) target.appendChild(player);\n else if (script && script.parentNode && script.parentNode !== document.head) script.parentNode.insertBefore(player, script);\n else document.body.appendChild(player);\n player.setFile(window.Dottie.parseDottie(data));\n }\n if (document.readyState === \"loading\" && (!script || script.parentNode === document.head || script.dataset.target)) {\n document.addEventListener(\"DOMContentLoaded\", mount);\n } else {\n mount();\n }\n})();\n";
4
4
  export interface CompileOptions {
5
5
  /** Page name or 1-based number; only that page goes in. The first page by default. */
@@ -24,5 +24,9 @@ export declare function arrowhead(tip: Point, from: Point, size: number): [Point
24
24
  export declare function connectorBounds(e: Element, index: Index): Rect;
25
25
  /** Point halfway along the route, where a label sits. */
26
26
  export declare function midpoint(e: Element, index: Index): Point;
27
+ /** Each element by id, the first with an id winning. Kept per elements array, so every follow, trace and render of
28
+ * one frame shares it; checked against the array's members each time, so a page changed in place is indexed anew. */
29
+ /** Whether `index` is the one `indexOf` last built for this page's elements (without checking them again). */
30
+ export declare function isIndexOf(page: Page, index: Index): boolean;
27
31
  export declare function indexOf(page: Page): Index;
28
32
  export { angle };
@@ -0,0 +1,18 @@
1
+ import type { Element } from "./model.ts";
2
+ import type { Point, Rect } from "./path.ts";
3
+ /** How far a route keeps from the shapes it goes round. */
4
+ export declare const MARGIN = 16;
5
+ /** What a bend costs, in points of length. */
6
+ export declare const BEND = 24;
7
+ /** Shapes smaller than this either way (packets, dots, small icons) aren't in the way. */
8
+ export declare const SMALLEST = 24;
9
+ /** More shapes in the way than this, and the plain route is kept. */
10
+ export declare const MOST = 48;
11
+ /** The box of `e` if a route goes round it: not a connector, text, freehand line or plain path, not invisible, and
12
+ * not small. */
13
+ export declare function obstacle(e: Element): Rect | null;
14
+ /** Whether the right-angled line through `points` passes through the inside of `r` (not just along its edge). */
15
+ export declare function crosses(points: Point[], r: Rect): boolean;
16
+ /** `plain` (the Z or L from `a` to `b`), or a way round the shapes among `elements` it crosses, leaving out `except`
17
+ * (the connector's own ends). */
18
+ export declare function avoiding(plain: Point[], a: Point, b: Point, startVertical: boolean, endVertical: boolean, elements: Iterable<Element>, except: Set<string>): Point[];
@@ -4,9 +4,13 @@ export declare const DEFAULT_COLOR: RGBA;
4
4
  export declare const clamp: (v: number | null, fallback: number, lo: number, hi: number) => number;
5
5
  /** The id of a flow's packet `k`: the flow's id with its last twelve digits standing for `k` (Flow.packetID). */
6
6
  export declare function packetID(flow: string, k: number): string;
7
- /** Every shape traffic from `from` can reach in `frame`, with the cheapest way to each (DottieDocument.flowTree):
8
- * by the connectors' cost (1 each unless set), ties to the shape reached first, earlier connectors first. */
9
- export declare function flowTree(from: string, frame: Page, offline?: Set<string>): FlowTree | null;
7
+ /** `cost` as routing uses it: 1 for null, kept within 0...1,000,000 (ConnectorData.routeCost). */
8
+ export declare const routeCost: (cost: number | null) => number;
9
+ /** Every shape traffic from `from` can reach in `frame`, with the cheapest way to each:
10
+ * by the connectors' cost (1 each unless set), ties to the shape reached first, earlier connectors first.
11
+ * With `until`, the search stops once that shape is settled: its way is final then, and it is the first goal of any
12
+ * list it heads, but the tree holds only the shapes settled before it. */
13
+ export declare function flowTree(from: string, frame: Page, offline?: Set<string>, until?: string): FlowTree | null;
10
14
  export declare class FlowTree {
11
15
  settled: Set<string>;
12
16
  came: Map<string, {
@@ -5,7 +5,7 @@ export { BUNDLED_FONTS } from "./text.ts";
5
5
  export { inspect, inspectFrame, inspectPage, sampleTimes } from "./inspect.ts";
6
6
  export { DottiePlayer, Playback, definePlayer, pageIndex, withRoughness } from "./player.ts";
7
7
  export { bounds, plan, svg, svgParts, type Plan, type Part } from "./svg.ts";
8
- export { themeNamed, themes, type Theme } from "./theme.ts";
8
+ export { pageTheme, paletteColor, themeNamed, themes, type Theme } from "./theme.ts";
9
9
  export { cameraView, frameTimes, posterTime, resolved, sceneAt, still, transientElements } from "./timeline.ts";
10
10
  export interface RenderOptions {
11
11
  /** Page name or 1-based number; the first page by default. */
@@ -20,4 +20,4 @@ export interface RenderOptions {
20
20
  /** One page of a drawing as an SVG document, as Dottie's own SVG export draws it. */
21
21
  export declare function render(source: string | DottieFile | unknown, options?: RenderOptions): string;
22
22
  /** The library's version. */
23
- export declare const VERSION = "0.8.0";
23
+ export declare const VERSION = "0.10.0";
@@ -28,20 +28,46 @@ export declare const emptyMetrics: () => FrameMetrics;
28
28
  export declare function metricValue(m: FrameMetrics, metric: string, id: string): number | null;
29
29
  /** A shape's delay as traffic feels it: 0...3600 seconds. */
30
30
  export declare function delayOf(e: Element): number;
31
+ /** One way a flow's traffic takes in a frame (`flowFrame`'s routes): to `goal` over the connectors `hops`
32
+ * ([connector, backwards]), carrying `amount` of its volume at a cost of `cost`; `waits` when it goes only as far as
33
+ * the queue it waits in. */
34
+ export interface FlowRoute {
35
+ goal: string;
36
+ hops: [string, boolean][];
37
+ amount: number;
38
+ waits: boolean;
39
+ cost: number;
40
+ }
31
41
  /** The key of a flow's queue at a shape in `FrameMetrics.carry` and `carried` (DottieDocument.queueKey). */
32
42
  export declare const queueKey: (shape: string, flow: string) => string;
33
43
  /** The packets the page's flows draw in `frame` (the page posed at `t`), with these values (null: every flow runs),
34
- * and the frame's metrics (DottieDocument.flowFrame). `since` is the seconds since the page's state last changed
44
+ * and the frame's metrics. `since` is the seconds since the page's state last changed
35
45
  * (null: `t`), and `carried` how much each flow's queue held at that moment: since then a queue grows by its
36
46
  * backlog, or drains at the room its way on has left. */
37
47
  export declare function flowFrame(flows: Flow[] | null, frame: Page, t: number, values: Record<string, boolean> | null, offline?: Set<string>, sinceChange?: number | null, carried?: Record<string, number>): {
38
48
  packets: Element[];
39
49
  metrics: FrameMetrics;
50
+ routes: Map<string, FlowRoute[]>;
40
51
  };
41
52
  /** The frame's metric for a condition's comparison: its target an element's anchor, or an element's or flow's id. */
42
53
  export declare function metricLookup(m: FrameMetrics, frame: Page): (t: MetricTerm, own: string | null) => number | null;
54
+ /** What finishing does to one element: which of its overrides that compare metrics hold (their looks apply, in
55
+ * order), and, for a gauge, the reading it shows. */
56
+ export interface Finish {
57
+ applied: number[];
58
+ gauge: {
59
+ value: number | null;
60
+ } | null;
61
+ }
62
+ /** For each of `elements`, the overrides that compare metrics that hold and the reading a gauge shows (easing, over
63
+ * `GAUGE_EASE` seconds since the state changed, from its reading then, `carried`); with no values ("all", the
64
+ * editor), nothing. The readings come back to carry over. */
65
+ export declare function finishPlan(elements: Element[], metrics: FrameMetrics, values: Record<string, boolean> | null, frame: Page, since?: number, carried?: Record<string, number>): {
66
+ plan: Finish[];
67
+ readings: Record<string, number>;
68
+ };
43
69
  /** `elements` with the looks of overrides that compare metrics applied, and gauges drawn as plain elements; with
44
- * no values ("all", the editor), both are left as they are (DottieDocument.finishing). */
70
+ * no values ("all", the editor), both are left as they are (`finishPlan`). */
45
71
  export declare function finishing(elements: Element[], metrics: FrameMetrics, values: Record<string, boolean> | null, frame: Page, flows: Flow[], since?: number, carried?: Record<string, number>): {
46
72
  elements: Element[];
47
73
  readings: Record<string, number>;
@@ -54,5 +80,5 @@ export declare const GAUGE_BLUE: RGBA, GAUGE_TRACK: RGBA, GAUGE_GRAY: RGBA;
54
80
  export declare function formatted(metric: string, v: number | null): string;
55
81
  /** `v` to `places` decimals, halves away from zero, trailing zeros dropped (DottieDocument.number). */
56
82
  export declare function formatNumber(v: number, places: number): string;
57
- /** A gauge drawn: its frame as a `.path` carrying the label, then the bar or dial (DottieDocument.gauge). */
83
+ /** A gauge drawn: its frame as a `.path` carrying the label, then the bar or dial. */
58
84
  export declare function gauge(e: Element, g: Gauge, value: number | null, frame: Page, flows: Flow[]): Element[];
@@ -29,6 +29,27 @@ export interface Style {
29
29
  dashOffset: number | null;
30
30
  /** The color of a shape's or connector's label; null follows `stroke`. Text boxes and notes ignore it. */
31
31
  textColor: RGBA | null;
32
+ /** Which colors are palette colors, by name (ADR 0005); set from the page's palette when it is read. */
33
+ named?: ColorNames | null;
34
+ }
35
+ /** Palette names for an element's colors (Theme.swift's ColorNames). */
36
+ export interface ColorNames {
37
+ fill: string | null;
38
+ stroke: string | null;
39
+ textColor: string | null;
40
+ }
41
+ /** A named color in a theme's palette. */
42
+ export interface PaletteColor {
43
+ name: string;
44
+ color: RGBA;
45
+ }
46
+ /** A theme made in the drawing (CustomTheme): it takes the place of the page's `theme`. */
47
+ export interface CustomTheme {
48
+ name: string;
49
+ background: RGBA;
50
+ ink: RGBA;
51
+ palette: PaletteColor[];
52
+ base: string | null;
32
53
  }
33
54
  /** `portIndex` pins the end to one of the bound element's `ports`, and wins over `port`. */
34
55
  export interface Endpoint {
@@ -55,6 +76,8 @@ export interface ConnectorData {
55
76
  waypoints: StrokePoint[] | null;
56
77
  /** Hops where the line crosses a connector drawn beneath it. */
57
78
  hops: boolean | null;
79
+ /** An elbow line goes round the shapes in its way instead of through them (elbow.ts). */
80
+ avoid?: boolean | null;
58
81
  /** What a flow's traffic pays to take this connector (ADR 0002); null is 1. */
59
82
  cost: number | null;
60
83
  }
@@ -163,6 +186,13 @@ export interface Element {
163
186
  delay?: number | null;
164
187
  /** A shape that is a queue: backlog waits at the nearest one before whatever is full. */
165
188
  queue?: boolean | null;
189
+ /** The container this element is in (ADR 0006). */
190
+ containerID?: string | null;
191
+ /** On a rectangle: it's a container. Its title band is its `labelRect`, kept by the app, so drawing needs nothing more. */
192
+ container?: {
193
+ fixed: boolean | null;
194
+ lanes: "rows" | "columns" | null;
195
+ } | null;
166
196
  /** Shows a metric; drawn as plain paths and a label when the page is posed (metrics.ts). */
167
197
  gauge?: Gauge | null;
168
198
  }
@@ -250,6 +280,8 @@ export interface Page {
250
280
  layers: Layer[];
251
281
  elements: Element[];
252
282
  theme: string | null;
283
+ /** A theme of the page's own (ADR 0005), in place of `theme`. */
284
+ customTheme?: CustomTheme | null;
253
285
  timeline: Timeline | null;
254
286
  symbols: Symbol[] | null;
255
287
  /** The page's variables and their starting values (DottieDocument.variables). */
@@ -0,0 +1,12 @@
1
+ import type { Page } from "./model.ts";
2
+ /** Frames times elements below which planning in place is quicker than starting a worker. */
3
+ export declare const WORKER_WORK = 30000;
4
+ /** Roughly how much resolving every frame of `page` takes: none with a camera, which plans without resolving. */
5
+ export declare function planWork(page: Page): number;
6
+ /** Whether `page` is worth planning in a worker, and one can be had. */
7
+ export declare function plansInWorker(page: Page): boolean;
8
+ /** Plans `page` in the worker; when it resolves, `plan(page)` returns that plan at once. On any failure it resolves
9
+ * all the same, and `plan(page)` then plans in place. */
10
+ export declare function planInWorker(page: Page): Promise<void>;
11
+ /** In a worker started by `planInWorker`, answers its requests. Elsewhere it does nothing. */
12
+ export declare function servePlans(): void;
@@ -101,6 +101,10 @@ export declare class DottiePlayer extends ElementBase {
101
101
  private raf;
102
102
  private replayRaf;
103
103
  private loadToken;
104
+ /** Counts mounts, so a plan that comes back from a worker after a newer one is dropped. */
105
+ private mountToken;
106
+ /** The time a still shows; null while the drawing is animated. */
107
+ private stillTime;
104
108
  private visible;
105
109
  private observer;
106
110
  constructor();
@@ -111,8 +115,13 @@ export declare class DottiePlayer extends ElementBase {
111
115
  load(): Promise<void>;
112
116
  /** Shows an already-parsed file. */
113
117
  setFile(file: DottieFile): void;
118
+ private showFile;
119
+ /** Shows the file's page; then `mounted`. A big animation is planned in a worker first (planner.ts), and what was
120
+ * showing stays until it is ready; a newer mount, file or failed load in the meantime wins. */
114
121
  private mount;
122
+ private mountPage;
115
123
  get paused(): boolean;
124
+ /** The moment shown: a still's own time (its `at`, or the poster), else the current frame's. */
116
125
  get currentTime(): number;
117
126
  set currentTime(t: number);
118
127
  get duration(): number;
@@ -0,0 +1 @@
1
+ export {};
@@ -17,6 +17,12 @@ export interface Plan {
17
17
  /** What an animation shows over time (Exporter.animation): with a camera, its view at each frame, widened to
18
18
  * the first key's shape; without, the bounds of the whole animation for every frame. */
19
19
  export declare function plan(page: Page): Plan;
20
+ /** Whether `plan(page)` would return at once. */
21
+ export declare function hasPlan(page: Page): boolean;
22
+ /** Has `plan(page)` return `made`, a plan of this page made elsewhere (in a worker, planner.ts). */
23
+ export declare function rememberPlan(page: Page, made: Plan): void;
24
+ /** Whether `page` still holds exactly the fields it had when `fields` was copied from it. */
25
+ export declare function unchanged(page: Page, fields: Page): boolean;
20
26
  /** The opening `<svg>` tag for `b`, with the page color behind everything when `paint`. */
21
27
  export declare function svgOpen(b: Rect, background: RGBA | null, paint: boolean): string;
22
28
  export interface Part {
@@ -25,8 +31,9 @@ export interface Part {
25
31
  }
26
32
  /** The SVG for each thing drawn, back to front, keyed by element id (rock hatching as "rock"). With `links`, an
27
33
  * element whose click or `url` is a web address is wrapped in an `<a>` that opens it, the click's first (the players
28
- * make their own clickable groups). */
29
- export declare function svgParts(page: Page, background: RGBA | null, fixed?: Rect, links?: boolean): {
34
+ * make their own clickable groups). With `only`, just the parts whose keys it accepts, drawn as they are on the
35
+ * whole page (connectors still meet and hop the rest). */
36
+ export declare function svgParts(page: Page, background: RGBA | null, fixed?: Rect, links?: boolean, only?: (key: string) => boolean): {
30
37
  bounds: Rect;
31
38
  parts: Part[];
32
39
  };
@@ -1,4 +1,4 @@
1
- import { type Page, type Symbol, type SymbolPlayback } from "./model.ts";
1
+ import { type Element, type Page, type Symbol, type SymbolPlayback } from "./model.ts";
2
2
  /** The deepest instances nest, and the most elements expanding one page may make (Symbol.maxDepth, .maxElements). */
3
3
  export declare const MAX_DEPTH = 8;
4
4
  export declare const MAX_ELEMENTS = 20000;
@@ -15,9 +15,25 @@ export declare function filled(s: Symbol, args: Record<string, string> | null):
15
15
  /** The symbol as a page of its own (Symbol.page). */
16
16
  export declare function symbolPage(s: Symbol): Page;
17
17
  export declare function hasInstances(page: Page): boolean;
18
+ /** What each instance on a page expanded into, kept so that expanding the same page again at the same moment with
19
+ * a few instances' times changed (a button's other states) redoes only those. */
20
+ export declare class Expansions {
21
+ readonly page: Page;
22
+ readonly t: number;
23
+ readonly posing: boolean;
24
+ /** For each instance: its time override, the budget it found and left, and what it made. */
25
+ readonly made: Map<Element, {
26
+ override: number | undefined;
27
+ before: number;
28
+ after: number;
29
+ out: Element[];
30
+ }>;
31
+ constructor(page: Page, t: number, posing: boolean);
32
+ }
18
33
  /** The page with every instance replaced by what it shows at page time `t` (DottieDocument.expandingSymbols). `times`
19
- * puts instances on the page at a moment of their symbol's own: a button's other states, or a clip replaying. */
20
- export declare function expandingSymbols(page: Page, t: number, posing?: boolean, times?: Map<string, number>): Page;
34
+ * puts instances on the page at a moment of their symbol's own: a button's other states, or a clip replaying.
35
+ * `memo` records what each instance made, or, made for this page and moment, reuses it where nothing differs. */
36
+ export declare function expandingSymbols(page: Page, t: number, posing?: boolean, times?: Map<string, number>, memo?: Expansions): Page;
21
37
  export declare function symbolTable(page: Page): Map<string, Symbol>;
22
38
  /** The id an element of a symbol has inside instance `instance` (DottieDocument.derivedID). */
23
39
  export declare function derivedID(instance: string, inner: string): string;
@@ -1,10 +1,22 @@
1
- import type { RGBA } from "./model.ts";
1
+ import type { Page, PaletteColor, RGBA } from "./model.ts";
2
2
  export interface Theme {
3
3
  id: string;
4
4
  name: string;
5
5
  background: RGBA;
6
6
  ink: RGBA;
7
+ palette: PaletteColor[];
7
8
  }
9
+ /** The palette names every built-in theme has, in order. */
10
+ export declare const PALETTE_NAMES: string[];
11
+ /** Light pages. */
12
+ export declare const LIGHT_PALETTE: PaletteColor[];
8
13
  export declare const themes: Theme[];
9
14
  /** The theme a page names, or null (white page, black ink) for none or one this version doesn't know. */
10
15
  export declare function themeNamed(id: string | null | undefined): Theme | null;
16
+ /** The theme `page` is drawn in: its own, else the built-in it names, else null. */
17
+ export declare function pageTheme(page: Pick<Page, "theme" | "customTheme">): Theme | null;
18
+ /** The palette color `name` names on `page`, ignoring case. */
19
+ export declare function paletteColor(page: Pick<Page, "theme" | "customTheme">, name: string): RGBA | null;
20
+ /** `page` with every named color set from its palette (DottieDocument.resolvingPalette); a name the palette doesn't
21
+ * have keeps the color it had. */
22
+ export declare function resolvingPalette(page: Page): Page;
@@ -1,3 +1,4 @@
1
+ import { type Index } from "./connector.ts";
1
2
  import { type Ease, type Element, type Follow, type Page, type Timeline, type Track } from "./model.ts";
2
3
  import { Polyline, type Point, type Rect } from "./path.ts";
3
4
  import { type StateChoice } from "./state.ts";
@@ -13,8 +14,9 @@ export declare function isVisible(track: Track, t: number): boolean;
13
14
  export declare function applyTrack(track: Track, e: Element, t: number): Element;
14
15
  /** The path span placing the element at `t`, unless an x or y key after it has taken the element back. */
15
16
  export declare function followSpan(track: Track, t: number): Follow | null;
16
- /** The clean route of a connector, or the clean, rotated outline of any other element. */
17
- export declare function tracing(e: Element, page: Page): Polyline;
17
+ /** The clean route of a connector, or the clean, rotated outline of any other element. `index` is the page's,
18
+ * passed by callers that already have it. */
19
+ export declare function tracing(e: Element, page: Page, index?: Index): Polyline;
18
20
  /** `e` moved onto the path it is following at `t`, if any. `page` has every key applied. */
19
21
  export declare function following(track: Track, e: Element, t: number, page: Page): Element;
20
22
  /** Where the dashes of a line marching at `speed` stand at `t`, within one pattern `period` (Timeline.marchOffset):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phin-tech/dottie",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Render, play and compile Dottie (.dottie) drawings and animations in the browser",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",