@macrostrat/column-views 3.11.0 → 3.12.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/dist/age-model/data.cjs +57 -0
  3. package/dist/age-model/data.cjs.map +1 -0
  4. package/dist/age-model/data.d.ts +29 -0
  5. package/dist/age-model/data.js +57 -0
  6. package/dist/age-model/data.js.map +1 -0
  7. package/dist/age-model/details.cjs +261 -0
  8. package/dist/age-model/details.cjs.map +1 -0
  9. package/dist/age-model/details.d.ts +39 -0
  10. package/dist/age-model/details.js +258 -0
  11. package/dist/age-model/details.js.map +1 -0
  12. package/dist/age-model/details.module.sass.cjs +42 -0
  13. package/dist/age-model/details.module.sass.cjs.map +1 -0
  14. package/dist/age-model/details.module.sass.js +40 -0
  15. package/dist/age-model/details.module.sass.js.map +1 -0
  16. package/dist/age-model/index.d.ts +5 -0
  17. package/dist/age-model/legacy.cjs +28 -0
  18. package/dist/age-model/legacy.cjs.map +1 -0
  19. package/dist/age-model/legacy.d.ts +6 -0
  20. package/dist/age-model/legacy.js +26 -0
  21. package/dist/age-model/legacy.js.map +1 -0
  22. package/dist/age-model/surfaces.cjs +355 -0
  23. package/dist/age-model/surfaces.cjs.map +1 -0
  24. package/dist/age-model/surfaces.d.ts +68 -0
  25. package/dist/age-model/surfaces.js +352 -0
  26. package/dist/age-model/surfaces.js.map +1 -0
  27. package/dist/age-model/surfaces.module.sass.cjs +45 -0
  28. package/dist/age-model/surfaces.module.sass.cjs.map +1 -0
  29. package/dist/age-model/surfaces.module.sass.js +43 -0
  30. package/dist/age-model/surfaces.module.sass.js.map +1 -0
  31. package/dist/age-model/types.cjs +229 -0
  32. package/dist/age-model/types.cjs.map +1 -0
  33. package/dist/age-model/types.d.ts +112 -0
  34. package/dist/age-model/types.js +229 -0
  35. package/dist/age-model/types.js.map +1 -0
  36. package/dist/column-views.css +389 -57
  37. package/dist/column.cjs +20 -13
  38. package/dist/column.cjs.map +1 -1
  39. package/dist/column.d.ts +21 -6
  40. package/dist/column.js +21 -14
  41. package/dist/column.js.map +1 -1
  42. package/dist/column.module.sass.cjs +19 -15
  43. package/dist/column.module.sass.cjs.map +1 -1
  44. package/dist/column.module.sass.js +19 -15
  45. package/dist/column.module.sass.js.map +1 -1
  46. package/dist/data-provider/store.cjs +34 -1
  47. package/dist/data-provider/store.cjs.map +1 -1
  48. package/dist/data-provider/store.d.ts +5 -0
  49. package/dist/data-provider/store.js +35 -2
  50. package/dist/data-provider/store.js.map +1 -1
  51. package/dist/index.cjs +54 -3
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.ts +3 -1
  54. package/dist/index.js +54 -3
  55. package/dist/index.js.map +1 -1
  56. package/dist/notes.cjs +11 -2
  57. package/dist/notes.cjs.map +1 -1
  58. package/dist/notes.d.ts +11 -1
  59. package/dist/notes.js +11 -2
  60. package/dist/notes.js.map +1 -1
  61. package/dist/prepare-units/composite-scale.cjs +18 -16
  62. package/dist/prepare-units/composite-scale.cjs.map +1 -1
  63. package/dist/prepare-units/composite-scale.js +18 -16
  64. package/dist/prepare-units/composite-scale.js.map +1 -1
  65. package/dist/prepare-units/density.cjs +83 -0
  66. package/dist/prepare-units/density.cjs.map +1 -0
  67. package/dist/prepare-units/density.d.ts +92 -0
  68. package/dist/prepare-units/density.js +83 -0
  69. package/dist/prepare-units/density.js.map +1 -0
  70. package/dist/prepare-units/index.cjs +15 -7
  71. package/dist/prepare-units/index.cjs.map +1 -1
  72. package/dist/prepare-units/index.d.ts +1 -0
  73. package/dist/prepare-units/index.js +15 -7
  74. package/dist/prepare-units/index.js.map +1 -1
  75. package/dist/prepare-units/types.cjs.map +1 -1
  76. package/dist/prepare-units/types.d.ts +34 -13
  77. package/dist/prepare-units/types.js.map +1 -1
  78. package/dist/section.cjs +108 -24
  79. package/dist/section.cjs.map +1 -1
  80. package/dist/section.d.ts +66 -6
  81. package/dist/section.js +109 -25
  82. package/dist/section.js.map +1 -1
  83. package/dist/timescale-zoom.cjs +191 -0
  84. package/dist/timescale-zoom.cjs.map +1 -0
  85. package/dist/timescale-zoom.d.ts +74 -0
  86. package/dist/timescale-zoom.js +191 -0
  87. package/dist/timescale-zoom.js.map +1 -0
  88. package/dist/unit-details/age-range.cjs +1 -0
  89. package/dist/unit-details/age-range.cjs.map +1 -1
  90. package/dist/unit-details/age-range.d.ts +5 -1
  91. package/dist/unit-details/age-range.js +1 -0
  92. package/dist/unit-details/age-range.js.map +1 -1
  93. package/dist/units/composite.cjs +4 -1
  94. package/dist/units/composite.cjs.map +1 -1
  95. package/dist/units/composite.d.ts +2 -0
  96. package/dist/units/composite.js +4 -1
  97. package/dist/units/composite.js.map +1 -1
  98. package/package.json +7 -7
  99. package/src/age-model/data.ts +98 -0
  100. package/src/age-model/details.module.sass +108 -0
  101. package/src/age-model/details.ts +333 -0
  102. package/src/age-model/index.ts +5 -0
  103. package/src/age-model/legacy.ts +30 -0
  104. package/src/age-model/surfaces.module.sass +168 -0
  105. package/src/age-model/surfaces.ts +568 -0
  106. package/src/age-model/types.ts +392 -0
  107. package/src/column.module.sass +59 -8
  108. package/src/column.ts +49 -23
  109. package/src/data-provider/store.ts +50 -1
  110. package/src/index.ts +5 -1
  111. package/src/notes.ts +20 -2
  112. package/src/prepare-units/composite-scale.ts +34 -31
  113. package/src/prepare-units/density.ts +197 -0
  114. package/src/prepare-units/index.ts +25 -6
  115. package/src/prepare-units/types.ts +34 -13
  116. package/src/section.ts +219 -33
  117. package/src/timescale-zoom.ts +341 -0
  118. package/src/unit-details/age-range.ts +3 -3
  119. package/src/units/composite.ts +11 -0
  120. package/dist/age-model-overlay.cjs +0 -50
  121. package/dist/age-model-overlay.cjs.map +0 -1
  122. package/dist/age-model-overlay.d.ts +0 -24
  123. package/dist/age-model-overlay.js +0 -48
  124. package/dist/age-model-overlay.js.map +0 -1
  125. package/dist/age-model-overlay.module.sass.cjs +0 -12
  126. package/dist/age-model-overlay.module.sass.cjs.map +0 -1
  127. package/dist/age-model-overlay.module.sass.js +0 -11
  128. package/dist/age-model-overlay.module.sass.js.map +0 -1
  129. package/src/age-model-overlay.module.sass +0 -11
  130. package/src/age-model-overlay.ts +0 -96
@@ -0,0 +1,83 @@
1
+ import { ColumnAxisType } from "@macrostrat/column-components";
2
+ function unitHeight(px) {
3
+ return (ctx) => px / typicalExtent(ctx.unitExtents);
4
+ }
5
+ function sectionHeight(px) {
6
+ return (ctx) => px / ctx.extent;
7
+ }
8
+ function fixedDensity(px) {
9
+ return () => px;
10
+ }
11
+ function atLeast(...rules) {
12
+ return (ctx) => {
13
+ let density = 0;
14
+ for (const rule of rules) {
15
+ const value = resolveDensity(rule, ctx);
16
+ if (!Number.isFinite(value)) continue;
17
+ density = Math.max(density, value);
18
+ }
19
+ return density;
20
+ };
21
+ }
22
+ function resolveDensity(rule, ctx) {
23
+ if (typeof rule === "number") return rule;
24
+ return rule(ctx);
25
+ }
26
+ function typicalExtent(extents) {
27
+ const sorted = extents.filter((d) => d > 0).sort((a, b) => a - b);
28
+ if (sorted.length === 0) return NaN;
29
+ const mid = (sorted.length - 1) / 2;
30
+ const lower = Math.floor(mid);
31
+ const upper = Math.ceil(mid);
32
+ return (sorted[lower] + sorted[upper]) / 2;
33
+ }
34
+ const DEFAULT_TARGET_UNIT_HEIGHT = 20;
35
+ const DEFAULT_MIN_PIXEL_SCALE = 0.2;
36
+ function sectionDensity(opts) {
37
+ const { sectionOptions } = opts;
38
+ if (sectionOptions == null) {
39
+ const rule = densityRule(opts);
40
+ return (ctx) => rule(ctx);
41
+ }
42
+ return (ctx) => {
43
+ let overrides = sectionOptions;
44
+ if (typeof sectionOptions === "function") overrides = sectionOptions(ctx);
45
+ return densityRule({ ...opts, ...overrides })(ctx);
46
+ };
47
+ }
48
+ function densityRule(opts) {
49
+ const {
50
+ targetUnitHeight = DEFAULT_TARGET_UNIT_HEIGHT,
51
+ minPixelScale = DEFAULT_MIN_PIXEL_SCALE,
52
+ minSectionHeight
53
+ } = opts;
54
+ const derived = atLeast(
55
+ unitHeight(targetUnitHeight),
56
+ fixedDensity(minPixelScale),
57
+ sectionHeight(minSectionHeight ?? targetUnitHeight ?? 0)
58
+ );
59
+ return (ctx) => {
60
+ const stated = statedDensity(opts, ctx.axisType);
61
+ if (typeof stated === "function") return stated(ctx);
62
+ if (stated != null) return stated;
63
+ return derived(ctx);
64
+ };
65
+ }
66
+ function statedDensity(opts, axisType) {
67
+ const { pixelScale, pixelsPerMyr, pixelsPerMeter } = opts;
68
+ if (axisType === ColumnAxisType.AGE) {
69
+ return pixelsPerMyr ?? pixelScale;
70
+ }
71
+ return pixelsPerMeter ?? pixelScale;
72
+ }
73
+ export {
74
+ DEFAULT_TARGET_UNIT_HEIGHT,
75
+ atLeast,
76
+ fixedDensity,
77
+ resolveDensity,
78
+ sectionDensity,
79
+ sectionHeight,
80
+ statedDensity,
81
+ unitHeight
82
+ };
83
+ //# sourceMappingURL=density.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"density.js","sources":["../../src/prepare-units/density.ts"],"sourcesContent":["/** How tall a column draws comes down to one quantity: **density**, the pixels\n * given to one unit of the axis — a Myr on an age column, a metre otherwise.\n *\n * Every option that sets a column's height names that quantity. Most are\n * floors, differing only in the units they're stated in: room for a unit,\n * for a section, or for the density itself. They combine by taking the\n * largest, so each says \"at least this much\", whichever ends up binding.\n */\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport type { UnitLong } from \"@macrostrat/api-types\";\n\nexport interface SectionDensityContext {\n /** The section's extent, in axis units */\n extent: number;\n /** Extents of the units the render window actually shows, each clipped to\n * it. Measuring what's on screen is what makes a unit-height rule mean the\n * same thing at every zoom depth. */\n unitExtents: number[];\n /** The section's units, unclipped, for a rule that needs more than their\n * extents */\n units: UnitLong[];\n sectionID?: number;\n axisType: ColumnAxisType;\n}\n\n/** Pixels per axis unit, for one section */\nexport type SectionDensity = (ctx: SectionDensityContext) => number;\n\nexport type SectionDensityLike = number | SectionDensity;\n\n/** Room for a typical unit on screen: `px` tall, whatever its duration.\n *\n * \"Typical\" is the median of the visible extents, which is the only summary\n * that survives both tails. Unit durations are spread over orders of\n * magnitude: the arithmetic mean sits above any unit you would point at, so a\n * couple of long ones squeeze everything else below the target — and the\n * geometric mean fails the other way, since a single hair-thin unit (a\n * Holocene sliver beside a Pliocene terrace, say) drags the log-average down\n * and stretches the whole section to give that sliver its 20 pixels.\n */\nexport function unitHeight(px: number): SectionDensity {\n return (ctx) => px / typicalExtent(ctx.unitExtents);\n}\n\n/** Room for the section: `px` tall, whatever its extent. */\nexport function sectionHeight(px: number): SectionDensity {\n return (ctx) => px / ctx.extent;\n}\n\n/** A density stated outright, in pixels per axis unit. */\nexport function fixedDensity(px: number): SectionDensity {\n return () => px;\n}\n\n/** The rule that asks for the most room. Rules that don't resolve to a finite\n * number — a section of no extent, a window showing no units — are passed\n * over rather than swallowing the rest. */\nexport function atLeast(...rules: SectionDensityLike[]): SectionDensity {\n return (ctx) => {\n let density = 0;\n for (const rule of rules) {\n const value = resolveDensity(rule, ctx);\n if (!Number.isFinite(value)) continue;\n density = Math.max(density, value);\n }\n return density;\n };\n}\n\nexport function resolveDensity(\n rule: SectionDensityLike,\n ctx: SectionDensityContext,\n): number {\n if (typeof rule === \"number\") return rule;\n return rule(ctx);\n}\n\nfunction typicalExtent(extents: number[]): number {\n const sorted = extents.filter((d) => d > 0).sort((a, b) => a - b);\n if (sorted.length === 0) return NaN;\n const mid = (sorted.length - 1) / 2;\n const lower = Math.floor(mid);\n const upper = Math.ceil(mid);\n return (sorted[lower] + sorted[upper]) / 2;\n}\n\n/** Mirrors the default in `sectionDensity` */\nexport const DEFAULT_TARGET_UNIT_HEIGHT = 20;\n/** Small sections often have a unit or two, and no room for axis labels */\nconst DEFAULT_MIN_PIXEL_SCALE = 0.2;\n\n/** What a section is sized by. Stated for the column as a whole, and again\n * per section by `sectionOptions` where one needs different treatment. */\nexport interface SectionSizeOptions {\n /** A density stated outright, in pixels per axis unit: every section drawn\n * to the same scale whatever it holds. Rarely what you want within one\n * column, and the only way to make several of them comparable.\n *\n * Left out — the usual case — the density comes from the section's own\n * units, via `targetUnitHeight` and the floors. Set, it *is* the density:\n * the floors don't apply, since they would undo the scale you stated.\n *\n * It also takes a rule, for what the options here can't describe.\n *\n * This one is stated in whatever the axis measures, so it means a different\n * thing on an age axis than on a depth one. A view that switches between\n * them wants `pixelsPerMyr` and `pixelsPerMeter` instead. */\n pixelScale?: SectionDensityLike;\n /** Pixels per million years, on an age axis.\n *\n * The axis-specific spellings of `pixelScale`, and what to reach for when\n * the axis can change under you: useful values differ by orders of\n * magnitude between the two, so one number cannot serve both, any more than\n * `t_age` could serve as `t_pos`. Both can be held at once — the axis picks\n * — and either takes precedence over `pixelScale`. */\n pixelsPerMyr?: number;\n /** Pixels per metre, on a depth or height axis. Also the scale for an\n * approximate-height column, whose units are metres of measured thickness\n * however its axis is labeled. */\n pixelsPerMeter?: number;\n /** Room for a typical unit on screen. The knob that usually decides a\n * column, and the one to reach for to draw it larger or smaller. */\n targetUnitHeight?: number;\n /** Room for a section, however little it holds */\n minSectionHeight?: number;\n /** A floor on the density itself */\n minPixelScale?: number;\n}\n\n/** Sizing for one section, or a rule that works it out from what the section\n * holds. What it returns overrides the column-wide options for that section;\n * anything it leaves out keeps the column's value. */\nexport type SectionOptionsLike =\n | SectionSizeOptions\n | ((ctx: SectionDensityContext) => SectionSizeOptions);\n\nexport interface SectionDensityOptions extends SectionSizeOptions {\n /** Sizing decided per section */\n sectionOptions?: SectionOptionsLike;\n}\n\n/** The density rule a column uses, resolved per section so that\n * `sectionOptions` gets to see a section before saying how to draw it. */\nexport function sectionDensity(opts: SectionDensityOptions): SectionDensity {\n const { sectionOptions } = opts;\n if (sectionOptions == null) {\n const rule = densityRule(opts);\n return (ctx) => rule(ctx);\n }\n\n return (ctx) => {\n let overrides = sectionOptions;\n if (typeof sectionOptions === \"function\") overrides = sectionOptions(ctx);\n return densityRule({ ...opts, ...overrides })(ctx);\n };\n}\n\n/** The floors, combined: whichever asks for the most room wins. */\nfunction densityRule(opts: SectionSizeOptions): SectionDensity {\n const {\n targetUnitHeight = DEFAULT_TARGET_UNIT_HEIGHT,\n minPixelScale = DEFAULT_MIN_PIXEL_SCALE,\n minSectionHeight,\n } = opts;\n\n const derived = atLeast(\n unitHeight(targetUnitHeight),\n fixedDensity(minPixelScale),\n sectionHeight(minSectionHeight ?? targetUnitHeight ?? 0),\n );\n\n return (ctx) => {\n // A density given outright answers for the section by itself. The floors\n // exist to keep a column readable when its own contents decide the\n // density; a scale you stated is a decision already made, and a floor\n // would quietly undo it — which is the whole point of stating one,\n // usually so that several columns can be compared.\n const stated = statedDensity(opts, ctx.axisType);\n if (typeof stated === \"function\") return stated(ctx);\n if (stated != null) return stated;\n return derived(ctx);\n };\n}\n\n/** The density this axis was given, if any. The axis-specific spellings win\n * over the generic one, which is what lets both be held while the axis\n * changes. */\nexport function statedDensity(\n opts: SectionSizeOptions,\n axisType: ColumnAxisType,\n): SectionDensityLike | undefined {\n const { pixelScale, pixelsPerMyr, pixelsPerMeter } = opts;\n if (axisType === ColumnAxisType.AGE) {\n return pixelsPerMyr ?? pixelScale;\n }\n return pixelsPerMeter ?? pixelScale;\n}\n"],"names":[],"mappings":";AAwCO,SAAS,WAAW,IAA4B;AACrD,SAAO,CAAC,QAAQ,KAAK,cAAc,IAAI,WAAW;AACpD;AAGO,SAAS,cAAc,IAA4B;AACxD,SAAO,CAAC,QAAQ,KAAK,IAAI;AAC3B;AAGO,SAAS,aAAa,IAA4B;AACvD,SAAO,MAAM;AACf;AAKO,SAAS,WAAW,OAA6C;AACtE,SAAO,CAAC,QAAQ;AACd,QAAI,UAAU;AACd,eAAW,QAAQ,OAAO;AACxB,YAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,UAAI,CAAC,OAAO,SAAS,KAAK,EAAG;AAC7B,gBAAU,KAAK,IAAI,SAAS,KAAK;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eACd,MACA,KACQ;AACR,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,cAAc,SAA2B;AAChD,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAChE,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,OAAO,OAAO,SAAS,KAAK;AAClC,QAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAM,QAAQ,KAAK,KAAK,GAAG;AAC3B,UAAQ,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK;AAC3C;AAGO,MAAM,6BAA6B;AAE1C,MAAM,0BAA0B;AAsDzB,SAAS,eAAe,MAA6C;AAC1E,QAAM,EAAE,mBAAmB;AAC3B,MAAI,kBAAkB,MAAM;AAC1B,UAAM,OAAO,YAAY,IAAI;AAC7B,WAAO,CAAC,QAAQ,KAAK,GAAG;AAAA,EAC1B;AAEA,SAAO,CAAC,QAAQ;AACd,QAAI,YAAY;AAChB,QAAI,OAAO,mBAAmB,WAAY,aAAY,eAAe,GAAG;AACxE,WAAO,YAAY,EAAE,GAAG,MAAM,GAAG,UAAA,CAAW,EAAE,GAAG;AAAA,EACnD;AACF;AAGA,SAAS,YAAY,MAA0C;AAC7D,QAAM;AAAA,IACJ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB;AAAA,EAAA,IACE;AAEJ,QAAM,UAAU;AAAA,IACd,WAAW,gBAAgB;AAAA,IAC3B,aAAa,aAAa;AAAA,IAC1B,cAAc,oBAAoB,oBAAoB,CAAC;AAAA,EAAA;AAGzD,SAAO,CAAC,QAAQ;AAMd,UAAM,SAAS,cAAc,MAAM,IAAI,QAAQ;AAC/C,QAAI,OAAO,WAAW,WAAY,QAAO,OAAO,GAAG;AACnD,QAAI,UAAU,KAAM,QAAO;AAC3B,WAAO,QAAQ,GAAG;AAAA,EACpB;AACF;AAKO,SAAS,cACd,MACA,UACgC;AAChC,QAAM,EAAE,YAAY,cAAc,eAAA,IAAmB;AACrD,MAAI,aAAa,eAAe,KAAK;AACnC,WAAO,gBAAgB;AAAA,EACzB;AACA,SAAO,kBAAkB;AAC3B;"}
@@ -36,12 +36,19 @@ function prepareColumnUnits(units, options) {
36
36
  }
37
37
  const clipBeforeLayout = axisType != columnComponents.ColumnAxisType.AGE || hybridScale != null || scale != null;
38
38
  let units1 = units.map(helpers.preprocessSectionUnit);
39
- if (clipBeforeLayout) {
39
+ const window = {
40
+ t_age: t_age ?? -Infinity,
41
+ b_age: b_age ?? Infinity,
42
+ t_pos: t_pos ?? -Infinity,
43
+ b_pos: b_pos ?? Infinity
44
+ };
45
+ const isWindowed = axisType == columnComponents.ColumnAxisType.AGE ? t_age != null || b_age != null : t_pos != null || b_pos != null;
46
+ if (clipBeforeLayout && isWindowed) {
40
47
  units1 = units1.filter((d) => {
41
48
  if (axisType == columnComponents.ColumnAxisType.AGE) {
42
- return utils.agesOverlap(d, { t_age, b_age });
49
+ return utils.agesOverlap(d, window);
43
50
  } else {
44
- return utils.unitsOverlap(d, { t_pos, b_pos }, axisType);
51
+ return utils.unitsOverlap(d, window, axisType);
45
52
  }
46
53
  });
47
54
  }
@@ -100,10 +107,11 @@ function prepareColumnUnits(units, options) {
100
107
  );
101
108
  }
102
109
  if (focalWindow != null && (t_age != null || b_age != null)) {
103
- const floor = options.minSectionHeight ?? options.targetUnitHeight ?? 0;
110
+ const floor = layoutOptions.minSectionHeight ?? layoutOptions.targetUnitHeight ?? 0;
104
111
  const scales = compositeScale.resolveWindowScales(sectionsWithScales, focalWindow, floor);
105
- const scaleFor = (section) => scales.get(section) ?? section.scaleInfo.pixelScale;
106
- const window = windowPadding > 0 ? compositeScale.padWindowByPixels(
112
+ const natural = (section) => scales.get(section) ?? section.scaleInfo.pixelScale;
113
+ const scaleFor = natural;
114
+ const window2 = windowPadding > 0 ? compositeScale.padWindowByPixels(
107
115
  sectionsWithScales,
108
116
  focalWindow,
109
117
  windowPadding,
@@ -111,7 +119,7 @@ function prepareColumnUnits(units, options) {
111
119
  ) : focalWindow;
112
120
  sectionsWithScales = compositeScale.trimSectionsToWindow(
113
121
  sectionsWithScales,
114
- window,
122
+ window2,
115
123
  scaleFor
116
124
  );
117
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/prepare-units/index.ts"],"sourcesContent":["import {\n getSectionAgeRange,\n getSectionPosRange,\n groupUnitsIntoSectionsByOverlap,\n groupUnitsIntoSectionsBySectionID,\n mergeOverlappingSections,\n preprocessSectionUnit,\n preprocessUnits,\n UnitWithLayoutHints,\n} from \"./helpers\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { useMemo } from \"react\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport {\n collapseUnconformitiesByPixelHeight,\n computeSectionHeights,\n finalizeSectionHeights,\n padWindowByPixels,\n resolveWindowScales,\n trimSectionsToWindow,\n type CompositeColumnScale,\n} from \"./composite-scale\";\nimport {\n agesOverlap,\n MergeSectionsMode,\n PrepareColumnOptions,\n PreparedColumnData,\n unitsOverlap,\n} from \"./utils\";\nimport { SectionInfo } from \"./types\";\n\nexport * from \"./utils\";\nexport * from \"./types\";\nexport { preprocessUnits };\nexport type { CompositeColumnScale };\n\nexport function usePreparedColumnUnits(\n data: UnitLong[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** This function wraps and memoizes all preparation steps for converting\n * an array of units from the /units route to a form ready for usage.\n */\n return useMemo(() => {\n return prepareColumnUnits(data, options);\n }, [data, ...Object.values(options)]);\n}\n\nexport function prepareColumnUnits(\n units: UnitWithLayoutHints<UnitLong>[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** Prepare units for rendering into Macrostrat columns */\n\n let { t_age, b_age, t_pos, b_pos } = options;\n\n const {\n mergeSections = MergeSectionsMode.OVERLAPPING,\n axisType,\n unconformityHeight,\n collapseSmallUnconformities = false,\n hybridScale,\n scale,\n windowPadding = 0,\n } = options;\n\n let _totalHeight: number | null = null;\n\n if (scale != null) {\n // Set t_age and b_age based on scale domain if not already set\n const domain = scale.domain();\n if (axisType == ColumnAxisType.AGE) {\n if (t_age == null) t_age = Math.min(...domain);\n if (b_age == null) b_age = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_age) - scale(t_age));\n } else {\n if (t_pos == null) t_pos = Math.min(...domain);\n if (b_pos == null) b_pos = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_pos) - scale(t_pos));\n }\n }\n\n /** Age columns lay every section out at its full extent and clip to the\n * window at the end (see below), so that a section abutting the window is\n * sized by its own content rather than by the sliver that survives the clip.\n * Hybrid and externally-supplied scales build their own mapping and can't be\n * re-derived that way, so they keep the original clip-then-lay-out path. */\n const clipBeforeLayout =\n axisType != ColumnAxisType.AGE || hybridScale != null || scale != null;\n\n // Start by ensuring that ages and positions are numbers\n // also set up some values for eODP-style columns\n let units1 = units.map(preprocessSectionUnit);\n\n if (clipBeforeLayout) {\n /** Prototype filtering to age range */\n units1 = units1.filter((d) => {\n // Filter units by t_age and b_age, inclusive\n if (axisType == ColumnAxisType.AGE) {\n return agesOverlap(d, { t_age, b_age });\n } else {\n return unitsOverlap(d, { t_pos, b_pos } as any, axisType);\n }\n });\n }\n\n let mergeMode = mergeSections;\n // if (axisType != ColumnAxisType.AGE) {\n // // For non-age columns, we always merge sections.\n // // This is because the \"groupUnitsIntoSections\" function is not well-defined\n // // for non-age columns.\n // mergeMode = MergeSectionsMode.ALL;\n // }\n\n let sections0: SectionInfo<UnitLong>[];\n if (mergeMode == MergeSectionsMode.ALL) {\n // For the \"merge sections\" mode, we need to create a single section\n const [b_unit_pos, t_unit_pos] = getSectionPosRange(units1, axisType);\n const [b_unit_age, t_unit_age] = getSectionAgeRange(units1);\n sections0 = [\n {\n section_id: 0,\n /**\n * If ages limits are directly specified, use them to define the section bounds.\n * */\n t_pos: t_unit_pos,\n b_pos: b_unit_pos,\n t_age: t_unit_age,\n b_age: b_unit_age,\n units: units1,\n },\n ];\n } else if (axisType == ColumnAxisType.AGE) {\n sections0 = groupUnitsIntoSectionsBySectionID(units1, axisType);\n } else {\n sections0 = groupUnitsIntoSectionsByOverlap(units1, axisType);\n }\n\n // Limit sections to the range specified by t_age/b_age or t_pos/b_pos global options\n for (let section of clipBeforeLayout ? sections0 : []) {\n if (axisType == ColumnAxisType.AGE) {\n section.t_age = Math.max(section.t_age, t_age ?? -Infinity);\n section.b_age = Math.min(section.b_age, b_age ?? Infinity);\n } else if (axisType == ColumnAxisType.DEPTH) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n } else if (axisType == ColumnAxisType.HEIGHT) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n }\n }\n\n /** Merging overlapping sections really only makes sense for age/height/depth\n * columns. Ordinal columns are numbered by section so merging them\n * results in collisions.\n */\n let sections = sections0;\n if (\n mergeSections == MergeSectionsMode.OVERLAPPING &&\n axisType == ColumnAxisType.AGE\n ) {\n sections = mergeOverlappingSections(sections);\n }\n // Filter out undefined sections just in case\n sections = sections.filter((d) => d != null);\n\n // SCALES\n\n /** The window we've been asked to render. Unit density is derived from what\n * it shows (see `findAverageUnitHeight`), so it has to be known before any\n * section is laid out — but nothing is *clipped* to it until the very end.\n */\n const focalWindow: [number, number] | null = clipBeforeLayout\n ? null\n : [b_age ?? Infinity, t_age ?? -Infinity];\n\n const layoutOptions = { ...options, visibleWindow: focalWindow };\n\n /* Compute pixel scales etc. for sections\n * We need to do this now to determine which unconformities\n * are small enough to collapse.\n */\n let sectionsWithScales = computeSectionHeights(sections, layoutOptions);\n\n if (collapseSmallUnconformities && hybridScale == null) {\n // Collapse small unconformities in pixel height space\n // TODO: this doesn't seem to work properly for non-age columns?\n let threshold = unconformityHeight ?? 30;\n if (typeof collapseSmallUnconformities == \"number\") {\n threshold = collapseSmallUnconformities;\n }\n\n sectionsWithScales = collapseUnconformitiesByPixelHeight(\n sectionsWithScales,\n threshold,\n layoutOptions,\n );\n }\n\n /** Now that every section is laid out at full extent — with its own density\n * and `minSectionHeight` already settled — apply the rendered window. Padding\n * is spent here, against real pixel heights, so `windowPadding` px of an\n * abutting section is exactly that many pixels.\n */\n if (focalWindow != null && (t_age != null || b_age != null)) {\n // Resolve final densities first (a section the window cuts short is\n // stretched to `minSectionHeight`), then spend the padding budget against\n // them, so a margin is the pixels asked for rather than those pixels times\n // whatever stretch its neighbor happened to need.\n const floor = options.minSectionHeight ?? options.targetUnitHeight ?? 0;\n const scales = resolveWindowScales(sectionsWithScales, focalWindow, floor);\n const scaleFor = (section) =>\n scales.get(section) ?? section.scaleInfo.pixelScale;\n\n const window =\n windowPadding > 0\n ? padWindowByPixels(\n sectionsWithScales,\n focalWindow,\n windowPadding,\n scaleFor,\n )\n : focalWindow;\n\n sectionsWithScales = trimSectionsToWindow(\n sectionsWithScales,\n window,\n scaleFor,\n );\n }\n\n /** Prepare section scale information using groups.\n * Total height is computed from section scales.\n * */\n let { totalHeight, sections: sections2 } = finalizeSectionHeights(\n sectionsWithScales,\n unconformityHeight,\n );\n\n /** For each section, find units that are overlapping.\n * We do this after merging sections so that we can\n * handle cases where there are overlapping units across sections\n * */\n const sectionsOut = sections2.map((section) => {\n return {\n ...section,\n units: preprocessUnits(section, axisType),\n };\n });\n\n /** Reconstitute the units so that they are sorted by section and properly enhanced.\n * This is mostly important so that unit keyboard navigation\n * predictably selects adjacent units.\n */\n const units2 = sectionsOut.reduce((acc, group) => {\n const { units } = group;\n for (const unit of units) {\n acc.push(unit);\n }\n return acc;\n }, []);\n\n return {\n units: units2,\n totalHeight: _totalHeight ?? totalHeight,\n sections: sectionsOut,\n };\n}\n"],"names":["useMemo","MergeSectionsMode","ColumnAxisType","preprocessSectionUnit","agesOverlap","unitsOverlap","getSectionPosRange","getSectionAgeRange","groupUnitsIntoSectionsBySectionID","groupUnitsIntoSectionsByOverlap","mergeOverlappingSections","computeSectionHeights","collapseUnconformitiesByPixelHeight","resolveWindowScales","padWindowByPixels","trimSectionsToWindow","finalizeSectionHeights","preprocessUnits","units"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/prepare-units/index.ts"],"sourcesContent":["import {\n getSectionAgeRange,\n getSectionPosRange,\n groupUnitsIntoSectionsByOverlap,\n groupUnitsIntoSectionsBySectionID,\n mergeOverlappingSections,\n preprocessSectionUnit,\n preprocessUnits,\n UnitWithLayoutHints,\n} from \"./helpers\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { useMemo } from \"react\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport {\n collapseUnconformitiesByPixelHeight,\n computeSectionHeights,\n finalizeSectionHeights,\n padWindowByPixels,\n resolveWindowScales,\n trimSectionsToWindow,\n type CompositeColumnScale,\n} from \"./composite-scale\";\nimport {\n agesOverlap,\n MergeSectionsMode,\n PrepareColumnOptions,\n PreparedColumnData,\n unitsOverlap,\n} from \"./utils\";\nimport { type ColumnHeightScaleOptions, SectionInfo } from \"./types\";\n\nexport * from \"./utils\";\nexport * from \"./types\";\nexport * from \"./density\";\nexport { preprocessUnits };\nexport type { CompositeColumnScale };\n\nexport function usePreparedColumnUnits(\n data: UnitLong[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** This function wraps and memoizes all preparation steps for converting\n * an array of units from the /units route to a form ready for usage.\n */\n return useMemo(() => {\n return prepareColumnUnits(data, options);\n }, [data, ...Object.values(options)]);\n}\n\nexport function prepareColumnUnits(\n units: UnitWithLayoutHints<UnitLong>[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** Prepare units for rendering into Macrostrat columns */\n\n let { t_age, b_age, t_pos, b_pos } = options;\n\n const {\n mergeSections = MergeSectionsMode.OVERLAPPING,\n axisType,\n unconformityHeight,\n collapseSmallUnconformities = false,\n hybridScale,\n scale,\n windowPadding = 0,\n } = options;\n\n let _totalHeight: number | null = null;\n\n if (scale != null) {\n // Set t_age and b_age based on scale domain if not already set\n const domain = scale.domain();\n if (axisType == ColumnAxisType.AGE) {\n if (t_age == null) t_age = Math.min(...domain);\n if (b_age == null) b_age = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_age) - scale(t_age));\n } else {\n if (t_pos == null) t_pos = Math.min(...domain);\n if (b_pos == null) b_pos = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_pos) - scale(t_pos));\n }\n }\n\n /** Age columns lay every section out at its full extent and clip to the\n * window at the end (see below), so that a section abutting the window is\n * sized by its own content rather than by the sliver that survives the clip.\n * Hybrid and externally-supplied scales build their own mapping and can't be\n * re-derived that way, so they keep the original clip-then-lay-out path. */\n const clipBeforeLayout =\n axisType != ColumnAxisType.AGE || hybridScale != null || scale != null;\n\n // Start by ensuring that ages and positions are numbers\n // also set up some values for eODP-style columns\n let units1 = units.map(preprocessSectionUnit);\n\n /** A bound that isn't set doesn't bound anything. Passing `null` for one is\n * the ordinary way to say \"no window\", and comparing against it as though\n * it were an age would throw every unit out. */\n const window = {\n t_age: t_age ?? -Infinity,\n b_age: b_age ?? Infinity,\n t_pos: t_pos ?? -Infinity,\n b_pos: b_pos ?? Infinity,\n };\n const isWindowed =\n axisType == ColumnAxisType.AGE\n ? t_age != null || b_age != null\n : t_pos != null || b_pos != null;\n\n if (clipBeforeLayout && isWindowed) {\n /** Prototype filtering to age range */\n units1 = units1.filter((d) => {\n // Filter units by t_age and b_age, inclusive\n if (axisType == ColumnAxisType.AGE) {\n return agesOverlap(d, window);\n } else {\n return unitsOverlap(d, window as any, axisType);\n }\n });\n }\n\n let mergeMode = mergeSections;\n // if (axisType != ColumnAxisType.AGE) {\n // // For non-age columns, we always merge sections.\n // // This is because the \"groupUnitsIntoSections\" function is not well-defined\n // // for non-age columns.\n // mergeMode = MergeSectionsMode.ALL;\n // }\n\n let sections0: SectionInfo<UnitLong>[];\n if (mergeMode == MergeSectionsMode.ALL) {\n // For the \"merge sections\" mode, we need to create a single section\n const [b_unit_pos, t_unit_pos] = getSectionPosRange(units1, axisType);\n const [b_unit_age, t_unit_age] = getSectionAgeRange(units1);\n sections0 = [\n {\n section_id: 0,\n /**\n * If ages limits are directly specified, use them to define the section bounds.\n * */\n t_pos: t_unit_pos,\n b_pos: b_unit_pos,\n t_age: t_unit_age,\n b_age: b_unit_age,\n units: units1,\n },\n ];\n } else if (axisType == ColumnAxisType.AGE) {\n sections0 = groupUnitsIntoSectionsBySectionID(units1, axisType);\n } else {\n sections0 = groupUnitsIntoSectionsByOverlap(units1, axisType);\n }\n\n // Limit sections to the range specified by t_age/b_age or t_pos/b_pos global options\n for (let section of clipBeforeLayout ? sections0 : []) {\n if (axisType == ColumnAxisType.AGE) {\n section.t_age = Math.max(section.t_age, t_age ?? -Infinity);\n section.b_age = Math.min(section.b_age, b_age ?? Infinity);\n } else if (axisType == ColumnAxisType.DEPTH) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n } else if (axisType == ColumnAxisType.HEIGHT) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n }\n }\n\n /** Merging overlapping sections really only makes sense for age/height/depth\n * columns. Ordinal columns are numbered by section so merging them\n * results in collisions.\n */\n let sections = sections0;\n if (\n mergeSections == MergeSectionsMode.OVERLAPPING &&\n axisType == ColumnAxisType.AGE\n ) {\n sections = mergeOverlappingSections(sections);\n }\n // Filter out undefined sections just in case\n sections = sections.filter((d) => d != null);\n\n // SCALES\n\n /** The window we've been asked to render. Unit density is derived from what\n * it shows (see `findAverageUnitHeight`), so it has to be known before any\n * section is laid out — but nothing is *clipped* to it until the very end.\n */\n const focalWindow: [number, number] | null = clipBeforeLayout\n ? null\n : [b_age ?? Infinity, t_age ?? -Infinity];\n\n const layoutOptions = { ...options, visibleWindow: focalWindow };\n\n /* Compute pixel scales etc. for sections\n * We need to do this now to determine which unconformities\n * are small enough to collapse.\n */\n let sectionsWithScales = computeSectionHeights(sections, layoutOptions);\n\n if (collapseSmallUnconformities && hybridScale == null) {\n // Collapse small unconformities in pixel height space\n // TODO: this doesn't seem to work properly for non-age columns?\n let threshold = unconformityHeight ?? 30;\n if (typeof collapseSmallUnconformities == \"number\") {\n threshold = collapseSmallUnconformities;\n }\n\n sectionsWithScales = collapseUnconformitiesByPixelHeight(\n sectionsWithScales,\n threshold,\n layoutOptions,\n );\n }\n\n /** Now that every section is laid out at full extent — with its own density\n * and `minSectionHeight` already settled — apply the rendered window. Padding\n * is spent here, against real pixel heights, so `windowPadding` px of an\n * abutting section is exactly that many pixels.\n */\n if (focalWindow != null && (t_age != null || b_age != null)) {\n // Resolve final densities first (a section the window cuts short is\n // stretched to `minSectionHeight`), then spend the padding budget against\n // them, so a margin is the pixels asked for rather than those pixels times\n // whatever stretch its neighbor happened to need.\n const floor =\n layoutOptions.minSectionHeight ?? layoutOptions.targetUnitHeight ?? 0;\n const scales = resolveWindowScales(sectionsWithScales, focalWindow, floor);\n const natural = (section) =>\n scales.get(section) ?? section.scaleInfo.pixelScale;\n\n\n const scaleFor = natural;\n\n const window =\n windowPadding > 0\n ? padWindowByPixels(\n sectionsWithScales,\n focalWindow,\n windowPadding,\n scaleFor,\n )\n : focalWindow;\n\n sectionsWithScales = trimSectionsToWindow(\n sectionsWithScales,\n window,\n scaleFor,\n );\n }\n\n /** Prepare section scale information using groups.\n * Total height is computed from section scales.\n * */\n let { totalHeight, sections: sections2 } = finalizeSectionHeights(\n sectionsWithScales,\n unconformityHeight,\n );\n\n /** For each section, find units that are overlapping.\n * We do this after merging sections so that we can\n * handle cases where there are overlapping units across sections\n * */\n const sectionsOut = sections2.map((section) => {\n return {\n ...section,\n units: preprocessUnits(section, axisType),\n };\n });\n\n /** Reconstitute the units so that they are sorted by section and properly enhanced.\n * This is mostly important so that unit keyboard navigation\n * predictably selects adjacent units.\n */\n const units2 = sectionsOut.reduce((acc, group) => {\n const { units } = group;\n for (const unit of units) {\n acc.push(unit);\n }\n return acc;\n }, []);\n\n return {\n units: units2,\n totalHeight: _totalHeight ?? totalHeight,\n sections: sectionsOut,\n };\n}\n"],"names":["useMemo","MergeSectionsMode","ColumnAxisType","preprocessSectionUnit","agesOverlap","unitsOverlap","getSectionPosRange","getSectionAgeRange","groupUnitsIntoSectionsBySectionID","groupUnitsIntoSectionsByOverlap","mergeOverlappingSections","computeSectionHeights","collapseUnconformitiesByPixelHeight","resolveWindowScales","window","padWindowByPixels","trimSectionsToWindow","finalizeSectionHeights","preprocessUnits","units"],"mappings":"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"}
@@ -4,6 +4,7 @@ import { CompositeColumnScale } from './composite-scale';
4
4
  import { PrepareColumnOptions, PreparedColumnData } from './utils';
5
5
  export * from './utils';
6
6
  export * from './types';
7
+ export * from './density';
7
8
  export { preprocessUnits };
8
9
  export type { CompositeColumnScale };
9
10
  export declare function usePreparedColumnUnits(data: UnitLong[], options: PrepareColumnOptions): PreparedColumnData;
@@ -35,12 +35,19 @@ function prepareColumnUnits(units, options) {
35
35
  }
36
36
  const clipBeforeLayout = axisType != ColumnAxisType.AGE || hybridScale != null || scale != null;
37
37
  let units1 = units.map(preprocessSectionUnit);
38
- if (clipBeforeLayout) {
38
+ const window = {
39
+ t_age: t_age ?? -Infinity,
40
+ b_age: b_age ?? Infinity,
41
+ t_pos: t_pos ?? -Infinity,
42
+ b_pos: b_pos ?? Infinity
43
+ };
44
+ const isWindowed = axisType == ColumnAxisType.AGE ? t_age != null || b_age != null : t_pos != null || b_pos != null;
45
+ if (clipBeforeLayout && isWindowed) {
39
46
  units1 = units1.filter((d) => {
40
47
  if (axisType == ColumnAxisType.AGE) {
41
- return agesOverlap(d, { t_age, b_age });
48
+ return agesOverlap(d, window);
42
49
  } else {
43
- return unitsOverlap(d, { t_pos, b_pos }, axisType);
50
+ return unitsOverlap(d, window, axisType);
44
51
  }
45
52
  });
46
53
  }
@@ -99,10 +106,11 @@ function prepareColumnUnits(units, options) {
99
106
  );
100
107
  }
101
108
  if (focalWindow != null && (t_age != null || b_age != null)) {
102
- const floor = options.minSectionHeight ?? options.targetUnitHeight ?? 0;
109
+ const floor = layoutOptions.minSectionHeight ?? layoutOptions.targetUnitHeight ?? 0;
103
110
  const scales = resolveWindowScales(sectionsWithScales, focalWindow, floor);
104
- const scaleFor = (section) => scales.get(section) ?? section.scaleInfo.pixelScale;
105
- const window = windowPadding > 0 ? padWindowByPixels(
111
+ const natural = (section) => scales.get(section) ?? section.scaleInfo.pixelScale;
112
+ const scaleFor = natural;
113
+ const window2 = windowPadding > 0 ? padWindowByPixels(
106
114
  sectionsWithScales,
107
115
  focalWindow,
108
116
  windowPadding,
@@ -110,7 +118,7 @@ function prepareColumnUnits(units, options) {
110
118
  ) : focalWindow;
111
119
  sectionsWithScales = trimSectionsToWindow(
112
120
  sectionsWithScales,
113
- window,
121
+ window2,
114
122
  scaleFor
115
123
  );
116
124
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/prepare-units/index.ts"],"sourcesContent":["import {\n getSectionAgeRange,\n getSectionPosRange,\n groupUnitsIntoSectionsByOverlap,\n groupUnitsIntoSectionsBySectionID,\n mergeOverlappingSections,\n preprocessSectionUnit,\n preprocessUnits,\n UnitWithLayoutHints,\n} from \"./helpers\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { useMemo } from \"react\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport {\n collapseUnconformitiesByPixelHeight,\n computeSectionHeights,\n finalizeSectionHeights,\n padWindowByPixels,\n resolveWindowScales,\n trimSectionsToWindow,\n type CompositeColumnScale,\n} from \"./composite-scale\";\nimport {\n agesOverlap,\n MergeSectionsMode,\n PrepareColumnOptions,\n PreparedColumnData,\n unitsOverlap,\n} from \"./utils\";\nimport { SectionInfo } from \"./types\";\n\nexport * from \"./utils\";\nexport * from \"./types\";\nexport { preprocessUnits };\nexport type { CompositeColumnScale };\n\nexport function usePreparedColumnUnits(\n data: UnitLong[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** This function wraps and memoizes all preparation steps for converting\n * an array of units from the /units route to a form ready for usage.\n */\n return useMemo(() => {\n return prepareColumnUnits(data, options);\n }, [data, ...Object.values(options)]);\n}\n\nexport function prepareColumnUnits(\n units: UnitWithLayoutHints<UnitLong>[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** Prepare units for rendering into Macrostrat columns */\n\n let { t_age, b_age, t_pos, b_pos } = options;\n\n const {\n mergeSections = MergeSectionsMode.OVERLAPPING,\n axisType,\n unconformityHeight,\n collapseSmallUnconformities = false,\n hybridScale,\n scale,\n windowPadding = 0,\n } = options;\n\n let _totalHeight: number | null = null;\n\n if (scale != null) {\n // Set t_age and b_age based on scale domain if not already set\n const domain = scale.domain();\n if (axisType == ColumnAxisType.AGE) {\n if (t_age == null) t_age = Math.min(...domain);\n if (b_age == null) b_age = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_age) - scale(t_age));\n } else {\n if (t_pos == null) t_pos = Math.min(...domain);\n if (b_pos == null) b_pos = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_pos) - scale(t_pos));\n }\n }\n\n /** Age columns lay every section out at its full extent and clip to the\n * window at the end (see below), so that a section abutting the window is\n * sized by its own content rather than by the sliver that survives the clip.\n * Hybrid and externally-supplied scales build their own mapping and can't be\n * re-derived that way, so they keep the original clip-then-lay-out path. */\n const clipBeforeLayout =\n axisType != ColumnAxisType.AGE || hybridScale != null || scale != null;\n\n // Start by ensuring that ages and positions are numbers\n // also set up some values for eODP-style columns\n let units1 = units.map(preprocessSectionUnit);\n\n if (clipBeforeLayout) {\n /** Prototype filtering to age range */\n units1 = units1.filter((d) => {\n // Filter units by t_age and b_age, inclusive\n if (axisType == ColumnAxisType.AGE) {\n return agesOverlap(d, { t_age, b_age });\n } else {\n return unitsOverlap(d, { t_pos, b_pos } as any, axisType);\n }\n });\n }\n\n let mergeMode = mergeSections;\n // if (axisType != ColumnAxisType.AGE) {\n // // For non-age columns, we always merge sections.\n // // This is because the \"groupUnitsIntoSections\" function is not well-defined\n // // for non-age columns.\n // mergeMode = MergeSectionsMode.ALL;\n // }\n\n let sections0: SectionInfo<UnitLong>[];\n if (mergeMode == MergeSectionsMode.ALL) {\n // For the \"merge sections\" mode, we need to create a single section\n const [b_unit_pos, t_unit_pos] = getSectionPosRange(units1, axisType);\n const [b_unit_age, t_unit_age] = getSectionAgeRange(units1);\n sections0 = [\n {\n section_id: 0,\n /**\n * If ages limits are directly specified, use them to define the section bounds.\n * */\n t_pos: t_unit_pos,\n b_pos: b_unit_pos,\n t_age: t_unit_age,\n b_age: b_unit_age,\n units: units1,\n },\n ];\n } else if (axisType == ColumnAxisType.AGE) {\n sections0 = groupUnitsIntoSectionsBySectionID(units1, axisType);\n } else {\n sections0 = groupUnitsIntoSectionsByOverlap(units1, axisType);\n }\n\n // Limit sections to the range specified by t_age/b_age or t_pos/b_pos global options\n for (let section of clipBeforeLayout ? sections0 : []) {\n if (axisType == ColumnAxisType.AGE) {\n section.t_age = Math.max(section.t_age, t_age ?? -Infinity);\n section.b_age = Math.min(section.b_age, b_age ?? Infinity);\n } else if (axisType == ColumnAxisType.DEPTH) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n } else if (axisType == ColumnAxisType.HEIGHT) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n }\n }\n\n /** Merging overlapping sections really only makes sense for age/height/depth\n * columns. Ordinal columns are numbered by section so merging them\n * results in collisions.\n */\n let sections = sections0;\n if (\n mergeSections == MergeSectionsMode.OVERLAPPING &&\n axisType == ColumnAxisType.AGE\n ) {\n sections = mergeOverlappingSections(sections);\n }\n // Filter out undefined sections just in case\n sections = sections.filter((d) => d != null);\n\n // SCALES\n\n /** The window we've been asked to render. Unit density is derived from what\n * it shows (see `findAverageUnitHeight`), so it has to be known before any\n * section is laid out — but nothing is *clipped* to it until the very end.\n */\n const focalWindow: [number, number] | null = clipBeforeLayout\n ? null\n : [b_age ?? Infinity, t_age ?? -Infinity];\n\n const layoutOptions = { ...options, visibleWindow: focalWindow };\n\n /* Compute pixel scales etc. for sections\n * We need to do this now to determine which unconformities\n * are small enough to collapse.\n */\n let sectionsWithScales = computeSectionHeights(sections, layoutOptions);\n\n if (collapseSmallUnconformities && hybridScale == null) {\n // Collapse small unconformities in pixel height space\n // TODO: this doesn't seem to work properly for non-age columns?\n let threshold = unconformityHeight ?? 30;\n if (typeof collapseSmallUnconformities == \"number\") {\n threshold = collapseSmallUnconformities;\n }\n\n sectionsWithScales = collapseUnconformitiesByPixelHeight(\n sectionsWithScales,\n threshold,\n layoutOptions,\n );\n }\n\n /** Now that every section is laid out at full extent — with its own density\n * and `minSectionHeight` already settled — apply the rendered window. Padding\n * is spent here, against real pixel heights, so `windowPadding` px of an\n * abutting section is exactly that many pixels.\n */\n if (focalWindow != null && (t_age != null || b_age != null)) {\n // Resolve final densities first (a section the window cuts short is\n // stretched to `minSectionHeight`), then spend the padding budget against\n // them, so a margin is the pixels asked for rather than those pixels times\n // whatever stretch its neighbor happened to need.\n const floor = options.minSectionHeight ?? options.targetUnitHeight ?? 0;\n const scales = resolveWindowScales(sectionsWithScales, focalWindow, floor);\n const scaleFor = (section) =>\n scales.get(section) ?? section.scaleInfo.pixelScale;\n\n const window =\n windowPadding > 0\n ? padWindowByPixels(\n sectionsWithScales,\n focalWindow,\n windowPadding,\n scaleFor,\n )\n : focalWindow;\n\n sectionsWithScales = trimSectionsToWindow(\n sectionsWithScales,\n window,\n scaleFor,\n );\n }\n\n /** Prepare section scale information using groups.\n * Total height is computed from section scales.\n * */\n let { totalHeight, sections: sections2 } = finalizeSectionHeights(\n sectionsWithScales,\n unconformityHeight,\n );\n\n /** For each section, find units that are overlapping.\n * We do this after merging sections so that we can\n * handle cases where there are overlapping units across sections\n * */\n const sectionsOut = sections2.map((section) => {\n return {\n ...section,\n units: preprocessUnits(section, axisType),\n };\n });\n\n /** Reconstitute the units so that they are sorted by section and properly enhanced.\n * This is mostly important so that unit keyboard navigation\n * predictably selects adjacent units.\n */\n const units2 = sectionsOut.reduce((acc, group) => {\n const { units } = group;\n for (const unit of units) {\n acc.push(unit);\n }\n return acc;\n }, []);\n\n return {\n units: units2,\n totalHeight: _totalHeight ?? totalHeight,\n sections: sectionsOut,\n };\n}\n"],"names":["units"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/prepare-units/index.ts"],"sourcesContent":["import {\n getSectionAgeRange,\n getSectionPosRange,\n groupUnitsIntoSectionsByOverlap,\n groupUnitsIntoSectionsBySectionID,\n mergeOverlappingSections,\n preprocessSectionUnit,\n preprocessUnits,\n UnitWithLayoutHints,\n} from \"./helpers\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { useMemo } from \"react\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport {\n collapseUnconformitiesByPixelHeight,\n computeSectionHeights,\n finalizeSectionHeights,\n padWindowByPixels,\n resolveWindowScales,\n trimSectionsToWindow,\n type CompositeColumnScale,\n} from \"./composite-scale\";\nimport {\n agesOverlap,\n MergeSectionsMode,\n PrepareColumnOptions,\n PreparedColumnData,\n unitsOverlap,\n} from \"./utils\";\nimport { type ColumnHeightScaleOptions, SectionInfo } from \"./types\";\n\nexport * from \"./utils\";\nexport * from \"./types\";\nexport * from \"./density\";\nexport { preprocessUnits };\nexport type { CompositeColumnScale };\n\nexport function usePreparedColumnUnits(\n data: UnitLong[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** This function wraps and memoizes all preparation steps for converting\n * an array of units from the /units route to a form ready for usage.\n */\n return useMemo(() => {\n return prepareColumnUnits(data, options);\n }, [data, ...Object.values(options)]);\n}\n\nexport function prepareColumnUnits(\n units: UnitWithLayoutHints<UnitLong>[],\n options: PrepareColumnOptions,\n): PreparedColumnData {\n /** Prepare units for rendering into Macrostrat columns */\n\n let { t_age, b_age, t_pos, b_pos } = options;\n\n const {\n mergeSections = MergeSectionsMode.OVERLAPPING,\n axisType,\n unconformityHeight,\n collapseSmallUnconformities = false,\n hybridScale,\n scale,\n windowPadding = 0,\n } = options;\n\n let _totalHeight: number | null = null;\n\n if (scale != null) {\n // Set t_age and b_age based on scale domain if not already set\n const domain = scale.domain();\n if (axisType == ColumnAxisType.AGE) {\n if (t_age == null) t_age = Math.min(...domain);\n if (b_age == null) b_age = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_age) - scale(t_age));\n } else {\n if (t_pos == null) t_pos = Math.min(...domain);\n if (b_pos == null) b_pos = Math.max(...domain);\n _totalHeight = Math.abs(scale(b_pos) - scale(t_pos));\n }\n }\n\n /** Age columns lay every section out at its full extent and clip to the\n * window at the end (see below), so that a section abutting the window is\n * sized by its own content rather than by the sliver that survives the clip.\n * Hybrid and externally-supplied scales build their own mapping and can't be\n * re-derived that way, so they keep the original clip-then-lay-out path. */\n const clipBeforeLayout =\n axisType != ColumnAxisType.AGE || hybridScale != null || scale != null;\n\n // Start by ensuring that ages and positions are numbers\n // also set up some values for eODP-style columns\n let units1 = units.map(preprocessSectionUnit);\n\n /** A bound that isn't set doesn't bound anything. Passing `null` for one is\n * the ordinary way to say \"no window\", and comparing against it as though\n * it were an age would throw every unit out. */\n const window = {\n t_age: t_age ?? -Infinity,\n b_age: b_age ?? Infinity,\n t_pos: t_pos ?? -Infinity,\n b_pos: b_pos ?? Infinity,\n };\n const isWindowed =\n axisType == ColumnAxisType.AGE\n ? t_age != null || b_age != null\n : t_pos != null || b_pos != null;\n\n if (clipBeforeLayout && isWindowed) {\n /** Prototype filtering to age range */\n units1 = units1.filter((d) => {\n // Filter units by t_age and b_age, inclusive\n if (axisType == ColumnAxisType.AGE) {\n return agesOverlap(d, window);\n } else {\n return unitsOverlap(d, window as any, axisType);\n }\n });\n }\n\n let mergeMode = mergeSections;\n // if (axisType != ColumnAxisType.AGE) {\n // // For non-age columns, we always merge sections.\n // // This is because the \"groupUnitsIntoSections\" function is not well-defined\n // // for non-age columns.\n // mergeMode = MergeSectionsMode.ALL;\n // }\n\n let sections0: SectionInfo<UnitLong>[];\n if (mergeMode == MergeSectionsMode.ALL) {\n // For the \"merge sections\" mode, we need to create a single section\n const [b_unit_pos, t_unit_pos] = getSectionPosRange(units1, axisType);\n const [b_unit_age, t_unit_age] = getSectionAgeRange(units1);\n sections0 = [\n {\n section_id: 0,\n /**\n * If ages limits are directly specified, use them to define the section bounds.\n * */\n t_pos: t_unit_pos,\n b_pos: b_unit_pos,\n t_age: t_unit_age,\n b_age: b_unit_age,\n units: units1,\n },\n ];\n } else if (axisType == ColumnAxisType.AGE) {\n sections0 = groupUnitsIntoSectionsBySectionID(units1, axisType);\n } else {\n sections0 = groupUnitsIntoSectionsByOverlap(units1, axisType);\n }\n\n // Limit sections to the range specified by t_age/b_age or t_pos/b_pos global options\n for (let section of clipBeforeLayout ? sections0 : []) {\n if (axisType == ColumnAxisType.AGE) {\n section.t_age = Math.max(section.t_age, t_age ?? -Infinity);\n section.b_age = Math.min(section.b_age, b_age ?? Infinity);\n } else if (axisType == ColumnAxisType.DEPTH) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n } else if (axisType == ColumnAxisType.HEIGHT) {\n section.t_pos = Math.max(section.t_pos, t_pos ?? -Infinity);\n section.b_pos = Math.min(section.b_pos, b_pos ?? Infinity);\n }\n }\n\n /** Merging overlapping sections really only makes sense for age/height/depth\n * columns. Ordinal columns are numbered by section so merging them\n * results in collisions.\n */\n let sections = sections0;\n if (\n mergeSections == MergeSectionsMode.OVERLAPPING &&\n axisType == ColumnAxisType.AGE\n ) {\n sections = mergeOverlappingSections(sections);\n }\n // Filter out undefined sections just in case\n sections = sections.filter((d) => d != null);\n\n // SCALES\n\n /** The window we've been asked to render. Unit density is derived from what\n * it shows (see `findAverageUnitHeight`), so it has to be known before any\n * section is laid out — but nothing is *clipped* to it until the very end.\n */\n const focalWindow: [number, number] | null = clipBeforeLayout\n ? null\n : [b_age ?? Infinity, t_age ?? -Infinity];\n\n const layoutOptions = { ...options, visibleWindow: focalWindow };\n\n /* Compute pixel scales etc. for sections\n * We need to do this now to determine which unconformities\n * are small enough to collapse.\n */\n let sectionsWithScales = computeSectionHeights(sections, layoutOptions);\n\n if (collapseSmallUnconformities && hybridScale == null) {\n // Collapse small unconformities in pixel height space\n // TODO: this doesn't seem to work properly for non-age columns?\n let threshold = unconformityHeight ?? 30;\n if (typeof collapseSmallUnconformities == \"number\") {\n threshold = collapseSmallUnconformities;\n }\n\n sectionsWithScales = collapseUnconformitiesByPixelHeight(\n sectionsWithScales,\n threshold,\n layoutOptions,\n );\n }\n\n /** Now that every section is laid out at full extent — with its own density\n * and `minSectionHeight` already settled — apply the rendered window. Padding\n * is spent here, against real pixel heights, so `windowPadding` px of an\n * abutting section is exactly that many pixels.\n */\n if (focalWindow != null && (t_age != null || b_age != null)) {\n // Resolve final densities first (a section the window cuts short is\n // stretched to `minSectionHeight`), then spend the padding budget against\n // them, so a margin is the pixels asked for rather than those pixels times\n // whatever stretch its neighbor happened to need.\n const floor =\n layoutOptions.minSectionHeight ?? layoutOptions.targetUnitHeight ?? 0;\n const scales = resolveWindowScales(sectionsWithScales, focalWindow, floor);\n const natural = (section) =>\n scales.get(section) ?? section.scaleInfo.pixelScale;\n\n\n const scaleFor = natural;\n\n const window =\n windowPadding > 0\n ? padWindowByPixels(\n sectionsWithScales,\n focalWindow,\n windowPadding,\n scaleFor,\n )\n : focalWindow;\n\n sectionsWithScales = trimSectionsToWindow(\n sectionsWithScales,\n window,\n scaleFor,\n );\n }\n\n /** Prepare section scale information using groups.\n * Total height is computed from section scales.\n * */\n let { totalHeight, sections: sections2 } = finalizeSectionHeights(\n sectionsWithScales,\n unconformityHeight,\n );\n\n /** For each section, find units that are overlapping.\n * We do this after merging sections so that we can\n * handle cases where there are overlapping units across sections\n * */\n const sectionsOut = sections2.map((section) => {\n return {\n ...section,\n units: preprocessUnits(section, axisType),\n };\n });\n\n /** Reconstitute the units so that they are sorted by section and properly enhanced.\n * This is mostly important so that unit keyboard navigation\n * predictably selects adjacent units.\n */\n const units2 = sectionsOut.reduce((acc, group) => {\n const { units } = group;\n for (const unit of units) {\n acc.push(unit);\n }\n return acc;\n }, []);\n\n return {\n units: units2,\n totalHeight: _totalHeight ?? totalHeight,\n sections: sectionsOut,\n };\n}\n"],"names":["window","units"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sources":["../../src/prepare-units/types.ts"],"sourcesContent":["import type { UnitLong } from \"@macrostrat/api-types\";\nimport type { ColumnAxisType } from \"@macrostrat/column-components\";\nimport type { ScaleContinuousNumeric } from \"d3-scale\";\n\nexport interface ColumnHeightScaleOptions {\n /** A fixed pixel scale to use for the section (pixels per Myr) */\n pixelScale?: number;\n /** The target height of a constituent unit in pixels, for dynamic\n * scale generation */\n targetUnitHeight?: number;\n /** Min height of a section in pixels. Will override minPixelScale in some cases. */\n minSectionHeight?: number;\n /** The minimum pixel scale to use for the section (pixels per Myr). This is mostly\n * needed because small sections (<1-2 units) don't necessarily have space to comfortably\n * render two axis labels */\n minPixelScale?: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n /** Padding around the `t_age`/`b_age` window, in **pixels** of neighboring\n * column: how much of the abutting sections to reveal past the window.\n *\n * Resolved after every section is laid out at full extent, so it's exact —\n * each section's own density and each crossed unconformity's fixed height are\n * spent from the pixel budget. Padding collapses where the column runs out.\n * Ignored for hybrid or externally-supplied scales. */\n windowPadding?: number;\n // Axis scale type\n axisType?: ColumnAxisType;\n // Unconformity height in pixels\n unconformityHeight?: number;\n // Whether to collapse unconformities that are less than a height threshold\n collapseSmallUnconformities?: boolean | number;\n // A continuous scale to use instead of generating one\n // TODO: discontinuous scales are not yet supported\n scale?: ScaleContinuousNumeric<number, number>;\n // Hybrid scale type.\n // This overrides parameters such as the axis type\n hybridScale?: HybridScaleDefinition;\n}\n\nexport enum HybridScaleType {\n // An age-domain scale that puts equal vertical space between surfaces\n EquidistantSurfaces = \"equidistant-surfaces\",\n // A height-domain scale that is based on the average height of units between surfaces\n ApproximateHeight = \"approximate-height\",\n}\n\nexport enum HeightMethod {\n Minimum = \"minimum\",\n Average = \"average\",\n Maximum = \"maximum\",\n}\n\nexport interface HybridScaleOptions {\n pixelOffset?: number;\n pixelScale?: number;\n}\n\nexport type ApproxHeightScaleOptions = {\n minHeight?: number;\n defaultHeight?: number;\n heightMethod?: HeightMethod;\n};\n\nexport type HybridScaleDefinition =\n | ({\n type: HybridScaleType.ApproximateHeight;\n } & ApproxHeightScaleOptions)\n | {\n type: HybridScaleType.EquidistantSurfaces;\n };\n\nexport interface SectionScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n domain: [number, number];\n}\n\n/** Output of a section scale. For now, this assumes that the\n * mapping is linear, but it could be extended to support arbitrary\n * scale functions.\n */\nexport interface PackageScaleInfo {\n domain: [number, number];\n pixelHeight: number;\n // TODO: add a function\n scale: ScaleContinuousNumeric<number, number>;\n pixelScale?: number; // if it's a linear scale, this could be defined\n // Subsidiary scale for height mapping (for hybrid scales)\n heightScale?: ScaleContinuousNumeric<number, number>;\n}\n\nexport type PackageScaleLayoutData = PackageScaleInfo & {\n // A unique key for the section to use in React\n key: string;\n offset: number;\n // How much to\n paddingTop: number;\n};\nexport interface StratigraphicPackage {\n /** A collection of stratigraphic information organized in time, corresponding\n * to single or multiple columns. */\n t_age: number;\n b_age: number;\n}\n\nexport interface SectionInfo<\n T extends UnitLong = ExtUnit,\n> extends StratigraphicPackage {\n /** A time-bounded part of a single stratigraphic column. */\n section_id: number | number[];\n units: T[];\n b_pos?: number;\n t_pos?: number;\n}\n\nexport interface ExtUnit extends UnitLong {\n bottomOverlap: boolean;\n overlappingUnits: number[];\n column?: number;\n /* Positions (ages or heights) where the unit is clipped to its containing section.\n * This is relevant if we are filtering by age/height/depth range.\n */\n t_clip_pos?: number;\n b_clip_pos?: number;\n}\n\nexport type PackageLayoutData<T extends UnitLong = ExtUnit> = SectionInfo<T> & {\n scaleInfo: PackageScaleLayoutData;\n // A unique key for the section to use in React\n key: string;\n};\n\nexport interface CompositeScaleData {\n totalHeight: number;\n sections: PackageScaleLayoutData[];\n}\n\nexport interface ColumnScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n unconformityHeight: number;\n}\n\nexport interface CompositeColumnData<T extends UnitLong = ExtUnit> extends Omit<\n CompositeScaleData,\n \"sections\"\n> {\n sections: PackageLayoutData<T>[];\n}\n"],"names":["HybridScaleType","HeightMethod"],"mappings":";;AA2CO,IAAK,oCAAAA,qBAAL;AAELA,mBAAA,qBAAA,IAAsB;AAEtBA,mBAAA,mBAAA,IAAoB;AAJV,SAAAA;AAAA,GAAA,mBAAA,CAAA,CAAA;AAOL,IAAK,iCAAAC,kBAAL;AACLA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;;;"}
1
+ {"version":3,"file":"types.cjs","sources":["../../src/prepare-units/types.ts"],"sourcesContent":["import type { UnitLong } from \"@macrostrat/api-types\";\nimport type { ColumnAxisType } from \"@macrostrat/column-components\";\nimport type { ScaleContinuousNumeric } from \"d3-scale\";\nimport type { SectionDensityLike, SectionOptionsLike } from \"./density\";\n\nexport interface ColumnHeightScaleOptions {\n /** A density stated outright: pixels per Myr on an age column, per metre\n * otherwise, every section drawn to the same scale whatever it holds.\n * Rarely what you want within one column, and the only way to make several\n * of them comparable.\n *\n * It also takes a rule — a function of the section's context — for the\n * cases the options here can't describe. A rule is in sole charge of its\n * section: the floors don't apply to it. */\n pixelScale?: SectionDensityLike;\n /** Room for a typical unit the render window shows: this many pixels tall,\n * whatever its duration. The knob that usually decides a column — reach for\n * it to draw one larger or smaller — and the one that expands it as you\n * zoom in, since the units on screen keep their size while the time they\n * cover shrinks. See `./density` for what \"typical\" means. */\n targetUnitHeight?: number;\n /** Room for a section: at least this many pixels tall, whatever its extent.\n * Small sections have a unit or two and little room for axis labels. */\n minSectionHeight?: number;\n /** A floor on the density itself, in pixels per axis unit. */\n minPixelScale?: number;\n /** Sizing for a section in particular, or a rule that works it out from\n * what the section holds. Whatever it returns overrides the options above\n * for that section; anything it leaves out keeps the column's value. */\n sectionOptions?: SectionOptionsLike;\n /** Padding around the `t_age`/`b_age` window, in **pixels** of neighboring\n * column: how much of the abutting sections to reveal past the window.\n *\n * Resolved after every section is laid out at full extent, so it's exact —\n * each section's own density and each crossed unconformity's fixed height are\n * spent from the pixel budget. Padding collapses where the column runs out.\n * Ignored for hybrid or externally-supplied scales. */\n windowPadding?: number;\n // Axis scale type\n axisType?: ColumnAxisType;\n // Unconformity height in pixels\n unconformityHeight?: number;\n // Whether to collapse unconformities that are less than a height threshold\n collapseSmallUnconformities?: boolean | number;\n // A continuous scale to use instead of generating one\n // TODO: discontinuous scales are not yet supported\n scale?: ScaleContinuousNumeric<number, number>;\n // Hybrid scale type.\n // This overrides parameters such as the axis type\n hybridScale?: HybridScaleDefinition;\n}\n\nexport enum HybridScaleType {\n // An age-domain scale that puts equal vertical space between surfaces\n EquidistantSurfaces = \"equidistant-surfaces\",\n // A height-domain scale that is based on the average height of units between surfaces\n ApproximateHeight = \"approximate-height\",\n}\n\nexport enum HeightMethod {\n Minimum = \"minimum\",\n Average = \"average\",\n Maximum = \"maximum\",\n}\n\nexport interface HybridScaleOptions {\n pixelOffset?: number;\n pixelScale?: number;\n}\n\nexport type ApproxHeightScaleOptions = {\n minHeight?: number;\n defaultHeight?: number;\n heightMethod?: HeightMethod;\n};\n\nexport type HybridScaleDefinition =\n | ({\n type: HybridScaleType.ApproximateHeight;\n } & ApproxHeightScaleOptions)\n | {\n type: HybridScaleType.EquidistantSurfaces;\n };\n\nexport interface SectionScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n domain: [number, number];\n /** Named in the context a per-section rule sees */\n sectionID?: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n}\n\n/** Output of a section scale. For now, this assumes that the\n * mapping is linear, but it could be extended to support arbitrary\n * scale functions.\n */\nexport interface PackageScaleInfo {\n domain: [number, number];\n pixelHeight: number;\n // TODO: add a function\n scale: ScaleContinuousNumeric<number, number>;\n pixelScale?: number; // if it's a linear scale, this could be defined\n // Subsidiary scale for height mapping (for hybrid scales)\n heightScale?: ScaleContinuousNumeric<number, number>;\n}\n\nexport type PackageScaleLayoutData = PackageScaleInfo & {\n // A unique key for the section to use in React\n key: string;\n offset: number;\n // How much to\n paddingTop: number;\n};\nexport interface StratigraphicPackage {\n /** A collection of stratigraphic information organized in time, corresponding\n * to single or multiple columns. */\n t_age: number;\n b_age: number;\n}\n\nexport interface SectionInfo<\n T extends UnitLong = ExtUnit,\n> extends StratigraphicPackage {\n /** A time-bounded part of a single stratigraphic column. */\n section_id: number | number[];\n units: T[];\n b_pos?: number;\n t_pos?: number;\n}\n\nexport interface ExtUnit extends UnitLong {\n bottomOverlap: boolean;\n overlappingUnits: number[];\n column?: number;\n /* Positions (ages or heights) where the unit is clipped to its containing section.\n * This is relevant if we are filtering by age/height/depth range.\n */\n t_clip_pos?: number;\n b_clip_pos?: number;\n}\n\nexport type PackageLayoutData<T extends UnitLong = ExtUnit> = SectionInfo<T> & {\n scaleInfo: PackageScaleLayoutData;\n // A unique key for the section to use in React\n key: string;\n};\n\nexport interface CompositeScaleData {\n totalHeight: number;\n sections: PackageScaleLayoutData[];\n}\n\nexport interface ColumnScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n unconformityHeight: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n}\n\nexport interface CompositeColumnData<T extends UnitLong = ExtUnit> extends Omit<\n CompositeScaleData,\n \"sections\"\n> {\n sections: PackageLayoutData<T>[];\n}\n"],"names":["HybridScaleType","HeightMethod"],"mappings":";;AAoDO,IAAK,oCAAAA,qBAAL;AAELA,mBAAA,qBAAA,IAAsB;AAEtBA,mBAAA,mBAAA,IAAoB;AAJV,SAAAA;AAAA,GAAA,mBAAA,CAAA,CAAA;AAOL,IAAK,iCAAAC,kBAAL;AACLA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;;;"}
@@ -1,23 +1,32 @@
1
1
  import { UnitLong } from '@macrostrat/api-types';
2
2
  import { ColumnAxisType } from '@macrostrat/column-components';
3
3
  import { ScaleContinuousNumeric } from 'd3-scale';
4
+ import { SectionDensityLike, SectionOptionsLike } from './density';
4
5
  export interface ColumnHeightScaleOptions {
5
- /** A fixed pixel scale to use for the section (pixels per Myr) */
6
- pixelScale?: number;
7
- /** The target height of a constituent unit in pixels, for dynamic
8
- * scale generation */
6
+ /** A density stated outright: pixels per Myr on an age column, per metre
7
+ * otherwise, every section drawn to the same scale whatever it holds.
8
+ * Rarely what you want within one column, and the only way to make several
9
+ * of them comparable.
10
+ *
11
+ * It also takes a rule — a function of the section's context — for the
12
+ * cases the options here can't describe. A rule is in sole charge of its
13
+ * section: the floors don't apply to it. */
14
+ pixelScale?: SectionDensityLike;
15
+ /** Room for a typical unit the render window shows: this many pixels tall,
16
+ * whatever its duration. The knob that usually decides a column — reach for
17
+ * it to draw one larger or smaller — and the one that expands it as you
18
+ * zoom in, since the units on screen keep their size while the time they
19
+ * cover shrinks. See `./density` for what "typical" means. */
9
20
  targetUnitHeight?: number;
10
- /** Min height of a section in pixels. Will override minPixelScale in some cases. */
21
+ /** Room for a section: at least this many pixels tall, whatever its extent.
22
+ * Small sections have a unit or two and little room for axis labels. */
11
23
  minSectionHeight?: number;
12
- /** The minimum pixel scale to use for the section (pixels per Myr). This is mostly
13
- * needed because small sections (<1-2 units) don't necessarily have space to comfortably
14
- * render two axis labels */
24
+ /** A floor on the density itself, in pixels per axis unit. */
15
25
  minPixelScale?: number;
16
- /** The requested render window, `[b_age, t_age]`, if there is one. Set
17
- * internally by `prepareColumnUnits`: unit density is derived from the units
18
- * this window actually shows, so `targetUnitHeight` describes the units you
19
- * can see at any zoom depth rather than the section's overall average. */
20
- visibleWindow?: [number, number];
26
+ /** Sizing for a section in particular, or a rule that works it out from
27
+ * what the section holds. Whatever it returns overrides the options above
28
+ * for that section; anything it leaves out keeps the column's value. */
29
+ sectionOptions?: SectionOptionsLike;
21
30
  /** Padding around the `t_age`/`b_age` window, in **pixels** of neighboring
22
31
  * column: how much of the abutting sections to reveal past the window.
23
32
  *
@@ -58,6 +67,13 @@ export type HybridScaleDefinition = ({
58
67
  export interface SectionScaleOptions extends ColumnHeightScaleOptions {
59
68
  axisType: ColumnAxisType;
60
69
  domain: [number, number];
70
+ /** Named in the context a per-section rule sees */
71
+ sectionID?: number;
72
+ /** The requested render window, `[b_age, t_age]`, if there is one. Set
73
+ * internally by `prepareColumnUnits`: unit density is derived from the units
74
+ * this window actually shows, so `targetUnitHeight` describes the units you
75
+ * can see at any zoom depth rather than the section's overall average. */
76
+ visibleWindow?: [number, number];
61
77
  }
62
78
  /** Output of a section scale. For now, this assumes that the
63
79
  * mapping is linear, but it could be extended to support arbitrary
@@ -106,6 +122,11 @@ export interface CompositeScaleData {
106
122
  export interface ColumnScaleOptions extends ColumnHeightScaleOptions {
107
123
  axisType: ColumnAxisType;
108
124
  unconformityHeight: number;
125
+ /** The requested render window, `[b_age, t_age]`, if there is one. Set
126
+ * internally by `prepareColumnUnits`: unit density is derived from the units
127
+ * this window actually shows, so `targetUnitHeight` describes the units you
128
+ * can see at any zoom depth rather than the section's overall average. */
129
+ visibleWindow?: [number, number];
109
130
  }
110
131
  export interface CompositeColumnData<T extends UnitLong = ExtUnit> extends Omit<CompositeScaleData, "sections"> {
111
132
  sections: PackageLayoutData<T>[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../src/prepare-units/types.ts"],"sourcesContent":["import type { UnitLong } from \"@macrostrat/api-types\";\nimport type { ColumnAxisType } from \"@macrostrat/column-components\";\nimport type { ScaleContinuousNumeric } from \"d3-scale\";\n\nexport interface ColumnHeightScaleOptions {\n /** A fixed pixel scale to use for the section (pixels per Myr) */\n pixelScale?: number;\n /** The target height of a constituent unit in pixels, for dynamic\n * scale generation */\n targetUnitHeight?: number;\n /** Min height of a section in pixels. Will override minPixelScale in some cases. */\n minSectionHeight?: number;\n /** The minimum pixel scale to use for the section (pixels per Myr). This is mostly\n * needed because small sections (<1-2 units) don't necessarily have space to comfortably\n * render two axis labels */\n minPixelScale?: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n /** Padding around the `t_age`/`b_age` window, in **pixels** of neighboring\n * column: how much of the abutting sections to reveal past the window.\n *\n * Resolved after every section is laid out at full extent, so it's exact —\n * each section's own density and each crossed unconformity's fixed height are\n * spent from the pixel budget. Padding collapses where the column runs out.\n * Ignored for hybrid or externally-supplied scales. */\n windowPadding?: number;\n // Axis scale type\n axisType?: ColumnAxisType;\n // Unconformity height in pixels\n unconformityHeight?: number;\n // Whether to collapse unconformities that are less than a height threshold\n collapseSmallUnconformities?: boolean | number;\n // A continuous scale to use instead of generating one\n // TODO: discontinuous scales are not yet supported\n scale?: ScaleContinuousNumeric<number, number>;\n // Hybrid scale type.\n // This overrides parameters such as the axis type\n hybridScale?: HybridScaleDefinition;\n}\n\nexport enum HybridScaleType {\n // An age-domain scale that puts equal vertical space between surfaces\n EquidistantSurfaces = \"equidistant-surfaces\",\n // A height-domain scale that is based on the average height of units between surfaces\n ApproximateHeight = \"approximate-height\",\n}\n\nexport enum HeightMethod {\n Minimum = \"minimum\",\n Average = \"average\",\n Maximum = \"maximum\",\n}\n\nexport interface HybridScaleOptions {\n pixelOffset?: number;\n pixelScale?: number;\n}\n\nexport type ApproxHeightScaleOptions = {\n minHeight?: number;\n defaultHeight?: number;\n heightMethod?: HeightMethod;\n};\n\nexport type HybridScaleDefinition =\n | ({\n type: HybridScaleType.ApproximateHeight;\n } & ApproxHeightScaleOptions)\n | {\n type: HybridScaleType.EquidistantSurfaces;\n };\n\nexport interface SectionScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n domain: [number, number];\n}\n\n/** Output of a section scale. For now, this assumes that the\n * mapping is linear, but it could be extended to support arbitrary\n * scale functions.\n */\nexport interface PackageScaleInfo {\n domain: [number, number];\n pixelHeight: number;\n // TODO: add a function\n scale: ScaleContinuousNumeric<number, number>;\n pixelScale?: number; // if it's a linear scale, this could be defined\n // Subsidiary scale for height mapping (for hybrid scales)\n heightScale?: ScaleContinuousNumeric<number, number>;\n}\n\nexport type PackageScaleLayoutData = PackageScaleInfo & {\n // A unique key for the section to use in React\n key: string;\n offset: number;\n // How much to\n paddingTop: number;\n};\nexport interface StratigraphicPackage {\n /** A collection of stratigraphic information organized in time, corresponding\n * to single or multiple columns. */\n t_age: number;\n b_age: number;\n}\n\nexport interface SectionInfo<\n T extends UnitLong = ExtUnit,\n> extends StratigraphicPackage {\n /** A time-bounded part of a single stratigraphic column. */\n section_id: number | number[];\n units: T[];\n b_pos?: number;\n t_pos?: number;\n}\n\nexport interface ExtUnit extends UnitLong {\n bottomOverlap: boolean;\n overlappingUnits: number[];\n column?: number;\n /* Positions (ages or heights) where the unit is clipped to its containing section.\n * This is relevant if we are filtering by age/height/depth range.\n */\n t_clip_pos?: number;\n b_clip_pos?: number;\n}\n\nexport type PackageLayoutData<T extends UnitLong = ExtUnit> = SectionInfo<T> & {\n scaleInfo: PackageScaleLayoutData;\n // A unique key for the section to use in React\n key: string;\n};\n\nexport interface CompositeScaleData {\n totalHeight: number;\n sections: PackageScaleLayoutData[];\n}\n\nexport interface ColumnScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n unconformityHeight: number;\n}\n\nexport interface CompositeColumnData<T extends UnitLong = ExtUnit> extends Omit<\n CompositeScaleData,\n \"sections\"\n> {\n sections: PackageLayoutData<T>[];\n}\n"],"names":["HybridScaleType","HeightMethod"],"mappings":"AA2CO,IAAK,oCAAAA,qBAAL;AAELA,mBAAA,qBAAA,IAAsB;AAEtBA,mBAAA,mBAAA,IAAoB;AAJV,SAAAA;AAAA,GAAA,mBAAA,CAAA,CAAA;AAOL,IAAK,iCAAAC,kBAAL;AACLA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}
1
+ {"version":3,"file":"types.js","sources":["../../src/prepare-units/types.ts"],"sourcesContent":["import type { UnitLong } from \"@macrostrat/api-types\";\nimport type { ColumnAxisType } from \"@macrostrat/column-components\";\nimport type { ScaleContinuousNumeric } from \"d3-scale\";\nimport type { SectionDensityLike, SectionOptionsLike } from \"./density\";\n\nexport interface ColumnHeightScaleOptions {\n /** A density stated outright: pixels per Myr on an age column, per metre\n * otherwise, every section drawn to the same scale whatever it holds.\n * Rarely what you want within one column, and the only way to make several\n * of them comparable.\n *\n * It also takes a rule — a function of the section's context — for the\n * cases the options here can't describe. A rule is in sole charge of its\n * section: the floors don't apply to it. */\n pixelScale?: SectionDensityLike;\n /** Room for a typical unit the render window shows: this many pixels tall,\n * whatever its duration. The knob that usually decides a column — reach for\n * it to draw one larger or smaller — and the one that expands it as you\n * zoom in, since the units on screen keep their size while the time they\n * cover shrinks. See `./density` for what \"typical\" means. */\n targetUnitHeight?: number;\n /** Room for a section: at least this many pixels tall, whatever its extent.\n * Small sections have a unit or two and little room for axis labels. */\n minSectionHeight?: number;\n /** A floor on the density itself, in pixels per axis unit. */\n minPixelScale?: number;\n /** Sizing for a section in particular, or a rule that works it out from\n * what the section holds. Whatever it returns overrides the options above\n * for that section; anything it leaves out keeps the column's value. */\n sectionOptions?: SectionOptionsLike;\n /** Padding around the `t_age`/`b_age` window, in **pixels** of neighboring\n * column: how much of the abutting sections to reveal past the window.\n *\n * Resolved after every section is laid out at full extent, so it's exact —\n * each section's own density and each crossed unconformity's fixed height are\n * spent from the pixel budget. Padding collapses where the column runs out.\n * Ignored for hybrid or externally-supplied scales. */\n windowPadding?: number;\n // Axis scale type\n axisType?: ColumnAxisType;\n // Unconformity height in pixels\n unconformityHeight?: number;\n // Whether to collapse unconformities that are less than a height threshold\n collapseSmallUnconformities?: boolean | number;\n // A continuous scale to use instead of generating one\n // TODO: discontinuous scales are not yet supported\n scale?: ScaleContinuousNumeric<number, number>;\n // Hybrid scale type.\n // This overrides parameters such as the axis type\n hybridScale?: HybridScaleDefinition;\n}\n\nexport enum HybridScaleType {\n // An age-domain scale that puts equal vertical space between surfaces\n EquidistantSurfaces = \"equidistant-surfaces\",\n // A height-domain scale that is based on the average height of units between surfaces\n ApproximateHeight = \"approximate-height\",\n}\n\nexport enum HeightMethod {\n Minimum = \"minimum\",\n Average = \"average\",\n Maximum = \"maximum\",\n}\n\nexport interface HybridScaleOptions {\n pixelOffset?: number;\n pixelScale?: number;\n}\n\nexport type ApproxHeightScaleOptions = {\n minHeight?: number;\n defaultHeight?: number;\n heightMethod?: HeightMethod;\n};\n\nexport type HybridScaleDefinition =\n | ({\n type: HybridScaleType.ApproximateHeight;\n } & ApproxHeightScaleOptions)\n | {\n type: HybridScaleType.EquidistantSurfaces;\n };\n\nexport interface SectionScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n domain: [number, number];\n /** Named in the context a per-section rule sees */\n sectionID?: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n}\n\n/** Output of a section scale. For now, this assumes that the\n * mapping is linear, but it could be extended to support arbitrary\n * scale functions.\n */\nexport interface PackageScaleInfo {\n domain: [number, number];\n pixelHeight: number;\n // TODO: add a function\n scale: ScaleContinuousNumeric<number, number>;\n pixelScale?: number; // if it's a linear scale, this could be defined\n // Subsidiary scale for height mapping (for hybrid scales)\n heightScale?: ScaleContinuousNumeric<number, number>;\n}\n\nexport type PackageScaleLayoutData = PackageScaleInfo & {\n // A unique key for the section to use in React\n key: string;\n offset: number;\n // How much to\n paddingTop: number;\n};\nexport interface StratigraphicPackage {\n /** A collection of stratigraphic information organized in time, corresponding\n * to single or multiple columns. */\n t_age: number;\n b_age: number;\n}\n\nexport interface SectionInfo<\n T extends UnitLong = ExtUnit,\n> extends StratigraphicPackage {\n /** A time-bounded part of a single stratigraphic column. */\n section_id: number | number[];\n units: T[];\n b_pos?: number;\n t_pos?: number;\n}\n\nexport interface ExtUnit extends UnitLong {\n bottomOverlap: boolean;\n overlappingUnits: number[];\n column?: number;\n /* Positions (ages or heights) where the unit is clipped to its containing section.\n * This is relevant if we are filtering by age/height/depth range.\n */\n t_clip_pos?: number;\n b_clip_pos?: number;\n}\n\nexport type PackageLayoutData<T extends UnitLong = ExtUnit> = SectionInfo<T> & {\n scaleInfo: PackageScaleLayoutData;\n // A unique key for the section to use in React\n key: string;\n};\n\nexport interface CompositeScaleData {\n totalHeight: number;\n sections: PackageScaleLayoutData[];\n}\n\nexport interface ColumnScaleOptions extends ColumnHeightScaleOptions {\n axisType: ColumnAxisType;\n unconformityHeight: number;\n /** The requested render window, `[b_age, t_age]`, if there is one. Set\n * internally by `prepareColumnUnits`: unit density is derived from the units\n * this window actually shows, so `targetUnitHeight` describes the units you\n * can see at any zoom depth rather than the section's overall average. */\n visibleWindow?: [number, number];\n}\n\nexport interface CompositeColumnData<T extends UnitLong = ExtUnit> extends Omit<\n CompositeScaleData,\n \"sections\"\n> {\n sections: PackageLayoutData<T>[];\n}\n"],"names":["HybridScaleType","HeightMethod"],"mappings":"AAoDO,IAAK,oCAAAA,qBAAL;AAELA,mBAAA,qBAAA,IAAsB;AAEtBA,mBAAA,mBAAA,IAAoB;AAJV,SAAAA;AAAA,GAAA,mBAAA,CAAA,CAAA;AAOL,IAAK,iCAAAC,kBAAL;AACLA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AACVA,gBAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}