@macrostrat/column-views 3.11.0 → 3.12.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.
- package/CHANGELOG.md +184 -0
- package/dist/age-axis.cjs +1 -2
- package/dist/age-axis.cjs.map +1 -1
- package/dist/age-axis.js +1 -2
- package/dist/age-axis.js.map +1 -1
- package/dist/age-model/data.cjs +57 -0
- package/dist/age-model/data.cjs.map +1 -0
- package/dist/age-model/data.d.ts +29 -0
- package/dist/age-model/data.js +57 -0
- package/dist/age-model/data.js.map +1 -0
- package/dist/age-model/details.cjs +260 -0
- package/dist/age-model/details.cjs.map +1 -0
- package/dist/age-model/details.d.ts +39 -0
- package/dist/age-model/details.js +257 -0
- package/dist/age-model/details.js.map +1 -0
- package/dist/age-model/details.module.sass.cjs +42 -0
- package/dist/age-model/details.module.sass.cjs.map +1 -0
- package/dist/age-model/details.module.sass.js +40 -0
- package/dist/age-model/details.module.sass.js.map +1 -0
- package/dist/age-model/index.d.ts +5 -0
- package/dist/age-model/legacy.cjs +28 -0
- package/dist/age-model/legacy.cjs.map +1 -0
- package/dist/age-model/legacy.d.ts +6 -0
- package/dist/age-model/legacy.js +26 -0
- package/dist/age-model/legacy.js.map +1 -0
- package/dist/age-model/surfaces.cjs +354 -0
- package/dist/age-model/surfaces.cjs.map +1 -0
- package/dist/age-model/surfaces.d.ts +68 -0
- package/dist/age-model/surfaces.js +351 -0
- package/dist/age-model/surfaces.js.map +1 -0
- package/dist/age-model/surfaces.module.sass.cjs +45 -0
- package/dist/age-model/surfaces.module.sass.cjs.map +1 -0
- package/dist/age-model/surfaces.module.sass.js +43 -0
- package/dist/age-model/surfaces.module.sass.js.map +1 -0
- package/dist/age-model/types.cjs +229 -0
- package/dist/age-model/types.cjs.map +1 -0
- package/dist/age-model/types.d.ts +112 -0
- package/dist/age-model/types.js +229 -0
- package/dist/age-model/types.js.map +1 -0
- package/dist/column-views.css +406 -74
- package/dist/column.cjs +20 -13
- package/dist/column.cjs.map +1 -1
- package/dist/column.d.ts +21 -6
- package/dist/column.js +21 -14
- package/dist/column.js.map +1 -1
- package/dist/column.module.sass.cjs +19 -15
- package/dist/column.module.sass.cjs.map +1 -1
- package/dist/column.module.sass.js +19 -15
- package/dist/column.module.sass.js.map +1 -1
- package/dist/data-provider/store.cjs +34 -1
- package/dist/data-provider/store.cjs.map +1 -1
- package/dist/data-provider/store.d.ts +5 -0
- package/dist/data-provider/store.js +35 -2
- package/dist/data-provider/store.js.map +1 -1
- package/dist/index.cjs +78 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +55 -4
- package/dist/index.js.map +1 -1
- package/dist/notes.cjs +11 -2
- package/dist/notes.cjs.map +1 -1
- package/dist/notes.d.ts +11 -1
- package/dist/notes.js +11 -2
- package/dist/notes.js.map +1 -1
- package/dist/prepare-units/composite-scale.cjs +18 -16
- package/dist/prepare-units/composite-scale.cjs.map +1 -1
- package/dist/prepare-units/composite-scale.js +18 -16
- package/dist/prepare-units/composite-scale.js.map +1 -1
- package/dist/prepare-units/density.cjs +83 -0
- package/dist/prepare-units/density.cjs.map +1 -0
- package/dist/prepare-units/density.d.ts +92 -0
- package/dist/prepare-units/density.js +83 -0
- package/dist/prepare-units/density.js.map +1 -0
- package/dist/prepare-units/index.cjs +15 -7
- package/dist/prepare-units/index.cjs.map +1 -1
- package/dist/prepare-units/index.d.ts +1 -0
- package/dist/prepare-units/index.js +15 -7
- package/dist/prepare-units/index.js.map +1 -1
- package/dist/prepare-units/types.cjs.map +1 -1
- package/dist/prepare-units/types.d.ts +34 -13
- package/dist/prepare-units/types.js.map +1 -1
- package/dist/section.cjs +108 -24
- package/dist/section.cjs.map +1 -1
- package/dist/section.d.ts +66 -6
- package/dist/section.js +109 -25
- package/dist/section.js.map +1 -1
- package/dist/timescale-zoom.cjs +191 -0
- package/dist/timescale-zoom.cjs.map +1 -0
- package/dist/timescale-zoom.d.ts +74 -0
- package/dist/timescale-zoom.js +191 -0
- package/dist/timescale-zoom.js.map +1 -0
- package/dist/unit-details/age-range.cjs +14 -43
- package/dist/unit-details/age-range.cjs.map +1 -1
- package/dist/unit-details/age-range.d.ts +1 -13
- package/dist/unit-details/age-range.js +6 -43
- package/dist/unit-details/age-range.js.map +1 -1
- package/dist/unit-details/utils.cjs +0 -5
- package/dist/unit-details/utils.cjs.map +1 -1
- package/dist/unit-details/utils.js +0 -5
- package/dist/unit-details/utils.js.map +1 -1
- package/dist/units/composite.cjs +4 -1
- package/dist/units/composite.cjs.map +1 -1
- package/dist/units/composite.d.ts +2 -0
- package/dist/units/composite.js +4 -1
- package/dist/units/composite.js.map +1 -1
- package/package.json +8 -8
- package/src/age-model/data.ts +98 -0
- package/src/age-model/details.module.sass +108 -0
- package/src/age-model/details.ts +333 -0
- package/src/age-model/index.ts +5 -0
- package/src/age-model/legacy.ts +30 -0
- package/src/age-model/surfaces.module.sass +168 -0
- package/src/age-model/surfaces.ts +568 -0
- package/src/age-model/types.ts +392 -0
- package/src/column.module.sass +59 -8
- package/src/column.ts +49 -23
- package/src/data-provider/store.ts +50 -1
- package/src/index.ts +5 -1
- package/src/notes.ts +20 -2
- package/src/prepare-units/composite-scale.ts +34 -31
- package/src/prepare-units/density.ts +197 -0
- package/src/prepare-units/index.ts +25 -6
- package/src/prepare-units/types.ts +34 -13
- package/src/section.ts +219 -33
- package/src/timescale-zoom.ts +341 -0
- package/src/unit-details/age-range.ts +12 -58
- package/src/units/composite.ts +11 -0
- package/dist/age-model-overlay.cjs +0 -50
- package/dist/age-model-overlay.cjs.map +0 -1
- package/dist/age-model-overlay.d.ts +0 -24
- package/dist/age-model-overlay.js +0 -48
- package/dist/age-model-overlay.js.map +0 -1
- package/dist/age-model-overlay.module.sass.cjs +0 -12
- package/dist/age-model-overlay.module.sass.cjs.map +0 -1
- package/dist/age-model-overlay.module.sass.js +0 -11
- package/dist/age-model-overlay.module.sass.js.map +0 -1
- package/src/age-model-overlay.module.sass +0 -11
- package/src/age-model-overlay.ts +0 -96
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** Data hooks for a column's age model. */
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useAPIResult } from "@macrostrat/ui-components";
|
|
4
|
+
import { useMacrostratBaseURL } from "@macrostrat/data-provider";
|
|
5
|
+
import type { UnitLong } from "@macrostrat/api-types";
|
|
6
|
+
import { useMacrostratColumnData, useMacrostratUnits } from "../data-provider";
|
|
7
|
+
import {
|
|
8
|
+
type AgeModelBoundary,
|
|
9
|
+
type ColumnSurface,
|
|
10
|
+
surfacesFromBoundaries,
|
|
11
|
+
surfacesFromUnits,
|
|
12
|
+
} from "./types";
|
|
13
|
+
|
|
14
|
+
export const AGE_MODEL_ROUTE = "/age_model";
|
|
15
|
+
|
|
16
|
+
/** The age-model boundaries of a column, from `/age_model?col_id=` on the
|
|
17
|
+
* API the enclosing `MacrostratDataProvider` points at (production when there
|
|
18
|
+
* is none). `null` while loading or when `col_id` is not set. */
|
|
19
|
+
export function useColumnAgeModel(
|
|
20
|
+
col_id: number | null | undefined,
|
|
21
|
+
): AgeModelBoundary[] | null {
|
|
22
|
+
const baseURL = useMacrostratBaseURL();
|
|
23
|
+
const params = useMemo(() => ({ col_id }), [col_id]);
|
|
24
|
+
let route: string | null = null;
|
|
25
|
+
if (col_id != null) {
|
|
26
|
+
route = baseURL + AGE_MODEL_ROUTE;
|
|
27
|
+
}
|
|
28
|
+
return useAPIResult(route, params, unwrapAgeModel) ?? null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function unwrapAgeModel(res: any): AgeModelBoundary[] {
|
|
32
|
+
return res?.success?.data ?? [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Where a column's surfaces came from */
|
|
36
|
+
export type SurfacesSource = "provided" | "age-model" | "derived" | "loading";
|
|
37
|
+
|
|
38
|
+
export interface UseColumnSurfacesOptions {
|
|
39
|
+
/** Surfaces to show. When given, nothing is fetched. */
|
|
40
|
+
surfaces?: ColumnSurface[] | null;
|
|
41
|
+
/** The column whose age model to fetch. Defaults to the column being
|
|
42
|
+
* rendered (read from its units). */
|
|
43
|
+
col_id?: number | null;
|
|
44
|
+
/** When the age model has no boundaries, derive surfaces from the units
|
|
45
|
+
* instead (default `true`). */
|
|
46
|
+
fallbackToUnits?: boolean;
|
|
47
|
+
/** Promote `modeled` surfaces that must in fact constrain the age model to
|
|
48
|
+
* `relative` (default `true`) — see `inferTiePointStatuses`. */
|
|
49
|
+
inferTiePoints?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ColumnSurfacesData {
|
|
53
|
+
surfaces: ColumnSurface[];
|
|
54
|
+
source: SurfacesSource;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Resolve the surfaces to show for the enclosing `Column`: the ones passed
|
|
58
|
+
* in, else the column's age model, else (optionally) surfaces derived from
|
|
59
|
+
* its units. Must be used inside a `Column`. */
|
|
60
|
+
export function useColumnSurfaces(
|
|
61
|
+
options: UseColumnSurfacesOptions = {},
|
|
62
|
+
): ColumnSurfacesData {
|
|
63
|
+
const {
|
|
64
|
+
surfaces: provided,
|
|
65
|
+
col_id,
|
|
66
|
+
fallbackToUnits = true,
|
|
67
|
+
inferTiePoints = true,
|
|
68
|
+
} = options;
|
|
69
|
+
const units = useMacrostratUnits() as UnitLong[] | undefined;
|
|
70
|
+
const { axisType } = useMacrostratColumnData();
|
|
71
|
+
|
|
72
|
+
let fetchID: number | null = null;
|
|
73
|
+
if (provided == null) {
|
|
74
|
+
fetchID = col_id ?? units?.[0]?.col_id ?? null;
|
|
75
|
+
}
|
|
76
|
+
const boundaries = useColumnAgeModel(fetchID);
|
|
77
|
+
|
|
78
|
+
const fromAgeModel = useMemo(
|
|
79
|
+
() => surfacesFromBoundaries(boundaries, { inferTiePoints }),
|
|
80
|
+
[boundaries, inferTiePoints],
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const derived = useMemo(() => {
|
|
84
|
+
if (!fallbackToUnits) return [];
|
|
85
|
+
return surfacesFromUnits(units, { axisType });
|
|
86
|
+
}, [units, axisType, fallbackToUnits]);
|
|
87
|
+
|
|
88
|
+
if (provided != null) {
|
|
89
|
+
return { surfaces: provided, source: "provided" };
|
|
90
|
+
}
|
|
91
|
+
if (fetchID != null && boundaries == null) {
|
|
92
|
+
return { surfaces: [], source: "loading" };
|
|
93
|
+
}
|
|
94
|
+
if (fromAgeModel.length > 0) {
|
|
95
|
+
return { surfaces: fromAgeModel, source: "age-model" };
|
|
96
|
+
}
|
|
97
|
+
return { surfaces: derived, source: "derived" };
|
|
98
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
.surface-details-panel
|
|
2
|
+
display: flex
|
|
3
|
+
flex-direction: column
|
|
4
|
+
min-width: 0
|
|
5
|
+
|
|
6
|
+
.surface-details-header
|
|
7
|
+
display: flex
|
|
8
|
+
flex-direction: row
|
|
9
|
+
align-items: center
|
|
10
|
+
flex-wrap: wrap
|
|
11
|
+
gap: 0.5em
|
|
12
|
+
padding: 0.5em 0
|
|
13
|
+
border-bottom: 1px solid var(--pz-panel-rule-color, var(--panel-rule-color, #ddd))
|
|
14
|
+
.spacer
|
|
15
|
+
flex: 1
|
|
16
|
+
|
|
17
|
+
.surface-details-title
|
|
18
|
+
margin: 0
|
|
19
|
+
font-size: 1.1em
|
|
20
|
+
.surface-id
|
|
21
|
+
font-size: 0.85em
|
|
22
|
+
color: var(--text-subtle-color, var(--pz-text-subtle-color))
|
|
23
|
+
|
|
24
|
+
.surface-details-tags
|
|
25
|
+
display: flex
|
|
26
|
+
gap: 0.3em
|
|
27
|
+
|
|
28
|
+
.surface-details-content
|
|
29
|
+
padding: 0.5em 0
|
|
30
|
+
|
|
31
|
+
.no-surface .placeholder
|
|
32
|
+
color: var(--text-subtle-color, var(--pz-text-subtle-color))
|
|
33
|
+
margin: 0
|
|
34
|
+
|
|
35
|
+
.surface-tag
|
|
36
|
+
// A colored dot leading the status label
|
|
37
|
+
&:before
|
|
38
|
+
content: ''
|
|
39
|
+
display: inline-block
|
|
40
|
+
width: 0.6em
|
|
41
|
+
height: 0.6em
|
|
42
|
+
border-radius: 50%
|
|
43
|
+
margin-right: 0.4em
|
|
44
|
+
background-color: var(--surface-color, currentColor)
|
|
45
|
+
&.surface-type-tag:before
|
|
46
|
+
display: none
|
|
47
|
+
// An inferred status is marked, so the tag doesn't pass for a recorded one
|
|
48
|
+
&.inferred
|
|
49
|
+
font-style: italic
|
|
50
|
+
|
|
51
|
+
.inferred-marker
|
|
52
|
+
margin-left: 0.15em
|
|
53
|
+
opacity: 0.7
|
|
54
|
+
|
|
55
|
+
.calibration-interval
|
|
56
|
+
display: flex
|
|
57
|
+
align-items: baseline
|
|
58
|
+
gap: 0.5em
|
|
59
|
+
flex-wrap: wrap
|
|
60
|
+
|
|
61
|
+
.calibration-range
|
|
62
|
+
color: var(--text-subtle-color, var(--pz-text-subtle-color))
|
|
63
|
+
font-size: 0.9em
|
|
64
|
+
|
|
65
|
+
.calibration-proportion
|
|
66
|
+
margin-top: 0.2em
|
|
67
|
+
|
|
68
|
+
.surface-units-list
|
|
69
|
+
list-style: none
|
|
70
|
+
margin: 0
|
|
71
|
+
padding: 0
|
|
72
|
+
li
|
|
73
|
+
display: inline
|
|
74
|
+
&:after
|
|
75
|
+
content: ', '
|
|
76
|
+
&:last-child:after
|
|
77
|
+
content: ''
|
|
78
|
+
|
|
79
|
+
.no-units, .no-calibration
|
|
80
|
+
color: var(--text-subtle-color, var(--pz-text-subtle-color))
|
|
81
|
+
|
|
82
|
+
.surface-status-legend
|
|
83
|
+
list-style: none
|
|
84
|
+
margin: 0
|
|
85
|
+
padding: 0
|
|
86
|
+
display: flex
|
|
87
|
+
flex-direction: column
|
|
88
|
+
gap: 0.3em
|
|
89
|
+
font-size: 0.85em
|
|
90
|
+
&.with-descriptions
|
|
91
|
+
gap: 0.6em
|
|
92
|
+
|
|
93
|
+
.legend-item
|
|
94
|
+
display: flex
|
|
95
|
+
flex-direction: row
|
|
96
|
+
align-items: baseline
|
|
97
|
+
gap: 0.6em
|
|
98
|
+
.surface-label-marker
|
|
99
|
+
flex: none
|
|
100
|
+
width: 24px
|
|
101
|
+
align-self: center
|
|
102
|
+
|
|
103
|
+
.legend-label
|
|
104
|
+
font-weight: 500
|
|
105
|
+
|
|
106
|
+
.legend-description
|
|
107
|
+
color: var(--text-subtle-color, var(--pz-text-subtle-color))
|
|
108
|
+
font-size: 0.9em
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/** The inspector for a selected surface, and the small tags and legend that
|
|
2
|
+
* explain surface statuses and types. */
|
|
3
|
+
import hyper from "@macrostrat/hyper";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
import { type ReactNode, useMemo } from "react";
|
|
6
|
+
import { Button, Tag } from "@blueprintjs/core";
|
|
7
|
+
import {
|
|
8
|
+
DataField,
|
|
9
|
+
Identifier,
|
|
10
|
+
type IntervalShort,
|
|
11
|
+
IntervalTag,
|
|
12
|
+
UnitIdentifier,
|
|
13
|
+
Value,
|
|
14
|
+
} from "@macrostrat/data-components";
|
|
15
|
+
import { useMacrostratDefs } from "@macrostrat/data-provider";
|
|
16
|
+
import type { UnitLong } from "@macrostrat/api-types";
|
|
17
|
+
import { useColumnUnitsMap } from "../data-provider";
|
|
18
|
+
import { AgeLabel } from "../unit-details/age-range";
|
|
19
|
+
import { formatRange } from "../unit-details/utils";
|
|
20
|
+
import { ReferencesField } from "../unit-details/panel";
|
|
21
|
+
import { surfaceClasses } from "./surfaces";
|
|
22
|
+
import surfaceStyles from "./surfaces.module.sass";
|
|
23
|
+
import styles from "./details.module.sass";
|
|
24
|
+
import {
|
|
25
|
+
type BoundaryType,
|
|
26
|
+
type ColumnSurface,
|
|
27
|
+
type SurfaceStatus,
|
|
28
|
+
formatProportion,
|
|
29
|
+
surfaceStatuses,
|
|
30
|
+
surfaceStatusDescriptions,
|
|
31
|
+
surfaceStatusLabels,
|
|
32
|
+
} from "./types";
|
|
33
|
+
|
|
34
|
+
const h = hyper.styled({ ...surfaceStyles, ...styles });
|
|
35
|
+
|
|
36
|
+
export interface SurfaceDetailsPanelProps {
|
|
37
|
+
/** The surface to inspect; `null` renders the panel's empty state */
|
|
38
|
+
surface: ColumnSurface | null;
|
|
39
|
+
onClose?: () => void;
|
|
40
|
+
/** Called when a unit above or below the surface is clicked */
|
|
41
|
+
onSelectUnit?: (unitID: number) => void;
|
|
42
|
+
/** Extra controls for the header */
|
|
43
|
+
actions?: ReactNode;
|
|
44
|
+
/** Label for the measured-position field ("Height" or "Depth") */
|
|
45
|
+
positionLabel?: string;
|
|
46
|
+
className?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Details of one surface: its age, calibration, the units it separates, and
|
|
50
|
+
* provenance. A companion to `UnitDetailsPanel`. */
|
|
51
|
+
export function SurfaceDetailsPanel(props: SurfaceDetailsPanelProps) {
|
|
52
|
+
const {
|
|
53
|
+
surface,
|
|
54
|
+
onClose,
|
|
55
|
+
onSelectUnit,
|
|
56
|
+
actions,
|
|
57
|
+
positionLabel = "Position",
|
|
58
|
+
className,
|
|
59
|
+
} = props;
|
|
60
|
+
|
|
61
|
+
// A selection that hasn't been made yet is an ordinary state for a panel
|
|
62
|
+
// bound to one, not a caller error
|
|
63
|
+
if (surface == null) {
|
|
64
|
+
return h(
|
|
65
|
+
"div.surface-details-panel.no-surface",
|
|
66
|
+
{ className },
|
|
67
|
+
h("p.placeholder", "No surface selected."),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let closeButton: ReactNode = null;
|
|
72
|
+
if (onClose != null) {
|
|
73
|
+
closeButton = h(Button, {
|
|
74
|
+
icon: "cross",
|
|
75
|
+
variant: "minimal",
|
|
76
|
+
size: "small",
|
|
77
|
+
onClick: onClose,
|
|
78
|
+
"aria-label": "Close",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let positionField: ReactNode = null;
|
|
83
|
+
if (surface.position != null) {
|
|
84
|
+
positionField = h(DataField, {
|
|
85
|
+
label: positionLabel,
|
|
86
|
+
value: surface.position.toLocaleString("en-US", {
|
|
87
|
+
maximumFractionDigits: 2,
|
|
88
|
+
}),
|
|
89
|
+
unit: "m",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let sectionField: ReactNode = null;
|
|
94
|
+
if (surface.section_id != null) {
|
|
95
|
+
sectionField = h(
|
|
96
|
+
DataField,
|
|
97
|
+
{ label: "Section" },
|
|
98
|
+
h(Identifier, { id: surface.section_id }),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let refsField: ReactNode = null;
|
|
103
|
+
if (surface.ref_id != null) {
|
|
104
|
+
refsField = h(ReferencesField, { refs: [surface.ref_id] });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return h(
|
|
108
|
+
"div.surface-details-panel",
|
|
109
|
+
{ className: classNames(className, surfaceClasses(surface)) },
|
|
110
|
+
[
|
|
111
|
+
h("div.surface-details-header", [
|
|
112
|
+
h("h3.surface-details-title", [
|
|
113
|
+
"Surface ",
|
|
114
|
+
h(SurfaceIdentifier, { id: surface.id }),
|
|
115
|
+
]),
|
|
116
|
+
h("div.surface-details-tags", [
|
|
117
|
+
h(SurfaceStatusTag, {
|
|
118
|
+
status: surface.status,
|
|
119
|
+
inferred: surface.statusInferred,
|
|
120
|
+
}),
|
|
121
|
+
h(SurfaceTypeTag, { type: surface.type }),
|
|
122
|
+
]),
|
|
123
|
+
h("div.spacer"),
|
|
124
|
+
actions,
|
|
125
|
+
closeButton,
|
|
126
|
+
]),
|
|
127
|
+
h("div.surface-details-content", [
|
|
128
|
+
h(DataField, { label: "Model age" }, h(AgeLabel, { age: surface.age })),
|
|
129
|
+
h(SurfaceCalibrationField, { surface }),
|
|
130
|
+
positionField,
|
|
131
|
+
h(SurfaceUnitsField, {
|
|
132
|
+
label: "Unit above",
|
|
133
|
+
unitIDs: surface.unitsAbove,
|
|
134
|
+
onSelectUnit,
|
|
135
|
+
}),
|
|
136
|
+
h(SurfaceUnitsField, {
|
|
137
|
+
label: "Unit below",
|
|
138
|
+
unitIDs: surface.unitsBelow,
|
|
139
|
+
onSelectUnit,
|
|
140
|
+
}),
|
|
141
|
+
sectionField,
|
|
142
|
+
refsField,
|
|
143
|
+
]),
|
|
144
|
+
],
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function SurfaceIdentifier({ id }: { id: ColumnSurface["id"] }) {
|
|
149
|
+
if (typeof id === "number") {
|
|
150
|
+
return h(Identifier, { id });
|
|
151
|
+
}
|
|
152
|
+
return h("code.surface-id", String(id));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The calibration interval as a colored tag, with the surface's position in
|
|
156
|
+
* it: "Calymmian (1600–1400 Ma), 85% above base". */
|
|
157
|
+
function SurfaceCalibrationField({ surface }: { surface: ColumnSurface }) {
|
|
158
|
+
const { calibration, proportion } = surface;
|
|
159
|
+
const ids = useMemo(() => {
|
|
160
|
+
if (calibration == null) return [];
|
|
161
|
+
return [calibration.id];
|
|
162
|
+
}, [calibration?.id]);
|
|
163
|
+
// Interval colors come from the definitions table; the age model itself
|
|
164
|
+
// doesn't carry them
|
|
165
|
+
const intervalMap = useMacrostratDefs("intervals", ids, null);
|
|
166
|
+
|
|
167
|
+
if (calibration == null) {
|
|
168
|
+
return h(DataField, {
|
|
169
|
+
label: "Calibration",
|
|
170
|
+
value: "None",
|
|
171
|
+
className: "no-calibration",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const def = intervalMap?.get(calibration.id);
|
|
176
|
+
const interval: IntervalShort = {
|
|
177
|
+
id: calibration.id,
|
|
178
|
+
name: calibration.name,
|
|
179
|
+
b_age: calibration.b_age,
|
|
180
|
+
t_age: calibration.t_age,
|
|
181
|
+
color: def?.color,
|
|
182
|
+
rank: def?.rank,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return h(DataField, { label: "Calibration" }, [
|
|
186
|
+
h(
|
|
187
|
+
"div.calibration-interval",
|
|
188
|
+
h(IntervalTag, {
|
|
189
|
+
interval,
|
|
190
|
+
proportion,
|
|
191
|
+
}),
|
|
192
|
+
),
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function SurfaceUnitsField({
|
|
197
|
+
label,
|
|
198
|
+
unitIDs,
|
|
199
|
+
onSelectUnit,
|
|
200
|
+
}: {
|
|
201
|
+
label: string;
|
|
202
|
+
unitIDs: number[];
|
|
203
|
+
onSelectUnit?: (unitID: number) => void;
|
|
204
|
+
}) {
|
|
205
|
+
const unitsMap = useColumnUnitsMap();
|
|
206
|
+
if (unitIDs.length === 0) {
|
|
207
|
+
return h(DataField, { label, value: "None", className: "no-units" });
|
|
208
|
+
}
|
|
209
|
+
return h(
|
|
210
|
+
DataField,
|
|
211
|
+
{ label, className: "surface-units-field" },
|
|
212
|
+
h(
|
|
213
|
+
"ul.surface-units-list",
|
|
214
|
+
unitIDs.map((unitID) => {
|
|
215
|
+
const unit = unitsMap?.get(unitID) as UnitLong | undefined;
|
|
216
|
+
let onClick: (() => void) | undefined = undefined;
|
|
217
|
+
if (onSelectUnit != null) {
|
|
218
|
+
onClick = () => onSelectUnit(unitID);
|
|
219
|
+
}
|
|
220
|
+
return h(
|
|
221
|
+
"li",
|
|
222
|
+
{ key: unitID },
|
|
223
|
+
h(UnitIdentifier, {
|
|
224
|
+
unitID,
|
|
225
|
+
colID: unit?.col_id,
|
|
226
|
+
name: unit?.unit_name,
|
|
227
|
+
onClick,
|
|
228
|
+
}),
|
|
229
|
+
);
|
|
230
|
+
}),
|
|
231
|
+
),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function SurfaceStatusTag({
|
|
236
|
+
status,
|
|
237
|
+
inferred = false,
|
|
238
|
+
className,
|
|
239
|
+
}: {
|
|
240
|
+
status: SurfaceStatus;
|
|
241
|
+
/** The status was inferred rather than recorded (see
|
|
242
|
+
* `inferTiePointStatuses`); the tag says so. */
|
|
243
|
+
inferred?: boolean;
|
|
244
|
+
className?: string;
|
|
245
|
+
}) {
|
|
246
|
+
let label: ReactNode = surfaceStatusLabels[status] ?? status;
|
|
247
|
+
let title = surfaceStatusDescriptions[status];
|
|
248
|
+
if (inferred) {
|
|
249
|
+
label = [label, h("span.inferred-marker", "*")];
|
|
250
|
+
title = INFERRED_STATUS_DESCRIPTION;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return h(
|
|
254
|
+
Tag,
|
|
255
|
+
{
|
|
256
|
+
variant: "minimal",
|
|
257
|
+
className: classNames(
|
|
258
|
+
"surface-tag",
|
|
259
|
+
className,
|
|
260
|
+
surfaceClasses({ status }),
|
|
261
|
+
{ inferred },
|
|
262
|
+
),
|
|
263
|
+
title,
|
|
264
|
+
},
|
|
265
|
+
label,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const INFERRED_STATUS_DESCRIPTION =
|
|
270
|
+
"Recorded as modeled, but this surface cannot have been interpolated — it " +
|
|
271
|
+
"sits on the base or top of its interval, or is the edge of a gap-bound " +
|
|
272
|
+
"package — so it constrains the age model rather than falling out of it";
|
|
273
|
+
|
|
274
|
+
export function SurfaceTypeTag({
|
|
275
|
+
type,
|
|
276
|
+
className,
|
|
277
|
+
}: {
|
|
278
|
+
type: BoundaryType | null | undefined;
|
|
279
|
+
className?: string;
|
|
280
|
+
}) {
|
|
281
|
+
if (type == null || type === "") return null;
|
|
282
|
+
return h(
|
|
283
|
+
Tag,
|
|
284
|
+
{
|
|
285
|
+
variant: "minimal",
|
|
286
|
+
className: classNames("surface-tag", "surface-type-tag", className),
|
|
287
|
+
},
|
|
288
|
+
type,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface SurfaceStatusLegendProps {
|
|
293
|
+
statuses?: SurfaceStatus[];
|
|
294
|
+
showDescriptions?: boolean;
|
|
295
|
+
className?: string;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** A legend of surface line styles, one entry per boundary status. */
|
|
299
|
+
export function SurfaceStatusLegend(props: SurfaceStatusLegendProps) {
|
|
300
|
+
const {
|
|
301
|
+
statuses = surfaceStatuses,
|
|
302
|
+
showDescriptions = false,
|
|
303
|
+
className,
|
|
304
|
+
} = props;
|
|
305
|
+
return h(
|
|
306
|
+
"ul.surface-status-legend",
|
|
307
|
+
{
|
|
308
|
+
className: classNames(className, {
|
|
309
|
+
"with-descriptions": showDescriptions,
|
|
310
|
+
}),
|
|
311
|
+
},
|
|
312
|
+
statuses.map((status) => {
|
|
313
|
+
let description: ReactNode = null;
|
|
314
|
+
if (showDescriptions) {
|
|
315
|
+
description = h(
|
|
316
|
+
"div.legend-description",
|
|
317
|
+
surfaceStatusDescriptions[status],
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
return h(
|
|
321
|
+
"li.legend-item",
|
|
322
|
+
{ key: status, className: surfaceClasses({ status }) },
|
|
323
|
+
[
|
|
324
|
+
h("div.surface-label-marker"),
|
|
325
|
+
h("div.legend-text", [
|
|
326
|
+
h("div.legend-label", surfaceStatusLabels[status]),
|
|
327
|
+
description,
|
|
328
|
+
]),
|
|
329
|
+
],
|
|
330
|
+
);
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
333
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Earlier, in-development overlays, kept so existing consumers keep working.
|
|
2
|
+
* Both are now thin wrappers over `ColumnSurfaces`. */
|
|
3
|
+
import h from "@macrostrat/hyper";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import type { UnitLong } from "@macrostrat/api-types";
|
|
6
|
+
import { useMacrostratColumnData, useMacrostratUnits } from "../data-provider";
|
|
7
|
+
import { ColumnSurfaces } from "./surfaces";
|
|
8
|
+
import { surfacesFromUnits } from "./types";
|
|
9
|
+
|
|
10
|
+
/** @deprecated Use `ColumnSurfaces`, which also labels the surfaces and
|
|
11
|
+
* styles them by boundary status. */
|
|
12
|
+
export function BoundaryAgeModelOverlay() {
|
|
13
|
+
return h(ColumnSurfaces, {
|
|
14
|
+
showLabels: false,
|
|
15
|
+
extent: "column",
|
|
16
|
+
fallbackToUnits: false,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @deprecated Use `ColumnSurfaces` with `surfaces: surfacesFromUnits(units)`,
|
|
21
|
+
* or rely on its default fallback to unit-derived surfaces. */
|
|
22
|
+
export function ComputedSurfacesOverlay() {
|
|
23
|
+
const units = useMacrostratUnits() as UnitLong[];
|
|
24
|
+
const { axisType } = useMacrostratColumnData();
|
|
25
|
+
const surfaces = useMemo(
|
|
26
|
+
() => surfacesFromUnits(units, { axisType }),
|
|
27
|
+
[units, axisType],
|
|
28
|
+
);
|
|
29
|
+
return h(ColumnSurfaces, { surfaces, showLabels: false, extent: "column" });
|
|
30
|
+
}
|