@macrostrat/column-views 3.3.5 → 3.4.1

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 (72) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/column.cjs +2 -1
  3. package/dist/column.cjs.map +1 -1
  4. package/dist/column.js +2 -1
  5. package/dist/column.js.map +1 -1
  6. package/dist/data-provider/unit-selection.cjs +7 -3
  7. package/dist/data-provider/unit-selection.cjs.map +1 -1
  8. package/dist/data-provider/unit-selection.d.ts +1 -0
  9. package/dist/data-provider/unit-selection.js +7 -3
  10. package/dist/data-provider/unit-selection.js.map +1 -1
  11. package/dist/facets/carbon-isotopes/data-area.cjs +0 -3
  12. package/dist/facets/carbon-isotopes/data-area.cjs.map +1 -1
  13. package/dist/facets/carbon-isotopes/data-area.js +0 -3
  14. package/dist/facets/carbon-isotopes/data-area.js.map +1 -1
  15. package/dist/index.cjs +13 -8
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +7 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/prepare-units/composite-scale.cjs +0 -1
  20. package/dist/prepare-units/composite-scale.cjs.map +1 -1
  21. package/dist/prepare-units/composite-scale.js +0 -1
  22. package/dist/prepare-units/composite-scale.js.map +1 -1
  23. package/dist/prepare-units/helpers.cjs +83 -49
  24. package/dist/prepare-units/helpers.cjs.map +1 -1
  25. package/dist/prepare-units/helpers.d.ts +19 -2
  26. package/dist/prepare-units/helpers.js +84 -50
  27. package/dist/prepare-units/helpers.js.map +1 -1
  28. package/dist/prepare-units/index.cjs.map +1 -1
  29. package/dist/prepare-units/index.js.map +1 -1
  30. package/dist/section.cjs +1 -2
  31. package/dist/section.cjs.map +1 -1
  32. package/dist/section.js +1 -2
  33. package/dist/section.js.map +1 -1
  34. package/dist/unit-details/identifiers.cjs +56 -0
  35. package/dist/unit-details/identifiers.cjs.map +1 -0
  36. package/dist/unit-details/identifiers.d.ts +31 -0
  37. package/dist/unit-details/identifiers.js +54 -0
  38. package/dist/unit-details/identifiers.js.map +1 -0
  39. package/dist/unit-details/index.d.ts +2 -0
  40. package/dist/unit-details/panel.cjs +11 -88
  41. package/dist/unit-details/panel.cjs.map +1 -1
  42. package/dist/unit-details/panel.d.ts +3 -19
  43. package/dist/unit-details/panel.js +10 -87
  44. package/dist/unit-details/panel.js.map +1 -1
  45. package/dist/unit-details/popover.cjs +1 -2
  46. package/dist/unit-details/popover.cjs.map +1 -1
  47. package/dist/unit-details/popover.js +2 -3
  48. package/dist/unit-details/popover.js.map +1 -1
  49. package/dist/unit-details/strat-names.cjs +44 -0
  50. package/dist/unit-details/strat-names.cjs.map +1 -0
  51. package/dist/unit-details/strat-names.d.ts +14 -0
  52. package/dist/unit-details/strat-names.js +42 -0
  53. package/dist/unit-details/strat-names.js.map +1 -0
  54. package/dist/units/index.cjs +19 -6
  55. package/dist/units/index.cjs.map +1 -1
  56. package/dist/units/index.d.ts +11 -20
  57. package/dist/units/index.js +19 -6
  58. package/dist/units/index.js.map +1 -1
  59. package/package.json +14 -14
  60. package/src/column.ts +1 -1
  61. package/src/data-provider/unit-selection.ts +8 -4
  62. package/src/facets/carbon-isotopes/data-area.ts +0 -3
  63. package/src/prepare-units/composite-scale.ts +1 -1
  64. package/src/prepare-units/helpers.ts +121 -72
  65. package/src/prepare-units/index.ts +1 -1
  66. package/src/section.ts +0 -1
  67. package/src/unit-details/identifiers.ts +67 -0
  68. package/src/unit-details/index.ts +2 -0
  69. package/src/unit-details/panel.ts +13 -126
  70. package/src/unit-details/popover.ts +2 -7
  71. package/src/unit-details/strat-names.ts +57 -0
  72. package/src/units/index.ts +28 -8
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { AgeField, AgeLabel, AgeRange, Duration, IntervalProportions, getAge, ge
8
8
  import { AnnotatedUnitsColumn, ColumnNotesProvider, CompositeUnitComponent, CompositeUnitsColumn, LabelTrackerProvider, SectionLabelsColumn, TrackedLabeledUnit } from "./units/composite.js";
9
9
  import { BaseColumnsLayer, SelectedColumnOverlay, buildColumnsStyle } from "./maps/layers/columns.js";
10
10
  import { BaseMeasurementsColumn, TruncatedList, groupNotesByPixelDistance, mergeHeightRanges, standardizeMeasurementHeight } from "./facets/measurements/base.js";
11
- import { ClickableText, Identifier, LegendPanelHeader, ReferencesField, ThicknessField, UnitDetailsFeature, UnitDetailsPanel } from "./unit-details/panel.js";
11
+ import { ClickableText, Identifier, UnitIdentifier } from "./unit-details/identifiers.js";
12
12
  import { ColumnCenters, ColumnFeatures, ColumnKeyboardNavigation, Columns, CurrentColumn, MeasurementsLayer } from "./maps/column-navigation/svg/layers.js";
13
13
  import { ColumnCorrelationMap } from "./maps/column-correlation/core.js";
14
14
  import { ColumnCorrelationProvider, useCorrelationMapStore } from "./maps/column-correlation/state.js";
@@ -21,6 +21,7 @@ import { FossilDataType, useFossilData } from "./facets/fossils/provider.js";
21
21
  import { HeightMethod, HybridScaleType } from "./prepare-units/types.js";
22
22
  import { InsetMap } from "./maps/inset-map/index.js";
23
23
  import { IsotopesColumn, IsotopesDataset } from "./facets/carbon-isotopes/isotopes-column.js";
24
+ import { LegendPanelHeader, ReferencesField, ThicknessField, UnitDetailsFeature, UnitDetailsPanel } from "./unit-details/panel.js";
24
25
  import { LithologiesProvider, MacrostratColumnDataProvider, MacrostratColumnProvider, MacrostratColumnStateProvider, UnitSelectionProvider, columnUnitsAtom, columnUnitsMapAtom, scope, useColumnUnitsMap, useCompositeScale, useMacrostratColumnData, useMacrostratUnits } from "./data-provider/store.js";
25
26
  import { MacrostratUnitsOverlay, buildUnitsStyle } from "./maps/layers/units.js";
26
27
  import { MeasurementDataContext, MeasurementDataProvider, useMeasurementData } from "./facets/carbon-isotopes/data-provider.js";
@@ -28,9 +29,10 @@ import { MergeSectionsMode, agesOverlap, createUnitSorter, ensureArray, ensureRe
28
29
  import { PBDBFossilsColumn } from "./facets/fossils/index.js";
29
30
  import { PBDBOccurrencesMatrix } from "./facets/fossils/taxon-ranges.js";
30
31
  import { SGPMeasurementsColumn } from "./facets/measurements/sgp.js";
32
+ import { StratNameField } from "./unit-details/strat-names.js";
31
33
  import { UnitDetailsPanelWithNavigation } from "./unit-details/modal-panel.js";
32
34
  import { UnitDetailsPopover, UnitSelectionPopover } from "./unit-details/popover.js";
33
- import { UnitKeyboardNavigation, UnitSelectionCallbackManager, allowUnitSelectionAtom, selectedUnitIDAtom, useAtomOverlayPosition, useColumnRef, useSelectedUnit, useUnitSelectionDispatch, useUnitSelectionTarget } from "./data-provider/unit-selection.js";
35
+ import { UnitKeyboardNavigation, UnitSelectionCallbackManager, allowUnitSelectionAtom, selectedUnitIDAtom, useAtomOverlayPosition, useColumnRef, useSelectedUnit, useUnitSelection, useUnitSelectionDispatch, useUnitSelectionTarget } from "./data-provider/unit-selection.js";
34
36
  import { flattenLithologies, getMixedColorForData, getMixedUnitColor } from "./units/colors.js";
35
37
  import { parseLineFromString, stringifyLine } from "./correlation-chart/hash-string.js";
36
38
  import { preprocessUnits } from "./prepare-units/helpers.js";
@@ -102,6 +104,7 @@ export {
102
104
  SectionLabelsColumn,
103
105
  SelectedColumnOverlay,
104
106
  SimpleUnitsColumn,
107
+ StratNameField,
105
108
  ThicknessField,
106
109
  TrackedLabeledUnit,
107
110
  TruncatedList,
@@ -110,6 +113,7 @@ export {
110
113
  UnitDetailsPanel,
111
114
  UnitDetailsPanelWithNavigation,
112
115
  UnitDetailsPopover,
116
+ UnitIdentifier,
113
117
  UnitKeyboardNavigation,
114
118
  UnitSelectionCallbackManager,
115
119
  UnitSelectionPopover,
@@ -156,6 +160,7 @@ export {
156
160
  useSelectedUnit,
157
161
  useUnitColor,
158
162
  useUnitColorByEnvironment,
163
+ useUnitSelection,
159
164
  useUnitSelectionDispatch,
160
165
  useUnitSelectionTarget
161
166
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -207,7 +207,6 @@ function createCompositeScale(sections, interpolateUnconformities = false) {
207
207
  for (const scale2 of scales) {
208
208
  const range = scale2.range();
209
209
  if (pixelHeight > Math.min(...range) && pixelHeight <= Math.max(...range)) {
210
- console.log("Inverting scale at pixel height", pixelHeight);
211
210
  return scale2.invert(pixelHeight);
212
211
  }
213
212
  }
@@ -1 +1 @@
1
- {"version":3,"file":"composite-scale.cjs","sources":["../../src/prepare-units/composite-scale.ts"],"sourcesContent":["import { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { ensureArray, getUnitHeightRange } from \"./utils\";\nimport { ScaleContinuousNumeric, scaleLinear } from \"d3-scale\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport { buildHybridScale } from \"./dynamic-scales\";\nimport { ExtUnit, HybridScaleType, SectionInfo } from \"./types\";\nimport type {\n ColumnScaleOptions,\n CompositeColumnData,\n CompositeScaleData,\n PackageLayoutData,\n PackageScaleInfo,\n PackageScaleLayoutData,\n SectionScaleOptions,\n} from \"./types\";\n\n// Composite scale information augmented with units in each package\n\nexport function buildCompositeScaleInfo(\n inputScales: PackageScaleInfo[],\n unconformityHeight: number,\n): CompositeScaleData {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n let totalHeight = unconformityHeight / 2;\n let lastSectionTopHeight = 0;\n\n const packages2: PackageScaleLayoutData[] = [];\n for (const group of inputScales) {\n const { domain, scale } = group;\n const [b_age, t_age] = domain;\n const key = `package-${b_age}-${t_age}`;\n\n packages2.push({\n ...createPackageScale(group, totalHeight),\n key,\n offset: totalHeight,\n // Unconformity height above this particular section\n paddingTop: totalHeight - lastSectionTopHeight,\n });\n\n const pixelHeight = Math.abs(scale(b_age) - scale(t_age));\n lastSectionTopHeight = totalHeight + pixelHeight;\n totalHeight = lastSectionTopHeight + unconformityHeight;\n }\n totalHeight += unconformityHeight / 2;\n return {\n totalHeight,\n sections: packages2,\n };\n}\n\nexport function finalizeSectionHeights<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n unconformityHeight: number,\n): CompositeColumnData<T> {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n const sectionScales = sections.map((d) => d.scaleInfo);\n\n const { totalHeight, sections: packages } = buildCompositeScaleInfo(\n sectionScales,\n unconformityHeight,\n );\n\n // This could perhaps be simplified.\n const sections1: PackageLayoutData<T>[] = [];\n for (const i in sections) {\n const group = sections[i];\n const scaleInfo = packages[i];\n sections1.push({\n ...group,\n key: scaleInfo.key,\n scaleInfo,\n });\n }\n return {\n totalHeight,\n sections: sections1,\n };\n}\n\nexport interface SectionInfoWithScale<\n T extends UnitLong = ExtUnit,\n> extends SectionInfo<T> {\n scaleInfo: PackageScaleInfo;\n}\n\nexport function computeSectionHeights<T extends UnitLong>(\n sections: SectionInfo<T>[],\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n return sections.map((group) => {\n return addScaleToSection<T>(group, opts);\n });\n}\n\nfunction addScaleToSection<T extends UnitLong = ExtUnit>(\n group: SectionInfo<T>,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T> {\n const { t_age, b_age, t_pos, b_pos, units } = group;\n let _range = null;\n // if t_age and b_age are set for a group, use them to define the range...\n if (opts.axisType == ColumnAxisType.AGE) {\n _range = [b_age, t_age];\n } else {\n _range = [b_pos, t_pos];\n }\n\n const scaleInfo = buildSectionScale<T>(units, {\n ...opts,\n domain: _range,\n });\n\n return {\n ...group,\n scaleInfo,\n };\n}\n\nfunction buildSectionScale<T extends UnitLong>(\n data: T[],\n opts: SectionScaleOptions,\n): PackageScaleInfo {\n const {\n targetUnitHeight = 20,\n minPixelScale = 0.2,\n axisType,\n minSectionHeight,\n scale,\n hybridScale,\n } = opts;\n const domain = opts.domain ?? findSectionHeightRange(data, axisType);\n\n const dAge = Math.abs(domain[0] - domain[1]);\n\n let _pixelScale = opts.pixelScale;\n let pixelHeight: number;\n\n if (hybridScale != null) {\n /** In an equidistant surfaces scale, we want to determine the heights of surfaces\n * and then distribute units evenly between them.\n * This is somewhat like an ordinal scale\n */\n if (hybridScale.type === HybridScaleType.EquidistantSurfaces) {\n _pixelScale ??= targetUnitHeight;\n }\n\n return buildHybridScale(hybridScale, data, domain, {\n pixelOffset: 0,\n pixelScale: _pixelScale,\n });\n }\n\n if (scale == null) {\n if (_pixelScale == null) {\n const avgAgeRange = findAverageUnitHeight(data, axisType);\n // Get pixel height necessary to render average unit at target height\n _pixelScale = Math.max(targetUnitHeight / avgAgeRange, minPixelScale);\n\n // OLD METHOD that cares about overall section height vs. individual unit height\n // 0.2 pixel per myr is the floor scale\n //const targetHeight = targetUnitHeight * data.length;\n // 1 pixel per myr is the floor scale\n //_pixelScale = Math.max(targetHeight / dAge, minPixelScale);\n }\n\n let height = dAge * _pixelScale;\n // If height is less than minSectionHeight, set it to minSectionHeight\n const _minSectionHeight = minSectionHeight ?? targetUnitHeight ?? 0;\n pixelHeight = Math.max(height, _minSectionHeight);\n _pixelScale = pixelHeight / dAge;\n } else {\n // If a scale is provided, use it to compute pixel height\n pixelHeight = Math.abs(scale(domain[0]) - scale(domain[1]));\n }\n\n return createPackageScale(\n { scale, domain, pixelHeight, pixelScale: _pixelScale },\n 0,\n );\n}\n\nexport function createPackageScale(\n def: PackageScaleInfo,\n offset: number = 0,\n): PackageScaleInfo {\n /** Build a section scale */\n // Domain should be oriented from bottom to top, but scale is oriented from top to bottom\n const { domain, pixelScale, pixelHeight, scale, heightScale } = def;\n\n if (scale == null && pixelScale == null) {\n throw new Error(\"Either scale or pixelScale must be provided\");\n }\n\n let _scale: ScaleContinuousNumeric<number, number>;\n if (scale == null) {\n _scale = scaleLinear()\n .domain([domain[1], domain[0]])\n .range([offset, pixelHeight + offset]);\n } else {\n const domain0 = scale.domain();\n const range0 = scale.range();\n _scale = scale\n .copy()\n .domain(domain0)\n .range(range0.map((d) => d + offset));\n }\n\n _scale.clamp();\n\n let _heightScale = null;\n if (heightScale != null) {\n // Adjust height scale as well\n const range0 = scale.range();\n _heightScale = heightScale.copy().range(range0.map((d) => d + offset));\n _heightScale.clamp();\n }\n\n return {\n domain,\n pixelScale,\n pixelHeight,\n scale: _scale,\n // Internal details for hybrid scales. TODO: improve this\n heightScale: _heightScale,\n };\n}\n\nfunction findSectionHeightRange(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): [number, number] {\n if (axisType == null) {\n throw new Error(\"Axis type is not set\");\n }\n if (axisType === ColumnAxisType.AGE) {\n const t_age = Math.min(...data.map((d) => d.t_age));\n const b_age = Math.max(...data.map((d) => d.b_age));\n return [b_age, t_age];\n } else if (\n axisType == ColumnAxisType.DEPTH ||\n axisType == ColumnAxisType.ORDINAL\n ) {\n const t_pos = Math.min(...data.map((d) => d.t_pos));\n const b_pos = Math.max(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n } else if (axisType == ColumnAxisType.HEIGHT) {\n const t_pos = Math.max(...data.map((d) => d.t_pos));\n const b_pos = Math.min(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n }\n}\n\nfunction findAverageUnitHeight(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): number {\n const unitHeights = data.map((d) => {\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n return Math.abs(b_pos - t_pos);\n });\n return unitHeights.reduce((a, b) => a + b, 0) / unitHeights.length;\n}\n\nexport interface CompositeColumnScale {\n (age: number): number | null;\n copy(): CompositeColumnScale;\n domain(): [number, number];\n invert(pixelHeight: number): number | null;\n clamp(clamp: boolean): void;\n}\n\nexport function createCompositeScale(\n sections: PackageLayoutData[],\n interpolateUnconformities: boolean = false,\n): CompositeColumnScale {\n /** Create a scale that works across multiple packages */\n\n const scales: ScaleContinuousNumeric<number, number>[] = [];\n\n let lastScale: ScaleContinuousNumeric<number, number> | null = null;\n for (const section of sections) {\n const _scale = section.scaleInfo.scale.copy().clamp(true);\n scales.push(_scale);\n if (lastScale != null && interpolateUnconformities) {\n // Add a new scale that interpolates between lastScale and _scale\n const lastDomain = lastScale.domain();\n const lastRange = lastScale.range();\n const currentDomain = _scale.domain();\n const currentRange = _scale.range();\n\n const interpScale = scaleLinear()\n .domain([lastDomain[lastDomain.length - 1], currentDomain[0]])\n .range([lastRange[lastRange.length - 1], currentRange[0]])\n .clamp(true);\n scales.push(interpScale);\n }\n lastScale = _scale;\n }\n\n const scale: CompositeColumnScale = (age) => {\n for (const s of scales) {\n const domain = s.domain();\n if (\n domain[0] < domain[domain.length - 1] &&\n age >= domain[0] &&\n age <= domain[domain.length - 1]\n ) {\n // Age axes\n return s(age);\n } else if (age <= domain[0] && age >= domain[domain.length - 1]) {\n // Normal axes like height\n return s(age);\n }\n }\n return null;\n };\n\n scale.copy = () => {\n return createCompositeScale(sections, interpolateUnconformities);\n };\n\n scale.domain = () => {\n /** Return the domain of the scale */\n const vals = sections.flatMap((d) => d.scaleInfo.domain);\n if (vals[0] < vals[vals.length - 1]) {\n // age axes\n return [Math.min(...vals), Math.max(...vals)];\n }\n // Normal axes like height\n return [Math.max(...vals), Math.min(...vals)];\n };\n\n scale.invert = (pixelHeight) => {\n /** Invert the scale to get the age at a given pixel height */\n // Iterate through the sections to find the correct one\n for (const scale of scales) {\n const range = scale.range();\n if (\n pixelHeight > Math.min(...range) &&\n pixelHeight <= Math.max(...range)\n ) {\n console.log(\"Inverting scale at pixel height\", pixelHeight);\n return scale.invert(pixelHeight);\n }\n }\n return null;\n };\n\n scale.clamp = (clamp: boolean) => {\n /** Clamp all constituent scales */\n for (const s of scales) {\n s.clamp(clamp);\n }\n };\n\n return scale;\n}\n\n/** Collapse sections separated by unconformities that are smaller than a given pixel height. */\nexport function collapseUnconformitiesByPixelHeight<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n threshold: number,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n const newSections = [];\n let currentSection: SectionInfoWithScale<T> | null = null;\n for (const nextSection of sections) {\n if (currentSection == null) {\n currentSection = nextSection;\n continue;\n }\n let heights: [number, number];\n let pxHeights: [number, number];\n if (opts.axisType !== ColumnAxisType.AGE) {\n heights = [nextSection.t_pos, currentSection.b_pos];\n } else {\n heights = [nextSection.t_age, currentSection.b_age];\n }\n\n const _diff = (vals: number[]) => {\n return Math.abs(vals[0] - vals[1]);\n };\n\n pxHeights = [\n _diff(heights.map(nextSection.scaleInfo.scale)),\n _diff(heights.map(currentSection.scaleInfo.scale)),\n ];\n\n const pxHeight = Math.min(...pxHeights);\n\n if (pxHeight < threshold) {\n let t_pos: number;\n let b_pos: number;\n if (\n opts.axisType == ColumnAxisType.AGE ||\n opts.axisType == ColumnAxisType.DEPTH\n ) {\n t_pos = Math.min(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.max(currentSection.b_pos, nextSection.b_pos);\n } else {\n t_pos = Math.max(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.min(currentSection.b_pos, nextSection.b_pos);\n }\n\n // We need to merge the sections\n const compositeSection0: SectionInfo<T> = {\n units: [...currentSection.units, ...nextSection.units],\n section_id: [\n ...ensureArray(currentSection.section_id),\n ...ensureArray(nextSection.section_id),\n ],\n t_age: Math.min(currentSection.t_age, nextSection.t_age),\n b_age: Math.max(currentSection.b_age, nextSection.b_age),\n t_pos,\n b_pos,\n };\n\n currentSection = addScaleToSection(compositeSection0, opts);\n } else {\n // We need to keep the section\n newSections.push(currentSection);\n currentSection = nextSection;\n }\n }\n if (currentSection != null) {\n newSections.push(currentSection);\n }\n\n return newSections;\n}\n"],"names":["ColumnAxisType","HybridScaleType","buildHybridScale","scaleLinear","getUnitHeightRange","scale","ensureArray"],"mappings":"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"}
1
+ {"version":3,"file":"composite-scale.cjs","sources":["../../src/prepare-units/composite-scale.ts"],"sourcesContent":["import { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { ensureArray, getUnitHeightRange } from \"./utils\";\nimport { ScaleContinuousNumeric, scaleLinear } from \"d3-scale\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport { buildHybridScale } from \"./dynamic-scales\";\nimport { ExtUnit, HybridScaleType, SectionInfo } from \"./types\";\nimport type {\n ColumnScaleOptions,\n CompositeColumnData,\n CompositeScaleData,\n PackageLayoutData,\n PackageScaleInfo,\n PackageScaleLayoutData,\n SectionScaleOptions,\n} from \"./types\";\n\n// Composite scale information augmented with units in each package\n\nexport function buildCompositeScaleInfo(\n inputScales: PackageScaleInfo[],\n unconformityHeight: number,\n): CompositeScaleData {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n let totalHeight = unconformityHeight / 2;\n let lastSectionTopHeight = 0;\n\n const packages2: PackageScaleLayoutData[] = [];\n for (const group of inputScales) {\n const { domain, scale } = group;\n const [b_age, t_age] = domain;\n const key = `package-${b_age}-${t_age}`;\n\n packages2.push({\n ...createPackageScale(group, totalHeight),\n key,\n offset: totalHeight,\n // Unconformity height above this particular section\n paddingTop: totalHeight - lastSectionTopHeight,\n });\n\n const pixelHeight = Math.abs(scale(b_age) - scale(t_age));\n lastSectionTopHeight = totalHeight + pixelHeight;\n totalHeight = lastSectionTopHeight + unconformityHeight;\n }\n totalHeight += unconformityHeight / 2;\n return {\n totalHeight,\n sections: packages2,\n };\n}\n\nexport function finalizeSectionHeights<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n unconformityHeight: number,\n): CompositeColumnData<T> {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n const sectionScales = sections.map((d) => d.scaleInfo);\n\n const { totalHeight, sections: packages } = buildCompositeScaleInfo(\n sectionScales,\n unconformityHeight,\n );\n\n // This could perhaps be simplified.\n const sections1: PackageLayoutData<T>[] = [];\n for (const i in sections) {\n const group = sections[i];\n const scaleInfo = packages[i];\n sections1.push({\n ...group,\n key: scaleInfo.key,\n scaleInfo,\n });\n }\n return {\n totalHeight,\n sections: sections1,\n };\n}\n\nexport interface SectionInfoWithScale<\n T extends UnitLong = ExtUnit,\n> extends SectionInfo<T> {\n scaleInfo: PackageScaleInfo;\n}\n\nexport function computeSectionHeights<T extends UnitLong>(\n sections: SectionInfo<T>[],\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n return sections.map((group) => {\n return addScaleToSection<T>(group, opts);\n });\n}\n\nfunction addScaleToSection<T extends UnitLong = ExtUnit>(\n group: SectionInfo<T>,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T> {\n const { t_age, b_age, t_pos, b_pos, units } = group;\n let _range = null;\n // if t_age and b_age are set for a group, use them to define the range...\n if (opts.axisType == ColumnAxisType.AGE) {\n _range = [b_age, t_age];\n } else {\n _range = [b_pos, t_pos];\n }\n\n const scaleInfo = buildSectionScale<T>(units, {\n ...opts,\n domain: _range,\n });\n\n return {\n ...group,\n scaleInfo,\n };\n}\n\nfunction buildSectionScale<T extends UnitLong>(\n data: T[],\n opts: SectionScaleOptions,\n): PackageScaleInfo {\n const {\n targetUnitHeight = 20,\n minPixelScale = 0.2,\n axisType,\n minSectionHeight,\n scale,\n hybridScale,\n } = opts;\n const domain = opts.domain ?? findSectionHeightRange(data, axisType);\n\n const dAge = Math.abs(domain[0] - domain[1]);\n\n let _pixelScale = opts.pixelScale;\n let pixelHeight: number;\n\n if (hybridScale != null) {\n /** In an equidistant surfaces scale, we want to determine the heights of surfaces\n * and then distribute units evenly between them.\n * This is somewhat like an ordinal scale\n */\n if (hybridScale.type === HybridScaleType.EquidistantSurfaces) {\n _pixelScale ??= targetUnitHeight;\n }\n\n return buildHybridScale(hybridScale, data, domain, {\n pixelOffset: 0,\n pixelScale: _pixelScale,\n });\n }\n\n if (scale == null) {\n if (_pixelScale == null) {\n const avgAgeRange = findAverageUnitHeight(data, axisType);\n // Get pixel height necessary to render average unit at target height\n _pixelScale = Math.max(targetUnitHeight / avgAgeRange, minPixelScale);\n\n // OLD METHOD that cares about overall section height vs. individual unit height\n // 0.2 pixel per myr is the floor scale\n //const targetHeight = targetUnitHeight * data.length;\n // 1 pixel per myr is the floor scale\n //_pixelScale = Math.max(targetHeight / dAge, minPixelScale);\n }\n\n let height = dAge * _pixelScale;\n // If height is less than minSectionHeight, set it to minSectionHeight\n const _minSectionHeight = minSectionHeight ?? targetUnitHeight ?? 0;\n pixelHeight = Math.max(height, _minSectionHeight);\n _pixelScale = pixelHeight / dAge;\n } else {\n // If a scale is provided, use it to compute pixel height\n pixelHeight = Math.abs(scale(domain[0]) - scale(domain[1]));\n }\n\n return createPackageScale(\n { scale, domain, pixelHeight, pixelScale: _pixelScale },\n 0,\n );\n}\n\nexport function createPackageScale(\n def: PackageScaleInfo,\n offset: number = 0,\n): PackageScaleInfo {\n /** Build a section scale */\n // Domain should be oriented from bottom to top, but scale is oriented from top to bottom\n const { domain, pixelScale, pixelHeight, scale, heightScale } = def;\n\n if (scale == null && pixelScale == null) {\n throw new Error(\"Either scale or pixelScale must be provided\");\n }\n\n let _scale: ScaleContinuousNumeric<number, number>;\n if (scale == null) {\n _scale = scaleLinear()\n .domain([domain[1], domain[0]])\n .range([offset, pixelHeight + offset]);\n } else {\n const domain0 = scale.domain();\n const range0 = scale.range();\n _scale = scale\n .copy()\n .domain(domain0)\n .range(range0.map((d) => d + offset));\n }\n\n _scale.clamp();\n\n let _heightScale = null;\n if (heightScale != null) {\n // Adjust height scale as well\n const range0 = scale.range();\n _heightScale = heightScale.copy().range(range0.map((d) => d + offset));\n _heightScale.clamp();\n }\n\n return {\n domain,\n pixelScale,\n pixelHeight,\n scale: _scale,\n // Internal details for hybrid scales. TODO: improve this\n heightScale: _heightScale,\n };\n}\n\nfunction findSectionHeightRange(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): [number, number] {\n if (axisType == null) {\n throw new Error(\"Axis type is not set\");\n }\n if (axisType === ColumnAxisType.AGE) {\n const t_age = Math.min(...data.map((d) => d.t_age));\n const b_age = Math.max(...data.map((d) => d.b_age));\n return [b_age, t_age];\n } else if (\n axisType == ColumnAxisType.DEPTH ||\n axisType == ColumnAxisType.ORDINAL\n ) {\n const t_pos = Math.min(...data.map((d) => d.t_pos));\n const b_pos = Math.max(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n } else if (axisType == ColumnAxisType.HEIGHT) {\n const t_pos = Math.max(...data.map((d) => d.t_pos));\n const b_pos = Math.min(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n }\n}\n\nfunction findAverageUnitHeight(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): number {\n const unitHeights = data.map((d) => {\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n return Math.abs(b_pos - t_pos);\n });\n return unitHeights.reduce((a, b) => a + b, 0) / unitHeights.length;\n}\n\nexport interface CompositeColumnScale {\n (age: number): number | null;\n copy(): CompositeColumnScale;\n domain(): [number, number];\n invert(pixelHeight: number): number | null;\n clamp(clamp: boolean): void;\n}\n\nexport function createCompositeScale(\n sections: PackageLayoutData[],\n interpolateUnconformities: boolean = false,\n): CompositeColumnScale {\n /** Create a scale that works across multiple packages */\n\n const scales: ScaleContinuousNumeric<number, number>[] = [];\n\n let lastScale: ScaleContinuousNumeric<number, number> | null = null;\n for (const section of sections) {\n const _scale = section.scaleInfo.scale.copy().clamp(true);\n scales.push(_scale);\n if (lastScale != null && interpolateUnconformities) {\n // Add a new scale that interpolates between lastScale and _scale\n const lastDomain = lastScale.domain();\n const lastRange = lastScale.range();\n const currentDomain = _scale.domain();\n const currentRange = _scale.range();\n\n const interpScale = scaleLinear()\n .domain([lastDomain[lastDomain.length - 1], currentDomain[0]])\n .range([lastRange[lastRange.length - 1], currentRange[0]])\n .clamp(true);\n scales.push(interpScale);\n }\n lastScale = _scale;\n }\n\n const scale: CompositeColumnScale = (age) => {\n for (const s of scales) {\n const domain = s.domain();\n if (\n domain[0] < domain[domain.length - 1] &&\n age >= domain[0] &&\n age <= domain[domain.length - 1]\n ) {\n // Age axes\n return s(age);\n } else if (age <= domain[0] && age >= domain[domain.length - 1]) {\n // Normal axes like height\n return s(age);\n }\n }\n return null;\n };\n\n scale.copy = () => {\n return createCompositeScale(sections, interpolateUnconformities);\n };\n\n scale.domain = () => {\n /** Return the domain of the scale */\n const vals = sections.flatMap((d) => d.scaleInfo.domain);\n if (vals[0] < vals[vals.length - 1]) {\n // age axes\n return [Math.min(...vals), Math.max(...vals)];\n }\n // Normal axes like height\n return [Math.max(...vals), Math.min(...vals)];\n };\n\n scale.invert = (pixelHeight) => {\n /** Invert the scale to get the age at a given pixel height */\n // Iterate through the sections to find the correct one\n for (const scale of scales) {\n const range = scale.range();\n if (\n pixelHeight > Math.min(...range) &&\n pixelHeight <= Math.max(...range)\n ) {\n //console.log(\"Inverting scale at pixel height\", pixelHeight);\n return scale.invert(pixelHeight);\n }\n }\n return null;\n };\n\n scale.clamp = (clamp: boolean) => {\n /** Clamp all constituent scales */\n for (const s of scales) {\n s.clamp(clamp);\n }\n };\n\n return scale;\n}\n\n/** Collapse sections separated by unconformities that are smaller than a given pixel height. */\nexport function collapseUnconformitiesByPixelHeight<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n threshold: number,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n const newSections = [];\n let currentSection: SectionInfoWithScale<T> | null = null;\n for (const nextSection of sections) {\n if (currentSection == null) {\n currentSection = nextSection;\n continue;\n }\n let heights: [number, number];\n let pxHeights: [number, number];\n if (opts.axisType !== ColumnAxisType.AGE) {\n heights = [nextSection.t_pos, currentSection.b_pos];\n } else {\n heights = [nextSection.t_age, currentSection.b_age];\n }\n\n const _diff = (vals: number[]) => {\n return Math.abs(vals[0] - vals[1]);\n };\n\n pxHeights = [\n _diff(heights.map(nextSection.scaleInfo.scale)),\n _diff(heights.map(currentSection.scaleInfo.scale)),\n ];\n\n const pxHeight = Math.min(...pxHeights);\n\n if (pxHeight < threshold) {\n let t_pos: number;\n let b_pos: number;\n if (\n opts.axisType == ColumnAxisType.AGE ||\n opts.axisType == ColumnAxisType.DEPTH\n ) {\n t_pos = Math.min(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.max(currentSection.b_pos, nextSection.b_pos);\n } else {\n t_pos = Math.max(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.min(currentSection.b_pos, nextSection.b_pos);\n }\n\n // We need to merge the sections\n const compositeSection0: SectionInfo<T> = {\n units: [...currentSection.units, ...nextSection.units],\n section_id: [\n ...ensureArray(currentSection.section_id),\n ...ensureArray(nextSection.section_id),\n ],\n t_age: Math.min(currentSection.t_age, nextSection.t_age),\n b_age: Math.max(currentSection.b_age, nextSection.b_age),\n t_pos,\n b_pos,\n };\n\n currentSection = addScaleToSection(compositeSection0, opts);\n } else {\n // We need to keep the section\n newSections.push(currentSection);\n currentSection = nextSection;\n }\n }\n if (currentSection != null) {\n newSections.push(currentSection);\n }\n\n return newSections;\n}\n"],"names":["ColumnAxisType","HybridScaleType","buildHybridScale","scaleLinear","getUnitHeightRange","scale","ensureArray"],"mappings":";;;;;;;AAkBO,SAAS,wBACd,aACA,oBACoB;AAKpB,MAAI,cAAc,qBAAqB;AACvC,MAAI,uBAAuB;AAE3B,QAAM,YAAsC,CAAA;AAC5C,aAAW,SAAS,aAAa;AAC/B,UAAM,EAAE,QAAQ,MAAA,IAAU;AAC1B,UAAM,CAAC,OAAO,KAAK,IAAI;AACvB,UAAM,MAAM,WAAW,KAAK,IAAI,KAAK;AAErC,cAAU,KAAK;AAAA,MACb,GAAG,mBAAmB,OAAO,WAAW;AAAA,MACxC;AAAA,MACA,QAAQ;AAAA;AAAA,MAER,YAAY,cAAc;AAAA,IAAA,CAC3B;AAED,UAAM,cAAc,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,KAAK,CAAC;AACxD,2BAAuB,cAAc;AACrC,kBAAc,uBAAuB;AAAA,EACvC;AACA,iBAAe,qBAAqB;AACpC,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,EAAA;AAEd;AAEO,SAAS,uBACd,UACA,oBACwB;AAKxB,QAAM,gBAAgB,SAAS,IAAI,CAAC,MAAM,EAAE,SAAS;AAErD,QAAM,EAAE,aAAa,UAAU,SAAA,IAAa;AAAA,IAC1C;AAAA,IACA;AAAA,EAAA;AAIF,QAAM,YAAoC,CAAA;AAC1C,aAAW,KAAK,UAAU;AACxB,UAAM,QAAQ,SAAS,CAAC;AACxB,UAAM,YAAY,SAAS,CAAC;AAC5B,cAAU,KAAK;AAAA,MACb,GAAG;AAAA,MACH,KAAK,UAAU;AAAA,MACf;AAAA,IAAA,CACD;AAAA,EACH;AACA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,EAAA;AAEd;AAQO,SAAS,sBACd,UACA,MAC2B;AAC3B,SAAO,SAAS,IAAI,CAAC,UAAU;AAC7B,WAAO,kBAAqB,OAAO,IAAI;AAAA,EACzC,CAAC;AACH;AAEA,SAAS,kBACP,OACA,MACyB;AACzB,QAAM,EAAE,OAAO,OAAO,OAAO,OAAO,UAAU;AAC9C,MAAI,SAAS;AAEb,MAAI,KAAK,YAAYA,iBAAAA,eAAe,KAAK;AACvC,aAAS,CAAC,OAAO,KAAK;AAAA,EACxB,OAAO;AACL,aAAS,CAAC,OAAO,KAAK;AAAA,EACxB;AAEA,QAAM,YAAY,kBAAqB,OAAO;AAAA,IAC5C,GAAG;AAAA,IACH,QAAQ;AAAA,EAAA,CACT;AAED,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EAAA;AAEJ;AAEA,SAAS,kBACP,MACA,MACkB;AAClB,QAAM;AAAA,IACJ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AACJ,QAAM,SAAS,KAAK,UAAU,uBAAuB,MAAM,QAAQ;AAEnE,QAAM,OAAO,KAAK,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC;AAE3C,MAAI,cAAc,KAAK;AACvB,MAAI;AAEJ,MAAI,eAAe,MAAM;AAKvB,QAAI,YAAY,SAASC,MAAAA,gBAAgB,qBAAqB;AAC5D,sBAAgB;AAAA,IAClB;AAEA,WAAOC,+BAAiB,aAAa,MAAM,QAAQ;AAAA,MACjD,aAAa;AAAA,MACb,YAAY;AAAA,IAAA,CACb;AAAA,EACH;AAEA,MAAI,SAAS,MAAM;AACjB,QAAI,eAAe,MAAM;AACvB,YAAM,cAAc,sBAAsB,MAAM,QAAQ;AAExD,oBAAc,KAAK,IAAI,mBAAmB,aAAa,aAAa;AAAA,IAOtE;AAEA,QAAI,SAAS,OAAO;AAEpB,UAAM,oBAAoB,oBAAoB,oBAAoB;AAClE,kBAAc,KAAK,IAAI,QAAQ,iBAAiB;AAChD,kBAAc,cAAc;AAAA,EAC9B,OAAO;AAEL,kBAAc,KAAK,IAAI,MAAM,OAAO,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL,EAAE,OAAO,QAAQ,aAAa,YAAY,YAAA;AAAA,IAC1C;AAAA,EAAA;AAEJ;AAEO,SAAS,mBACd,KACA,SAAiB,GACC;AAGlB,QAAM,EAAE,QAAQ,YAAY,aAAa,OAAO,gBAAgB;AAEhE,MAAI,SAAS,QAAQ,cAAc,MAAM;AACvC,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAEA,MAAI;AACJ,MAAI,SAAS,MAAM;AACjB,aAASC,QAAAA,cACN,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC7B,MAAM,CAAC,QAAQ,cAAc,MAAM,CAAC;AAAA,EACzC,OAAO;AACL,UAAM,UAAU,MAAM,OAAA;AACtB,UAAM,SAAS,MAAM,MAAA;AACrB,aAAS,MACN,OACA,OAAO,OAAO,EACd,MAAM,OAAO,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;AAAA,EACxC;AAEA,SAAO,MAAA;AAEP,MAAI,eAAe;AACnB,MAAI,eAAe,MAAM;AAEvB,UAAM,SAAS,MAAM,MAAA;AACrB,mBAAe,YAAY,KAAA,EAAO,MAAM,OAAO,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;AACrE,iBAAa,MAAA;AAAA,EACf;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA;AAAA,IAEP,aAAa;AAAA,EAAA;AAEjB;AAEA,SAAS,uBACP,MACA,UACkB;AAClB,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AACA,MAAI,aAAaH,iBAAAA,eAAe,KAAK;AACnC,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,WAAO,CAAC,OAAO,KAAK;AAAA,EACtB,WACE,YAAYA,iBAAAA,eAAe,SAC3B,YAAYA,iBAAAA,eAAe,SAC3B;AACA,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,WAAO,CAAC,OAAO,KAAK;AAAA,EACtB,WAAW,YAAYA,iBAAAA,eAAe,QAAQ;AAC5C,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,WAAO,CAAC,OAAO,KAAK;AAAA,EACtB;AACF;AAEA,SAAS,sBACP,MACA,UACQ;AACR,QAAM,cAAc,KAAK,IAAI,CAAC,MAAM;AAClC,UAAM,CAAC,OAAO,KAAK,IAAII,MAAAA,mBAAmB,GAAG,QAAQ;AACrD,WAAO,KAAK,IAAI,QAAQ,KAAK;AAAA,EAC/B,CAAC;AACD,SAAO,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,YAAY;AAC9D;AAUO,SAAS,qBACd,UACA,4BAAqC,OACf;AAGtB,QAAM,SAAmD,CAAA;AAEzD,MAAI,YAA2D;AAC/D,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,QAAQ,UAAU,MAAM,KAAA,EAAO,MAAM,IAAI;AACxD,WAAO,KAAK,MAAM;AAClB,QAAI,aAAa,QAAQ,2BAA2B;AAElD,YAAM,aAAa,UAAU,OAAA;AAC7B,YAAM,YAAY,UAAU,MAAA;AAC5B,YAAM,gBAAgB,OAAO,OAAA;AAC7B,YAAM,eAAe,OAAO,MAAA;AAE5B,YAAM,cAAcD,QAAAA,cACjB,OAAO,CAAC,WAAW,WAAW,SAAS,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,EAC5D,MAAM,CAAC,UAAU,UAAU,SAAS,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,EACxD,MAAM,IAAI;AACb,aAAO,KAAK,WAAW;AAAA,IACzB;AACA,gBAAY;AAAA,EACd;AAEA,QAAM,QAA8B,CAAC,QAAQ;AAC3C,eAAW,KAAK,QAAQ;AACtB,YAAM,SAAS,EAAE,OAAA;AACjB,UACE,OAAO,CAAC,IAAI,OAAO,OAAO,SAAS,CAAC,KACpC,OAAO,OAAO,CAAC,KACf,OAAO,OAAO,OAAO,SAAS,CAAC,GAC/B;AAEA,eAAO,EAAE,GAAG;AAAA,MACd,WAAW,OAAO,OAAO,CAAC,KAAK,OAAO,OAAO,OAAO,SAAS,CAAC,GAAG;AAE/D,eAAO,EAAE,GAAG;AAAA,MACd;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM;AACjB,WAAO,qBAAqB,UAAU,yBAAyB;AAAA,EACjE;AAEA,QAAM,SAAS,MAAM;AAEnB,UAAM,OAAO,SAAS,QAAQ,CAAC,MAAM,EAAE,UAAU,MAAM;AACvD,QAAI,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS,CAAC,GAAG;AAEnC,aAAO,CAAC,KAAK,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;AAAA,IAC9C;AAEA,WAAO,CAAC,KAAK,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;AAAA,EAC9C;AAEA,QAAM,SAAS,CAAC,gBAAgB;AAG9B,eAAWE,UAAS,QAAQ;AAC1B,YAAM,QAAQA,OAAM,MAAA;AACpB,UACE,cAAc,KAAK,IAAI,GAAG,KAAK,KAC/B,eAAe,KAAK,IAAI,GAAG,KAAK,GAChC;AAEA,eAAOA,OAAM,OAAO,WAAW;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,UAAmB;AAEhC,eAAW,KAAK,QAAQ;AACtB,QAAE,MAAM,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,oCACd,UACA,WACA,MAC2B;AAC3B,QAAM,cAAc,CAAA;AACpB,MAAI,iBAAiD;AACrD,aAAW,eAAe,UAAU;AAClC,QAAI,kBAAkB,MAAM;AAC1B,uBAAiB;AACjB;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACJ,QAAI,KAAK,aAAaL,iBAAAA,eAAe,KAAK;AACxC,gBAAU,CAAC,YAAY,OAAO,eAAe,KAAK;AAAA,IACpD,OAAO;AACL,gBAAU,CAAC,YAAY,OAAO,eAAe,KAAK;AAAA,IACpD;AAEA,UAAM,QAAQ,CAAC,SAAmB;AAChC,aAAO,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;AAAA,IACnC;AAEA,gBAAY;AAAA,MACV,MAAM,QAAQ,IAAI,YAAY,UAAU,KAAK,CAAC;AAAA,MAC9C,MAAM,QAAQ,IAAI,eAAe,UAAU,KAAK,CAAC;AAAA,IAAA;AAGnD,UAAM,WAAW,KAAK,IAAI,GAAG,SAAS;AAEtC,QAAI,WAAW,WAAW;AACxB,UAAI;AACJ,UAAI;AACJ,UACE,KAAK,YAAYA,gCAAe,OAChC,KAAK,YAAYA,iBAAAA,eAAe,OAChC;AACA,gBAAQ,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AACxD,gBAAQ,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AAAA,MAC1D,OAAO;AACL,gBAAQ,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AACxD,gBAAQ,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AAAA,MAC1D;AAGA,YAAM,oBAAoC;AAAA,QACxC,OAAO,CAAC,GAAG,eAAe,OAAO,GAAG,YAAY,KAAK;AAAA,QACrD,YAAY;AAAA,UACV,GAAGM,MAAAA,YAAY,eAAe,UAAU;AAAA,UACxC,GAAGA,MAAAA,YAAY,YAAY,UAAU;AAAA,QAAA;AAAA,QAEvC,OAAO,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AAAA,QACvD,OAAO,KAAK,IAAI,eAAe,OAAO,YAAY,KAAK;AAAA,QACvD;AAAA,QACA;AAAA,MAAA;AAGF,uBAAiB,kBAAkB,mBAAmB,IAAI;AAAA,IAC5D,OAAO;AAEL,kBAAY,KAAK,cAAc;AAC/B,uBAAiB;AAAA,IACnB;AAAA,EACF;AACA,MAAI,kBAAkB,MAAM;AAC1B,gBAAY,KAAK,cAAc;AAAA,EACjC;AAEA,SAAO;AACT;;;;;;;"}
@@ -205,7 +205,6 @@ function createCompositeScale(sections, interpolateUnconformities = false) {
205
205
  for (const scale2 of scales) {
206
206
  const range = scale2.range();
207
207
  if (pixelHeight > Math.min(...range) && pixelHeight <= Math.max(...range)) {
208
- console.log("Inverting scale at pixel height", pixelHeight);
209
208
  return scale2.invert(pixelHeight);
210
209
  }
211
210
  }
@@ -1 +1 @@
1
- {"version":3,"file":"composite-scale.js","sources":["../../src/prepare-units/composite-scale.ts"],"sourcesContent":["import { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { ensureArray, getUnitHeightRange } from \"./utils\";\nimport { ScaleContinuousNumeric, scaleLinear } from \"d3-scale\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport { buildHybridScale } from \"./dynamic-scales\";\nimport { ExtUnit, HybridScaleType, SectionInfo } from \"./types\";\nimport type {\n ColumnScaleOptions,\n CompositeColumnData,\n CompositeScaleData,\n PackageLayoutData,\n PackageScaleInfo,\n PackageScaleLayoutData,\n SectionScaleOptions,\n} from \"./types\";\n\n// Composite scale information augmented with units in each package\n\nexport function buildCompositeScaleInfo(\n inputScales: PackageScaleInfo[],\n unconformityHeight: number,\n): CompositeScaleData {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n let totalHeight = unconformityHeight / 2;\n let lastSectionTopHeight = 0;\n\n const packages2: PackageScaleLayoutData[] = [];\n for (const group of inputScales) {\n const { domain, scale } = group;\n const [b_age, t_age] = domain;\n const key = `package-${b_age}-${t_age}`;\n\n packages2.push({\n ...createPackageScale(group, totalHeight),\n key,\n offset: totalHeight,\n // Unconformity height above this particular section\n paddingTop: totalHeight - lastSectionTopHeight,\n });\n\n const pixelHeight = Math.abs(scale(b_age) - scale(t_age));\n lastSectionTopHeight = totalHeight + pixelHeight;\n totalHeight = lastSectionTopHeight + unconformityHeight;\n }\n totalHeight += unconformityHeight / 2;\n return {\n totalHeight,\n sections: packages2,\n };\n}\n\nexport function finalizeSectionHeights<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n unconformityHeight: number,\n): CompositeColumnData<T> {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n const sectionScales = sections.map((d) => d.scaleInfo);\n\n const { totalHeight, sections: packages } = buildCompositeScaleInfo(\n sectionScales,\n unconformityHeight,\n );\n\n // This could perhaps be simplified.\n const sections1: PackageLayoutData<T>[] = [];\n for (const i in sections) {\n const group = sections[i];\n const scaleInfo = packages[i];\n sections1.push({\n ...group,\n key: scaleInfo.key,\n scaleInfo,\n });\n }\n return {\n totalHeight,\n sections: sections1,\n };\n}\n\nexport interface SectionInfoWithScale<\n T extends UnitLong = ExtUnit,\n> extends SectionInfo<T> {\n scaleInfo: PackageScaleInfo;\n}\n\nexport function computeSectionHeights<T extends UnitLong>(\n sections: SectionInfo<T>[],\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n return sections.map((group) => {\n return addScaleToSection<T>(group, opts);\n });\n}\n\nfunction addScaleToSection<T extends UnitLong = ExtUnit>(\n group: SectionInfo<T>,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T> {\n const { t_age, b_age, t_pos, b_pos, units } = group;\n let _range = null;\n // if t_age and b_age are set for a group, use them to define the range...\n if (opts.axisType == ColumnAxisType.AGE) {\n _range = [b_age, t_age];\n } else {\n _range = [b_pos, t_pos];\n }\n\n const scaleInfo = buildSectionScale<T>(units, {\n ...opts,\n domain: _range,\n });\n\n return {\n ...group,\n scaleInfo,\n };\n}\n\nfunction buildSectionScale<T extends UnitLong>(\n data: T[],\n opts: SectionScaleOptions,\n): PackageScaleInfo {\n const {\n targetUnitHeight = 20,\n minPixelScale = 0.2,\n axisType,\n minSectionHeight,\n scale,\n hybridScale,\n } = opts;\n const domain = opts.domain ?? findSectionHeightRange(data, axisType);\n\n const dAge = Math.abs(domain[0] - domain[1]);\n\n let _pixelScale = opts.pixelScale;\n let pixelHeight: number;\n\n if (hybridScale != null) {\n /** In an equidistant surfaces scale, we want to determine the heights of surfaces\n * and then distribute units evenly between them.\n * This is somewhat like an ordinal scale\n */\n if (hybridScale.type === HybridScaleType.EquidistantSurfaces) {\n _pixelScale ??= targetUnitHeight;\n }\n\n return buildHybridScale(hybridScale, data, domain, {\n pixelOffset: 0,\n pixelScale: _pixelScale,\n });\n }\n\n if (scale == null) {\n if (_pixelScale == null) {\n const avgAgeRange = findAverageUnitHeight(data, axisType);\n // Get pixel height necessary to render average unit at target height\n _pixelScale = Math.max(targetUnitHeight / avgAgeRange, minPixelScale);\n\n // OLD METHOD that cares about overall section height vs. individual unit height\n // 0.2 pixel per myr is the floor scale\n //const targetHeight = targetUnitHeight * data.length;\n // 1 pixel per myr is the floor scale\n //_pixelScale = Math.max(targetHeight / dAge, minPixelScale);\n }\n\n let height = dAge * _pixelScale;\n // If height is less than minSectionHeight, set it to minSectionHeight\n const _minSectionHeight = minSectionHeight ?? targetUnitHeight ?? 0;\n pixelHeight = Math.max(height, _minSectionHeight);\n _pixelScale = pixelHeight / dAge;\n } else {\n // If a scale is provided, use it to compute pixel height\n pixelHeight = Math.abs(scale(domain[0]) - scale(domain[1]));\n }\n\n return createPackageScale(\n { scale, domain, pixelHeight, pixelScale: _pixelScale },\n 0,\n );\n}\n\nexport function createPackageScale(\n def: PackageScaleInfo,\n offset: number = 0,\n): PackageScaleInfo {\n /** Build a section scale */\n // Domain should be oriented from bottom to top, but scale is oriented from top to bottom\n const { domain, pixelScale, pixelHeight, scale, heightScale } = def;\n\n if (scale == null && pixelScale == null) {\n throw new Error(\"Either scale or pixelScale must be provided\");\n }\n\n let _scale: ScaleContinuousNumeric<number, number>;\n if (scale == null) {\n _scale = scaleLinear()\n .domain([domain[1], domain[0]])\n .range([offset, pixelHeight + offset]);\n } else {\n const domain0 = scale.domain();\n const range0 = scale.range();\n _scale = scale\n .copy()\n .domain(domain0)\n .range(range0.map((d) => d + offset));\n }\n\n _scale.clamp();\n\n let _heightScale = null;\n if (heightScale != null) {\n // Adjust height scale as well\n const range0 = scale.range();\n _heightScale = heightScale.copy().range(range0.map((d) => d + offset));\n _heightScale.clamp();\n }\n\n return {\n domain,\n pixelScale,\n pixelHeight,\n scale: _scale,\n // Internal details for hybrid scales. TODO: improve this\n heightScale: _heightScale,\n };\n}\n\nfunction findSectionHeightRange(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): [number, number] {\n if (axisType == null) {\n throw new Error(\"Axis type is not set\");\n }\n if (axisType === ColumnAxisType.AGE) {\n const t_age = Math.min(...data.map((d) => d.t_age));\n const b_age = Math.max(...data.map((d) => d.b_age));\n return [b_age, t_age];\n } else if (\n axisType == ColumnAxisType.DEPTH ||\n axisType == ColumnAxisType.ORDINAL\n ) {\n const t_pos = Math.min(...data.map((d) => d.t_pos));\n const b_pos = Math.max(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n } else if (axisType == ColumnAxisType.HEIGHT) {\n const t_pos = Math.max(...data.map((d) => d.t_pos));\n const b_pos = Math.min(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n }\n}\n\nfunction findAverageUnitHeight(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): number {\n const unitHeights = data.map((d) => {\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n return Math.abs(b_pos - t_pos);\n });\n return unitHeights.reduce((a, b) => a + b, 0) / unitHeights.length;\n}\n\nexport interface CompositeColumnScale {\n (age: number): number | null;\n copy(): CompositeColumnScale;\n domain(): [number, number];\n invert(pixelHeight: number): number | null;\n clamp(clamp: boolean): void;\n}\n\nexport function createCompositeScale(\n sections: PackageLayoutData[],\n interpolateUnconformities: boolean = false,\n): CompositeColumnScale {\n /** Create a scale that works across multiple packages */\n\n const scales: ScaleContinuousNumeric<number, number>[] = [];\n\n let lastScale: ScaleContinuousNumeric<number, number> | null = null;\n for (const section of sections) {\n const _scale = section.scaleInfo.scale.copy().clamp(true);\n scales.push(_scale);\n if (lastScale != null && interpolateUnconformities) {\n // Add a new scale that interpolates between lastScale and _scale\n const lastDomain = lastScale.domain();\n const lastRange = lastScale.range();\n const currentDomain = _scale.domain();\n const currentRange = _scale.range();\n\n const interpScale = scaleLinear()\n .domain([lastDomain[lastDomain.length - 1], currentDomain[0]])\n .range([lastRange[lastRange.length - 1], currentRange[0]])\n .clamp(true);\n scales.push(interpScale);\n }\n lastScale = _scale;\n }\n\n const scale: CompositeColumnScale = (age) => {\n for (const s of scales) {\n const domain = s.domain();\n if (\n domain[0] < domain[domain.length - 1] &&\n age >= domain[0] &&\n age <= domain[domain.length - 1]\n ) {\n // Age axes\n return s(age);\n } else if (age <= domain[0] && age >= domain[domain.length - 1]) {\n // Normal axes like height\n return s(age);\n }\n }\n return null;\n };\n\n scale.copy = () => {\n return createCompositeScale(sections, interpolateUnconformities);\n };\n\n scale.domain = () => {\n /** Return the domain of the scale */\n const vals = sections.flatMap((d) => d.scaleInfo.domain);\n if (vals[0] < vals[vals.length - 1]) {\n // age axes\n return [Math.min(...vals), Math.max(...vals)];\n }\n // Normal axes like height\n return [Math.max(...vals), Math.min(...vals)];\n };\n\n scale.invert = (pixelHeight) => {\n /** Invert the scale to get the age at a given pixel height */\n // Iterate through the sections to find the correct one\n for (const scale of scales) {\n const range = scale.range();\n if (\n pixelHeight > Math.min(...range) &&\n pixelHeight <= Math.max(...range)\n ) {\n console.log(\"Inverting scale at pixel height\", pixelHeight);\n return scale.invert(pixelHeight);\n }\n }\n return null;\n };\n\n scale.clamp = (clamp: boolean) => {\n /** Clamp all constituent scales */\n for (const s of scales) {\n s.clamp(clamp);\n }\n };\n\n return scale;\n}\n\n/** Collapse sections separated by unconformities that are smaller than a given pixel height. */\nexport function collapseUnconformitiesByPixelHeight<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n threshold: number,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n const newSections = [];\n let currentSection: SectionInfoWithScale<T> | null = null;\n for (const nextSection of sections) {\n if (currentSection == null) {\n currentSection = nextSection;\n continue;\n }\n let heights: [number, number];\n let pxHeights: [number, number];\n if (opts.axisType !== ColumnAxisType.AGE) {\n heights = [nextSection.t_pos, currentSection.b_pos];\n } else {\n heights = [nextSection.t_age, currentSection.b_age];\n }\n\n const _diff = (vals: number[]) => {\n return Math.abs(vals[0] - vals[1]);\n };\n\n pxHeights = [\n _diff(heights.map(nextSection.scaleInfo.scale)),\n _diff(heights.map(currentSection.scaleInfo.scale)),\n ];\n\n const pxHeight = Math.min(...pxHeights);\n\n if (pxHeight < threshold) {\n let t_pos: number;\n let b_pos: number;\n if (\n opts.axisType == ColumnAxisType.AGE ||\n opts.axisType == ColumnAxisType.DEPTH\n ) {\n t_pos = Math.min(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.max(currentSection.b_pos, nextSection.b_pos);\n } else {\n t_pos = Math.max(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.min(currentSection.b_pos, nextSection.b_pos);\n }\n\n // We need to merge the sections\n const compositeSection0: SectionInfo<T> = {\n units: [...currentSection.units, ...nextSection.units],\n section_id: [\n ...ensureArray(currentSection.section_id),\n ...ensureArray(nextSection.section_id),\n ],\n t_age: Math.min(currentSection.t_age, nextSection.t_age),\n b_age: Math.max(currentSection.b_age, nextSection.b_age),\n t_pos,\n b_pos,\n };\n\n currentSection = addScaleToSection(compositeSection0, opts);\n } else {\n // We need to keep the section\n newSections.push(currentSection);\n currentSection = nextSection;\n }\n }\n if (currentSection != null) {\n newSections.push(currentSection);\n }\n\n return newSections;\n}\n"],"names":["scale"],"mappings":"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"}
1
+ {"version":3,"file":"composite-scale.js","sources":["../../src/prepare-units/composite-scale.ts"],"sourcesContent":["import { ColumnAxisType } from \"@macrostrat/column-components\";\nimport { ensureArray, getUnitHeightRange } from \"./utils\";\nimport { ScaleContinuousNumeric, scaleLinear } from \"d3-scale\";\nimport { UnitLong } from \"@macrostrat/api-types\";\nimport { buildHybridScale } from \"./dynamic-scales\";\nimport { ExtUnit, HybridScaleType, SectionInfo } from \"./types\";\nimport type {\n ColumnScaleOptions,\n CompositeColumnData,\n CompositeScaleData,\n PackageLayoutData,\n PackageScaleInfo,\n PackageScaleLayoutData,\n SectionScaleOptions,\n} from \"./types\";\n\n// Composite scale information augmented with units in each package\n\nexport function buildCompositeScaleInfo(\n inputScales: PackageScaleInfo[],\n unconformityHeight: number,\n): CompositeScaleData {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n let totalHeight = unconformityHeight / 2;\n let lastSectionTopHeight = 0;\n\n const packages2: PackageScaleLayoutData[] = [];\n for (const group of inputScales) {\n const { domain, scale } = group;\n const [b_age, t_age] = domain;\n const key = `package-${b_age}-${t_age}`;\n\n packages2.push({\n ...createPackageScale(group, totalHeight),\n key,\n offset: totalHeight,\n // Unconformity height above this particular section\n paddingTop: totalHeight - lastSectionTopHeight,\n });\n\n const pixelHeight = Math.abs(scale(b_age) - scale(t_age));\n lastSectionTopHeight = totalHeight + pixelHeight;\n totalHeight = lastSectionTopHeight + unconformityHeight;\n }\n totalHeight += unconformityHeight / 2;\n return {\n totalHeight,\n sections: packages2,\n };\n}\n\nexport function finalizeSectionHeights<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n unconformityHeight: number,\n): CompositeColumnData<T> {\n /** Finalize the heights of sections, including the heights of unconformities\n * between them.\n */\n\n const sectionScales = sections.map((d) => d.scaleInfo);\n\n const { totalHeight, sections: packages } = buildCompositeScaleInfo(\n sectionScales,\n unconformityHeight,\n );\n\n // This could perhaps be simplified.\n const sections1: PackageLayoutData<T>[] = [];\n for (const i in sections) {\n const group = sections[i];\n const scaleInfo = packages[i];\n sections1.push({\n ...group,\n key: scaleInfo.key,\n scaleInfo,\n });\n }\n return {\n totalHeight,\n sections: sections1,\n };\n}\n\nexport interface SectionInfoWithScale<\n T extends UnitLong = ExtUnit,\n> extends SectionInfo<T> {\n scaleInfo: PackageScaleInfo;\n}\n\nexport function computeSectionHeights<T extends UnitLong>(\n sections: SectionInfo<T>[],\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n return sections.map((group) => {\n return addScaleToSection<T>(group, opts);\n });\n}\n\nfunction addScaleToSection<T extends UnitLong = ExtUnit>(\n group: SectionInfo<T>,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T> {\n const { t_age, b_age, t_pos, b_pos, units } = group;\n let _range = null;\n // if t_age and b_age are set for a group, use them to define the range...\n if (opts.axisType == ColumnAxisType.AGE) {\n _range = [b_age, t_age];\n } else {\n _range = [b_pos, t_pos];\n }\n\n const scaleInfo = buildSectionScale<T>(units, {\n ...opts,\n domain: _range,\n });\n\n return {\n ...group,\n scaleInfo,\n };\n}\n\nfunction buildSectionScale<T extends UnitLong>(\n data: T[],\n opts: SectionScaleOptions,\n): PackageScaleInfo {\n const {\n targetUnitHeight = 20,\n minPixelScale = 0.2,\n axisType,\n minSectionHeight,\n scale,\n hybridScale,\n } = opts;\n const domain = opts.domain ?? findSectionHeightRange(data, axisType);\n\n const dAge = Math.abs(domain[0] - domain[1]);\n\n let _pixelScale = opts.pixelScale;\n let pixelHeight: number;\n\n if (hybridScale != null) {\n /** In an equidistant surfaces scale, we want to determine the heights of surfaces\n * and then distribute units evenly between them.\n * This is somewhat like an ordinal scale\n */\n if (hybridScale.type === HybridScaleType.EquidistantSurfaces) {\n _pixelScale ??= targetUnitHeight;\n }\n\n return buildHybridScale(hybridScale, data, domain, {\n pixelOffset: 0,\n pixelScale: _pixelScale,\n });\n }\n\n if (scale == null) {\n if (_pixelScale == null) {\n const avgAgeRange = findAverageUnitHeight(data, axisType);\n // Get pixel height necessary to render average unit at target height\n _pixelScale = Math.max(targetUnitHeight / avgAgeRange, minPixelScale);\n\n // OLD METHOD that cares about overall section height vs. individual unit height\n // 0.2 pixel per myr is the floor scale\n //const targetHeight = targetUnitHeight * data.length;\n // 1 pixel per myr is the floor scale\n //_pixelScale = Math.max(targetHeight / dAge, minPixelScale);\n }\n\n let height = dAge * _pixelScale;\n // If height is less than minSectionHeight, set it to minSectionHeight\n const _minSectionHeight = minSectionHeight ?? targetUnitHeight ?? 0;\n pixelHeight = Math.max(height, _minSectionHeight);\n _pixelScale = pixelHeight / dAge;\n } else {\n // If a scale is provided, use it to compute pixel height\n pixelHeight = Math.abs(scale(domain[0]) - scale(domain[1]));\n }\n\n return createPackageScale(\n { scale, domain, pixelHeight, pixelScale: _pixelScale },\n 0,\n );\n}\n\nexport function createPackageScale(\n def: PackageScaleInfo,\n offset: number = 0,\n): PackageScaleInfo {\n /** Build a section scale */\n // Domain should be oriented from bottom to top, but scale is oriented from top to bottom\n const { domain, pixelScale, pixelHeight, scale, heightScale } = def;\n\n if (scale == null && pixelScale == null) {\n throw new Error(\"Either scale or pixelScale must be provided\");\n }\n\n let _scale: ScaleContinuousNumeric<number, number>;\n if (scale == null) {\n _scale = scaleLinear()\n .domain([domain[1], domain[0]])\n .range([offset, pixelHeight + offset]);\n } else {\n const domain0 = scale.domain();\n const range0 = scale.range();\n _scale = scale\n .copy()\n .domain(domain0)\n .range(range0.map((d) => d + offset));\n }\n\n _scale.clamp();\n\n let _heightScale = null;\n if (heightScale != null) {\n // Adjust height scale as well\n const range0 = scale.range();\n _heightScale = heightScale.copy().range(range0.map((d) => d + offset));\n _heightScale.clamp();\n }\n\n return {\n domain,\n pixelScale,\n pixelHeight,\n scale: _scale,\n // Internal details for hybrid scales. TODO: improve this\n heightScale: _heightScale,\n };\n}\n\nfunction findSectionHeightRange(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): [number, number] {\n if (axisType == null) {\n throw new Error(\"Axis type is not set\");\n }\n if (axisType === ColumnAxisType.AGE) {\n const t_age = Math.min(...data.map((d) => d.t_age));\n const b_age = Math.max(...data.map((d) => d.b_age));\n return [b_age, t_age];\n } else if (\n axisType == ColumnAxisType.DEPTH ||\n axisType == ColumnAxisType.ORDINAL\n ) {\n const t_pos = Math.min(...data.map((d) => d.t_pos));\n const b_pos = Math.max(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n } else if (axisType == ColumnAxisType.HEIGHT) {\n const t_pos = Math.max(...data.map((d) => d.t_pos));\n const b_pos = Math.min(...data.map((d) => d.b_pos));\n return [b_pos, t_pos];\n }\n}\n\nfunction findAverageUnitHeight(\n data: UnitLong[],\n axisType: ColumnAxisType,\n): number {\n const unitHeights = data.map((d) => {\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n return Math.abs(b_pos - t_pos);\n });\n return unitHeights.reduce((a, b) => a + b, 0) / unitHeights.length;\n}\n\nexport interface CompositeColumnScale {\n (age: number): number | null;\n copy(): CompositeColumnScale;\n domain(): [number, number];\n invert(pixelHeight: number): number | null;\n clamp(clamp: boolean): void;\n}\n\nexport function createCompositeScale(\n sections: PackageLayoutData[],\n interpolateUnconformities: boolean = false,\n): CompositeColumnScale {\n /** Create a scale that works across multiple packages */\n\n const scales: ScaleContinuousNumeric<number, number>[] = [];\n\n let lastScale: ScaleContinuousNumeric<number, number> | null = null;\n for (const section of sections) {\n const _scale = section.scaleInfo.scale.copy().clamp(true);\n scales.push(_scale);\n if (lastScale != null && interpolateUnconformities) {\n // Add a new scale that interpolates between lastScale and _scale\n const lastDomain = lastScale.domain();\n const lastRange = lastScale.range();\n const currentDomain = _scale.domain();\n const currentRange = _scale.range();\n\n const interpScale = scaleLinear()\n .domain([lastDomain[lastDomain.length - 1], currentDomain[0]])\n .range([lastRange[lastRange.length - 1], currentRange[0]])\n .clamp(true);\n scales.push(interpScale);\n }\n lastScale = _scale;\n }\n\n const scale: CompositeColumnScale = (age) => {\n for (const s of scales) {\n const domain = s.domain();\n if (\n domain[0] < domain[domain.length - 1] &&\n age >= domain[0] &&\n age <= domain[domain.length - 1]\n ) {\n // Age axes\n return s(age);\n } else if (age <= domain[0] && age >= domain[domain.length - 1]) {\n // Normal axes like height\n return s(age);\n }\n }\n return null;\n };\n\n scale.copy = () => {\n return createCompositeScale(sections, interpolateUnconformities);\n };\n\n scale.domain = () => {\n /** Return the domain of the scale */\n const vals = sections.flatMap((d) => d.scaleInfo.domain);\n if (vals[0] < vals[vals.length - 1]) {\n // age axes\n return [Math.min(...vals), Math.max(...vals)];\n }\n // Normal axes like height\n return [Math.max(...vals), Math.min(...vals)];\n };\n\n scale.invert = (pixelHeight) => {\n /** Invert the scale to get the age at a given pixel height */\n // Iterate through the sections to find the correct one\n for (const scale of scales) {\n const range = scale.range();\n if (\n pixelHeight > Math.min(...range) &&\n pixelHeight <= Math.max(...range)\n ) {\n //console.log(\"Inverting scale at pixel height\", pixelHeight);\n return scale.invert(pixelHeight);\n }\n }\n return null;\n };\n\n scale.clamp = (clamp: boolean) => {\n /** Clamp all constituent scales */\n for (const s of scales) {\n s.clamp(clamp);\n }\n };\n\n return scale;\n}\n\n/** Collapse sections separated by unconformities that are smaller than a given pixel height. */\nexport function collapseUnconformitiesByPixelHeight<T extends UnitLong>(\n sections: SectionInfoWithScale<T>[],\n threshold: number,\n opts: ColumnScaleOptions,\n): SectionInfoWithScale<T>[] {\n const newSections = [];\n let currentSection: SectionInfoWithScale<T> | null = null;\n for (const nextSection of sections) {\n if (currentSection == null) {\n currentSection = nextSection;\n continue;\n }\n let heights: [number, number];\n let pxHeights: [number, number];\n if (opts.axisType !== ColumnAxisType.AGE) {\n heights = [nextSection.t_pos, currentSection.b_pos];\n } else {\n heights = [nextSection.t_age, currentSection.b_age];\n }\n\n const _diff = (vals: number[]) => {\n return Math.abs(vals[0] - vals[1]);\n };\n\n pxHeights = [\n _diff(heights.map(nextSection.scaleInfo.scale)),\n _diff(heights.map(currentSection.scaleInfo.scale)),\n ];\n\n const pxHeight = Math.min(...pxHeights);\n\n if (pxHeight < threshold) {\n let t_pos: number;\n let b_pos: number;\n if (\n opts.axisType == ColumnAxisType.AGE ||\n opts.axisType == ColumnAxisType.DEPTH\n ) {\n t_pos = Math.min(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.max(currentSection.b_pos, nextSection.b_pos);\n } else {\n t_pos = Math.max(currentSection.t_pos, nextSection.t_pos);\n b_pos = Math.min(currentSection.b_pos, nextSection.b_pos);\n }\n\n // We need to merge the sections\n const compositeSection0: SectionInfo<T> = {\n units: [...currentSection.units, ...nextSection.units],\n section_id: [\n ...ensureArray(currentSection.section_id),\n ...ensureArray(nextSection.section_id),\n ],\n t_age: Math.min(currentSection.t_age, nextSection.t_age),\n b_age: Math.max(currentSection.b_age, nextSection.b_age),\n t_pos,\n b_pos,\n };\n\n currentSection = addScaleToSection(compositeSection0, opts);\n } else {\n // We need to keep the section\n newSections.push(currentSection);\n currentSection = nextSection;\n }\n }\n if (currentSection != null) {\n newSections.push(currentSection);\n }\n\n return newSections;\n}\n"],"names":["scale"],"mappings":"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"}
@@ -5,64 +5,97 @@ const columnComponents = require("@macrostrat/column-components");
5
5
  const utils = require("./utils.cjs");
6
6
  const stratigraphyUtils = require("@macrostrat/stratigraphy-utils");
7
7
  const dt = 1e-3;
8
- function preprocessUnits(section, axisType = columnComponents.ColumnAxisType.AGE) {
9
- let units = section.units;
10
- let divisions = units.map((...args) => extendDivision(...args, axisType));
11
- for (let d of divisions) {
12
- const overlappingUnits = divisions.filter(
13
- (u) => d.overlappingUnits.includes(u.unit_id)
14
- );
15
- const columns = overlappingUnits.map((d2) => d2.column);
16
- if (columns.includes(d.column)) {
17
- let col = 0;
18
- while (columns.includes(col)) {
19
- col++;
20
- }
21
- d.column ??= col;
22
- }
23
- const [b_pos, t_pos] = utils.getUnitHeightRange(d, axisType);
24
- if (axisType == columnComponents.ColumnAxisType.AGE) {
25
- if (b_pos > section.b_age) {
26
- d.b_clip_pos = section.b_age;
27
- }
28
- if (t_pos < section.t_age) {
29
- d.t_clip_pos = section.t_age;
8
+ class UnitGroup {
9
+ units;
10
+ constructor(units) {
11
+ this.units = units;
12
+ }
13
+ get t_age() {
14
+ return Math.min(...this.units.map((d) => d.t_age));
15
+ }
16
+ get b_age() {
17
+ return Math.max(...this.units.map((d) => d.b_age));
18
+ }
19
+ getUnits() {
20
+ return assignColumnsToUnitsWithinOverlappingGroup(this);
21
+ }
22
+ }
23
+ function groupUnitsByMutualOverlap(units, tolerance = dt) {
24
+ const sections = groupUnitsIntoSectionsByOverlap(
25
+ units,
26
+ columnComponents.ColumnAxisType.AGE,
27
+ tolerance
28
+ );
29
+ return sections.map((d) => {
30
+ return new UnitGroup(d.units);
31
+ });
32
+ }
33
+ const sortByAge = utils.createUnitSorter(columnComponents.ColumnAxisType.AGE);
34
+ function assignColumnsToUnitsWithinOverlappingGroup(group2) {
35
+ const sortedUnits = [...group2.units].sort((a, b) => b.b_age - a.b_age);
36
+ const columns = [];
37
+ for (const unit of sortedUnits) {
38
+ let didAddToExistingColumn = false;
39
+ for (const column of columns) {
40
+ const lastUnit = column[column.length - 1];
41
+ if (!utils.unitsOverlap(unit, lastUnit, columnComponents.ColumnAxisType.AGE, dt)) {
42
+ column.push(unit);
43
+ didAddToExistingColumn = true;
44
+ break;
30
45
  }
31
46
  }
32
- if (axisType == columnComponents.ColumnAxisType.DEPTH) {
33
- if (b_pos > section.b_pos) {
34
- d.b_clip_pos = section.b_pos;
35
- }
36
- if (t_pos < section.t_pos) {
37
- d.t_clip_pos = section.t_pos;
38
- }
47
+ if (!didAddToExistingColumn) {
48
+ columns.push([unit]);
39
49
  }
40
50
  }
41
- return divisions;
51
+ const units = columns.flatMap(
52
+ (column, columnIndex) => column.map((unit) => {
53
+ return {
54
+ ...unit,
55
+ overlap: {
56
+ column: columnIndex,
57
+ nColumns: columns.length,
58
+ unitGroup: group2
59
+ }
60
+ };
61
+ })
62
+ );
63
+ return units.toSorted(sortByAge);
42
64
  }
43
- function extendDivision(unit, i, divisions, axisType = columnComponents.ColumnAxisType.AGE) {
65
+ function preprocessUnits(section, axisType = columnComponents.ColumnAxisType.AGE) {
66
+ let units = section.units;
44
67
  let tolerance = 1e-3;
45
68
  if (axisType != columnComponents.ColumnAxisType.AGE) {
46
69
  tolerance = 0.01;
47
70
  }
48
- const overlappingUnits = divisions.filter(
49
- (d) => d.unit_id != unit.unit_id && utils.unitsOverlap(unit, d, axisType, tolerance)
71
+ const unitGroups = groupUnitsByMutualOverlap(units, tolerance);
72
+ const divisions = [];
73
+ for (const group2 of unitGroups) {
74
+ divisions.push(...group2.getUnits());
75
+ }
76
+ return divisions.map(
77
+ (d) => enhanceUnitWithClippingPosition(section, d, axisType)
50
78
  );
51
- const u_pos = utils.getUnitHeightRange(unit, axisType);
52
- const bottomOverlap = overlappingUnits.some((d) => {
53
- const d_pos = utils.getUnitHeightRange(d, axisType);
54
- return d_pos[0] < u_pos[0] + dt;
55
- });
56
- let column = 0;
57
- if (overlappingUnits.length == 1) {
58
- column = 1;
79
+ }
80
+ function enhanceUnitWithClippingPosition(section, d, axisType) {
81
+ const [b_pos, t_pos] = utils.getUnitHeightRange(d, axisType);
82
+ if (axisType == columnComponents.ColumnAxisType.AGE) {
83
+ if (b_pos > section.b_age) {
84
+ d.b_clip_pos = section.b_age;
85
+ }
86
+ if (t_pos < section.t_age) {
87
+ d.t_clip_pos = section.t_age;
88
+ }
59
89
  }
60
- return {
61
- ...unit,
62
- bottomOverlap,
63
- column: unit.column ?? column,
64
- overlappingUnits: overlappingUnits.map((d) => d.unit_id)
65
- };
90
+ if (axisType == columnComponents.ColumnAxisType.DEPTH) {
91
+ if (b_pos > section.b_pos) {
92
+ d.b_clip_pos = section.b_pos;
93
+ }
94
+ if (t_pos < section.t_pos) {
95
+ d.t_clip_pos = section.t_pos;
96
+ }
97
+ }
98
+ return d;
66
99
  }
67
100
  function groupUnitsIntoSectionsBySectionID(units, axisType = columnComponents.ColumnAxisType.AGE) {
68
101
  let groups = Array.from(d3Array.group(units, (d) => d.section_id));
@@ -77,12 +110,12 @@ function groupUnitsIntoSectionsBySectionID(units, axisType = columnComponents.Co
77
110
  groups1.sort(compareSections);
78
111
  return groups1;
79
112
  }
80
- function groupUnitsIntoSectionsByOverlap(units, axisType = columnComponents.ColumnAxisType.AGE) {
113
+ function groupUnitsIntoSectionsByOverlap(units, axisType = columnComponents.ColumnAxisType.AGE, tolerance = dt) {
81
114
  const sectionList = [];
82
115
  for (const unit of units) {
83
116
  const heightRange = utils.getUnitHeightRange(unit, axisType);
84
117
  let section = sectionList.find(
85
- (s) => stratigraphyUtils.compareAgeRanges(heightRange, s.heightRange) !== stratigraphyUtils.AgeRangeRelationship.Disjoint
118
+ (s) => stratigraphyUtils.compareAgeRanges(heightRange, s.heightRange, tolerance) !== stratigraphyUtils.AgeRangeRelationship.Disjoint
86
119
  );
87
120
  if (section == null) {
88
121
  sectionList.push({
@@ -188,6 +221,7 @@ function preprocessSectionUnit(unit) {
188
221
  unit_name
189
222
  };
190
223
  }
224
+ exports.enhanceUnitWithClippingPosition = enhanceUnitWithClippingPosition;
191
225
  exports.getSectionAgeRange = getSectionAgeRange;
192
226
  exports.getSectionPosRange = getSectionPosRange;
193
227
  exports.groupUnitsIntoSectionsByOverlap = groupUnitsIntoSectionsByOverlap;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.cjs","sources":["../../src/prepare-units/helpers.ts"],"sourcesContent":["import type { BaseUnit, UnitLong } from \"@macrostrat/api-types\";\nimport { group } from \"d3-array\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport {\n createUnitSorter,\n ensureArray,\n ensureRealFloat,\n getUnitHeightRange,\n unitsOverlap,\n} from \"./utils\";\nimport {\n AgeRangeRelationship,\n compareAgeRanges,\n} from \"@macrostrat/stratigraphy-utils\";\nimport type { ExtUnit, SectionInfo, StratigraphicPackage } from \"./types\";\n\nconst dt = 0.001;\n\nexport function preprocessUnits<T extends UnitLong = UnitLong>(\n section: SectionInfo<T>,\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): ExtUnit[] {\n /** Preprocess units to add overlapping units and columns. */\n let units = section.units;\n\n let divisions = units.map((...args) => extendDivision(...args, axisType));\n for (let d of divisions) {\n const overlappingUnits = divisions.filter((u) =>\n d.overlappingUnits.includes(u.unit_id),\n );\n\n // Overlapping columns\n const columns = overlappingUnits.map((d) => d.column);\n\n if (columns.includes(d.column)) {\n let col = 0;\n // Go through columns to find a better index\n while (columns.includes(col)) {\n col++;\n }\n d.column ??= col;\n }\n\n // If unit overlaps the edges of a section, set the clip positions\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n if (axisType == ColumnAxisType.AGE) {\n if (b_pos > section.b_age) {\n d.b_clip_pos = section.b_age;\n }\n if (t_pos < section.t_age) {\n d.t_clip_pos = section.t_age;\n }\n }\n if (axisType == ColumnAxisType.DEPTH) {\n if (b_pos > section.b_pos) {\n d.b_clip_pos = section.b_pos;\n }\n if (t_pos < section.t_pos) {\n d.t_clip_pos = section.t_pos;\n }\n }\n // if (axisType == ColumnAxisType.HEIGHT) {\n // if (b_pos < section.b_pos) {\n // d.b_clip_pos = section.b_pos;\n // }\n // if (t_pos > section.t_pos) {\n // d.t_clip_pos = section.t_pos;\n // }\n // }\n }\n\n return divisions;\n}\n\nfunction extendDivision(\n unit: UnitLong,\n i: number,\n divisions: UnitLong[],\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): ExtUnit {\n // TODO: make this configurable\n let tolerance = 0.001; // 1 kyr tolerance for age columns\n if (axisType != ColumnAxisType.AGE) {\n tolerance = 0.01; // 1cm tolerance for height/depth columns\n }\n\n const overlappingUnits = divisions.filter(\n (d) =>\n d.unit_id != unit.unit_id && unitsOverlap(unit, d, axisType, tolerance),\n );\n const u_pos = getUnitHeightRange(unit, axisType);\n const bottomOverlap = overlappingUnits.some((d) => {\n const d_pos = getUnitHeightRange(d, axisType);\n // Check if the unit is below the current unit\n return d_pos[0] < u_pos[0] + dt;\n });\n let column = 0;\n if (overlappingUnits.length == 1) {\n column = 1;\n }\n\n return {\n ...unit,\n bottomOverlap,\n column: unit.column ?? column,\n overlappingUnits: overlappingUnits.map((d) => d.unit_id),\n };\n}\n\nexport function groupUnitsIntoSectionsBySectionID<T extends UnitLong>(\n units: T[],\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): SectionInfo<T>[] {\n /** Group units into sections by section_id.\n * This works for large-scale Macrostrat columns, where units are grouped by section_id.\n * */\n let groups = Array.from(group(units, (d) => d.section_id));\n const unitComparator = createUnitSorter(axisType);\n\n const groups1 = groups.map(([section_id, sectionUnits]) => {\n const [b_age, t_age] = getSectionAgeRange(sectionUnits);\n const [b_pos, t_pos] = getSectionPosRange(sectionUnits, axisType);\n\n // sort units by position\n sectionUnits.sort(unitComparator);\n return { section_id, t_age, b_age, b_pos, t_pos, units: sectionUnits };\n });\n // Sort sections by increasing top age, then increasing bottom age.\n // Sections have no relative ordinal position other than age...\n const compareSections = createUnitSorter(axisType) as (\n a: StratigraphicPackage,\n b: StratigraphicPackage,\n ) => number;\n groups1.sort(compareSections);\n return groups1;\n}\n\ninterface WorkingSection {\n units: UnitLong[];\n // Position or age\n heightRange?: [number, number];\n}\n\nexport function groupUnitsIntoSectionsByOverlap<T extends UnitLong>(\n units: T[],\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): SectionInfo<T>[] {\n /** Group units into sections by overlap.\n * This creates \"synthetic\" sections that correspond to packages bound by scale gaps.\n * This is most useful in the height and depth domains, where gaps (e.g., missing core) are\n * common.\n * */\n // Start with each unit as its own \"section\", and progressively merge...\n const sectionList: WorkingSection[] = [];\n for (const unit of units) {\n // Check if the unit overlaps with any existing section\n const heightRange = getUnitHeightRange(unit, axisType);\n let section: WorkingSection | undefined = sectionList.find(\n (s) =>\n compareAgeRanges(heightRange, s.heightRange) !==\n AgeRangeRelationship.Disjoint,\n );\n if (section == null) {\n // No overlap, create a new section\n sectionList.push({\n heightRange,\n units: [unit],\n });\n } else {\n // Overlap, merge the unit into the section\n section.units.push(unit);\n // Update the height range\n if (axisType == ColumnAxisType.DEPTH || axisType == ColumnAxisType.AGE) {\n section.heightRange = [\n Math.max(section.heightRange[0], heightRange[0]),\n Math.min(section.heightRange[1], heightRange[1]),\n ];\n } else {\n section.heightRange = [\n Math.min(section.heightRange[0], heightRange[0]),\n Math.max(section.heightRange[1], heightRange[1]),\n ];\n }\n }\n }\n // We should have a section for each unit, now we can convert to SectionInfo\n // Ages have to be really actually ages, not heights\n\n return sectionList.map((section, i) => {\n const [b_age, t_age] = getSectionAgeRange(section.units);\n const [b_pos, t_pos] = getSectionPosRange(section.units, axisType);\n return {\n // Negative section IDs are used to indicate that these are synthetic sections\n section_id: -i,\n t_age,\n b_age,\n t_pos,\n b_pos,\n units: section.units as T[],\n };\n });\n}\n\nexport function getSectionPosRange(\n units: BaseUnit[],\n axisType: ColumnAxisType,\n): [number, number] {\n /** Get the overall position range of a set of units. */\n const t_positions = units.map((d) => {\n switch (axisType) {\n case ColumnAxisType.AGE:\n return d.t_age;\n case ColumnAxisType.DEPTH:\n case ColumnAxisType.HEIGHT:\n case ColumnAxisType.ORDINAL:\n return d.t_pos;\n default:\n throw new Error(`Unknown axis type: ${axisType}`);\n }\n });\n const b_positions = units.map((d) => {\n switch (axisType) {\n case ColumnAxisType.AGE:\n return d.b_age;\n case ColumnAxisType.DEPTH:\n case ColumnAxisType.HEIGHT:\n case ColumnAxisType.ORDINAL:\n return d.b_pos;\n default:\n throw new Error(`Unknown axis type: ${axisType}`);\n }\n });\n if (axisType == ColumnAxisType.AGE || axisType == ColumnAxisType.DEPTH) {\n return [Math.max(...b_positions), Math.min(...t_positions)];\n } else {\n return [Math.min(...b_positions), Math.max(...t_positions)];\n }\n}\n\nexport function getSectionAgeRange(units: BaseUnit[]): [number, number] {\n /** Get the overall age range of a set of units. */\n return getSectionPosRange(units, ColumnAxisType.AGE);\n}\n\nexport function mergeOverlappingSections<T extends UnitLong>(\n sections: SectionInfo<T>[],\n): SectionInfo<T>[] {\n /** Columns can have sections that overlap in time. Here, we merge overlapping\n * sections into a single section to correctly render gap-bound packages.\n */\n const [firstSection, ...rest] = sections;\n const newSections = [firstSection];\n for (const section of rest) {\n const lastSection = newSections[newSections.length - 1];\n if (\n lastSection.b_age < section.t_age ||\n lastSection.t_age > section.b_age\n ) {\n // No overlap, add the section as normal\n newSections.push(section);\n continue;\n }\n\n // Overlap, merge the sections\n lastSection.section_id = [\n ...ensureArray(lastSection.section_id),\n ...ensureArray(section.section_id),\n ];\n lastSection.units.push(...section.units);\n lastSection.b_age = Math.max(lastSection.b_age, section.b_age);\n lastSection.t_age = Math.min(lastSection.t_age, section.t_age);\n }\n return newSections;\n}\n\nexport function preprocessSectionUnit(unit: UnitLong): UnitLong {\n /** Preprocess a single unit for a \"section\" column type.\n * This mostly handles vagaries of eODP-style columns.\n * */\n\n let b_pos = unit.b_pos;\n let t_pos = unit.t_pos;\n\n let unit_name = unit.unit_name;\n\n // eODP columns sometimes have overlapping core sections, which are encoded in the name field\n // Match eODP section names\n const match = unit.unit_name.match(/^(\\d+(\\.\\d+)?)-(\\d+(\\.\\d+)?): (.+)/);\n\n if (match) {\n // These values should already be set if we've used the show_positions flag\n t_pos ??= ensureRealFloat(match[1]);\n b_pos ??= ensureRealFloat(match[3]);\n unit_name = match[5];\n }\n\n return {\n ...unit,\n b_pos: ensureRealFloat(b_pos),\n t_pos: ensureRealFloat(t_pos),\n unit_name,\n };\n}\n"],"names":["ColumnAxisType","d","getUnitHeightRange","unitsOverlap","group","createUnitSorter","compareAgeRanges","AgeRangeRelationship","ensureArray","ensureRealFloat"],"mappings":"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"}
1
+ {"version":3,"file":"helpers.cjs","sources":["../../src/prepare-units/helpers.ts"],"sourcesContent":["import type { BaseUnit, UnitLong } from \"@macrostrat/api-types\";\nimport { group } from \"d3-array\";\nimport { ColumnAxisType } from \"@macrostrat/column-components\";\nimport {\n createUnitSorter,\n ensureArray,\n ensureRealFloat,\n getUnitHeightRange,\n unitsOverlap,\n} from \"./utils\";\nimport {\n AgeRangeRelationship,\n compareAgeRanges,\n} from \"@macrostrat/stratigraphy-utils\";\nimport type { ExtUnit, SectionInfo, StratigraphicPackage } from \"./types\";\n\nconst dt = 0.001;\n\nexport type UnitWithDefinedOverlap<T extends BaseUnit> = T & {\n overlap: UnitOverlapInfo<T>;\n};\n\ntype UnitOverlapInfo<T extends BaseUnit> = {\n column: number;\n nColumns: number;\n unitGroup: UnitGroup<T>;\n};\n\nclass UnitGroup<T extends BaseUnit> implements StratigraphicPackage {\n units: T[];\n\n constructor(units: T[]) {\n this.units = units;\n }\n\n get t_age(): number {\n return Math.min(...this.units.map((d) => d.t_age));\n }\n\n get b_age(): number {\n return Math.max(...this.units.map((d) => d.b_age));\n }\n\n getUnits(): UnitWithDefinedOverlap<T>[] {\n return assignColumnsToUnitsWithinOverlappingGroup(this);\n }\n}\n\nfunction groupUnitsByMutualOverlap<T extends BaseUnit>(\n units: T[],\n tolerance: number = dt,\n): UnitGroup<T>[] {\n /** Group units within a section that have mutual overlap. */\n const sections = groupUnitsIntoSectionsByOverlap(\n units,\n ColumnAxisType.AGE,\n tolerance,\n );\n return sections.map((d) => {\n return new UnitGroup(d.units);\n });\n}\n\nconst sortByAge = createUnitSorter(ColumnAxisType.AGE);\n\nfunction assignColumnsToUnitsWithinOverlappingGroup<T extends BaseUnit>(\n group: UnitGroup<T>,\n): UnitWithDefinedOverlap<T>[] {\n /** A relatively naïve function to assign columns to units within a mutually overlapping group.\n * This gets the number of columns that would be needed to accommodate the units in the group.\n * It then assigns columns to units in the group based on the number of columns needed, with\n * lower units further to the left.\n */\n\n const sortedUnits = [...group.units].sort((a, b) => b.b_age - a.b_age);\n\n const columns: T[][] = [];\n\n for (const unit of sortedUnits) {\n // Find a column that is not already occupied by an overlapping unit\n let didAddToExistingColumn = false;\n for (const column of columns) {\n const lastUnit = column[column.length - 1];\n if (!unitsOverlap(unit, lastUnit, ColumnAxisType.AGE, dt)) {\n column.push(unit);\n didAddToExistingColumn = true;\n break;\n }\n }\n if (!didAddToExistingColumn) {\n columns.push([unit]);\n }\n }\n\n const units: UnitWithDefinedOverlap<T>[] = columns.flatMap(\n (column, columnIndex) =>\n column.map((unit) => {\n return {\n ...unit,\n overlap: {\n column: columnIndex,\n nColumns: columns.length,\n unitGroup: group,\n },\n };\n }),\n );\n\n return units.toSorted(sortByAge);\n}\n\nexport function preprocessUnits<T extends UnitLong = UnitLong>(\n section: SectionInfo<T>,\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): ExtUnit[] {\n /** Preprocess units to add overlapping units and columns. */\n let units = section.units;\n\n let tolerance = 0.001; // 1 kyr tolerance for age columns\n if (axisType != ColumnAxisType.AGE) {\n tolerance = 0.01; // 1cm tolerance for height/depth columns\n }\n\n const unitGroups = groupUnitsByMutualOverlap(units, tolerance);\n\n const divisions: any[] = [];\n // Serialize all groups' units to a single array\n for (const group of unitGroups) {\n divisions.push(...group.getUnits());\n }\n\n return divisions.map((d) =>\n enhanceUnitWithClippingPosition(section, d, axisType),\n );\n}\n\nexport function enhanceUnitWithClippingPosition(section, d, axisType) {\n const [b_pos, t_pos] = getUnitHeightRange(d, axisType);\n if (axisType == ColumnAxisType.AGE) {\n if (b_pos > section.b_age) {\n d.b_clip_pos = section.b_age;\n }\n if (t_pos < section.t_age) {\n d.t_clip_pos = section.t_age;\n }\n }\n if (axisType == ColumnAxisType.DEPTH) {\n if (b_pos > section.b_pos) {\n d.b_clip_pos = section.b_pos;\n }\n if (t_pos < section.t_pos) {\n d.t_clip_pos = section.t_pos;\n }\n }\n return d;\n}\n\nexport function groupUnitsIntoSectionsBySectionID<T extends UnitLong>(\n units: T[],\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n): SectionInfo<T>[] {\n /** Group units into sections by section_id.\n * This works for large-scale Macrostrat columns, where units are grouped by section_id.\n * */\n let groups = Array.from(group(units, (d) => d.section_id));\n const unitComparator = createUnitSorter(axisType);\n\n const groups1 = groups.map(([section_id, sectionUnits]) => {\n const [b_age, t_age] = getSectionAgeRange(sectionUnits);\n const [b_pos, t_pos] = getSectionPosRange(sectionUnits, axisType);\n\n // sort units by position\n sectionUnits.sort(unitComparator);\n return { section_id, t_age, b_age, b_pos, t_pos, units: sectionUnits };\n });\n // Sort sections by increasing top age, then increasing bottom age.\n // Sections have no relative ordinal position other than age...\n const compareSections = createUnitSorter(axisType) as (\n a: StratigraphicPackage,\n b: StratigraphicPackage,\n ) => number;\n groups1.sort(compareSections);\n return groups1;\n}\n\ninterface WorkingSection {\n units: UnitLong[];\n // Position or age\n heightRange?: [number, number];\n}\n\nexport function groupUnitsIntoSectionsByOverlap<T extends BaseUnit>(\n units: T[],\n axisType: ColumnAxisType = ColumnAxisType.AGE,\n tolerance: number = dt,\n): SectionInfo<T>[] {\n /** Group units into sections by overlap.\n * This creates \"synthetic\" sections that correspond to packages bound by scale gaps.\n * This is most useful in the height and depth domains, where gaps (e.g., missing core) are\n * common.\n * */\n // Start with each unit as its own \"section\", and progressively merge...\n const sectionList: WorkingSection[] = [];\n for (const unit of units) {\n // Check if the unit overlaps with any existing section\n const heightRange = getUnitHeightRange(unit, axisType);\n let section: WorkingSection | undefined = sectionList.find(\n (s) =>\n compareAgeRanges(heightRange, s.heightRange, tolerance) !==\n AgeRangeRelationship.Disjoint,\n );\n if (section == null) {\n // No overlap, create a new section\n sectionList.push({\n heightRange,\n units: [unit],\n });\n } else {\n // Overlap, merge the unit into the section\n section.units.push(unit);\n // Update the height range\n if (axisType == ColumnAxisType.DEPTH || axisType == ColumnAxisType.AGE) {\n section.heightRange = [\n Math.max(section.heightRange[0], heightRange[0]),\n Math.min(section.heightRange[1], heightRange[1]),\n ];\n } else {\n section.heightRange = [\n Math.min(section.heightRange[0], heightRange[0]),\n Math.max(section.heightRange[1], heightRange[1]),\n ];\n }\n }\n }\n // We should have a section for each unit, now we can convert to SectionInfo\n // Ages have to be really actually ages, not heights\n\n return sectionList.map((section, i) => {\n const [b_age, t_age] = getSectionAgeRange(section.units);\n const [b_pos, t_pos] = getSectionPosRange(section.units, axisType);\n return {\n // Negative section IDs are used to indicate that these are synthetic sections\n section_id: -i,\n t_age,\n b_age,\n t_pos,\n b_pos,\n units: section.units as T[],\n };\n });\n}\n\nexport function getSectionPosRange(\n units: BaseUnit[],\n axisType: ColumnAxisType,\n): [number, number] {\n /** Get the overall position range of a set of units. */\n const t_positions = units.map((d) => {\n switch (axisType) {\n case ColumnAxisType.AGE:\n return d.t_age;\n case ColumnAxisType.DEPTH:\n case ColumnAxisType.HEIGHT:\n case ColumnAxisType.ORDINAL:\n return d.t_pos;\n default:\n throw new Error(`Unknown axis type: ${axisType}`);\n }\n });\n const b_positions = units.map((d) => {\n switch (axisType) {\n case ColumnAxisType.AGE:\n return d.b_age;\n case ColumnAxisType.DEPTH:\n case ColumnAxisType.HEIGHT:\n case ColumnAxisType.ORDINAL:\n return d.b_pos;\n default:\n throw new Error(`Unknown axis type: ${axisType}`);\n }\n });\n if (axisType == ColumnAxisType.AGE || axisType == ColumnAxisType.DEPTH) {\n return [Math.max(...b_positions), Math.min(...t_positions)];\n } else {\n return [Math.min(...b_positions), Math.max(...t_positions)];\n }\n}\n\nexport function getSectionAgeRange(units: BaseUnit[]): [number, number] {\n /** Get the overall age range of a set of units. */\n return getSectionPosRange(units, ColumnAxisType.AGE);\n}\n\nexport function mergeOverlappingSections<T extends UnitLong>(\n sections: SectionInfo<T>[],\n): SectionInfo<T>[] {\n /** Columns can have sections that overlap in time. Here, we merge overlapping\n * sections into a single section to correctly render gap-bound packages.\n */\n const [firstSection, ...rest] = sections;\n const newSections = [firstSection];\n for (const section of rest) {\n const lastSection = newSections[newSections.length - 1];\n if (\n lastSection.b_age < section.t_age ||\n lastSection.t_age > section.b_age\n ) {\n // No overlap, add the section as normal\n newSections.push(section);\n continue;\n }\n\n // Overlap, merge the sections\n lastSection.section_id = [\n ...ensureArray(lastSection.section_id),\n ...ensureArray(section.section_id),\n ];\n lastSection.units.push(...section.units);\n lastSection.b_age = Math.max(lastSection.b_age, section.b_age);\n lastSection.t_age = Math.min(lastSection.t_age, section.t_age);\n }\n return newSections;\n}\n\nexport function preprocessSectionUnit(unit: UnitLong): UnitLong {\n /** Preprocess a single unit for a \"section\" column type.\n * This mostly handles vagaries of eODP-style columns.\n * */\n\n let b_pos = unit.b_pos;\n let t_pos = unit.t_pos;\n\n let unit_name = unit.unit_name;\n\n // eODP columns sometimes have overlapping core sections, which are encoded in the name field\n // Match eODP section names\n const match = unit.unit_name.match(/^(\\d+(\\.\\d+)?)-(\\d+(\\.\\d+)?): (.+)/);\n\n if (match) {\n // These values should already be set if we've used the show_positions flag\n t_pos ??= ensureRealFloat(match[1]);\n b_pos ??= ensureRealFloat(match[3]);\n unit_name = match[5];\n }\n\n return {\n ...unit,\n b_pos: ensureRealFloat(b_pos),\n t_pos: ensureRealFloat(t_pos),\n unit_name,\n };\n}\n"],"names":["ColumnAxisType","createUnitSorter","group","unitsOverlap","getUnitHeightRange","compareAgeRanges","AgeRangeRelationship","ensureArray","ensureRealFloat"],"mappings":"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"}
@@ -1,10 +1,27 @@
1
1
  import { BaseUnit, UnitLong } from '@macrostrat/api-types';
2
2
  import { ColumnAxisType } from '@macrostrat/column-components';
3
- import { ExtUnit, SectionInfo } from './types';
3
+ import { ExtUnit, SectionInfo, StratigraphicPackage } from './types';
4
+ export type UnitWithDefinedOverlap<T extends BaseUnit> = T & {
5
+ overlap: UnitOverlapInfo<T>;
6
+ };
7
+ type UnitOverlapInfo<T extends BaseUnit> = {
8
+ column: number;
9
+ nColumns: number;
10
+ unitGroup: UnitGroup<T>;
11
+ };
12
+ declare class UnitGroup<T extends BaseUnit> implements StratigraphicPackage {
13
+ units: T[];
14
+ constructor(units: T[]);
15
+ get t_age(): number;
16
+ get b_age(): number;
17
+ getUnits(): UnitWithDefinedOverlap<T>[];
18
+ }
4
19
  export declare function preprocessUnits<T extends UnitLong = UnitLong>(section: SectionInfo<T>, axisType?: ColumnAxisType): ExtUnit[];
20
+ export declare function enhanceUnitWithClippingPosition(section: any, d: any, axisType: any): any;
5
21
  export declare function groupUnitsIntoSectionsBySectionID<T extends UnitLong>(units: T[], axisType?: ColumnAxisType): SectionInfo<T>[];
6
- export declare function groupUnitsIntoSectionsByOverlap<T extends UnitLong>(units: T[], axisType?: ColumnAxisType): SectionInfo<T>[];
22
+ export declare function groupUnitsIntoSectionsByOverlap<T extends BaseUnit>(units: T[], axisType?: ColumnAxisType, tolerance?: number): SectionInfo<T>[];
7
23
  export declare function getSectionPosRange(units: BaseUnit[], axisType: ColumnAxisType): [number, number];
8
24
  export declare function getSectionAgeRange(units: BaseUnit[]): [number, number];
9
25
  export declare function mergeOverlappingSections<T extends UnitLong>(sections: SectionInfo<T>[]): SectionInfo<T>[];
10
26
  export declare function preprocessSectionUnit(unit: UnitLong): UnitLong;
27
+ export {};