@macrostrat/column-views 3.3.5 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/column.cjs +2 -1
- package/dist/column.cjs.map +1 -1
- package/dist/column.js +2 -1
- package/dist/column.js.map +1 -1
- package/dist/data-provider/unit-selection.cjs +7 -3
- package/dist/data-provider/unit-selection.cjs.map +1 -1
- package/dist/data-provider/unit-selection.d.ts +1 -0
- package/dist/data-provider/unit-selection.js +7 -3
- package/dist/data-provider/unit-selection.js.map +1 -1
- package/dist/index.cjs +13 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-units/helpers.cjs +83 -49
- package/dist/prepare-units/helpers.cjs.map +1 -1
- package/dist/prepare-units/helpers.d.ts +19 -2
- package/dist/prepare-units/helpers.js +84 -50
- package/dist/prepare-units/helpers.js.map +1 -1
- package/dist/prepare-units/index.cjs.map +1 -1
- package/dist/prepare-units/index.js.map +1 -1
- package/dist/section.cjs +1 -2
- package/dist/section.cjs.map +1 -1
- package/dist/section.js +1 -2
- package/dist/section.js.map +1 -1
- package/dist/unit-details/identifiers.cjs +56 -0
- package/dist/unit-details/identifiers.cjs.map +1 -0
- package/dist/unit-details/identifiers.d.ts +31 -0
- package/dist/unit-details/identifiers.js +54 -0
- package/dist/unit-details/identifiers.js.map +1 -0
- package/dist/unit-details/index.d.ts +2 -0
- package/dist/unit-details/panel.cjs +11 -88
- package/dist/unit-details/panel.cjs.map +1 -1
- package/dist/unit-details/panel.d.ts +3 -19
- package/dist/unit-details/panel.js +10 -87
- package/dist/unit-details/panel.js.map +1 -1
- package/dist/unit-details/popover.cjs +1 -2
- package/dist/unit-details/popover.cjs.map +1 -1
- package/dist/unit-details/popover.js +2 -3
- package/dist/unit-details/popover.js.map +1 -1
- package/dist/unit-details/strat-names.cjs +44 -0
- package/dist/unit-details/strat-names.cjs.map +1 -0
- package/dist/unit-details/strat-names.d.ts +14 -0
- package/dist/unit-details/strat-names.js +42 -0
- package/dist/unit-details/strat-names.js.map +1 -0
- package/dist/units/index.cjs +20 -6
- package/dist/units/index.cjs.map +1 -1
- package/dist/units/index.d.ts +11 -20
- package/dist/units/index.js +20 -6
- package/dist/units/index.js.map +1 -1
- package/package.json +14 -14
- package/src/column.ts +1 -1
- package/src/data-provider/unit-selection.ts +8 -4
- package/src/prepare-units/helpers.ts +121 -72
- package/src/prepare-units/index.ts +1 -1
- package/src/section.ts +0 -1
- package/src/unit-details/identifiers.ts +67 -0
- package/src/unit-details/index.ts +2 -0
- package/src/unit-details/panel.ts +13 -126
- package/src/unit-details/popover.ts +2 -7
- package/src/unit-details/strat-names.ts +57 -0
- package/src/units/index.ts +31 -8
package/dist/units/index.js
CHANGED
|
@@ -34,13 +34,27 @@ function BasicUnitComponent({ division, ...rest }) {
|
|
|
34
34
|
patternID: division.patternID
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
-
function UnitComponent({
|
|
37
|
+
function UnitComponent({
|
|
38
|
+
division,
|
|
39
|
+
nColumns = 2,
|
|
40
|
+
...rest
|
|
41
|
+
}) {
|
|
38
42
|
const width = rest.width ?? useColumnLayout()?.width;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
let _nColumns = nColumns;
|
|
44
|
+
if (isNaN(_nColumns)) {
|
|
45
|
+
_nColumns = 2;
|
|
46
|
+
}
|
|
47
|
+
let columnIx = 0;
|
|
48
|
+
let x = 0;
|
|
49
|
+
console.log(rest, _nColumns, width);
|
|
50
|
+
let reducedWidth = _nColumns;
|
|
51
|
+
if ("overlap" in division) {
|
|
52
|
+
const overlap = division.overlap;
|
|
53
|
+
_nColumns = Math.min(_nColumns, overlap.nColumns);
|
|
54
|
+
columnIx = overlap.column;
|
|
55
|
+
reducedWidth = width / _nColumns;
|
|
56
|
+
x = columnIx * width / _nColumns;
|
|
57
|
+
}
|
|
44
58
|
return h(TrackedLabeledUnit, {
|
|
45
59
|
division,
|
|
46
60
|
...rest,
|
package/dist/units/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/units/index.ts"],"sourcesContent":["import h from \"@macrostrat/hyper\";\nimport {\n LithologyColumn,\n useGeologicPattern,\n} from \"@macrostrat/column-components\";\nimport { UnitNamesColumn } from \"./names\";\nimport { ICompositeUnitProps } from \"./composite\";\nimport { UnitBoxes, UnitProps } from \"./boxes\";\nimport { useColumnLayout } from \"@macrostrat/column-components\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { getMixedUnitColor } from \"./colors\";\nimport { TrackedLabeledUnit } from \"./composite\";\nimport { useEnvironments, useLithologies } from \"@macrostrat/data-provider\";\nimport { useMemo } from \"react\";\nimport { resolveID } from \"./resolvers\";\nimport { Lithology } from \"@macrostrat/api-types\";\n\nexport * from \"./composite\";\nexport * from \"./types\";\nexport * from \"./colors\";\n\nexport function UnitsColumn({ width = 100 }) {\n /*\n A column showing units with USGS color fill\n */\n return h(LithologyColumn, { width }, h(UnitBoxes));\n}\n\nexport function SimpleUnitsColumn(props: ICompositeUnitProps) {\n /*\n A column with units and names either\n overlapping or offset to the right\n */\n const { columnWidth, width, gutterWidth = 0, labelOffset = 30 } = props;\n\n return h([\n h(UnitsColumn, {\n width: columnWidth,\n }),\n h(UnitNamesColumn, {\n transform: `translate(${columnWidth + gutterWidth})`,\n paddingLeft: labelOffset,\n width: width - columnWidth - gutterWidth,\n }),\n ]);\n}\n\nexport function BasicUnitComponent({ division, ...rest }) {\n /** A unit that allows directly setting colors and patterns. */\n\n return h(UnitComponent, {\n division,\n ...rest,\n backgroundColor: division.color,\n patternID: division.patternID,\n });\n}\n\nexport function UnitComponent({
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/units/index.ts"],"sourcesContent":["import h from \"@macrostrat/hyper\";\nimport {\n LithologyColumn,\n useGeologicPattern,\n} from \"@macrostrat/column-components\";\nimport { UnitNamesColumn } from \"./names\";\nimport { ICompositeUnitProps } from \"./composite\";\nimport { UnitBoxes, UnitProps } from \"./boxes\";\nimport { useColumnLayout } from \"@macrostrat/column-components\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { getMixedUnitColor } from \"./colors\";\nimport { TrackedLabeledUnit } from \"./composite\";\nimport { useEnvironments, useLithologies } from \"@macrostrat/data-provider\";\nimport { useMemo } from \"react\";\nimport { resolveID } from \"./resolvers\";\nimport { BaseUnit, Lithology } from \"@macrostrat/api-types\";\nimport { UnitWithDefinedOverlap } from \"../prepare-units/helpers.ts\";\n\nexport * from \"./composite\";\nexport * from \"./types\";\nexport * from \"./colors\";\n\nexport function UnitsColumn({ width = 100 }) {\n /*\n A column showing units with USGS color fill\n */\n return h(LithologyColumn, { width }, h(UnitBoxes));\n}\n\nexport function SimpleUnitsColumn(props: ICompositeUnitProps) {\n /*\n A column with units and names either\n overlapping or offset to the right\n */\n const { columnWidth, width, gutterWidth = 0, labelOffset = 30 } = props;\n\n return h([\n h(UnitsColumn, {\n width: columnWidth,\n }),\n h(UnitNamesColumn, {\n transform: `translate(${columnWidth + gutterWidth})`,\n paddingLeft: labelOffset,\n width: width - columnWidth - gutterWidth,\n }),\n ]);\n}\n\nexport function BasicUnitComponent({ division, ...rest }) {\n /** A unit that allows directly setting colors and patterns. */\n\n return h(UnitComponent, {\n division,\n ...rest,\n backgroundColor: division.color,\n patternID: division.patternID,\n });\n}\n\ninterface UnitComponentProps<T extends BaseUnit> {\n division: UnitWithDefinedOverlap<T> | T;\n nColumns: number;\n width?: number;\n}\n\nexport function UnitComponent<T extends BaseUnit>({\n division,\n nColumns = 2,\n ...rest\n}: UnitComponentProps<T>) {\n const width = rest.width ?? useColumnLayout()?.width;\n\n let _nColumns = nColumns;\n if (isNaN(_nColumns)) {\n _nColumns = 2;\n }\n let columnIx = 0;\n let x = 0;\n\n console.log(rest, _nColumns, width);\n\n let reducedWidth = _nColumns;\n //const nOverlappingUnits = division.overlappingUnits?.length ?? 0;\n if (\"overlap\" in division) {\n const overlap = division.overlap;\n _nColumns = Math.min(_nColumns, overlap.nColumns);\n columnIx = overlap.column;\n reducedWidth = width / _nColumns;\n x = (columnIx * width) / _nColumns;\n }\n return h(TrackedLabeledUnit, {\n division,\n ...rest,\n width: reducedWidth,\n x,\n });\n}\n\ninterface UnitColorOptions {\n asBackground?: boolean;\n}\n\nexport function useUnitColor(unit, opts: UnitColorOptions = {}): string | null {\n /** Get the color for a unit based on its lithology */\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || lithMap == null) return null;\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, lithMap, inDarkMode, asBackground]);\n}\n\nexport function ColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColor(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nexport function useUnitColorByEnvironment(\n unit,\n opts: UnitColorOptions = {},\n): string | null {\n /** Get the color for a unit based on its lithology */\n const environmentMap = useEnvironments();\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || environmentMap == null) return null;\n let c = getMixedUnitColor(unit, environmentMap, inDarkMode, asBackground, {\n key: \"environ\",\n id_key: \"environ_id\",\n });\n if (c != null) {\n return c;\n }\n // Fallback to lithology color if no environment color is found\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, environmentMap, lithMap, inDarkMode, asBackground]);\n}\n\nexport function EnvironmentColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColorByEnvironment(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nfunction getPatternID(\n liths: Array<Lithology>,\n lithMap: Map<number, Lithology>,\n): string | null {\n if (lithMap == null || liths == null || liths.length == 0) {\n return null;\n }\n const patternIDs = new Set<string>();\n for (const lith of liths) {\n const lithData = lithMap.get(lith.lith_id);\n if (lithData) {\n patternIDs.add(`${lithData.fill}`);\n }\n }\n let id = patternIDs.values()[0];\n if (id == \"0\") return null;\n return id;\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@macrostrat/column-views",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Data views for Macrostrat stratigraphic columns",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,21 +45,21 @@
|
|
|
45
45
|
"react": "^18.0.0||^19.0.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@blueprintjs/core": "^6.
|
|
49
|
-
"@macrostrat/api-types": "^1.
|
|
48
|
+
"@blueprintjs/core": "^6.14.0",
|
|
49
|
+
"@macrostrat/api-types": "^1.2.0",
|
|
50
50
|
"@macrostrat/color-utils": "^1.2.2",
|
|
51
|
-
"@macrostrat/column-components": "^2.0.
|
|
52
|
-
"@macrostrat/data-components": "^1.1.
|
|
53
|
-
"@macrostrat/data-provider": "^1.0.
|
|
51
|
+
"@macrostrat/column-components": "^2.0.8",
|
|
52
|
+
"@macrostrat/data-components": "^1.1.10",
|
|
53
|
+
"@macrostrat/data-provider": "^1.0.4",
|
|
54
54
|
"@macrostrat/hyper": "^3.1.1",
|
|
55
|
-
"@macrostrat/map-interface": "^2.2.
|
|
56
|
-
"@macrostrat/map-styles": "^2.2.
|
|
57
|
-
"@macrostrat/mapbox-react": "^3.2.
|
|
55
|
+
"@macrostrat/map-interface": "^2.2.6",
|
|
56
|
+
"@macrostrat/map-styles": "^2.2.3",
|
|
57
|
+
"@macrostrat/mapbox-react": "^3.2.2",
|
|
58
58
|
"@macrostrat/mapbox-utils": "^1.7.4",
|
|
59
|
-
"@macrostrat/stratigraphy-utils": "^1.
|
|
59
|
+
"@macrostrat/stratigraphy-utils": "^1.3.0",
|
|
60
60
|
"@macrostrat/svg-map-components": "^2.0.3",
|
|
61
61
|
"@macrostrat/timescale": "^3.1.3",
|
|
62
|
-
"@macrostrat/ui-components": "^5.0.
|
|
62
|
+
"@macrostrat/ui-components": "^5.0.10",
|
|
63
63
|
"@turf/boolean-point-in-polygon": "^7.3.2",
|
|
64
64
|
"@turf/buffer": "^7.3.2",
|
|
65
65
|
"@turf/centroid": "^7.3.2",
|
|
@@ -82,8 +82,7 @@
|
|
|
82
82
|
"d3-path": "^3.1.0",
|
|
83
83
|
"d3-scale": "^4.0.2",
|
|
84
84
|
"d3-shape": "^3.2.0",
|
|
85
|
-
"jotai": "^2.
|
|
86
|
-
"jotai-scope": "^0.10.0",
|
|
85
|
+
"jotai": "^2.20.0",
|
|
87
86
|
"mapbox-gl": "^3.0.0",
|
|
88
87
|
"p-map": "^7.0.4",
|
|
89
88
|
"react-spring": "^9.7.5",
|
|
@@ -92,7 +91,8 @@
|
|
|
92
91
|
"zustand-computed": "^2.0.2"
|
|
93
92
|
},
|
|
94
93
|
"devDependencies": {
|
|
95
|
-
"@macrostrat/web-components-bundler": "1.0.1"
|
|
94
|
+
"@macrostrat/web-components-bundler": "1.0.1",
|
|
95
|
+
"jotai-scope": "^0.11.0"
|
|
96
96
|
},
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public"
|
package/src/column.ts
CHANGED
|
@@ -118,7 +118,7 @@ export function Column(props: ColumnProps) {
|
|
|
118
118
|
|
|
119
119
|
/* Make pixelScale and targetUnitHeight mutually exclusive. PixelScale implies
|
|
120
120
|
* standardization of scales in all sections */
|
|
121
|
-
let _targetUnitHeight = targetUnitHeight;
|
|
121
|
+
let _targetUnitHeight: number | null = targetUnitHeight;
|
|
122
122
|
let _minSectionHeight = minSectionHeight;
|
|
123
123
|
let _minPixelScale = minPixelScale;
|
|
124
124
|
if (pixelScale != null) {
|
|
@@ -16,6 +16,10 @@ type UnitSelectDispatch = (
|
|
|
16
16
|
target: HTMLElement | null,
|
|
17
17
|
) => void;
|
|
18
18
|
|
|
19
|
+
export function useUnitSelection() {
|
|
20
|
+
return scope.use(selectedUnitAtom);
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
export function useUnitSelectionDispatch(): UnitSelectDispatch {
|
|
20
24
|
return scope.useSetAtom(selectedUnitAtom);
|
|
21
25
|
}
|
|
@@ -70,6 +74,7 @@ const selectedUnitAtom = atom(
|
|
|
70
74
|
): BaseUnit | null => {
|
|
71
75
|
if (!get(allowUnitSelectionAtom)) {
|
|
72
76
|
console.error("Unit selection is disabled.");
|
|
77
|
+
return null;
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
let unitID: number | null = null;
|
|
@@ -83,8 +88,8 @@ const selectedUnitAtom = atom(
|
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
if (unitID != null) {
|
|
86
|
-
// Verify that the unit exists in the current colum, else throw
|
|
87
91
|
const unitsMap = get(columnUnitsMapAtom);
|
|
92
|
+
// Verify that the unit exists in the current colum, else throw
|
|
88
93
|
if (!unitsMap?.has(unitID)) {
|
|
89
94
|
throw new Error(
|
|
90
95
|
`Unit with ID ${unitID} not found in current column units.`,
|
|
@@ -150,9 +155,8 @@ if (props.onClickedColumn) {
|
|
|
150
155
|
export function useUnitSelectionTarget(
|
|
151
156
|
unit: IUnit,
|
|
152
157
|
): [React.RefObject<HTMLElement>, boolean, (evt: Event) => void] {
|
|
153
|
-
const ref = useRef<HTMLElement>();
|
|
154
|
-
const selectedUnit =
|
|
155
|
-
const selectUnit = useUnitSelectionDispatch();
|
|
158
|
+
const ref = useRef<HTMLElement>(null);
|
|
159
|
+
const [selectedUnit, selectUnit] = useUnitSelection();
|
|
156
160
|
const selected = selectedUnit?.unit_id == unit.unit_id;
|
|
157
161
|
|
|
158
162
|
const onClick = useCallback(
|
|
@@ -16,95 +16,143 @@ import type { ExtUnit, SectionInfo, StratigraphicPackage } from "./types";
|
|
|
16
16
|
|
|
17
17
|
const dt = 0.001;
|
|
18
18
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
): ExtUnit[] {
|
|
23
|
-
/** Preprocess units to add overlapping units and columns. */
|
|
24
|
-
let units = section.units;
|
|
19
|
+
export type UnitWithDefinedOverlap<T extends BaseUnit> = T & {
|
|
20
|
+
overlap: UnitOverlapInfo<T>;
|
|
21
|
+
};
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
type UnitOverlapInfo<T extends BaseUnit> = {
|
|
24
|
+
column: number;
|
|
25
|
+
nColumns: number;
|
|
26
|
+
unitGroup: UnitGroup<T>;
|
|
27
|
+
};
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
class UnitGroup<T extends BaseUnit> implements StratigraphicPackage {
|
|
30
|
+
units: T[];
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
while (columns.includes(col)) {
|
|
39
|
-
col++;
|
|
40
|
-
}
|
|
41
|
-
d.column ??= col;
|
|
42
|
-
}
|
|
32
|
+
constructor(units: T[]) {
|
|
33
|
+
this.units = units;
|
|
34
|
+
}
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
get t_age(): number {
|
|
37
|
+
return Math.min(...this.units.map((d) => d.t_age));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get b_age(): number {
|
|
41
|
+
return Math.max(...this.units.map((d) => d.b_age));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getUnits(): UnitWithDefinedOverlap<T>[] {
|
|
45
|
+
return assignColumnsToUnitsWithinOverlappingGroup(this);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function groupUnitsByMutualOverlap<T extends BaseUnit>(
|
|
50
|
+
units: T[],
|
|
51
|
+
tolerance: number = dt,
|
|
52
|
+
): UnitGroup<T>[] {
|
|
53
|
+
/** Group units within a section that have mutual overlap. */
|
|
54
|
+
const sections = groupUnitsIntoSectionsByOverlap(
|
|
55
|
+
units,
|
|
56
|
+
ColumnAxisType.AGE,
|
|
57
|
+
tolerance,
|
|
58
|
+
);
|
|
59
|
+
return sections.map((d) => {
|
|
60
|
+
return new UnitGroup(d.units);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const sortByAge = createUnitSorter(ColumnAxisType.AGE);
|
|
65
|
+
|
|
66
|
+
function assignColumnsToUnitsWithinOverlappingGroup<T extends BaseUnit>(
|
|
67
|
+
group: UnitGroup<T>,
|
|
68
|
+
): UnitWithDefinedOverlap<T>[] {
|
|
69
|
+
/** A relatively naïve function to assign columns to units within a mutually overlapping group.
|
|
70
|
+
* This gets the number of columns that would be needed to accommodate the units in the group.
|
|
71
|
+
* It then assigns columns to units in the group based on the number of columns needed, with
|
|
72
|
+
* lower units further to the left.
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
const sortedUnits = [...group.units].sort((a, b) => b.b_age - a.b_age);
|
|
76
|
+
|
|
77
|
+
const columns: T[][] = [];
|
|
78
|
+
|
|
79
|
+
for (const unit of sortedUnits) {
|
|
80
|
+
// Find a column that is not already occupied by an overlapping unit
|
|
81
|
+
let didAddToExistingColumn = false;
|
|
82
|
+
for (const column of columns) {
|
|
83
|
+
const lastUnit = column[column.length - 1];
|
|
84
|
+
if (!unitsOverlap(unit, lastUnit, ColumnAxisType.AGE, dt)) {
|
|
85
|
+
column.push(unit);
|
|
86
|
+
didAddToExistingColumn = true;
|
|
87
|
+
break;
|
|
52
88
|
}
|
|
53
89
|
}
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
d.b_clip_pos = section.b_pos;
|
|
57
|
-
}
|
|
58
|
-
if (t_pos < section.t_pos) {
|
|
59
|
-
d.t_clip_pos = section.t_pos;
|
|
60
|
-
}
|
|
90
|
+
if (!didAddToExistingColumn) {
|
|
91
|
+
columns.push([unit]);
|
|
61
92
|
}
|
|
62
|
-
// if (axisType == ColumnAxisType.HEIGHT) {
|
|
63
|
-
// if (b_pos < section.b_pos) {
|
|
64
|
-
// d.b_clip_pos = section.b_pos;
|
|
65
|
-
// }
|
|
66
|
-
// if (t_pos > section.t_pos) {
|
|
67
|
-
// d.t_clip_pos = section.t_pos;
|
|
68
|
-
// }
|
|
69
|
-
// }
|
|
70
93
|
}
|
|
71
94
|
|
|
72
|
-
|
|
95
|
+
const units: UnitWithDefinedOverlap<T>[] = columns.flatMap(
|
|
96
|
+
(column, columnIndex) =>
|
|
97
|
+
column.map((unit) => {
|
|
98
|
+
return {
|
|
99
|
+
...unit,
|
|
100
|
+
overlap: {
|
|
101
|
+
column: columnIndex,
|
|
102
|
+
nColumns: columns.length,
|
|
103
|
+
unitGroup: group,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
return units.toSorted(sortByAge);
|
|
73
110
|
}
|
|
74
111
|
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
i: number,
|
|
78
|
-
divisions: UnitLong[],
|
|
112
|
+
export function preprocessUnits<T extends UnitLong = UnitLong>(
|
|
113
|
+
section: SectionInfo<T>,
|
|
79
114
|
axisType: ColumnAxisType = ColumnAxisType.AGE,
|
|
80
|
-
): ExtUnit {
|
|
81
|
-
|
|
115
|
+
): ExtUnit[] {
|
|
116
|
+
/** Preprocess units to add overlapping units and columns. */
|
|
117
|
+
let units = section.units;
|
|
118
|
+
|
|
82
119
|
let tolerance = 0.001; // 1 kyr tolerance for age columns
|
|
83
120
|
if (axisType != ColumnAxisType.AGE) {
|
|
84
121
|
tolerance = 0.01; // 1cm tolerance for height/depth columns
|
|
85
122
|
}
|
|
86
123
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
const d_pos = getUnitHeightRange(d, axisType);
|
|
94
|
-
// Check if the unit is below the current unit
|
|
95
|
-
return d_pos[0] < u_pos[0] + dt;
|
|
96
|
-
});
|
|
97
|
-
let column = 0;
|
|
98
|
-
if (overlappingUnits.length == 1) {
|
|
99
|
-
column = 1;
|
|
124
|
+
const unitGroups = groupUnitsByMutualOverlap(units, tolerance);
|
|
125
|
+
|
|
126
|
+
const divisions: any[] = [];
|
|
127
|
+
// Serialize all groups' units to a single array
|
|
128
|
+
for (const group of unitGroups) {
|
|
129
|
+
divisions.push(...group.getUnits());
|
|
100
130
|
}
|
|
101
131
|
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
132
|
+
return divisions.map((d) =>
|
|
133
|
+
enhanceUnitWithClippingPosition(section, d, axisType),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function enhanceUnitWithClippingPosition(section, d, axisType) {
|
|
138
|
+
const [b_pos, t_pos] = getUnitHeightRange(d, axisType);
|
|
139
|
+
if (axisType == ColumnAxisType.AGE) {
|
|
140
|
+
if (b_pos > section.b_age) {
|
|
141
|
+
d.b_clip_pos = section.b_age;
|
|
142
|
+
}
|
|
143
|
+
if (t_pos < section.t_age) {
|
|
144
|
+
d.t_clip_pos = section.t_age;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (axisType == ColumnAxisType.DEPTH) {
|
|
148
|
+
if (b_pos > section.b_pos) {
|
|
149
|
+
d.b_clip_pos = section.b_pos;
|
|
150
|
+
}
|
|
151
|
+
if (t_pos < section.t_pos) {
|
|
152
|
+
d.t_clip_pos = section.t_pos;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return d;
|
|
108
156
|
}
|
|
109
157
|
|
|
110
158
|
export function groupUnitsIntoSectionsBySectionID<T extends UnitLong>(
|
|
@@ -141,9 +189,10 @@ interface WorkingSection {
|
|
|
141
189
|
heightRange?: [number, number];
|
|
142
190
|
}
|
|
143
191
|
|
|
144
|
-
export function groupUnitsIntoSectionsByOverlap<T extends
|
|
192
|
+
export function groupUnitsIntoSectionsByOverlap<T extends BaseUnit>(
|
|
145
193
|
units: T[],
|
|
146
194
|
axisType: ColumnAxisType = ColumnAxisType.AGE,
|
|
195
|
+
tolerance: number = dt,
|
|
147
196
|
): SectionInfo<T>[] {
|
|
148
197
|
/** Group units into sections by overlap.
|
|
149
198
|
* This creates "synthetic" sections that correspond to packages bound by scale gaps.
|
|
@@ -157,7 +206,7 @@ export function groupUnitsIntoSectionsByOverlap<T extends UnitLong>(
|
|
|
157
206
|
const heightRange = getUnitHeightRange(unit, axisType);
|
|
158
207
|
let section: WorkingSection | undefined = sectionList.find(
|
|
159
208
|
(s) =>
|
|
160
|
-
compareAgeRanges(heightRange, s.heightRange) !==
|
|
209
|
+
compareAgeRanges(heightRange, s.heightRange, tolerance) !==
|
|
161
210
|
AgeRangeRelationship.Disjoint,
|
|
162
211
|
);
|
|
163
212
|
if (section == null) {
|
package/src/section.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isClickable, ItemInteractionProps } from "@macrostrat/data-components";
|
|
2
|
+
import h from "./panel.module.sass";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
|
|
6
|
+
export function ClickableText({
|
|
7
|
+
className,
|
|
8
|
+
...rest
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
} & ItemInteractionProps) {
|
|
13
|
+
/** An optionally clickable text element */
|
|
14
|
+
const clickable = isClickable(rest);
|
|
15
|
+
const tag = clickable ? "a" : "span";
|
|
16
|
+
return h(tag, { className: classNames(className, { clickable }), ...rest });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Identifier({
|
|
20
|
+
id,
|
|
21
|
+
className,
|
|
22
|
+
...rest
|
|
23
|
+
}: {
|
|
24
|
+
id: number | string;
|
|
25
|
+
className?: string;
|
|
26
|
+
} & ItemInteractionProps) {
|
|
27
|
+
/** An item that displays a numeric identifier, optionally clickable */
|
|
28
|
+
return h(
|
|
29
|
+
ClickableText,
|
|
30
|
+
{
|
|
31
|
+
className: classNames("identifier", className),
|
|
32
|
+
...rest,
|
|
33
|
+
},
|
|
34
|
+
id,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type UnitInfo = {
|
|
39
|
+
unitID: number;
|
|
40
|
+
colID?: number;
|
|
41
|
+
name?: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function UnitIdentifier({
|
|
45
|
+
unitID,
|
|
46
|
+
colID,
|
|
47
|
+
name,
|
|
48
|
+
...interactionProps
|
|
49
|
+
}: UnitInfo & ItemInteractionProps) {
|
|
50
|
+
if (name != null) {
|
|
51
|
+
return h(
|
|
52
|
+
ClickableText,
|
|
53
|
+
{
|
|
54
|
+
className: "unit-name",
|
|
55
|
+
...interactionProps,
|
|
56
|
+
},
|
|
57
|
+
name,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return h(Identifier, {
|
|
62
|
+
className: "unit-id",
|
|
63
|
+
key: unitID,
|
|
64
|
+
id: unitID,
|
|
65
|
+
...interactionProps,
|
|
66
|
+
});
|
|
67
|
+
}
|