Skip to content

Commit 6de2a11

Browse files
committed
Merge branch 'unit-details'
* unit-details: Refactor column views Fixed unit selection Added popover component Starting point for pattern recoloring and reweighting Change styling system for patterns Pretty decent unit details view Improved unit details Better unit details panel
2 parents 7e5c143 + 5bb1b3b commit 6de2a11

28 files changed

+1150
-325
lines changed

.storybook/main.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ const config: StorybookConfig = {
77
"../packages/**/*.mdx",
88
"../packages/**/*.stories.@(mdx|js|jsx|ts|tsx)",
99
],
10+
staticDirs: [
11+
{
12+
from: "../deps/geologic-patterns/assets/svg",
13+
to: "/patterns",
14+
},
15+
],
1016
addons: [
1117
getAbsolutePath("@storybook/addon-links"),
1218
getAbsolutePath("@storybook/addon-essentials"),

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"@macrostrat/timescale": "./packages/timescale/src",
2020
"@macrostrat/mapbox-styles": "./packages/mapbox-styles/src",
2121
"@macrostrat/ui-components": "./packages/ui-components/src",
22-
"@macrostrat/column-components": "./packages/column-components/src"
22+
"@macrostrat/column-components": "./packages/column-components/src",
23+
"@macrostrat/chronostrat-utils": "./packages/chronostrat-utils/src"
2324
},
2425
"devDependencies": {
2526
"@babel/core": "^7.18.6",
@@ -77,7 +78,8 @@
7778
"map-interface",
7879
"style-system",
7980
"vite-plugin-hyperstyles",
80-
"color-utils"
81+
"color-utils",
82+
"chronostrat-utils"
8183
],
8284
"workspaces": [
8385
"packages/*",
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@macrostrat/chronostrat-utils",
3+
"version": "1.0.0",
4+
"description": "Chronostratigraphy utility functions",
5+
"type": "module",
6+
"main": "dist/main.js",
7+
"types": "dist/types.d.ts",
8+
"source": "src/index.ts",
9+
"scripts": {
10+
"build": "parcel build"
11+
},
12+
"author": "Daven Quinn",
13+
"license": "ISC",
14+
"exports": {
15+
".": {
16+
"typescript": "./src",
17+
"import": "./dist/main.js",
18+
"require": "./dist/main.js",
19+
"types:": "./dist/types.d.ts"
20+
}
21+
},
22+
"files": [
23+
"dist",
24+
"src"
25+
],
26+
"repository": {
27+
"type": "git",
28+
"url": "https://github.com/UW-Macrostrat/web-components.git",
29+
"directory": "packages/chronostrat-utils"
30+
}
31+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export type AgeRange = [number, number];
2+
3+
enum MergeMode {
4+
Inner,
5+
Outer,
6+
}
7+
8+
export function mergeAgeRanges(
9+
ranges: AgeRange[],
10+
mergeMode: MergeMode = MergeMode.Outer
11+
): AgeRange {
12+
/** Merge a set of age ranges to get the inner or outer bounds */
13+
let min = Infinity;
14+
let max = 0;
15+
// Negative ages are not handled
16+
17+
if (mergeMode === MergeMode.Inner) {
18+
min = Math.min(...ranges.map((d) => d[0]));
19+
max = Math.max(...ranges.map((d) => d[1]));
20+
} else {
21+
min = Math.max(...ranges.map((d) => d[0]));
22+
max = Math.min(...ranges.map((d) => d[1]));
23+
}
24+
25+
// Age ranges should start with the oldest (largest) age
26+
if (min < max) {
27+
return [max, min];
28+
}
29+
return [min, max];
30+
}
31+
32+
enum AgeRangeRelationship {
33+
Disjoint,
34+
Contains,
35+
Contained,
36+
Identical,
37+
}
38+
39+
function convertToForwardOrdinal(a: AgeRange): AgeRange {
40+
/** Age ranges are naturally expressed as [b_age, t_age] where
41+
* b_age is the older age and t_age is the younger age. This function
42+
* converts the age range to [min, max] where min is the oldest age,
43+
* expressed as negative numbers. This assists with intuitive ordering
44+
* in certain cases.
45+
*/
46+
return [-a[0], -a[1]];
47+
}
48+
49+
export function compareAgeRanges(
50+
a: AgeRange,
51+
b: AgeRange
52+
): AgeRangeRelationship {
53+
const a1 = convertToForwardOrdinal(a);
54+
const b1 = convertToForwardOrdinal(b);
55+
/** Compare two age ranges */
56+
if (a1[0] > b1[1] || a1[1] < b1[0]) {
57+
return AgeRangeRelationship.Disjoint;
58+
}
59+
if (a1[0] === b1[0] && a1[1] === b1[1]) {
60+
return AgeRangeRelationship.Identical;
61+
}
62+
if (a1[0] <= b1[0] && a1[1] >= b1[1]) {
63+
return AgeRangeRelationship.Contains;
64+
}
65+
if (a1[0] >= b1[0] && a1[1] <= b1[1]) {
66+
return AgeRangeRelationship.Contained;
67+
}
68+
}

packages/column-components/src/lithology/column-patterns.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ function PatternDefsProvider(props: LithProviderProps) {
8484
);
8585
}
8686

87+
export function usePatternResolver() {
88+
const ctx = useContext(PatternDefsContext);
89+
console.log(ctx);
90+
return ctx?.resolvePattern;
91+
}
92+
8793
function useGeologicPattern(patternID: string, fallback: string = "#aaa") {
8894
const ctx1 = useContext(GeologicPatternContext);
8995
const ctx = useContext(PatternDefsContext);

packages/column-components/stories/base-section.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,9 @@ import styles from "./measured-section.stories.module.sass";
2121

2222
const h = hyper.styled(styles);
2323

24-
function patternPath(id) {
25-
return `../../../deps/geologic-patterns/assets/svg/${id}.svg`;
26-
}
27-
28-
const patterns = import.meta.glob(
29-
"../../../deps/geologic-patterns/assets/svg/*.svg",
30-
{ eager: true, query: "url" }
31-
);
32-
33-
const resolvePattern = (id) => {
34-
const _id = patternPath(id);
35-
return patterns[_id]?.default;
24+
// Patterns are included as static files in the storybook main.ts
25+
export const resolvePattern = (id) => {
26+
return `/patterns/${id}.svg`;
3627
};
3728

3829
export function PatternProvider({ children }) {

packages/column-views/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"@macrostrat/map-components": "workspace:*",
1111
"@macrostrat/timescale": "workspace:*",
1212
"d3-array": "^3.2.1",
13-
"d3-geo-voronoi": "^2.0.1"
13+
"d3-geo-voronoi": "^2.0.1",
14+
"zustand": "^5.0.3"
1415
},
1516
"peerDependencies": {
1617
"@blueprintjs/core": "^3.43.0 || ^4.3.0 || ^5.0.0",

packages/column-views/src/column.module.sass

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
.column-container
77
--background-color: var(--column-background-color, #000)
88
--stroke-color: var(--column-stroke-color, #fff)
9+
color-scheme: dark
910

1011
.column-container :global
1112
.column

packages/column-views/src/helpers.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { BaseUnit, UnitLong } from "@macrostrat/api-types";
2+
import { IUnit } from "./units";
3+
import { group } from "d3-array";
24

35
// Time resolution is 100 years
46
const dt = 0.0001;
@@ -13,7 +15,7 @@ interface ExtUnit extends UnitLong {
1315
column?: number;
1416
}
1517

16-
function extendDivision(
18+
export function extendDivision(
1719
unit: UnitLong,
1820
i: number,
1921
divisions: UnitLong[]
@@ -39,7 +41,7 @@ function extendDivision(
3941
};
4042
}
4143

42-
function preprocessUnits(units: UnitLong[]) {
44+
export function preprocessUnits(units: UnitLong[]) {
4345
let divisions = units.map(extendDivision);
4446
for (let d of divisions) {
4547
const overlappingUnits = divisions.filter((u) =>
@@ -74,4 +76,55 @@ function preprocessUnits(units: UnitLong[]) {
7476
return divisions;
7577
}
7678

77-
export { extendDivision, preprocessUnits };
79+
export interface SectionInfo {
80+
section_id: number | number[];
81+
t_age: number;
82+
b_age: number;
83+
units: IUnit[];
84+
}
85+
86+
export function groupUnitsIntoSections(units: IUnit[]): SectionInfo[] {
87+
let groups = Array.from(group(units, (d) => d.section_id));
88+
return groups.map(([section_id, units]) => {
89+
const t_age = Math.min(...units.map((d) => d.t_age));
90+
const b_age = Math.max(...units.map((d) => d.b_age));
91+
return { section_id, t_age, b_age, units };
92+
});
93+
}
94+
95+
export function _mergeOverlappingSections(
96+
sections: SectionInfo[]
97+
): SectionInfo[] {
98+
/** Columns can have sections that overlap in time. Here, we merge overlapping
99+
* sections into a single section to correctly render gap-bound packages.
100+
*/
101+
const [firstSection, ...rest] = sections;
102+
const newSections = [firstSection];
103+
for (const section of rest) {
104+
const lastSection = newSections[newSections.length - 1];
105+
if (
106+
lastSection.b_age < section.t_age ||
107+
lastSection.t_age > section.b_age
108+
) {
109+
// No overlap, add the section as normal
110+
newSections.push(section);
111+
continue;
112+
}
113+
// Overlap, merge the sections
114+
lastSection.section_id = [
115+
...ensureArray(lastSection.section_id),
116+
...ensureArray(section.section_id),
117+
];
118+
lastSection.units.push(...section.units);
119+
lastSection.b_age = Math.max(lastSection.b_age, section.b_age);
120+
lastSection.t_age = Math.min(lastSection.t_age, section.t_age);
121+
}
122+
return newSections;
123+
}
124+
125+
export function ensureArray<T>(x: T | T[]): T[] {
126+
if (Array.isArray(x)) {
127+
return x;
128+
}
129+
return [x];
130+
}

0 commit comments

Comments
 (0)