Skip to content

Commit 822577e

Browse files
authored
Merge pull request #219 from UW-Macrostrat/unit-details-updates
Unit details updates
2 parents d5018ff + 631da34 commit 822577e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1131
-871
lines changed

packages/column-views/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format
44
is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this
55
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.2.2] - 2026-02-09
8+
9+
- Move `AgeField` and `AgeRange` to separate exports
10+
- Improve handling of interval ranges
11+
712
## [3.2.1] - 2026-02-08
813

914
- Export `ThicknessField` for unit details panels

packages/column-views/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@macrostrat/column-views",
3-
"version": "3.2.1",
3+
"version": "3.2.2",
44
"description": "Data views for Macrostrat stratigraphic columns",
55
"repository": {
66
"type": "git",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.interval-proportions
2+
display: inline-flex
3+
flex-flow: row wrap
4+
gap: 0.5em
5+
text-align: right
6+
align-items: baseline
7+
8+
.interval-proportions, .discourage-break
9+
align-items: baseline
10+
white-space: nowrap
11+
display: inline-flex
12+
gap: 0.5em
13+
14+
.sep
15+
color: var(--secondary-color)
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import {
2+
DataField,
3+
IntervalShort,
4+
IntervalTag,
5+
ItemList,
6+
Value,
7+
} from "@macrostrat/data-components";
8+
import { useMacrostratDefs } from "@macrostrat/data-provider";
9+
import h from "./age-range.module.sass";
10+
import { formatProportion, formatRange } from "./utils";
11+
12+
export function AgeField({ unit, children }) {
13+
const [b_age, t_age, _unit] = getAgeRange(unit);
14+
15+
return h(
16+
DataField,
17+
{
18+
label: "Age",
19+
value: formatRange(b_age, t_age),
20+
unit: _unit,
21+
},
22+
children,
23+
);
24+
}
25+
26+
export function AgeLabel({
27+
age,
28+
maximumFractionDigits = 2,
29+
minimumFractionDigits = 0,
30+
className,
31+
}: {
32+
age: number;
33+
className?: string;
34+
maximumFractionDigits?: number;
35+
minimumFractionDigits?: number;
36+
}) {
37+
/** Component to display a single age value with unit conversion from
38+
* Ma to ka or Ga as appropriate.
39+
*/
40+
const [value, unit] = getAge(age);
41+
42+
const _value = value.toLocaleString("en-US", {
43+
maximumFractionDigits,
44+
minimumFractionDigits,
45+
});
46+
47+
return h(Value, { value: _value, unit, className });
48+
}
49+
50+
export function Duration({
51+
value,
52+
maximumFractionDigits = 2,
53+
minimumFractionDigits = 0,
54+
}) {
55+
let unit = "Myr";
56+
if (value < 0.8) {
57+
unit = "kyr";
58+
value *= 1000;
59+
if (value < 5) {
60+
unit = "yr";
61+
value *= 1000;
62+
}
63+
} else if (value > 1000) {
64+
unit = "Gyr";
65+
value /= 1000;
66+
}
67+
68+
let _value = value.toLocaleString("en-US", {
69+
maximumFractionDigits,
70+
minimumFractionDigits,
71+
});
72+
73+
return h(Value, { value: _value, unit });
74+
}
75+
76+
export function IntervalProportions({ unit, onClickItem }) {
77+
/** Display the proportions of the unit that belong to the base and top intervals, if they are different */
78+
if (
79+
unit.b_int_id == null &&
80+
unit.t_int_id == null &&
81+
unit.b_prop == null &&
82+
unit.t_prop == null
83+
)
84+
return null;
85+
86+
const i0 = unit.b_int_id;
87+
const i1 = unit.t_int_id;
88+
let b_prop = unit.b_prop ?? 0;
89+
let t_prop = unit.t_prop ?? 1;
90+
91+
const intervalMap = useMacrostratDefs("intervals");
92+
const int0 = intervalMap?.get(i0) ?? {};
93+
94+
const interval0: IntervalShort = {
95+
...int0,
96+
id: i0,
97+
name: unit.b_int_name,
98+
};
99+
100+
let p0: any = null;
101+
const int1 = intervalMap?.get(i1) ?? {};
102+
const p1: any = h(Proportion, { value: t_prop });
103+
104+
if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {
105+
// We have a single interval with undefined proportions
106+
p0 = h(Proportion, { value: b_prop });
107+
}
108+
109+
if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {
110+
p0 = h("span.joint-proportion", [p0, " ", h("span.sep", "to"), " ", p1]);
111+
}
112+
113+
const clickable = onClickItem != null;
114+
115+
const handleClick = (event: MouseEvent) => {
116+
if (onClickItem) {
117+
onClickItem(event, interval0);
118+
}
119+
};
120+
121+
return h(ItemList, { className: "interval-proportions" }, [
122+
h(IntervalTag, {
123+
className: clickable ? "clickable" : "",
124+
onClick: clickable ? handleClick : undefined,
125+
interval: interval0,
126+
prefix: p0,
127+
}),
128+
h.if(i0 != i1)("span.discourage-break", [
129+
h("span.sep", " to "),
130+
h(IntervalTag, {
131+
className: clickable ? "clickable" : "",
132+
onClick: clickable ? handleClick : undefined,
133+
interval: {
134+
...int1,
135+
id: i1,
136+
name: unit.t_int_name,
137+
},
138+
prefix: p1,
139+
}),
140+
]),
141+
]);
142+
}
143+
144+
function Proportion({ value }) {
145+
let content = null;
146+
if (value == 0) {
147+
content = "base";
148+
} else if (value == 1) {
149+
content = "top";
150+
} else {
151+
content = formatProportion(value * 100) + "%";
152+
}
153+
154+
return h("span.proportion", content);
155+
}
156+
157+
export function getAgeRange(_unit) {
158+
let b_age = _unit.b_age;
159+
let t_age = _unit.t_age;
160+
let unit = "Ma";
161+
162+
if (b_age < 0.8 && t_age < 1.2) {
163+
b_age *= 1000;
164+
t_age *= 1000;
165+
unit = "ka";
166+
} else if (b_age > 800 && t_age > 1200) {
167+
b_age /= 1000;
168+
t_age /= 1000;
169+
unit = "Ga";
170+
}
171+
172+
return [b_age, t_age, unit];
173+
}
174+
175+
export function getAge(value) {
176+
/** Get the age value in Ma, ka, or Ga as appropriate */
177+
let unit = "Ma";
178+
if (value < 0.8) {
179+
unit = "ka";
180+
value *= 1000;
181+
if (value < 5) {
182+
unit = "yr";
183+
value *= 1000;
184+
}
185+
} else if (value > 1000) {
186+
unit = "Ga";
187+
value /= 1000;
188+
}
189+
190+
return [value, unit];
191+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./panel";
22
export * from "./popover";
33
export * from "./modal-panel";
4+
export * from "./age-range";

packages/column-views/src/unit-details/panel.module.sass

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,6 @@
8282
margin: 0
8383
padding-left: 0
8484

85-
.interval-proportions
86-
flex-grow: 1
87-
width: 100%
88-
text-align: right
89-
.discourage-break
90-
white-space: nowrap
91-
.sep
92-
margin: 0 0.3em
93-
9485
.clickable
9586
cursor: pointer
9687

0 commit comments

Comments
 (0)