@nowline/layout 0.8.5 → 0.9.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/dist/axis-columns.d.ts +70 -0
- package/dist/axis-columns.d.ts.map +1 -0
- package/dist/axis-columns.js +104 -0
- package/dist/axis-columns.js.map +1 -0
- package/dist/band-scale.d.ts.map +1 -1
- package/dist/calendar-resolver.d.ts +27 -0
- package/dist/calendar-resolver.d.ts.map +1 -0
- package/dist/calendar-resolver.js +132 -0
- package/dist/calendar-resolver.js.map +1 -0
- package/dist/calendar.d.ts +0 -19
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +4 -44
- package/dist/calendar.js.map +1 -1
- package/dist/canvas-width.d.ts +23 -0
- package/dist/canvas-width.d.ts.map +1 -0
- package/dist/canvas-width.js +26 -0
- package/dist/canvas-width.js.map +1 -0
- package/dist/capacity.d.ts +28 -0
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +64 -29
- package/dist/capacity.js.map +1 -1
- package/dist/chart-translation.d.ts +22 -0
- package/dist/chart-translation.d.ts.map +1 -0
- package/dist/chart-translation.js +83 -0
- package/dist/chart-translation.js.map +1 -0
- package/dist/container-header-geometry.d.ts +64 -0
- package/dist/container-header-geometry.d.ts.map +1 -0
- package/dist/container-header-geometry.js +89 -0
- package/dist/container-header-geometry.js.map +1 -0
- package/dist/dsl-utils.d.ts +3 -4
- package/dist/dsl-utils.d.ts.map +1 -1
- package/dist/dsl-utils.js +8 -25
- package/dist/dsl-utils.js.map +1 -1
- package/dist/edge-routing.d.ts +69 -78
- package/dist/edge-routing.d.ts.map +1 -1
- package/dist/edge-routing.js +271 -401
- package/dist/edge-routing.js.map +1 -1
- package/dist/frame-tab-geometry.d.ts +24 -14
- package/dist/frame-tab-geometry.d.ts.map +1 -1
- package/dist/frame-tab-geometry.js +69 -23
- package/dist/frame-tab-geometry.js.map +1 -1
- package/dist/header-card-geometry.d.ts +12 -0
- package/dist/header-card-geometry.d.ts.map +1 -1
- package/dist/header-card-geometry.js +14 -2
- package/dist/header-card-geometry.js.map +1 -1
- package/dist/header-logo.d.ts +28 -0
- package/dist/header-logo.d.ts.map +1 -0
- package/dist/header-logo.js +51 -0
- package/dist/header-logo.js.map +1 -0
- package/dist/i18n.d.ts +11 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +11 -1
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +20 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +1 -1
- package/dist/inline-date-pin-geometry.d.ts +19 -11
- package/dist/inline-date-pin-geometry.d.ts.map +1 -1
- package/dist/inline-date-pin-geometry.js +45 -46
- package/dist/inline-date-pin-geometry.js.map +1 -1
- package/dist/item-bar-geometry.d.ts +192 -4
- package/dist/item-bar-geometry.d.ts.map +1 -1
- package/dist/item-bar-geometry.js +258 -5
- package/dist/item-bar-geometry.js.map +1 -1
- package/dist/item-port-geometry.d.ts +13 -0
- package/dist/item-port-geometry.d.ts.map +1 -0
- package/dist/item-port-geometry.js +63 -0
- package/dist/item-port-geometry.js.map +1 -0
- package/dist/layout-context.d.ts +115 -51
- package/dist/layout-context.d.ts.map +1 -1
- package/dist/layout-context.js +96 -5
- package/dist/layout-context.js.map +1 -1
- package/dist/layout-insights.d.ts.map +1 -1
- package/dist/layout-insights.js +73 -1
- package/dist/layout-insights.js.map +1 -1
- package/dist/layout.d.ts +35 -0
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +18 -1315
- package/dist/layout.js.map +1 -1
- package/dist/nodes/anchor-node.d.ts.map +1 -1
- package/dist/nodes/anchor-node.js +11 -4
- package/dist/nodes/anchor-node.js.map +1 -1
- package/dist/nodes/content-extent.d.ts +24 -0
- package/dist/nodes/content-extent.d.ts.map +1 -0
- package/dist/nodes/content-extent.js +100 -0
- package/dist/nodes/content-extent.js.map +1 -0
- package/dist/nodes/dependency-edges.d.ts +6 -0
- package/dist/nodes/dependency-edges.d.ts.map +1 -0
- package/dist/nodes/dependency-edges.js +148 -0
- package/dist/nodes/dependency-edges.js.map +1 -0
- package/dist/nodes/footnote-node.d.ts +24 -3
- package/dist/nodes/footnote-node.d.ts.map +1 -1
- package/dist/nodes/footnote-node.js +129 -25
- package/dist/nodes/footnote-node.js.map +1 -1
- package/dist/nodes/group-node.d.ts +10 -21
- package/dist/nodes/group-node.d.ts.map +1 -1
- package/dist/nodes/group-node.js +79 -154
- package/dist/nodes/group-node.js.map +1 -1
- package/dist/nodes/header-node.d.ts +56 -0
- package/dist/nodes/header-node.d.ts.map +1 -0
- package/dist/nodes/header-node.js +163 -0
- package/dist/nodes/header-node.js.map +1 -0
- package/dist/nodes/include-node.d.ts +22 -12
- package/dist/nodes/include-node.d.ts.map +1 -1
- package/dist/nodes/include-node.js +95 -62
- package/dist/nodes/include-node.js.map +1 -1
- package/dist/nodes/item-measure.d.ts +135 -0
- package/dist/nodes/item-measure.d.ts.map +1 -0
- package/dist/nodes/item-measure.js +514 -0
- package/dist/nodes/item-measure.js.map +1 -0
- package/dist/nodes/item-node.d.ts +162 -9
- package/dist/nodes/item-node.d.ts.map +1 -1
- package/dist/nodes/item-node.js +256 -69
- package/dist/nodes/item-node.js.map +1 -1
- package/dist/nodes/marker-band.d.ts +118 -0
- package/dist/nodes/marker-band.d.ts.map +1 -0
- package/dist/nodes/marker-band.js +303 -0
- package/dist/nodes/marker-band.js.map +1 -0
- package/dist/nodes/marker-geometry.js +1 -1
- package/dist/nodes/marker-geometry.js.map +1 -1
- package/dist/nodes/milestone-node.d.ts +112 -15
- package/dist/nodes/milestone-node.d.ts.map +1 -1
- package/dist/nodes/milestone-node.js +246 -95
- package/dist/nodes/milestone-node.js.map +1 -1
- package/dist/nodes/nowline-node.d.ts +8 -0
- package/dist/nodes/nowline-node.d.ts.map +1 -0
- package/dist/nodes/nowline-node.js +74 -0
- package/dist/nodes/nowline-node.js.map +1 -0
- package/dist/nodes/parallel-node.d.ts +7 -12
- package/dist/nodes/parallel-node.d.ts.map +1 -1
- package/dist/nodes/parallel-node.js +66 -32
- package/dist/nodes/parallel-node.js.map +1 -1
- package/dist/nodes/region-markers.d.ts +41 -0
- package/dist/nodes/region-markers.d.ts.map +1 -0
- package/dist/nodes/region-markers.js +130 -0
- package/dist/nodes/region-markers.js.map +1 -0
- package/dist/nodes/roadmap-node.d.ts +9 -72
- package/dist/nodes/roadmap-node.d.ts.map +1 -1
- package/dist/nodes/roadmap-node.js +38 -788
- package/dist/nodes/roadmap-node.js.map +1 -1
- package/dist/nodes/row-track.d.ts +33 -0
- package/dist/nodes/row-track.d.ts.map +1 -0
- package/dist/nodes/row-track.js +170 -0
- package/dist/nodes/row-track.js.map +1 -0
- package/dist/nodes/sequence-item.d.ts +25 -0
- package/dist/nodes/sequence-item.d.ts.map +1 -0
- package/dist/nodes/sequence-item.js +396 -0
- package/dist/nodes/sequence-item.js.map +1 -0
- package/dist/nodes/sequence-one.d.ts +5 -0
- package/dist/nodes/sequence-one.d.ts.map +1 -0
- package/dist/nodes/sequence-one.js +26 -0
- package/dist/nodes/sequence-one.js.map +1 -0
- package/dist/nodes/swimlane-node.d.ts +5 -17
- package/dist/nodes/swimlane-node.d.ts.map +1 -1
- package/dist/nodes/swimlane-node.js +62 -147
- package/dist/nodes/swimlane-node.js.map +1 -1
- package/dist/nodes/wave-node.d.ts +52 -0
- package/dist/nodes/wave-node.d.ts.map +1 -0
- package/dist/nodes/wave-node.js +483 -0
- package/dist/nodes/wave-node.js.map +1 -0
- package/dist/non-working-display.d.ts +14 -0
- package/dist/non-working-display.d.ts.map +1 -0
- package/dist/non-working-display.js +28 -0
- package/dist/non-working-display.js.map +1 -0
- package/dist/phases/date-window.d.ts +48 -0
- package/dist/phases/date-window.d.ts.map +1 -0
- package/dist/phases/date-window.js +130 -0
- package/dist/phases/date-window.js.map +1 -0
- package/dist/phases/finalize.d.ts +198 -0
- package/dist/phases/finalize.d.ts.map +1 -0
- package/dist/phases/finalize.js +1058 -0
- package/dist/phases/finalize.js.map +1 -0
- package/dist/phases/measure.d.ts +77 -0
- package/dist/phases/measure.d.ts.map +1 -0
- package/dist/phases/measure.js +222 -0
- package/dist/phases/measure.js.map +1 -0
- package/dist/phases/place.d.ts +28 -0
- package/dist/phases/place.d.ts.map +1 -0
- package/dist/phases/place.js +225 -0
- package/dist/phases/place.js.map +1 -0
- package/dist/renderable.d.ts.map +1 -1
- package/dist/renderable.js +23 -3
- package/dist/renderable.js.map +1 -1
- package/dist/resolve-today.d.ts +11 -1
- package/dist/resolve-today.d.ts.map +1 -1
- package/dist/resolve-today.js +26 -12
- package/dist/resolve-today.js.map +1 -1
- package/dist/row-packer.d.ts +42 -16
- package/dist/row-packer.d.ts.map +1 -1
- package/dist/row-packer.js +51 -78
- package/dist/row-packer.js.map +1 -1
- package/dist/schedule.d.ts +58 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +280 -106
- package/dist/schedule.js.map +1 -1
- package/dist/start-rules.d.ts +27 -0
- package/dist/start-rules.d.ts.map +1 -0
- package/dist/start-rules.js +91 -0
- package/dist/start-rules.js.map +1 -0
- package/dist/start-terms.d.ts +23 -0
- package/dist/start-terms.d.ts.map +1 -0
- package/dist/start-terms.js +27 -0
- package/dist/start-terms.js.map +1 -0
- package/dist/status-dot.d.ts +46 -0
- package/dist/status-dot.d.ts.map +1 -0
- package/dist/status-dot.js +78 -0
- package/dist/status-dot.js.map +1 -0
- package/dist/style-resolution.d.ts.map +1 -1
- package/dist/style-resolution.js +23 -43
- package/dist/style-resolution.js.map +1 -1
- package/dist/text-measure.d.ts +28 -0
- package/dist/text-measure.d.ts.map +1 -0
- package/dist/text-measure.js +70 -0
- package/dist/text-measure.js.map +1 -0
- package/dist/themes/contrast.d.ts +4 -0
- package/dist/themes/contrast.d.ts.map +1 -0
- package/dist/themes/contrast.js +32 -0
- package/dist/themes/contrast.js.map +1 -0
- package/dist/themes/dark.d.ts.map +1 -1
- package/dist/themes/dark.js +28 -1
- package/dist/themes/dark.js.map +1 -1
- package/dist/themes/grayscale.d.ts.map +1 -1
- package/dist/themes/grayscale.js +28 -1
- package/dist/themes/grayscale.js.map +1 -1
- package/dist/themes/index.d.ts +4 -11
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +6 -4
- package/dist/themes/index.js.map +1 -1
- package/dist/themes/light.d.ts.map +1 -1
- package/dist/themes/light.js +28 -1
- package/dist/themes/light.js.map +1 -1
- package/dist/themes/shape.d.ts +31 -0
- package/dist/themes/shape.d.ts.map +1 -1
- package/dist/themes/shared.d.ts +44 -50
- package/dist/themes/shared.d.ts.map +1 -1
- package/dist/themes/shared.js +79 -83
- package/dist/themes/shared.js.map +1 -1
- package/dist/time-scale.d.ts +42 -6
- package/dist/time-scale.d.ts.map +1 -1
- package/dist/time-scale.js +109 -17
- package/dist/time-scale.js.map +1 -1
- package/dist/types.d.ts +528 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/view-preset.d.ts +61 -6
- package/dist/view-preset.d.ts.map +1 -1
- package/dist/view-preset.js +439 -24
- package/dist/view-preset.js.map +1 -1
- package/dist/wave-barrier.d.ts +107 -0
- package/dist/wave-barrier.d.ts.map +1 -0
- package/dist/wave-barrier.js +174 -0
- package/dist/wave-barrier.js.map +1 -0
- package/dist/wave-hatch.d.ts +4 -0
- package/dist/wave-hatch.d.ts.map +1 -0
- package/dist/wave-hatch.js +21 -0
- package/dist/wave-hatch.js.map +1 -0
- package/dist/wave-layout.d.ts +99 -0
- package/dist/wave-layout.d.ts.map +1 -0
- package/dist/wave-layout.js +130 -0
- package/dist/wave-layout.js.map +1 -0
- package/dist/working-calendar.d.ts +128 -4
- package/dist/working-calendar.d.ts.map +1 -1
- package/dist/working-calendar.js +725 -51
- package/dist/working-calendar.js.map +1 -1
- package/dist/working-span.d.ts +11 -0
- package/dist/working-span.d.ts.map +1 -0
- package/dist/working-span.js +18 -0
- package/dist/working-span.js.map +1 -0
- package/package.json +7 -7
- package/src/axis-columns.ts +140 -0
- package/src/calendar-resolver.ts +161 -0
- package/src/calendar.ts +4 -45
- package/src/canvas-width.ts +36 -0
- package/src/capacity.ts +71 -30
- package/src/chart-translation.ts +88 -0
- package/src/container-header-geometry.ts +116 -0
- package/src/dsl-utils.ts +8 -26
- package/src/edge-routing.ts +347 -491
- package/src/frame-tab-geometry.ts +78 -25
- package/src/header-card-geometry.ts +17 -2
- package/src/header-logo.ts +67 -0
- package/src/i18n.ts +22 -1
- package/src/index.ts +97 -12
- package/src/inline-date-pin-geometry.ts +55 -58
- package/src/item-bar-geometry.ts +341 -5
- package/src/item-port-geometry.ts +69 -0
- package/src/layout-context.ts +210 -72
- package/src/layout-insights.ts +109 -2
- package/src/layout.ts +57 -1530
- package/src/nodes/anchor-node.ts +11 -4
- package/src/nodes/content-extent.ts +107 -0
- package/src/nodes/dependency-edges.ts +171 -0
- package/src/nodes/footnote-node.ts +171 -31
- package/src/nodes/group-node.ts +92 -215
- package/src/nodes/header-node.ts +255 -0
- package/src/nodes/include-node.ts +124 -110
- package/src/nodes/item-measure.ts +723 -0
- package/src/nodes/item-node.ts +358 -80
- package/src/nodes/marker-band.ts +406 -0
- package/src/nodes/marker-geometry.ts +1 -1
- package/src/nodes/milestone-node.ts +321 -136
- package/src/nodes/nowline-node.ts +87 -0
- package/src/nodes/parallel-node.ts +69 -39
- package/src/nodes/region-markers.ts +194 -0
- package/src/nodes/roadmap-node.ts +46 -950
- package/src/nodes/row-track.ts +217 -0
- package/src/nodes/sequence-item.ts +433 -0
- package/src/nodes/sequence-one.ts +40 -0
- package/src/nodes/swimlane-node.ts +66 -206
- package/src/nodes/wave-node.ts +609 -0
- package/src/non-working-display.ts +32 -0
- package/src/phases/date-window.ts +191 -0
- package/src/phases/finalize.ts +1303 -0
- package/src/phases/measure.ts +329 -0
- package/src/phases/place.ts +318 -0
- package/src/renderable.ts +23 -3
- package/src/resolve-today.ts +28 -25
- package/src/row-packer.ts +85 -84
- package/src/schedule.ts +362 -114
- package/src/start-rules.ts +113 -0
- package/src/start-terms.ts +38 -0
- package/src/status-dot.ts +81 -0
- package/src/style-resolution.ts +27 -57
- package/src/text-measure.ts +71 -0
- package/src/themes/contrast.ts +34 -0
- package/src/themes/dark.ts +28 -1
- package/src/themes/grayscale.ts +28 -1
- package/src/themes/index.ts +10 -7
- package/src/themes/light.ts +28 -1
- package/src/themes/shape.ts +38 -0
- package/src/themes/shared.ts +85 -93
- package/src/time-scale.ts +117 -19
- package/src/types.ts +529 -20
- package/src/view-preset.ts +520 -27
- package/src/wave-barrier.ts +242 -0
- package/src/wave-hatch.ts +25 -0
- package/src/wave-layout.ts +203 -0
- package/src/working-calendar.ts +875 -57
- package/src/working-span.ts +19 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { AnchorDeclaration, MilestoneDeclaration } from '@nowline/core';
|
|
2
|
+
import type { TimeScale } from '../time-scale.js';
|
|
3
|
+
import type { BoundingBox, MarkerRowPlacement, PositionedNonWorkingRun, PositionedWorkingException } from '../types.js';
|
|
4
|
+
import type { MilestonePlacement } from './milestone-node.js';
|
|
5
|
+
/** A packed marker band: its rows and each marker's placement at the band's y. */
|
|
6
|
+
export interface MarkerBand {
|
|
7
|
+
/** Rows the band holds: at least 1 when it has any marker, else 0. */
|
|
8
|
+
rowCount: number;
|
|
9
|
+
placements: Map<string, MarkerRowPlacement>;
|
|
10
|
+
}
|
|
11
|
+
/** A marker pinned by its `date:`: a dated anchor or milestone inside the window. */
|
|
12
|
+
export type DatePinnedMarker = MarkerEntity & {
|
|
13
|
+
date: Date;
|
|
14
|
+
isMilestone: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The date-pinned anchors, then the date-pinned milestones, each at the x
|
|
18
|
+
* of its `date:`. A marker with no date, or a date outside the window,
|
|
19
|
+
* is left out; after-only milestones are placed with the lanes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function datePinnedMarkerEntries(anchors: ReadonlyMap<string, AnchorDeclaration>, milestones: ReadonlyMap<string, MilestoneDeclaration>, scale: TimeScale): DatePinnedMarker[];
|
|
22
|
+
/**
|
|
23
|
+
* The calendar's marker-row entries: the titled non-working runs, then the
|
|
24
|
+
* working exceptions. Callers append them after the anchors and
|
|
25
|
+
* milestones.
|
|
26
|
+
*/
|
|
27
|
+
export declare function calendarMarkerEntries(runs: ReadonlyArray<PositionedNonWorkingRun> | undefined, exceptions: ReadonlyArray<PositionedWorkingException> | undefined): MarkerEntity[];
|
|
28
|
+
/**
|
|
29
|
+
* Each packed placement at the band's y: row `r`'s centre sits
|
|
30
|
+
* `MARKER_ROW_CENTER_OFFSET_PX + r * MARKER_ROW_PITCH_PX` below
|
|
31
|
+
* `markerRowY`, and its label box 4 px above the centre.
|
|
32
|
+
*/
|
|
33
|
+
export declare function markerRowPlacements(packed: ReadonlyMap<string, PackedPlacement>, markerRowY: number): Map<string, MarkerRowPlacement>;
|
|
34
|
+
/** The marker-row id of a titled non-working run: `nonworking:<ISO from>`. */
|
|
35
|
+
export declare function nonWorkingRunMarkerId(run: PositionedNonWorkingRun): string;
|
|
36
|
+
/** The marker-row id of a working exception: `working:<ISO from>`. */
|
|
37
|
+
export declare function workingExceptionMarkerId(exception: PositionedWorkingException): string;
|
|
38
|
+
/**
|
|
39
|
+
* The canvas right edge the marker-row labels need. A label (anchor,
|
|
40
|
+
* milestone, titled run or working exception) that fits neither right of
|
|
41
|
+
* its x (against `chartRightX`) nor left of it (against `chartLeftX`)
|
|
42
|
+
* would fall back to the left and draw over a beside header card, so the
|
|
43
|
+
* canvas grows to hold it on the right instead. A slipped milestone's
|
|
44
|
+
* label never fits on the left, where its span runs.
|
|
45
|
+
*/
|
|
46
|
+
export declare function markerLabelsRightX(entries: ReadonlyArray<MarkerEntity>, chartLeftX: number, chartRightX: number, estimateTextWidth: (text: string, fontSize: number) => number): number;
|
|
47
|
+
export interface MarkerEntity {
|
|
48
|
+
id: string;
|
|
49
|
+
centerX: number;
|
|
50
|
+
radius: number;
|
|
51
|
+
title: string;
|
|
52
|
+
fontSize: number;
|
|
53
|
+
bold: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* A slipped milestone's planned x: its entry sits at the slipped x
|
|
56
|
+
* (`centerX`, where the label goes), and the span from the planned
|
|
57
|
+
* diamond to it is reserved on its row.
|
|
58
|
+
*/
|
|
59
|
+
slipFromX?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface PackedPlacement {
|
|
62
|
+
rowIndex: number;
|
|
63
|
+
labelBox: BoundingBox;
|
|
64
|
+
labelSide: 'left' | 'right';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A slack or overrun arrow between two markers, drawn on `from`'s row
|
|
68
|
+
* between the two diamonds (specs/rendering.md, Milestones, "Marker
|
|
69
|
+
* predecessors"). A milestone's arrow from a group or parallel starts on
|
|
70
|
+
* the milestone's own row and is not one.
|
|
71
|
+
*/
|
|
72
|
+
export interface MarkerArrow {
|
|
73
|
+
from: string;
|
|
74
|
+
to: string;
|
|
75
|
+
}
|
|
76
|
+
/** The arrows between markers that `placements` draw, source to target. */
|
|
77
|
+
export declare function markerArrows(placements: readonly MilestonePlacement[]): MarkerArrow[];
|
|
78
|
+
/**
|
|
79
|
+
* Pack anchors + milestones into marker rows using a bottom-first
|
|
80
|
+
* tick-order strategy. Markers default to the row CLOSEST to the
|
|
81
|
+
* chart; conflicts push them UP toward the date ticks (the inverse of
|
|
82
|
+
* swimlane items which default to the top and push down).
|
|
83
|
+
*
|
|
84
|
+
* Walk order is left-to-right by `centerX` (tick order, not file
|
|
85
|
+
* declaration). For each marker:
|
|
86
|
+
* 1. Try the bottommost existing row (highest `rowIndex`), right
|
|
87
|
+
* side first then left, working UP through the rows.
|
|
88
|
+
* 2. If neither side fits at any existing row, GROW: prepend a new
|
|
89
|
+
* row at `rowIndex = 0`. Every previously-placed marker has its
|
|
90
|
+
* `rowIndex` incremented by 1 so the bottom corridor stays
|
|
91
|
+
* stable as the band expands upward toward the ticks.
|
|
92
|
+
*
|
|
93
|
+
* `arrows` (the marker-to-marker arrows, `markerArrows`) add three rules,
|
|
94
|
+
* so an arrow crosses no other marker and ends on its target's line:
|
|
95
|
+
* - An arrow's run, on its source's row between the two diamonds, is
|
|
96
|
+
* reserved on that row like a label: no other diamond, label or run
|
|
97
|
+
* may overlap it.
|
|
98
|
+
* - A target sits at or above each source's row (cut lines run down
|
|
99
|
+
* from a diamond). A source whose target is placed and that fits no
|
|
100
|
+
* allowed row grows a fresh row right below the target instead of
|
|
101
|
+
* at the top; when the rules contradict (a marker both a source and
|
|
102
|
+
* a target on one row), it grows at the top.
|
|
103
|
+
* - A label takes a side its own arrows do not run along, when that
|
|
104
|
+
* side fits; otherwise it keeps the usual right-then-left order.
|
|
105
|
+
* With no arrows the pack is unchanged.
|
|
106
|
+
*
|
|
107
|
+
* Returns row-relative placements (no centerY yet — caller fills that
|
|
108
|
+
* in once `markerRowY` is known). Row indices follow the existing
|
|
109
|
+
* convention: 0 = top of band (closest to ticks), `rowCount - 1` =
|
|
110
|
+
* bottom of band (closest to chart). The "bottom-first" preference
|
|
111
|
+
* lives entirely in the search order and grow direction; geometry
|
|
112
|
+
* stays anchored to `markerRowY` at the top.
|
|
113
|
+
*/
|
|
114
|
+
export declare function packMarkerRow(entries: MarkerEntity[], chartLeftX: number, chartRightX: number, estimateTextWidth: (text: string, fontSize: number) => number, arrows?: readonly MarkerArrow[]): {
|
|
115
|
+
placements: Map<string, PackedPlacement>;
|
|
116
|
+
rowCount: number;
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=marker-band.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker-band.d.ts","sourceRoot":"","sources":["../../src/nodes/marker-band.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EACR,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC7B,MAAM,aAAa,CAAC;AASrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACvB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC/C;AAED,qFAAqF;AACrF,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnF;;;;GAIG;AACH,wBAAgB,uBAAuB,CACnC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,EACrD,KAAK,EAAE,SAAS,GACjB,gBAAgB,EAAE,CAyBpB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACjC,IAAI,EAAE,aAAa,CAAC,uBAAuB,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,aAAa,CAAC,0BAA0B,CAAC,GAAG,SAAS,GAClE,YAAY,EAAE,CAEhB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC5C,UAAU,EAAE,MAAM,GACnB,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAYjC;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CAE1E;AAED,sEAAsE;AACtE,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,0BAA0B,GAAG,MAAM,CAEtF;AAsCD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,EACpC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAC9D,MAAM,CAYR;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAUD,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACd;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,WAAW,EAAE,CAQrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,EAC7D,MAAM,GAAE,SAAS,WAAW,EAAO,GACpC;IAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAkIhE"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// MarkerBand — the marker row's entries, packer and placements. Anchors,
|
|
2
|
+
// milestones, the titled non-working runs and the working exceptions all
|
|
3
|
+
// pack into one band of rows above the chart. The measure phase packs an
|
|
4
|
+
// estimate to size the band before any lane is placed; finalize packs
|
|
5
|
+
// every marker once the canvas is final (specs/layout-phases.md §3.3).
|
|
6
|
+
// Both build their entries and turn the packed rows into y positions
|
|
7
|
+
// with the helpers here; `markerLabelsRightX` sizes the canvas for the
|
|
8
|
+
// labels that fit on neither side.
|
|
9
|
+
import { parseIsoDate, propValue } from '../dsl-utils.js';
|
|
10
|
+
import { GUTTER_PX } from '../themes/shared.js';
|
|
11
|
+
import { MARKER_BOLD_WIDTH_FACTOR, MARKER_DIAMOND_RADIUS_PX, MARKER_LABEL_GAP_PX, MARKER_LABEL_HEIGHT_PX, MARKER_ROW_CENTER_OFFSET_PX, MARKER_ROW_PITCH_PX, } from './marker-geometry.js';
|
|
12
|
+
/**
|
|
13
|
+
* The date-pinned anchors, then the date-pinned milestones, each at the x
|
|
14
|
+
* of its `date:`. A marker with no date, or a date outside the window,
|
|
15
|
+
* is left out; after-only milestones are placed with the lanes.
|
|
16
|
+
*/
|
|
17
|
+
export function datePinnedMarkerEntries(anchors, milestones, scale) {
|
|
18
|
+
const entries = [];
|
|
19
|
+
const add = (id, decl, isMilestone) => {
|
|
20
|
+
const date = parseIsoDate(propValue(decl.properties, 'date'));
|
|
21
|
+
if (!date)
|
|
22
|
+
return;
|
|
23
|
+
const x = scale.forwardWithinDomain(date);
|
|
24
|
+
if (x === null)
|
|
25
|
+
return;
|
|
26
|
+
entries.push({
|
|
27
|
+
id,
|
|
28
|
+
centerX: x,
|
|
29
|
+
radius: MARKER_DIAMOND_RADIUS_PX,
|
|
30
|
+
title: decl.title ?? id,
|
|
31
|
+
fontSize: 10,
|
|
32
|
+
bold: isMilestone,
|
|
33
|
+
date,
|
|
34
|
+
isMilestone,
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
for (const [id, anchor] of anchors)
|
|
38
|
+
add(id, anchor, false);
|
|
39
|
+
for (const [id, milestone] of milestones)
|
|
40
|
+
add(id, milestone, true);
|
|
41
|
+
return entries;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The calendar's marker-row entries: the titled non-working runs, then the
|
|
45
|
+
* working exceptions. Callers append them after the anchors and
|
|
46
|
+
* milestones.
|
|
47
|
+
*/
|
|
48
|
+
export function calendarMarkerEntries(runs, exceptions) {
|
|
49
|
+
return [...nonWorkingRunEntries(runs), ...workingExceptionEntries(exceptions)];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Each packed placement at the band's y: row `r`'s centre sits
|
|
53
|
+
* `MARKER_ROW_CENTER_OFFSET_PX + r * MARKER_ROW_PITCH_PX` below
|
|
54
|
+
* `markerRowY`, and its label box 4 px above the centre.
|
|
55
|
+
*/
|
|
56
|
+
export function markerRowPlacements(packed, markerRowY) {
|
|
57
|
+
const out = new Map();
|
|
58
|
+
for (const [id, p] of packed) {
|
|
59
|
+
const centerY = markerRowY + MARKER_ROW_CENTER_OFFSET_PX + p.rowIndex * MARKER_ROW_PITCH_PX;
|
|
60
|
+
out.set(id, {
|
|
61
|
+
rowIndex: p.rowIndex,
|
|
62
|
+
centerY,
|
|
63
|
+
labelBox: { ...p.labelBox, y: centerY - 4 },
|
|
64
|
+
labelSide: p.labelSide,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/** The marker-row id of a titled non-working run: `nonworking:<ISO from>`. */
|
|
70
|
+
export function nonWorkingRunMarkerId(run) {
|
|
71
|
+
return `nonworking:${run.from.toISOString().slice(0, 10)}`;
|
|
72
|
+
}
|
|
73
|
+
/** The marker-row id of a working exception: `working:<ISO from>`. */
|
|
74
|
+
export function workingExceptionMarkerId(exception) {
|
|
75
|
+
return `working:${exception.from.toISOString().slice(0, 10)}`;
|
|
76
|
+
}
|
|
77
|
+
/** A zero-radius marker-row entry for a calendar label at `x`. */
|
|
78
|
+
function calendarLabelEntry(id, x, label) {
|
|
79
|
+
return { id, centerX: x, radius: 0, title: label, fontSize: 10, bold: false };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Marker-row entries for the titled runs (specs/working-calendar.md
|
|
83
|
+
* §7.4): a zero-radius marker at the run's x (the seam under `hide`, the
|
|
84
|
+
* band's left edge under `show`) whose title is the run's label. Callers
|
|
85
|
+
* append them after the anchors and milestones, so the stable sort in
|
|
86
|
+
* `packMarkerRow` places a marker that ties a run on x first.
|
|
87
|
+
*/
|
|
88
|
+
function nonWorkingRunEntries(runs) {
|
|
89
|
+
const entries = [];
|
|
90
|
+
for (const run of runs ?? []) {
|
|
91
|
+
if (run.label === undefined)
|
|
92
|
+
continue;
|
|
93
|
+
entries.push(calendarLabelEntry(nonWorkingRunMarkerId(run), run.x, run.label));
|
|
94
|
+
}
|
|
95
|
+
return entries;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Marker-row entries for the working exceptions (specs/working-calendar.md
|
|
99
|
+
* §7.4), packed beside the titled runs' and on the same terms: a zero-radius
|
|
100
|
+
* marker at the first turned day's x.
|
|
101
|
+
*/
|
|
102
|
+
function workingExceptionEntries(exceptions) {
|
|
103
|
+
return (exceptions ?? []).map((exception) => calendarLabelEntry(workingExceptionMarkerId(exception), exception.x, exception.label));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The canvas right edge the marker-row labels need. A label (anchor,
|
|
107
|
+
* milestone, titled run or working exception) that fits neither right of
|
|
108
|
+
* its x (against `chartRightX`) nor left of it (against `chartLeftX`)
|
|
109
|
+
* would fall back to the left and draw over a beside header card, so the
|
|
110
|
+
* canvas grows to hold it on the right instead. A slipped milestone's
|
|
111
|
+
* label never fits on the left, where its span runs.
|
|
112
|
+
*/
|
|
113
|
+
export function markerLabelsRightX(entries, chartLeftX, chartRightX, estimateTextWidth) {
|
|
114
|
+
let rightX = chartRightX;
|
|
115
|
+
for (const e of entries) {
|
|
116
|
+
const labelWidth = markerLabelWidth(e, estimateTextWidth);
|
|
117
|
+
const rightEnd = e.centerX + e.radius + MARKER_LABEL_GAP_PX + labelWidth;
|
|
118
|
+
const leftStart = e.centerX - e.radius - MARKER_LABEL_GAP_PX - labelWidth;
|
|
119
|
+
const fitsLeft = leftStart >= chartLeftX && e.slipFromX === undefined;
|
|
120
|
+
if (rightEnd > chartRightX && !fitsLeft) {
|
|
121
|
+
rightX = Math.max(rightX, rightEnd + GUTTER_PX);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return rightX;
|
|
125
|
+
}
|
|
126
|
+
/** A marker label's width: bold labels widen by `MARKER_BOLD_WIDTH_FACTOR`. */
|
|
127
|
+
function markerLabelWidth(e, estimateTextWidth) {
|
|
128
|
+
return estimateTextWidth(e.title, e.fontSize) * (e.bold ? MARKER_BOLD_WIDTH_FACTOR : 1);
|
|
129
|
+
}
|
|
130
|
+
/** The arrows between markers that `placements` draw, source to target. */
|
|
131
|
+
export function markerArrows(placements) {
|
|
132
|
+
const out = [];
|
|
133
|
+
for (const p of placements) {
|
|
134
|
+
for (const a of p.slackArrows ?? []) {
|
|
135
|
+
if ('marker' in a && a.marker !== p.id)
|
|
136
|
+
out.push({ from: a.marker, to: p.id });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Pack anchors + milestones into marker rows using a bottom-first
|
|
143
|
+
* tick-order strategy. Markers default to the row CLOSEST to the
|
|
144
|
+
* chart; conflicts push them UP toward the date ticks (the inverse of
|
|
145
|
+
* swimlane items which default to the top and push down).
|
|
146
|
+
*
|
|
147
|
+
* Walk order is left-to-right by `centerX` (tick order, not file
|
|
148
|
+
* declaration). For each marker:
|
|
149
|
+
* 1. Try the bottommost existing row (highest `rowIndex`), right
|
|
150
|
+
* side first then left, working UP through the rows.
|
|
151
|
+
* 2. If neither side fits at any existing row, GROW: prepend a new
|
|
152
|
+
* row at `rowIndex = 0`. Every previously-placed marker has its
|
|
153
|
+
* `rowIndex` incremented by 1 so the bottom corridor stays
|
|
154
|
+
* stable as the band expands upward toward the ticks.
|
|
155
|
+
*
|
|
156
|
+
* `arrows` (the marker-to-marker arrows, `markerArrows`) add three rules,
|
|
157
|
+
* so an arrow crosses no other marker and ends on its target's line:
|
|
158
|
+
* - An arrow's run, on its source's row between the two diamonds, is
|
|
159
|
+
* reserved on that row like a label: no other diamond, label or run
|
|
160
|
+
* may overlap it.
|
|
161
|
+
* - A target sits at or above each source's row (cut lines run down
|
|
162
|
+
* from a diamond). A source whose target is placed and that fits no
|
|
163
|
+
* allowed row grows a fresh row right below the target instead of
|
|
164
|
+
* at the top; when the rules contradict (a marker both a source and
|
|
165
|
+
* a target on one row), it grows at the top.
|
|
166
|
+
* - A label takes a side its own arrows do not run along, when that
|
|
167
|
+
* side fits; otherwise it keeps the usual right-then-left order.
|
|
168
|
+
* With no arrows the pack is unchanged.
|
|
169
|
+
*
|
|
170
|
+
* Returns row-relative placements (no centerY yet — caller fills that
|
|
171
|
+
* in once `markerRowY` is known). Row indices follow the existing
|
|
172
|
+
* convention: 0 = top of band (closest to ticks), `rowCount - 1` =
|
|
173
|
+
* bottom of band (closest to chart). The "bottom-first" preference
|
|
174
|
+
* lives entirely in the search order and grow direction; geometry
|
|
175
|
+
* stays anchored to `markerRowY` at the top.
|
|
176
|
+
*/
|
|
177
|
+
export function packMarkerRow(entries, chartLeftX, chartRightX, estimateTextWidth, arrows = []) {
|
|
178
|
+
const sorted = [...entries].sort((a, b) => a.centerX - b.centerX);
|
|
179
|
+
const placements = new Map();
|
|
180
|
+
let rowSpans = [];
|
|
181
|
+
const byId = new Map(entries.map((e) => [e.id, e]));
|
|
182
|
+
const knownArrows = arrows.filter((a) => byId.has(a.from) && byId.has(a.to));
|
|
183
|
+
for (const e of sorted) {
|
|
184
|
+
const labelWidth = markerLabelWidth(e, estimateTextWidth);
|
|
185
|
+
const naturalRightX = e.centerX + e.radius + MARKER_LABEL_GAP_PX;
|
|
186
|
+
const naturalLeftX = e.centerX - e.radius - MARKER_LABEL_GAP_PX - labelWidth;
|
|
187
|
+
const fitsRightCanvas = naturalRightX + labelWidth <= chartRightX;
|
|
188
|
+
const fitsLeftCanvas = naturalLeftX >= chartLeftX;
|
|
189
|
+
const diamondLeft = e.centerX - e.radius;
|
|
190
|
+
const diamondRight = e.centerX + e.radius;
|
|
191
|
+
const sideXLeft = (s) => (s === 'right' ? naturalRightX : naturalLeftX);
|
|
192
|
+
const sideFitsCanvas = (s) => s === 'right' ? fitsRightCanvas : fitsLeftCanvas;
|
|
193
|
+
// The runs of e's own arrows, on e's row between the two diamonds,
|
|
194
|
+
// and a slipped milestone's span from its planned diamond.
|
|
195
|
+
const slipRun = e.slipFromX === undefined
|
|
196
|
+
? []
|
|
197
|
+
: [{ left: e.slipFromX - e.radius, right: e.centerX - e.radius }];
|
|
198
|
+
const runs = knownArrows
|
|
199
|
+
.filter((a) => a.from === e.id)
|
|
200
|
+
.map((a) => {
|
|
201
|
+
const to = byId.get(a.to);
|
|
202
|
+
return {
|
|
203
|
+
left: Math.min(e.centerX, to.centerX) + e.radius,
|
|
204
|
+
right: Math.max(e.centerX, to.centerX) - to.radius,
|
|
205
|
+
};
|
|
206
|
+
})
|
|
207
|
+
.concat(slipRun)
|
|
208
|
+
.filter((r) => r.right > r.left);
|
|
209
|
+
// An arrow meets its target's line only when the target sits at or
|
|
210
|
+
// above the source's row (cut lines run down from a diamond).
|
|
211
|
+
let minRow = -1;
|
|
212
|
+
let maxRow = Number.POSITIVE_INFINITY;
|
|
213
|
+
for (const a of knownArrows) {
|
|
214
|
+
if (a.to === e.id) {
|
|
215
|
+
const from = placements.get(a.from);
|
|
216
|
+
if (from)
|
|
217
|
+
maxRow = Math.min(maxRow, from.rowIndex);
|
|
218
|
+
}
|
|
219
|
+
if (a.from === e.id) {
|
|
220
|
+
const to = placements.get(a.to);
|
|
221
|
+
if (to)
|
|
222
|
+
minRow = Math.max(minRow, to.rowIndex);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// A label on the side its own arrow leaves would sit on the arrow.
|
|
226
|
+
const crossesOwnRun = (s) => {
|
|
227
|
+
const xLeft = sideXLeft(s);
|
|
228
|
+
return runs.some((r) => r.left < xLeft + labelWidth && r.right > xLeft);
|
|
229
|
+
};
|
|
230
|
+
const freeSide = (s) => sideFitsCanvas(s) && !crossesOwnRun(s);
|
|
231
|
+
// A slipped milestone's label never goes back over its span; the
|
|
232
|
+
// canvas grew for it (`markerLabelsRightX`).
|
|
233
|
+
const growSide = freeSide('right') || e.slipFromX !== undefined
|
|
234
|
+
? 'right'
|
|
235
|
+
: freeSide('left')
|
|
236
|
+
? 'left'
|
|
237
|
+
: fitsRightCanvas
|
|
238
|
+
? 'right'
|
|
239
|
+
: 'left';
|
|
240
|
+
const collidesAt = (xLeft, row) => {
|
|
241
|
+
const extLeft = Math.min(diamondLeft, xLeft);
|
|
242
|
+
const extRight = Math.max(diamondRight, xLeft + labelWidth);
|
|
243
|
+
const own = [{ left: extLeft, right: extRight }, ...runs];
|
|
244
|
+
return rowSpans[row].some((s) => own.some((o) => s.left < o.right && s.right > o.left));
|
|
245
|
+
};
|
|
246
|
+
let placedRow = -1;
|
|
247
|
+
let placedSide = 'right';
|
|
248
|
+
let placedXLeft = naturalRightX;
|
|
249
|
+
// Bottom-first: try the highest existing row first, working up
|
|
250
|
+
// toward row 0 (closest to the ticks).
|
|
251
|
+
outer: for (let row = rowSpans.length - 1; row >= 0; row--) {
|
|
252
|
+
if (row < minRow || row > maxRow)
|
|
253
|
+
continue;
|
|
254
|
+
for (const side of ['right', 'left']) {
|
|
255
|
+
if (!freeSide(side))
|
|
256
|
+
continue;
|
|
257
|
+
const xLeft = sideXLeft(side);
|
|
258
|
+
if (collidesAt(xLeft, row))
|
|
259
|
+
continue;
|
|
260
|
+
placedRow = row;
|
|
261
|
+
placedSide = side;
|
|
262
|
+
placedXLeft = xLeft;
|
|
263
|
+
break outer;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (placedRow === -1 && minRow >= 0 && minRow < maxRow) {
|
|
267
|
+
// An arrow source that must stay at or below its target and fits
|
|
268
|
+
// no row there: a fresh row right below the target, which keeps
|
|
269
|
+
// every placed arrow's source at or below its target.
|
|
270
|
+
const at = minRow + 1;
|
|
271
|
+
for (const [id, p] of placements) {
|
|
272
|
+
if (p.rowIndex >= at)
|
|
273
|
+
placements.set(id, { ...p, rowIndex: p.rowIndex + 1 });
|
|
274
|
+
}
|
|
275
|
+
rowSpans.splice(at, 0, []);
|
|
276
|
+
placedRow = at;
|
|
277
|
+
placedSide = growSide;
|
|
278
|
+
placedXLeft = sideXLeft(placedSide);
|
|
279
|
+
}
|
|
280
|
+
else if (placedRow === -1) {
|
|
281
|
+
// No existing row fits — prepend a fresh top row and shift
|
|
282
|
+
// every previous placement DOWN by one slot (rowIndex += 1)
|
|
283
|
+
// so the bottom corridor stays stable.
|
|
284
|
+
for (const [id, p] of placements) {
|
|
285
|
+
placements.set(id, { ...p, rowIndex: p.rowIndex + 1 });
|
|
286
|
+
}
|
|
287
|
+
rowSpans = [[], ...rowSpans];
|
|
288
|
+
placedRow = 0;
|
|
289
|
+
placedSide = growSide;
|
|
290
|
+
placedXLeft = sideXLeft(placedSide);
|
|
291
|
+
}
|
|
292
|
+
const extLeft = Math.min(diamondLeft, placedXLeft);
|
|
293
|
+
const extRight = Math.max(diamondRight, placedXLeft + labelWidth);
|
|
294
|
+
rowSpans[placedRow].push({ left: extLeft, right: extRight }, ...runs);
|
|
295
|
+
placements.set(e.id, {
|
|
296
|
+
rowIndex: placedRow,
|
|
297
|
+
labelBox: { x: placedXLeft, y: 0, width: labelWidth, height: MARKER_LABEL_HEIGHT_PX },
|
|
298
|
+
labelSide: placedSide,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return { placements, rowCount: rowSpans.length };
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=marker-band.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker-band.js","sourceRoot":"","sources":["../../src/nodes/marker-band.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// the timeline header. The marker band stacks N rows tall when
|
|
9
9
|
// anchors and milestones can't fit on a single row without colliding.
|
|
10
10
|
// - The bare `13` (= PITCH / 2) midpoint that used to sprinkle
|
|
11
|
-
//
|
|
11
|
+
// the roadmap composition code is derived from this constant — bumping the
|
|
12
12
|
// pitch automatically re-centers labels.
|
|
13
13
|
//
|
|
14
14
|
// Diamond + label box dimensions are reused by every marker (anchor +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marker-geometry.js","sourceRoot":"","sources":["../../src/nodes/marker-geometry.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,uEAAuE;AACvE,wDAAwD;AACxD,EAAE;AACF,wCAAwC;AACxC,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,0EAA0E;AAC1E,iEAAiE;AACjE
|
|
1
|
+
{"version":3,"file":"marker-geometry.js","sourceRoot":"","sources":["../../src/nodes/marker-geometry.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,uEAAuE;AACvE,wDAAwD;AACxD,EAAE;AACF,wCAAwC;AACxC,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,0EAA0E;AAC1E,iEAAiE;AACjE,+EAA+E;AAC/E,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,8DAA8D;AAC9D,gEAAgE;AAEhE,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,GAAG,CAAC,CAAC;AAEnE,uEAAuE;AACvE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C,mEAAmE;AACnE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC"}
|
|
@@ -1,25 +1,44 @@
|
|
|
1
1
|
import type { MilestoneDeclaration } from '@nowline/core';
|
|
2
2
|
import type { LayoutContext } from '../layout-context.js';
|
|
3
|
-
import type { PositionedMilestone } from '../types.js';
|
|
3
|
+
import type { MarkerRowPlacement, PositionedMilestone, ResolvedStyle, SlackCorridor } from '../types.js';
|
|
4
4
|
/**
|
|
5
|
-
* One predecessor of a milestone with everything the
|
|
6
|
-
* pipeline
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* One predecessor of a milestone with everything placement and the
|
|
6
|
+
* slack-arrow pipeline need: its end in time (`endX`, also where its slack
|
|
7
|
+
* or overrun line starts, specs/true-width-layout.md §3.5), an item's
|
|
8
|
+
* attach y in the chart's local frame (bar bottom strip when text spills,
|
|
9
|
+
* nominal row midline otherwise), and its flow key (used to dedupe so a
|
|
10
|
+
* chained-flow's siblings collapse to the last entry).
|
|
10
11
|
*/
|
|
11
12
|
export interface MilestonePredecessor {
|
|
12
13
|
ref: string;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Where the predecessor ends in time: an item's duration end, a
|
|
16
|
+
* marker's x, a wave's `E_k`. The milestone sits on the latest one and
|
|
17
|
+
* overruns a date by it (specs/scheduler-unification.md §8 decision 6);
|
|
18
|
+
* its slack or overrun line starts here.
|
|
19
|
+
*/
|
|
20
|
+
endX: number;
|
|
21
|
+
/**
|
|
22
|
+
* An item's attach y. Undefined for every other reference: a marker
|
|
23
|
+
* (its arrow starts on its marker row, known only after the final
|
|
24
|
+
* pack), a wave, a group or a parallel.
|
|
25
|
+
*/
|
|
26
|
+
y: number | undefined;
|
|
27
|
+
/** Set when `ref` names an anchor or milestone of this file. */
|
|
28
|
+
marker?: true;
|
|
15
29
|
flowKey: string;
|
|
30
|
+
/**
|
|
31
|
+
* Set when `ref` names a wave: `endX` is the seeded wave end `E_k`.
|
|
32
|
+
* Wave references draw no slack arrows (specs/waves.md §5.3).
|
|
33
|
+
*/
|
|
34
|
+
wave?: string;
|
|
16
35
|
}
|
|
17
36
|
/**
|
|
18
|
-
* Resolve each `after:` reference into a `MilestonePredecessor`.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
37
|
+
* Resolve each `after:` reference into a `MilestonePredecessor`. Its
|
|
38
|
+
* `endX` is the reference's right edge in time (`entityRightEdges`, an
|
|
39
|
+
* item's duration end, a marker's cut-line x), where its slack line
|
|
40
|
+
* starts: a bar spans exactly its dates, so its end date is its edge
|
|
41
|
+
* (specs/true-width-layout.md §3.5). Refs whose target is unknown drop
|
|
23
42
|
* silently — matches the legacy continue path.
|
|
24
43
|
*/
|
|
25
44
|
export declare function collectMilestonePredecessors(refs: string[], ctx: LayoutContext): MilestonePredecessor[];
|
|
@@ -33,6 +52,54 @@ export declare function collectMilestonePredecessors(refs: string[], ctx: Layout
|
|
|
33
52
|
* each survive as their flow's last entry.
|
|
34
53
|
*/
|
|
35
54
|
export declare function lastPredecessorPerFlow(preds: MilestonePredecessor[]): MilestonePredecessor[];
|
|
55
|
+
/**
|
|
56
|
+
* Where a milestone's slack or overrun arrow starts: at `x` on a chart y
|
|
57
|
+
* (an item predecessor's attach y, in the chart's local frame), or at `x`
|
|
58
|
+
* on the row of `marker` in the marker band, which `positionMilestones`
|
|
59
|
+
* reads from the final pack.
|
|
60
|
+
*/
|
|
61
|
+
export type MilestoneArrowStart = {
|
|
62
|
+
x: number;
|
|
63
|
+
y: number;
|
|
64
|
+
} | {
|
|
65
|
+
x: number;
|
|
66
|
+
marker: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* The predecessor a dated milestone slips to: the one that ends latest in
|
|
70
|
+
* time and is not a wave (an overrunning wave is taken separately, by
|
|
71
|
+
* `overrunningWave`).
|
|
72
|
+
*/
|
|
73
|
+
export declare function latestArrowPredecessor(preds: MilestonePredecessor[]): MilestonePredecessor | null;
|
|
74
|
+
/**
|
|
75
|
+
* A milestone as placement leaves it: its x, slack arrows, overrun and cut
|
|
76
|
+
* lines, but no marker row or label box. Those come from the unified
|
|
77
|
+
* marker re-pack, which needs every milestone's x and the final canvas;
|
|
78
|
+
* `positionMilestones` combines the two.
|
|
79
|
+
*/
|
|
80
|
+
export interface MilestonePlacement {
|
|
81
|
+
id: string;
|
|
82
|
+
title: string;
|
|
83
|
+
x: number;
|
|
84
|
+
radius: number;
|
|
85
|
+
/** True for a `date:` milestone, false for an after-only one. */
|
|
86
|
+
fixed: boolean;
|
|
87
|
+
slackArrows: MilestoneArrowStart[] | undefined;
|
|
88
|
+
isOverrun: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Where an overrun dated milestone actually lands: the end of its
|
|
91
|
+
* latest predecessor (or overrunning wave), past `x`. Omitted when it
|
|
92
|
+
* does not overrun, or when the two diamonds would meet.
|
|
93
|
+
*/
|
|
94
|
+
slipX?: number;
|
|
95
|
+
style: ResolvedStyle;
|
|
96
|
+
cutTopY: number;
|
|
97
|
+
cutBottomY: number;
|
|
98
|
+
onWaveBoundary?: true;
|
|
99
|
+
overrunByWave?: string;
|
|
100
|
+
overrunDate?: string;
|
|
101
|
+
hiddenDate?: string;
|
|
102
|
+
}
|
|
36
103
|
export declare class MilestoneNode {
|
|
37
104
|
readonly id: string;
|
|
38
105
|
readonly milestone: MilestoneDeclaration;
|
|
@@ -41,8 +108,38 @@ export declare class MilestoneNode {
|
|
|
41
108
|
* Returns null when the milestone is neither date-pinned nor has a
|
|
42
109
|
* resolvable `after:` predecessor (skipped silently — matches the
|
|
43
110
|
* legacy `buildMilestones` continue-paths).
|
|
111
|
+
*
|
|
112
|
+
* Writes the milestone's entity edges and midpoint; later milestones'
|
|
113
|
+
* `after:` references read the edges. The midpoint's y is an
|
|
114
|
+
* estimate: the pre-pack row of a dated milestone, the band's first
|
|
115
|
+
* row for an after-only one. Nothing reads it before f6 replaces it
|
|
116
|
+
* with the final pack's row, except f6's coverage trace, which
|
|
117
|
+
* reports a milestone whose row differs from it.
|
|
44
118
|
*/
|
|
45
|
-
place(ctx: LayoutContext):
|
|
119
|
+
place(ctx: LayoutContext): MilestonePlacement | null;
|
|
46
120
|
}
|
|
47
|
-
export declare function buildMilestones(milestones: Map<string, MilestoneDeclaration>, ctx: LayoutContext):
|
|
121
|
+
export declare function buildMilestones(milestones: Map<string, MilestoneDeclaration>, ctx: LayoutContext): MilestonePlacement[];
|
|
122
|
+
/**
|
|
123
|
+
* Build the positioned milestones from their placements and the unified
|
|
124
|
+
* marker re-pack (`rows`, keyed by id), in placement order. The re-pack
|
|
125
|
+
* packs every placed milestone and anchor, so a missing row is an
|
|
126
|
+
* invariant violation and throws. An arrow that starts on a marker row
|
|
127
|
+
* takes that row's centre, already final; one from an item keeps its
|
|
128
|
+
* chart y. Optional keys stay omitted when the placement omits them.
|
|
129
|
+
*/
|
|
130
|
+
export declare function positionMilestones(placements: readonly MilestonePlacement[], rows: ReadonlyMap<string, MarkerRowPlacement>): PositionedMilestone[];
|
|
131
|
+
/**
|
|
132
|
+
* Collect slack-arrow corridors from the resolved milestones using the
|
|
133
|
+
* current entity-edge maps. The result mirrors what
|
|
134
|
+
* `MilestoneNode.place` would emit on `slackArrows`, so the row-packer
|
|
135
|
+
* and the renderer agree on every arrow's geometry.
|
|
136
|
+
*
|
|
137
|
+
* Each non-binding item predecessor (`x < maxEnd`) of an after-only
|
|
138
|
+
* milestone becomes one corridor. A date-pinned milestone draws no arrow
|
|
139
|
+
* (an overrun slips it, in the marker band), so it owns none. An arrow
|
|
140
|
+
* from a marker runs in the marker band, above the lanes, so it owns no
|
|
141
|
+
* corridor; nor does a wave predecessor, which draws no slack arrow (a
|
|
142
|
+
* floating milestone bound by a wave still sets `maxEnd`).
|
|
143
|
+
*/
|
|
144
|
+
export declare function collectSlackCorridors(milestones: Map<string, import('@nowline/core').MilestoneDeclaration>, ctx: LayoutContext): SlackCorridor[];
|
|
48
145
|
//# sourceMappingURL=milestone-node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"milestone-node.d.ts","sourceRoot":"","sources":["../../src/nodes/milestone-node.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"milestone-node.d.ts","sourceRoot":"","sources":["../../src/nodes/milestone-node.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EACR,kBAAkB,EAElB,mBAAmB,EACnB,aAAa,EACb,aAAa,EAChB,MAAM,aAAa,CAAC;AAIrB;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtB,gEAAgE;IAChE,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CACxC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,aAAa,GACnB,oBAAoB,EAAE,CAyBxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CAO5F;AAED;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAwB3F;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,GAAG,IAAI,CAOjG;AAoBD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,mBAAmB,EAAE,GAAG,SAAS,CAAC;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,aAAa;aAEF,EAAE,EAAE,MAAM;aACV,SAAS,EAAE,oBAAoB;IAFnD,YACoB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,oBAAoB,EAC/C;IAEJ;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,kBAAkB,GAAG,IAAI,CA2GnD;CACJ;AAED,wBAAgB,eAAe,CAC3B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC7C,GAAG,EAAE,aAAa,GACnB,kBAAkB,EAAE,CAOtB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,UAAU,EAAE,SAAS,kBAAkB,EAAE,EACzC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAC9C,mBAAmB,EAAE,CAiCvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACjC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,eAAe,EAAE,oBAAoB,CAAC,EACrE,GAAG,EAAE,aAAa,GACnB,aAAa,EAAE,CA8BjB"}
|