@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
package/src/themes/light.ts
CHANGED
|
@@ -64,13 +64,19 @@ export const lightTheme: Theme = {
|
|
|
64
64
|
shadow: 'subtle',
|
|
65
65
|
cornerRadius: 'sm',
|
|
66
66
|
},
|
|
67
|
+
// Containers shade their body with `bg` as a light tint
|
|
68
|
+
// (CONTAINER_BODY_FILL_OPACITY); groups and parallels get distinct
|
|
69
|
+
// ones, and a parallel's header bracket is dashed, a group's solid
|
|
70
|
+
// (specs/true-width-layout.md §3.3).
|
|
67
71
|
parallel: {
|
|
68
72
|
...baseEntity,
|
|
69
|
-
|
|
73
|
+
bg: '#635cf1',
|
|
74
|
+
bracket: 'dashed',
|
|
70
75
|
padding: 'xs',
|
|
71
76
|
},
|
|
72
77
|
group: {
|
|
73
78
|
...baseEntity,
|
|
79
|
+
bg: '#ea9818',
|
|
74
80
|
bracket: 'solid',
|
|
75
81
|
padding: 'xs',
|
|
76
82
|
fg: '#475569',
|
|
@@ -127,6 +133,8 @@ export const lightTheme: Theme = {
|
|
|
127
133
|
timeline: {
|
|
128
134
|
gridLine: '#cbd5e1',
|
|
129
135
|
minorGridLine: '#e2e8f0',
|
|
136
|
+
nonWorkingSeam: '#a0aec0',
|
|
137
|
+
nonWorkingFill: '#64748b',
|
|
130
138
|
tickMark: '#cbd5e1',
|
|
131
139
|
labelText: '#64748b',
|
|
132
140
|
panelFill: '#ffffff',
|
|
@@ -199,6 +207,15 @@ export const lightTheme: Theme = {
|
|
|
199
207
|
badgeStroke: '#cbd5e1',
|
|
200
208
|
badgeText: '#475569',
|
|
201
209
|
},
|
|
210
|
+
wave: {
|
|
211
|
+
stripFill: '#f0fdfa',
|
|
212
|
+
stripFillAlt: '#ccfbf1',
|
|
213
|
+
labelText: '#134e4a',
|
|
214
|
+
labelMuted: '#0f766e',
|
|
215
|
+
boundary: '#0d9488',
|
|
216
|
+
hatch: '#0f172a',
|
|
217
|
+
hatchOnDark: '#ffffff',
|
|
218
|
+
},
|
|
202
219
|
arrowhead: {
|
|
203
220
|
neutral: '#475569',
|
|
204
221
|
light: '#94a3b8',
|
|
@@ -212,6 +229,16 @@ export const lightTheme: Theme = {
|
|
|
212
229
|
planned: '#94a3b8',
|
|
213
230
|
neutral: '#94a3b8',
|
|
214
231
|
},
|
|
232
|
+
// Item bar fill per status, applied by layout when the item's resolved
|
|
233
|
+
// `bg` is still `entities.item.bg` (m2d Resolution 3).
|
|
234
|
+
statusTint: {
|
|
235
|
+
done: '#ecfdf5',
|
|
236
|
+
inProgress: '#eff6ff',
|
|
237
|
+
atRisk: '#fffbeb',
|
|
238
|
+
blocked: '#fee2e2',
|
|
239
|
+
planned: '#f8fafc',
|
|
240
|
+
neutral: '#f8fafc',
|
|
241
|
+
},
|
|
215
242
|
// Status-dot palettes — the renderer picks one based on the
|
|
216
243
|
// bar's effective bg luminance.
|
|
217
244
|
//
|
package/src/themes/shape.ts
CHANGED
|
@@ -82,6 +82,15 @@ export interface Theme {
|
|
|
82
82
|
// when the roadmap's resolved `minor-grid` style is `true`. A step
|
|
83
83
|
// lighter than `gridLine` so the major lines still dominate.
|
|
84
84
|
minorGridLine: string;
|
|
85
|
+
// Faint dotted seam where hidden non-working days collapse between
|
|
86
|
+
// two working-day columns and no grid line already marks the spot
|
|
87
|
+
// (specs/working-calendar.md §7.4). Darker than `gridLine`, so it
|
|
88
|
+
// reads as a join rather than a column boundary.
|
|
89
|
+
nonWorkingSeam: string;
|
|
90
|
+
// Fill of a non-working band under the `show` display, painted at
|
|
91
|
+
// `NON_WORKING_FILL_OPACITY` over the row tints (specs/working-
|
|
92
|
+
// calendar.md §7.3): a faint shade a grid line still reads over.
|
|
93
|
+
nonWorkingFill: string;
|
|
85
94
|
tickMark: string;
|
|
86
95
|
labelText: string;
|
|
87
96
|
// m2.5d: lifted from renderTimeline.
|
|
@@ -160,6 +169,22 @@ export interface Theme {
|
|
|
160
169
|
badgeStroke: string;
|
|
161
170
|
badgeText: string;
|
|
162
171
|
};
|
|
172
|
+
/**
|
|
173
|
+
* Wave tokens (specs/waves.md section 9.10). `stripFill` and
|
|
174
|
+
* `stripFillAlt` alternate across the wave strip cells; `labelText`
|
|
175
|
+
* and `labelMuted` paint strip labels and secondary text; `boundary`
|
|
176
|
+
* is the vertical wave boundary line; `hatch` and `hatchOnDark` are
|
|
177
|
+
* the background-work hatch stroke on light and dark bar fills.
|
|
178
|
+
*/
|
|
179
|
+
wave: {
|
|
180
|
+
stripFill: string;
|
|
181
|
+
stripFillAlt: string;
|
|
182
|
+
labelText: string;
|
|
183
|
+
labelMuted: string;
|
|
184
|
+
boundary: string;
|
|
185
|
+
hatch: string;
|
|
186
|
+
hatchOnDark: string;
|
|
187
|
+
};
|
|
163
188
|
// m2.5d: lifted from renderEdge marker defs.
|
|
164
189
|
arrowhead: {
|
|
165
190
|
neutral: string;
|
|
@@ -175,6 +200,19 @@ export interface Theme {
|
|
|
175
200
|
planned: string;
|
|
176
201
|
neutral: string;
|
|
177
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* Item bar fill per status when the item's resolved `bg` is the theme's
|
|
205
|
+
* item default (`entities.item.bg`); an explicit `bg:` wins. Same keys as
|
|
206
|
+
* `status`, which colors the border the same way for `entities.item.fg`.
|
|
207
|
+
*/
|
|
208
|
+
statusTint: {
|
|
209
|
+
done: string;
|
|
210
|
+
inProgress: string;
|
|
211
|
+
atRisk: string;
|
|
212
|
+
blocked: string;
|
|
213
|
+
planned: string;
|
|
214
|
+
neutral: string;
|
|
215
|
+
};
|
|
178
216
|
/**
|
|
179
217
|
* Upper-right status-dot colors. Two palettes — the renderer
|
|
180
218
|
* picks `onLight` for bars whose effective bg is light/pale and
|
package/src/themes/shared.ts
CHANGED
|
@@ -21,15 +21,6 @@ export const PADDING_PX: Record<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl', numbe
|
|
|
21
21
|
xl: 32,
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export const HEADER_HEIGHT_PX: Record<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl', number> = {
|
|
25
|
-
none: 0,
|
|
26
|
-
xs: 24,
|
|
27
|
-
sm: 36,
|
|
28
|
-
md: 56,
|
|
29
|
-
lg: 80,
|
|
30
|
-
xl: 112,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
24
|
export const TEXT_SIZE_PX: Record<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl', number> = {
|
|
34
25
|
none: 0,
|
|
35
26
|
xs: 10,
|
|
@@ -63,8 +54,10 @@ export const LOGO_SIZE_PX: Record<'xs' | 'sm' | 'md' | 'lg' | 'xl', number> = {
|
|
|
63
54
|
// `defaultRowBand()` keeps the legacy 64/56 split byte-stable; new
|
|
64
55
|
// callers should consume `bandScale.step()` and `bandScale.bandwidth()`.
|
|
65
56
|
|
|
66
|
-
// Minimum
|
|
67
|
-
|
|
57
|
+
// Minimum painted bar width: a bar spans exactly its dates, so this floor
|
|
58
|
+
// only keeps a sub-pixel or zero-duration item visible
|
|
59
|
+
// (specs/true-width-layout.md §3.1).
|
|
60
|
+
export const MIN_ITEM_WIDTH = 1;
|
|
68
61
|
|
|
69
62
|
// Height (px) of the bottom progress strip drawn along the item bar's
|
|
70
63
|
// bottom edge. Single source of truth used by:
|
|
@@ -80,28 +73,43 @@ export const MIN_ITEM_WIDTH = 8;
|
|
|
80
73
|
export const PROGRESS_STRIP_HEIGHT_PX = 4;
|
|
81
74
|
|
|
82
75
|
// Timeline tick header band — a single row that holds the date labels
|
|
83
|
-
// (e.g. "Jan 05", "Feb 14").
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// the
|
|
88
|
-
|
|
89
|
-
|
|
76
|
+
// (e.g. "Jan 05", "Feb 14"). The roadmap's `header-height` style key
|
|
77
|
+
// picks the panel height from this table; `none` drops the panel (top
|
|
78
|
+
// and mirrored bottom) entirely. Layout sizes the panel; the renderer
|
|
79
|
+
// paints the labels at `timelineTickLabelBaselineOffsetPx(height)` from
|
|
80
|
+
// the panel's top, so the dates stay centered at every bucket.
|
|
81
|
+
export const HEADER_HEIGHT_PX: Record<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl', number> = {
|
|
82
|
+
none: 0,
|
|
83
|
+
xs: 16,
|
|
84
|
+
sm: 20,
|
|
85
|
+
md: 24,
|
|
86
|
+
lg: 32,
|
|
87
|
+
xl: 40,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/** Tick panel height at the default `header-height:md`. */
|
|
91
|
+
export const TIMELINE_TICK_PANEL_HEIGHT_PX = HEADER_HEIGHT_PX.md;
|
|
90
92
|
|
|
91
93
|
/**
|
|
92
|
-
* Baseline Y of the tick-label text relative to the tick panel's top
|
|
93
|
-
*
|
|
94
|
+
* Baseline Y of the tick-label text relative to the tick panel's top,
|
|
95
|
+
* for a panel `panelHeightPx` tall. Approximately vertically centers a
|
|
96
|
+
* 10 pt label: half the panel plus ~3 px of descender allowance.
|
|
94
97
|
*/
|
|
95
|
-
export
|
|
98
|
+
export function timelineTickLabelBaselineOffsetPx(panelHeightPx: number): number {
|
|
99
|
+
return Math.round(panelHeightPx / 2 + 3);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Tick-label baseline offset at the default panel height. */
|
|
103
|
+
export const TIMELINE_TICK_LABEL_BASELINE_OFFSET_PX = timelineTickLabelBaselineOffsetPx(
|
|
104
|
+
TIMELINE_TICK_PANEL_HEIGHT_PX,
|
|
105
|
+
);
|
|
96
106
|
|
|
97
107
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* against their neighbors (no gutter) — only block boundaries get this
|
|
102
|
-
* gutter.
|
|
108
|
+
* Font size of the tick labels. Layout reads it to decide whether a
|
|
109
|
+
* partial edge column is wide enough to hold its label; the renderer
|
|
110
|
+
* paints at the same size.
|
|
103
111
|
*/
|
|
104
|
-
export const
|
|
112
|
+
export const TIMELINE_TICK_LABEL_FONT_SIZE_PX = 10;
|
|
105
113
|
|
|
106
114
|
// Frame-tab chiclet — the rounded label tab that overhangs a swimlane
|
|
107
115
|
// frame and the dashed include-region border. Both surfaces share the
|
|
@@ -117,60 +125,6 @@ export const FRAME_TAB_HEIGHT_PX = 22;
|
|
|
117
125
|
/** Baseline Y of the chiclet label relative to the tab's top edge. */
|
|
118
126
|
export const FRAME_TAB_LABEL_BASELINE_OFFSET_PX = 15;
|
|
119
127
|
|
|
120
|
-
// Group title chiclet — the small label tab anchored flush in the upper-left
|
|
121
|
-
// corner of a styled group's bounding box. Smaller than the frame-tab so it
|
|
122
|
-
// reads as a "container label" rather than a sibling of the swimlane tab.
|
|
123
|
-
//
|
|
124
|
-
// The chiclet's top edge aligns with the group box's top edge and its left
|
|
125
|
-
// edge aligns with the box's left edge (no overhang). The group reserves
|
|
126
|
-
// `GROUP_TITLE_TAB_HEIGHT_PX + GROUP_TITLE_TAB_GUTTER_PX` of vertical top
|
|
127
|
-
// padding inside the box before the first child row begins, so the chiclet
|
|
128
|
-
// never overlaps content. Bumping the height without re-tuning
|
|
129
|
-
// `GROUP_TITLE_TAB_LABEL_BASELINE_OFFSET_PX` mis-centers the label.
|
|
130
|
-
|
|
131
|
-
/** Height (px) of the group-title chiclet anchored at the box's upper-left. */
|
|
132
|
-
export const GROUP_TITLE_TAB_HEIGHT_PX = 16;
|
|
133
|
-
|
|
134
|
-
/** Horizontal padding (px) on each side of the title text inside the chiclet. */
|
|
135
|
-
export const GROUP_TITLE_TAB_PAD_X_PX = 6;
|
|
136
|
-
|
|
137
|
-
/** Vertical gap (px) between the chiclet's bottom edge and the first inner row. */
|
|
138
|
-
export const GROUP_TITLE_TAB_GUTTER_PX = 4;
|
|
139
|
-
|
|
140
|
-
/** Baseline Y of the chiclet label relative to the chiclet's top edge.
|
|
141
|
-
* Tuned for a 9 pt bold glyph roughly vertically centered in a 16 px tab. */
|
|
142
|
-
export const GROUP_TITLE_TAB_LABEL_BASELINE_OFFSET_PX = 11;
|
|
143
|
-
|
|
144
|
-
/** Font size (px) of the group-title chiclet label. */
|
|
145
|
-
export const GROUP_TITLE_TAB_LABEL_FONT_SIZE_PX = 9;
|
|
146
|
-
|
|
147
|
-
/** Approximate per-character width factor used to size the chiclet to its
|
|
148
|
-
* title text. Mirrors the constant used in the renderer's pre-port code
|
|
149
|
-
* so the chiclet hugs short titles without clipping long ones. */
|
|
150
|
-
export const GROUP_TITLE_TAB_CHAR_WIDTH_PX = 5.5;
|
|
151
|
-
|
|
152
|
-
/** Padding (px) reserved on the inside-bottom of a styled group box before
|
|
153
|
-
* its lower stroke. Symmetric with the chiclet gutter so children breathe
|
|
154
|
-
* on both ends. */
|
|
155
|
-
export const GROUP_BOTTOM_PAD_PX = 4;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Vertical space (px) reserved ABOVE a bracket-style (no-fill) group's
|
|
159
|
-
* box to host its overhanging title label. Bracket groups paint their
|
|
160
|
-
* label at `box.y - 2` (baseline) in the renderer — the glyph extent
|
|
161
|
-
* lives entirely ABOVE box.y. Without an explicit reservation, that
|
|
162
|
-
* overhang collides with the previous sibling's bracket-foot when two
|
|
163
|
-
* bracket-titled groups stack in a parallel (the foot ends right where
|
|
164
|
-
* the next label's top would render). The group shifts its own box.y
|
|
165
|
-
* down by this amount so the label has clear space above it; the
|
|
166
|
-
* caller advances by `bracketLabelOverhang + box.height + interRowGap`.
|
|
167
|
-
*
|
|
168
|
-
* Filled-style ("chiclet") groups use `GROUP_TITLE_TAB_HEIGHT_PX +
|
|
169
|
-
* GROUP_TITLE_TAB_GUTTER_PX` instead — the chiclet sits INSIDE the box,
|
|
170
|
-
* so they need no above-box reservation.
|
|
171
|
-
*/
|
|
172
|
-
export const GROUP_BRACKET_LABEL_OVERHANG_PX = 12;
|
|
173
|
-
|
|
174
128
|
/**
|
|
175
129
|
* Dashed-accent pattern (px on / px off) used for two nowline accents
|
|
176
130
|
* that read as "structural emphasis": the milestone vertical cut line
|
|
@@ -226,15 +180,15 @@ export const NOW_PILL_LABEL_INSET_X_PX = 6;
|
|
|
226
180
|
*/
|
|
227
181
|
export const NOWLINE_STROKE_WIDTH_PX = 2.25;
|
|
228
182
|
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
|
|
183
|
+
// The seam a bar gives up on each side, from inside its dates, so two bars
|
|
184
|
+
// that abut in time show a 2 px gap between their strokes
|
|
185
|
+
// (specs/true-width-layout.md §3.1). A bar too short for both seams and the
|
|
186
|
+
// `MIN_ITEM_WIDTH` floor shrinks its seams instead, staying centred in its
|
|
187
|
+
// dates.
|
|
188
|
+
export const ITEM_SEAM_PX = 1;
|
|
234
189
|
|
|
235
190
|
// Canonical content gutter — the rest-state spacing between adjacent
|
|
236
191
|
// pieces of chart content. Used for:
|
|
237
|
-
// - the gap between two adjacent items in a track (= 2 × ITEM_INSET_PX),
|
|
238
192
|
// - the gap between the header card and the chart's left edge (originX
|
|
239
193
|
// offset from chartLeftX),
|
|
240
194
|
// - the bottom margin around the attribution wordmark.
|
|
@@ -244,11 +198,14 @@ export const ITEM_INSET_PX = 6;
|
|
|
244
198
|
// That's a runtime concern — the layout engine emits a static positioned
|
|
245
199
|
// model and the interactive shell animates spacing on top. Keep this
|
|
246
200
|
// constant as the rest-state baseline.
|
|
247
|
-
export const GUTTER_PX =
|
|
201
|
+
export const GUTTER_PX = 12;
|
|
248
202
|
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
|
|
203
|
+
// Pixels per day at the days scale (`scale:1d`). A day literal labels
|
|
204
|
+
// every column, so a day must hold its widest `M/D` label (`12/31`, about
|
|
205
|
+
// 29 px at the 10 px tick font), as a 40 px week holds `Sep 28`. That
|
|
206
|
+
// also keeps a day here wider than a day inside a default week column
|
|
207
|
+
// (8 px under business, about 5.7 px under full).
|
|
208
|
+
export const DEFAULT_PIXELS_PER_DAY = 32;
|
|
252
209
|
|
|
253
210
|
// Header box defaults per position. The beside-mode card width is dynamic
|
|
254
211
|
// (sized to the title + author text, clamped to MIN..MAX with text wrap),
|
|
@@ -266,13 +223,15 @@ export const HEADER_ABOVE_HEIGHT_PX = 72;
|
|
|
266
223
|
// │ Footnotes ↑ │ header band (HEADER_HEIGHT)
|
|
267
224
|
// │ │ │
|
|
268
225
|
// ├─────────────────────────┘ │ gap = PANEL_PADDING
|
|
269
|
-
// │ N Title — description │ row
|
|
226
|
+
// │ N Title — description │ row (ROW_HEIGHT each)
|
|
227
|
+
// │ that wraps at the title │ wrapped row
|
|
270
228
|
// │ N … │
|
|
271
229
|
// │ │
|
|
272
230
|
// └───────────────────────────────┘ bottom pad = PANEL_PADDING
|
|
273
231
|
//
|
|
274
232
|
// Total panel height (when entries.length > 0):
|
|
275
|
-
// HEADER_HEIGHT +
|
|
233
|
+
// HEADER_HEIGHT + rows × ROW_HEIGHT + PANEL_PADDING, where rows counts
|
|
234
|
+
// every entry's rows (wrapped ones included) and each region heading.
|
|
276
235
|
|
|
277
236
|
/** Height (px) of the header band above the entry rows. */
|
|
278
237
|
export const FOOTNOTE_HEADER_HEIGHT_PX = 28;
|
|
@@ -367,3 +326,36 @@ export const LABEL_THINNING: Record<'days' | 'weeks' | 'months' | 'quarters' | '
|
|
|
367
326
|
quarters: 4,
|
|
368
327
|
years: 5,
|
|
369
328
|
};
|
|
329
|
+
|
|
330
|
+
// Opacity of a non-working band (`timeline.nonWorkingFill`) under the
|
|
331
|
+
// `show` display (specs/working-calendar.md §7.3).
|
|
332
|
+
export const NON_WORKING_FILL_OPACITY = 0.1;
|
|
333
|
+
|
|
334
|
+
// Waves (specs/waves.md section 9.10; hatch geometry section 9.3).
|
|
335
|
+
export const WAVE_STRIP_HEIGHT_PX = 20;
|
|
336
|
+
export const WAVE_BOUNDARY_WIDTH_PX = 2;
|
|
337
|
+
export const WAVE_CROSS_DASH = '2 2';
|
|
338
|
+
export const WAVE_HATCH_OPACITY = 0.13;
|
|
339
|
+
export const WAVE_HATCH_TILE_PX = 6;
|
|
340
|
+
export const WAVE_HATCH_STROKE_PX = 2;
|
|
341
|
+
export const WAVE_STYLED_TINT_OPACITY = 0.12;
|
|
342
|
+
export const WAVE_STYLED_STRIP_MIX_OPACITY = 0.25;
|
|
343
|
+
export const WAVE_STRIP_LABEL_FONT_SIZE_PX = 10;
|
|
344
|
+
export const WAVE_LEGEND_LINE_PX = 14;
|
|
345
|
+
export const WAVE_LEGEND_GAP_PX = 8;
|
|
346
|
+
// Wave strip and legend geometry (specs/waves.md §9.1, §9.5).
|
|
347
|
+
/** Horizontal padding on each side of a strip label in the fit test. */
|
|
348
|
+
export const WAVE_STRIP_LABEL_PAD_PX = 6;
|
|
349
|
+
/** Horizontal padding of a strip label's halo on each side. */
|
|
350
|
+
export const WAVE_LABEL_HALO_PAD_PX = 2;
|
|
351
|
+
/** Vertical inset of a strip label's halo from the strip's top and bottom. */
|
|
352
|
+
export const WAVE_LABEL_HALO_INSET_Y_PX = 3;
|
|
353
|
+
/** How far a strip cell sits inside the backing panel: half its 1 px stroke. */
|
|
354
|
+
export const WAVE_CELL_INSET_PX = 0.5;
|
|
355
|
+
/** Legend swatch (a hatched bar) size. */
|
|
356
|
+
export const WAVE_LEGEND_SWATCH_WIDTH_PX = 18;
|
|
357
|
+
export const WAVE_LEGEND_SWATCH_HEIGHT_PX = 10;
|
|
358
|
+
/** Gap between a legend swatch and its text. */
|
|
359
|
+
export const WAVE_LEGEND_SWATCH_GAP_PX = 6;
|
|
360
|
+
/** Legend text baseline below its line's top (10 px text in a 14 px line). */
|
|
361
|
+
export const WAVE_LEGEND_BASELINE_OFFSET_PX = 11;
|
package/src/time-scale.ts
CHANGED
|
@@ -3,23 +3,39 @@
|
|
|
3
3
|
// also exposes `invert(x) -> Date` for the m4 editor work and that
|
|
4
4
|
// composes with a `WorkingCalendar` for non-continuous time models.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
// (`originX +
|
|
8
|
-
//
|
|
9
|
-
// `
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
// x is linear in the working-day index from the domain start
|
|
7
|
+
// (specs/working-calendar.md §7.1): `originX + index * pixelsPerDay`.
|
|
8
|
+
// With no calendar, or one with no non-working day, the index is
|
|
9
|
+
// `daysBetween`, so the forward direction matches the legacy
|
|
10
|
+
// arithmetic byte-for-byte. Under a calendar with non-working days a
|
|
11
|
+
// hidden date maps to the start of the next working day, and `invert`
|
|
12
|
+
// returns the working day whose start is nearest x.
|
|
13
|
+
//
|
|
14
|
+
// Under the `show` display (§7.3) a calendar's non-working days keep their
|
|
15
|
+
// full width instead: x is linear in calendar days, and `startX` /
|
|
16
|
+
// `advanceX` step an item over the non-working days it crosses. Every
|
|
17
|
+
// branch for it is gated on `showsNonWorking`, so `hide`, a calendar with no
|
|
18
|
+
// non-working day and a scale with no calendar keep the code above verbatim.
|
|
19
|
+
|
|
20
|
+
import { addDays, daysBetween } from './calendar.js';
|
|
21
|
+
import type { NonWorkingDisplay } from './non-working-display.js';
|
|
14
22
|
import type { WorkingCalendar } from './working-calendar.js';
|
|
15
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Tolerance, in days, for reading a day off an x. Pixel sums carry float
|
|
26
|
+
* noise, so an x a hair before a day's start counts as that day.
|
|
27
|
+
*/
|
|
28
|
+
const DAY_EPSILON = 1e-6;
|
|
29
|
+
|
|
16
30
|
export interface TimeScaleOptions {
|
|
17
31
|
/** [start, end] in calendar dates (UTC midnight assumed). */
|
|
18
32
|
domain: [Date, Date];
|
|
19
33
|
/** [originX, originX + chartWidth]. */
|
|
20
34
|
range: [number, number];
|
|
21
|
-
/**
|
|
35
|
+
/** The working calendar; without one every day is a working day. */
|
|
22
36
|
calendar?: WorkingCalendar;
|
|
37
|
+
/** How non-working days are drawn; `hide` when omitted. */
|
|
38
|
+
nonWorking?: NonWorkingDisplay;
|
|
23
39
|
}
|
|
24
40
|
|
|
25
41
|
export class TimeScale {
|
|
@@ -27,15 +43,43 @@ export class TimeScale {
|
|
|
27
43
|
readonly range: [number, number];
|
|
28
44
|
readonly pixelsPerDay: number;
|
|
29
45
|
readonly calendar?: WorkingCalendar;
|
|
30
|
-
|
|
46
|
+
/** The requested display; `showsNonWorking` says whether it takes effect. */
|
|
47
|
+
readonly nonWorking: NonWorkingDisplay;
|
|
31
48
|
|
|
32
49
|
constructor(opts: TimeScaleOptions) {
|
|
33
50
|
this.domain = opts.domain;
|
|
34
51
|
this.range = opts.range;
|
|
35
52
|
this.calendar = opts.calendar;
|
|
36
|
-
|
|
53
|
+
this.nonWorking = opts.nonWorking ?? 'hide';
|
|
54
|
+
const spanDays = Math.max(
|
|
55
|
+
1,
|
|
56
|
+
this.showsNonWorking
|
|
57
|
+
? daysBetween(opts.domain[0], opts.domain[1])
|
|
58
|
+
: this.indexOf(opts.domain[1]),
|
|
59
|
+
);
|
|
37
60
|
this.pixelsPerDay = (opts.range[1] - opts.range[0]) / spanDays;
|
|
38
|
-
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* True when non-working days are drawn at full width: the `show`
|
|
65
|
+
* display over a calendar that has non-working days. The one predicate
|
|
66
|
+
* every show-only branch in the layout is gated on.
|
|
67
|
+
*/
|
|
68
|
+
get showsNonWorking(): boolean {
|
|
69
|
+
return this.nonWorking === 'show' && this.calendar?.hasNonWorkingDays === true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Working days from the domain start to `date` (calendar days without a calendar). */
|
|
73
|
+
private indexOf(date: Date): number {
|
|
74
|
+
return this.calendar
|
|
75
|
+
? this.calendar.workingIndexOf(this.domain[0], date)
|
|
76
|
+
: daysBetween(this.domain[0], date);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Calendar days from the domain start to `x`, and the whole day `x` lies in. */
|
|
80
|
+
private dayAt(x: number): { days: number; day: number } {
|
|
81
|
+
const days = (x - this.range[0]) / this.pixelsPerDay;
|
|
82
|
+
return { days, day: Math.floor(days + DAY_EPSILON) };
|
|
39
83
|
}
|
|
40
84
|
|
|
41
85
|
/**
|
|
@@ -44,14 +88,17 @@ export class TimeScale {
|
|
|
44
88
|
* `forwardWithinDomain`).
|
|
45
89
|
*/
|
|
46
90
|
forward(date: Date): number {
|
|
47
|
-
|
|
48
|
-
|
|
91
|
+
if (this.showsNonWorking) {
|
|
92
|
+
return this.range[0] + daysBetween(this.domain[0], date) * this.pixelsPerDay;
|
|
93
|
+
}
|
|
94
|
+
return this.range[0] + this.indexOf(date) * this.pixelsPerDay;
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
/**
|
|
52
98
|
* Project a date onto the x-axis, returning `null` when the date
|
|
53
|
-
* is outside [domain[0], domain[1]].
|
|
54
|
-
*
|
|
99
|
+
* is outside [domain[0], domain[1]]. The guard compares raw dates,
|
|
100
|
+
* so a hidden day inside the window still projects. Replaces the
|
|
101
|
+
* legacy `xForDate(date, timeline)` helper.
|
|
55
102
|
*/
|
|
56
103
|
forwardWithinDomain(date: Date): number | null {
|
|
57
104
|
if (date < this.domain[0] || date > this.domain[1]) return null;
|
|
@@ -59,11 +106,62 @@ export class TimeScale {
|
|
|
59
106
|
}
|
|
60
107
|
|
|
61
108
|
/**
|
|
62
|
-
* Inverse projection
|
|
63
|
-
*
|
|
109
|
+
* Inverse projection: the working day whose start is nearest x
|
|
110
|
+
* (UTC midnight). Never a non-working day, except under `show`, where
|
|
111
|
+
* every day has width and this is the calendar day nearest x.
|
|
64
112
|
*/
|
|
65
113
|
invert(x: number): Date {
|
|
66
|
-
|
|
114
|
+
const index = Math.round((x - this.range[0]) / this.pixelsPerDay);
|
|
115
|
+
if (this.showsNonWorking) return addDays(this.domain[0], index);
|
|
116
|
+
return this.calendar
|
|
117
|
+
? this.calendar.dateAtWorkingIndex(this.domain[0], index)
|
|
118
|
+
: addDays(this.domain[0], index);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The working-day index at `x`, with the fraction of a working day it
|
|
123
|
+
* is into. Under `show` an x inside a non-working day reads as the start
|
|
124
|
+
* of the next working day; otherwise x is linear in the index.
|
|
125
|
+
*/
|
|
126
|
+
indexAtX(x: number): number {
|
|
127
|
+
const { days, day } = this.dayAt(x);
|
|
128
|
+
if (!this.showsNonWorking || !this.calendar) return days;
|
|
129
|
+
const date = addDays(this.domain[0], day);
|
|
130
|
+
const index = this.calendar.workingIndexOf(this.domain[0], date);
|
|
131
|
+
if (!this.calendar.isWorkingDay(date)) return index;
|
|
132
|
+
return index + Math.max(0, days - day);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Where an item placed at `x` starts. Under `show` an x inside a
|
|
137
|
+
* non-working day moves forward to the start of the next working day;
|
|
138
|
+
* an x inside a working day keeps its fraction, so a start mid-Friday
|
|
139
|
+
* stays mid-Friday. The identity otherwise.
|
|
140
|
+
*/
|
|
141
|
+
startX(x: number): number {
|
|
142
|
+
if (!this.showsNonWorking || !this.calendar) return x;
|
|
143
|
+
const date = addDays(this.domain[0], this.dayAt(x).day);
|
|
144
|
+
if (this.calendar.isWorkingDay(date)) return x;
|
|
145
|
+
const index = this.calendar.workingIndexOf(this.domain[0], date);
|
|
146
|
+
return this.forward(this.calendar.dateAtWorkingIndex(this.domain[0], index));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The x where `n` working days from `startX(x)` end. Under `show` that is
|
|
151
|
+
* the end of the last working day the span reaches, with a partial day
|
|
152
|
+
* interpolated, so a Mon-Fri item ends on Friday evening and the weekend
|
|
153
|
+
* after it stays open. `x + n * pixelsPerDay` otherwise.
|
|
154
|
+
*/
|
|
155
|
+
advanceX(x: number, n: number): number {
|
|
156
|
+
if (!this.showsNonWorking || !this.calendar) return x + n * this.pixelsPerDay;
|
|
157
|
+
const start = this.startX(x);
|
|
158
|
+
if (n <= 0) return start;
|
|
159
|
+
const target = this.indexAtX(start) + n;
|
|
160
|
+
// The working day the span ends in, and how much of it it covers (0, 1].
|
|
161
|
+
const lastDay = Math.ceil(target - DAY_EPSILON) - 1;
|
|
162
|
+
const covered = target - lastDay;
|
|
163
|
+
const lastDate = this.calendar.dateAtWorkingIndex(this.domain[0], lastDay);
|
|
164
|
+
return this.forward(lastDate) + covered * this.pixelsPerDay;
|
|
67
165
|
}
|
|
68
166
|
|
|
69
167
|
/** First pixel of the chart (start of range). */
|