@macrostrat/column-views 1.0.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +3 -0
  3. package/dist/age-axis.7ce58d66.js +41 -0
  4. package/dist/age-axis.7ce58d66.js.map +1 -0
  5. package/dist/boxes.6d3192e6.js +164 -0
  6. package/dist/boxes.6d3192e6.js.map +1 -0
  7. package/dist/boxes.module.998ff312.js +13 -0
  8. package/dist/boxes.module.998ff312.js.map +1 -0
  9. package/dist/boxes.module.dd631fe3.css +4 -0
  10. package/dist/boxes.module.dd631fe3.css.map +1 -0
  11. package/dist/carbon-isotopes.6d9bddcf.js +11 -0
  12. package/dist/carbon-isotopes.6d9bddcf.js.map +1 -0
  13. package/dist/column.e35a471f.js +149 -0
  14. package/dist/column.e35a471f.js.map +1 -0
  15. package/dist/column.e901b5d4.js +117 -0
  16. package/dist/column.e901b5d4.js.map +1 -0
  17. package/dist/column.module.2e29259c.js +22 -0
  18. package/dist/column.module.2e29259c.js.map +1 -0
  19. package/dist/column.module.35184ea7.css +157 -0
  20. package/dist/column.module.35184ea7.css.map +1 -0
  21. package/dist/column.module.35ba04e7.js +34 -0
  22. package/dist/column.module.35ba04e7.js.map +1 -0
  23. package/dist/column.module.c9df6edf.css +138 -0
  24. package/dist/column.module.c9df6edf.css.map +1 -0
  25. package/dist/composite.494beffc.js +153 -0
  26. package/dist/composite.494beffc.js.map +1 -0
  27. package/dist/composite.module.5cc0e747.css +4 -0
  28. package/dist/composite.module.5cc0e747.css.map +1 -0
  29. package/dist/composite.module.6359deba.js +13 -0
  30. package/dist/composite.module.6359deba.js.map +1 -0
  31. package/dist/core.f3824dd8.js +89 -0
  32. package/dist/core.f3824dd8.js.map +1 -0
  33. package/dist/data-area.f9bb9ad9.js +86 -0
  34. package/dist/data-area.f9bb9ad9.js.map +1 -0
  35. package/dist/data-provider.61ef7f9a.js +25 -0
  36. package/dist/data-provider.61ef7f9a.js.map +1 -0
  37. package/dist/helpers.2af05ee4.js +94 -0
  38. package/dist/helpers.2af05ee4.js.map +1 -0
  39. package/dist/index.d.ts +363 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +19 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/index.module.8fad0020.js +37 -0
  44. package/dist/index.module.8fad0020.js.map +1 -0
  45. package/dist/index.module.de76feb2.css +65 -0
  46. package/dist/index.module.de76feb2.css.map +1 -0
  47. package/dist/isotopes-column.b5442b4d.js +163 -0
  48. package/dist/isotopes-column.b5442b4d.js.map +1 -0
  49. package/dist/layers.946aaa37.js +231 -0
  50. package/dist/layers.946aaa37.js.map +1 -0
  51. package/dist/map.e782010f.js +82 -0
  52. package/dist/map.e782010f.js.map +1 -0
  53. package/dist/names.ab14789e.js +65 -0
  54. package/dist/names.ab14789e.js.map +1 -0
  55. package/dist/providers.abcb2cbe.js +25 -0
  56. package/dist/providers.abcb2cbe.js.map +1 -0
  57. package/dist/resolvers.2949c4c0.js +83 -0
  58. package/dist/resolvers.2949c4c0.js.map +1 -0
  59. package/dist/section.6f6fc929.js +118 -0
  60. package/dist/section.6f6fc929.js.map +1 -0
  61. package/dist/selection-popover.7e008544.js +60 -0
  62. package/dist/selection-popover.7e008544.js.map +1 -0
  63. package/dist/selection-popover.module.2732ebc0.css +34 -0
  64. package/dist/selection-popover.module.2732ebc0.css.map +1 -0
  65. package/dist/selection-popover.module.fdbfb40e.js +22 -0
  66. package/dist/selection-popover.module.fdbfb40e.js.map +1 -0
  67. package/dist/selection.add9f8b0.js +117 -0
  68. package/dist/selection.add9f8b0.js.map +1 -0
  69. package/dist/store.c5271371.js +18 -0
  70. package/dist/store.c5271371.js.map +1 -0
  71. package/dist/types.ff938b22.js +18 -0
  72. package/dist/types.ff938b22.js.map +1 -0
  73. package/dist/unit-details.0c1edd00.js +209 -0
  74. package/dist/unit-details.0c1edd00.js.map +1 -0
  75. package/dist/units.5ec6a44c.js +42 -0
  76. package/dist/units.5ec6a44c.js.map +1 -0
  77. package/package.json +66 -0
  78. package/src/age-axis.ts +42 -0
  79. package/src/carbon-isotopes/column.module.sass +136 -0
  80. package/src/carbon-isotopes/column.ts +131 -0
  81. package/src/carbon-isotopes/core.ts +78 -0
  82. package/src/carbon-isotopes/data-area.ts +96 -0
  83. package/src/carbon-isotopes/data-provider.ts +19 -0
  84. package/src/carbon-isotopes/index.ts +3 -0
  85. package/src/carbon-isotopes/isotopes-column.ts +214 -0
  86. package/src/column.module.sass +114 -0
  87. package/src/column.ts +185 -0
  88. package/src/helpers.ts +133 -0
  89. package/src/index.ts +7 -0
  90. package/src/map/animated.ts +78 -0
  91. package/src/map/index.ts +86 -0
  92. package/src/map/layers.ts +316 -0
  93. package/src/providers.ts +34 -0
  94. package/src/section.ts +129 -0
  95. package/src/selection-popover.module.sass +27 -0
  96. package/src/selection-popover.ts +71 -0
  97. package/src/store.ts +12 -0
  98. package/src/unit-details/index.module.sass +51 -0
  99. package/src/unit-details/index.ts +215 -0
  100. package/src/units/boxes.module.sass +3 -0
  101. package/src/units/boxes.ts +221 -0
  102. package/src/units/composite.module.sass +2 -0
  103. package/src/units/composite.ts +266 -0
  104. package/src/units/index.ts +36 -0
  105. package/src/units/names.ts +118 -0
  106. package/src/units/resolvers.ts +111 -0
  107. package/src/units/selection.ts +167 -0
  108. package/src/units/types.ts +26 -0
  109. package/src/units/units.scss +16 -0
@@ -0,0 +1,114 @@
1
+ .column-container
2
+ --column-background-color: var(--background-color, #fff)
3
+ --column-stroke-color: var(--text-color, #000)
4
+ --column-text-color: var(--text-color, #000)
5
+
6
+ @media (prefers-color-scheme: dark)
7
+ .column-container
8
+ --column-background-color: var(--background-color, #000)
9
+ --column-stroke-color: var(--text-color, #fff)
10
+ --column-text-color: var(--text-color, #fff)
11
+ color-scheme: dark
12
+
13
+ .column-container :global
14
+ .column
15
+ display: flex
16
+ flex-direction: row
17
+ position: relative
18
+
19
+ .age-axis-label
20
+ writing-mode: vertical-lr
21
+ transform: rotate(180deg)
22
+ font-size: 12px
23
+ text-align: center
24
+ position: sticky
25
+ top: 0
26
+ max-height: 100vh
27
+
28
+ .tick text
29
+ text-anchor: middle
30
+ font-weight: 400 !important
31
+ transform: rotate(-90deg) translate(8px, -12px)
32
+
33
+ rect.unit
34
+ stroke: var(--column-stroke-color)
35
+ stroke-width: 1px
36
+
37
+ g.lithology-column use.frame
38
+ stroke: var(--column-stroke-color)
39
+ stroke-width: 1.5px !important
40
+ pointer-events: none
41
+
42
+ .column-container :global .unit-label
43
+ text-align: center
44
+
45
+ .column-container :global .col-note-label
46
+ font-size: 10px
47
+ margin-top: 3px
48
+ padding: 2px
49
+ padding-left: 3px
50
+ line-height: 9px
51
+ border-left: none !important
52
+
53
+ .column-container :global g.height-range
54
+ display: none
55
+
56
+ .column-container :global .note-inner
57
+ border: none
58
+
59
+ .column-container :global .frame rect
60
+ fill: transparent
61
+
62
+ .column-container :global .labeled-unit .unit-overlay
63
+ font-size: 10px
64
+ font-style: italic
65
+ display: flex
66
+ align-items: center
67
+ justify-content: center
68
+
69
+ .column-container :global .labeled-unit .unit-overlay .unit-label
70
+ display: block
71
+ text-shadow: 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color), 0px 0px 4px var(--column-background-color)
72
+
73
+ .column-container :global .default-buttons
74
+ width: 100%
75
+ margin: 0 -10px
76
+
77
+ .column-container :global div.section
78
+ display: flex
79
+ flex-direction: row
80
+
81
+ .column-container :global div.section :global(.timescale)
82
+ transform: translateY(0.5)
83
+
84
+ .column-container :global .section .divisions .unit
85
+ cursor: pointer
86
+
87
+ .column-container :global rect.selection-overlay
88
+ fill: rgba(255,0,0,0.5)
89
+
90
+ .column-container :global div.timescale
91
+ width: calc(6em + 4px)
92
+ --timescale-level-size: 1.5em
93
+
94
+ .unconformity
95
+ height: 0px
96
+ font-size: 10px
97
+ font-style: italic
98
+ text-align: center
99
+ margin-left: calc(6em + 4px + 40px)
100
+
101
+ .unconformity-text
102
+ transform: translateY(-0.5em)
103
+ width: var(--column-width)
104
+ color: var(--column-stroke-color)
105
+
106
+ .column-container.dark-mode :global
107
+ color: var(--column-text-color)
108
+
109
+ .column-container.dark-mode :global .timescale
110
+ color: #000
111
+
112
+ .column-container.dark-mode :global g.inner pattern image
113
+ filter: invert(80%)
114
+
package/src/column.ts ADDED
@@ -0,0 +1,185 @@
1
+ import {
2
+ ColumnAxisType,
3
+ ColumnLayoutContext,
4
+ ColumnProvider,
5
+ } from "@macrostrat/column-components";
6
+ import { hyperStyled } from "@macrostrat/hyper";
7
+ import { useDarkMode } from "@macrostrat/ui-components";
8
+ import classNames from "classnames";
9
+ import { createRef, RefObject, useContext, useMemo, useState } from "react";
10
+ import styles from "./column.module.sass";
11
+ import {
12
+ TrackedLabeledUnit,
13
+ UnitKeyboardNavigation,
14
+ UnitSelectionProvider,
15
+ useUnitSelectionDispatch,
16
+ } from "./units";
17
+ import { SectionInfo } from "./section";
18
+ import { RectBounds } from "./units/boxes";
19
+ import { UnitSelectionPopover } from "./selection-popover";
20
+ import { MacrostratUnitsProvider } from "./store";
21
+ import { IColumnProps, Section } from "./section";
22
+ import {
23
+ _mergeOverlappingSections,
24
+ ensureArray,
25
+ groupUnitsIntoSections,
26
+ } from "./helpers";
27
+
28
+ const h = hyperStyled(styles);
29
+
30
+ export function UnitComponent({ division, nColumns = 2, ...rest }) {
31
+ const { width } = useContext(ColumnLayoutContext);
32
+
33
+ //const nCols = Math.min(nColumns, division.overlappingUnits.length+1)
34
+ //console.log(division);
35
+ return h(TrackedLabeledUnit, {
36
+ division,
37
+ ...rest,
38
+ width: division.overlappingUnits.length > 0 ? width / nColumns : width,
39
+ x: (division.column * width) / nColumns,
40
+ });
41
+ }
42
+
43
+ function Unconformity({ upperUnits = [], lowerUnits = [], style }) {
44
+ if (upperUnits.length == 0 || lowerUnits.length == 0) {
45
+ return null;
46
+ }
47
+
48
+ const ageGap = lowerUnits[0].t_age - upperUnits[upperUnits.length - 1].b_age;
49
+
50
+ return h("div.unconformity", { style }, [
51
+ h("div.unconformity-text", `${ageGap.toFixed(1)} Ma`),
52
+ ]);
53
+ }
54
+
55
+ function sectionClassName(section: SectionInfo) {
56
+ return `section-${ensureArray(section.section_id).join("-")}`;
57
+ }
58
+
59
+ export interface ColumnProps extends IColumnProps {
60
+ unconformityLabels?: boolean;
61
+ className?: string;
62
+ mergeOverlappingSections?: boolean;
63
+ showLabelColumn?: boolean;
64
+ columnRef?: RefObject<HTMLElement>;
65
+ keyboardNavigation?: boolean;
66
+ showUnitPopover?: boolean;
67
+ t_age?: number;
68
+ b_age?: number;
69
+ }
70
+
71
+ export function Column(props: ColumnProps) {
72
+ const { showUnitPopover = false, ...rest } = props;
73
+ const ref = createRef<HTMLElement>();
74
+ // Selected item position
75
+ const [position, setPosition] = useState<RectBounds | null>(null);
76
+
77
+ if (!showUnitPopover) {
78
+ return h(_Column, rest);
79
+ }
80
+
81
+ return h(
82
+ UnitSelectionProvider,
83
+ {
84
+ onUnitSelected: (unit, target: SVGElement | HTMLElement | null) => {
85
+ if (!showUnitPopover) return;
86
+
87
+ if (unit == null) {
88
+ setPosition(null);
89
+ return;
90
+ }
91
+ const el: HTMLElement = ref.current;
92
+ if (el == null || target == null) return;
93
+ const rect = el.getBoundingClientRect();
94
+ const targetRect = target.getBoundingClientRect();
95
+ setPosition({
96
+ x: targetRect.left - rect.left,
97
+ y: targetRect.top - rect.top,
98
+ width: targetRect.width,
99
+ height: targetRect.height,
100
+ });
101
+ },
102
+ },
103
+ h(
104
+ _Column,
105
+ { ...rest, columnRef: ref },
106
+ h(UnitSelectionPopover, { position })
107
+ )
108
+ );
109
+ }
110
+
111
+ function _Column(props: Omit<ColumnProps, "showUnitPopover">) {
112
+ const {
113
+ data,
114
+ unitComponent = UnitComponent,
115
+ unconformityLabels = true,
116
+ showLabels = true,
117
+ width = 300,
118
+ columnWidth = 150,
119
+ className: baseClassName,
120
+ showLabelColumn = true,
121
+ mergeOverlappingSections = true,
122
+ keyboardNavigation = false,
123
+ columnRef,
124
+ children,
125
+ ...rest
126
+ } = props;
127
+
128
+ const darkMode = useDarkMode();
129
+ const sectionGroups = useMemo(() => {
130
+ let res = groupUnitsIntoSections(data);
131
+ if (mergeOverlappingSections) {
132
+ res = _mergeOverlappingSections(res);
133
+ }
134
+ return res;
135
+ }, [data, mergeOverlappingSections]);
136
+
137
+ const className = classNames(baseClassName, {
138
+ "dark-mode": darkMode?.isEnabled ?? false,
139
+ });
140
+
141
+ // Clear unit selection on click outside of units, if we have a dispatch function
142
+ const dispatch = useUnitSelectionDispatch();
143
+
144
+ return h(
145
+ "div.column-container",
146
+ {
147
+ className,
148
+ onClick(evt) {
149
+ dispatch?.(null, null, evt as any);
150
+ },
151
+ },
152
+ h(MacrostratUnitsProvider, { units: data }, [
153
+ h("div.column", { ref: columnRef }, [
154
+ h("div.age-axis-label", "Age (Ma)"),
155
+ h(
156
+ "div.main-column",
157
+ sectionGroups.map((group, i) => {
158
+ const { section_id: id, units: data } = group;
159
+ const lastGroup = sectionGroups[i - 1];
160
+ return h([
161
+ h.if(unconformityLabels)(Unconformity, {
162
+ upperUnits: lastGroup?.units,
163
+ lowerUnits: data,
164
+ style: { width: showLabels ? columnWidth : width },
165
+ }),
166
+ h(`div.section`, { className: sectionClassName(group) }, [
167
+ h(Section, {
168
+ data,
169
+ unitComponent,
170
+ showLabels,
171
+ width,
172
+ columnWidth,
173
+ showLabelColumn,
174
+ ...rest,
175
+ }),
176
+ ]),
177
+ ]);
178
+ })
179
+ ),
180
+ h.if(keyboardNavigation)(UnitKeyboardNavigation, { units: data }),
181
+ children,
182
+ ]),
183
+ ])
184
+ );
185
+ }
package/src/helpers.ts ADDED
@@ -0,0 +1,133 @@
1
+ import { BaseUnit, UnitLong } from "@macrostrat/api-types";
2
+ import { IUnit } from "./units";
3
+ import { SectionInfo } from "./section";
4
+ import { group } from "d3-array";
5
+ import {
6
+ AgeRange,
7
+ compareAgeRanges,
8
+ AgeRangeRelationship,
9
+ } from "@macrostrat/stratigraphy-utils";
10
+
11
+ const dt = 0.001;
12
+
13
+ function unitsOverlap<T extends BaseUnit>(a: T, b: T) {
14
+ const rel = compareAgeRanges(unitAgeRange(a), unitAgeRange(b), 0.001);
15
+ return rel != AgeRangeRelationship.Disjoint;
16
+ }
17
+
18
+ function unitAgeRange<T extends BaseUnit>(unit: T): AgeRange {
19
+ return [unit.b_age, unit.t_age];
20
+ }
21
+
22
+ interface ExtUnit extends UnitLong {
23
+ bottomOverlap: boolean;
24
+ overlappingUnits: number[];
25
+ column?: number;
26
+ }
27
+
28
+ export function extendDivision(
29
+ unit: UnitLong,
30
+ i: number,
31
+ divisions: UnitLong[]
32
+ ): ExtUnit {
33
+ const overlappingUnits = divisions.filter(
34
+ (d) => d.unit_id != unit.unit_id && unitsOverlap(unit, d)
35
+ );
36
+ let bottomOverlap = false;
37
+ for (const d of overlappingUnits) {
38
+ if (d.b_age < unit.b_age + dt) bottomOverlap = true;
39
+ }
40
+
41
+ let column = 0;
42
+ if (overlappingUnits.length == 1) {
43
+ column = 1;
44
+ }
45
+
46
+ return {
47
+ ...unit,
48
+ bottomOverlap,
49
+ column,
50
+ overlappingUnits: overlappingUnits.map((d) => d.unit_id),
51
+ };
52
+ }
53
+
54
+ export function preprocessUnits(units: UnitLong[]) {
55
+ let divisions = units.map(extendDivision);
56
+ for (let d of divisions) {
57
+ const overlappingUnits = divisions.filter((u) =>
58
+ d.overlappingUnits.includes(u.unit_id)
59
+ );
60
+
61
+ const maxNOverlapping = Math.max(
62
+ Math.max(
63
+ ...d.overlappingUnits.map(
64
+ (uid) =>
65
+ divisions.find((u) => u.unit_id == uid).overlappingUnits.length
66
+ ),
67
+ 0
68
+ )
69
+ );
70
+
71
+ //d.maxNOverlapping = maxNOverlapping;
72
+
73
+ // Overlapping columns
74
+ const columns = overlappingUnits.map((d) => d.column);
75
+
76
+ if (columns.includes(d.column)) {
77
+ let col = 0;
78
+ // Go through columns to find a better index
79
+ while (columns.includes(col)) {
80
+ col++;
81
+ }
82
+ d.column = col;
83
+ }
84
+ }
85
+
86
+ return divisions;
87
+ }
88
+
89
+ export function groupUnitsIntoSections(units: IUnit[]): SectionInfo[] {
90
+ let groups = Array.from(group(units, (d) => d.section_id));
91
+ return groups.map(([section_id, units]) => {
92
+ const t_age = Math.min(...units.map((d) => d.t_age));
93
+ const b_age = Math.max(...units.map((d) => d.b_age));
94
+ return { section_id, t_age, b_age, units };
95
+ });
96
+ }
97
+
98
+ export function _mergeOverlappingSections(
99
+ sections: SectionInfo[]
100
+ ): SectionInfo[] {
101
+ /** Columns can have sections that overlap in time. Here, we merge overlapping
102
+ * sections into a single section to correctly render gap-bound packages.
103
+ */
104
+ const [firstSection, ...rest] = sections;
105
+ const newSections = [firstSection];
106
+ for (const section of rest) {
107
+ const lastSection = newSections[newSections.length - 1];
108
+ if (
109
+ lastSection.b_age < section.t_age ||
110
+ lastSection.t_age > section.b_age
111
+ ) {
112
+ // No overlap, add the section as normal
113
+ newSections.push(section);
114
+ continue;
115
+ }
116
+ // Overlap, merge the sections
117
+ lastSection.section_id = [
118
+ ...ensureArray(lastSection.section_id),
119
+ ...ensureArray(section.section_id),
120
+ ];
121
+ lastSection.units.push(...section.units);
122
+ lastSection.b_age = Math.max(lastSection.b_age, section.b_age);
123
+ lastSection.t_age = Math.min(lastSection.t_age, section.t_age);
124
+ }
125
+ return newSections;
126
+ }
127
+
128
+ export function ensureArray<T>(x: T | T[]): T[] {
129
+ if (Array.isArray(x)) {
130
+ return x;
131
+ }
132
+ return [x];
133
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from "./units";
2
+ export * from "./age-axis";
3
+ export * from "./carbon-isotopes";
4
+ export * from "./providers";
5
+ export * from "./helpers";
6
+ export * from "./map";
7
+ export * from "./column";
@@ -0,0 +1,78 @@
1
+ import { useState } from "react";
2
+ import h from "@macrostrat/hyper";
3
+ import { Globe } from "@macrostrat/svg-map-components";
4
+ import { Button } from "@blueprintjs/core";
5
+ import { geoCentroid } from "d3-geo";
6
+ import { LandLayer } from "@macrostrat/svg-map-components";
7
+ import { Columns, CurrentColumn } from "./layers";
8
+ import classNames from "classnames";
9
+ import { useSpring, animated } from "react-spring";
10
+
11
+ const AnimatedGlobe = animated(Globe);
12
+
13
+ const MapViewFrame = (props) => {
14
+ const [expanded, setExpanded] = useState(false);
15
+ const className = classNames({ expanded }, "context-map");
16
+ const { children, center, margin = 10 } = props;
17
+ const baseSize = 250;
18
+ const sz = expanded ? 450 : baseSize;
19
+
20
+ let scale = sz / 2 - margin;
21
+ if (expanded) {
22
+ scale *= 3;
23
+ }
24
+
25
+ const targetProps = {
26
+ width: sz,
27
+ height: sz,
28
+ scale,
29
+ };
30
+
31
+ const animationProps = useSpring(targetProps);
32
+
33
+ return h(
34
+ "div.map-placeholder",
35
+ { style: { width: baseSize, height: baseSize } },
36
+ [
37
+ h(animated.div, { className, style: animationProps }, [
38
+ h(
39
+ AnimatedGlobe,
40
+ {
41
+ ...targetProps,
42
+ margin,
43
+ center,
44
+ allowDrag: expanded,
45
+ allowZoom: false,
46
+ keepNorthUp: true,
47
+ onClick() {
48
+ setExpanded(true);
49
+ },
50
+ },
51
+ [h(LandLayer), children]
52
+ ),
53
+ h.if(expanded)(Button, {
54
+ className: "close-button",
55
+ icon: "cross",
56
+ minimal: true,
57
+ onClick() {
58
+ setExpanded(false);
59
+ },
60
+ intent: "danger",
61
+ }),
62
+ ]),
63
+ ]
64
+ );
65
+ };
66
+
67
+ export const AnimatedMapView = (props) => {
68
+ const { currentColumn, setCurrentColumn, children, ...rest } = props;
69
+ const center = geoCentroid(currentColumn);
70
+
71
+ return h(MapViewFrame, { center, ...rest }, [
72
+ h(Columns, { onClick: setCurrentColumn, ...rest }),
73
+ children,
74
+ h.if(currentColumn != null)(CurrentColumn, {
75
+ feature: currentColumn,
76
+ }),
77
+ ]);
78
+ };
@@ -0,0 +1,86 @@
1
+ import { useRef } from "react";
2
+ import h from "@macrostrat/hyper";
3
+ import { Globe, LandLayer } from "@macrostrat/svg-map-components";
4
+ import { geoCentroid } from "d3-geo";
5
+ import { useElementSize } from "@macrostrat/ui-components";
6
+ import { Columns, CurrentColumn } from "./layers";
7
+
8
+ function ResizableMapFrame(props) {
9
+ const { center, children, style, margin, className, allowZoom, ...rest } =
10
+ props;
11
+ let { scale } = props;
12
+ const ref = useRef(null);
13
+ const sz = useElementSize(ref);
14
+ const { width, height } = sz ?? { width: 0, height: 0 };
15
+ if (scale == null) {
16
+ scale = Math.min(width, height) + 2 * margin;
17
+ }
18
+
19
+ let zoomScaleExtent = null;
20
+
21
+ if (allowZoom) {
22
+ zoomScaleExtent = [
23
+ 0.1 * Math.min(width, height),
24
+ 2 * Math.max(width, height),
25
+ ];
26
+ }
27
+
28
+ return h("div.map-area", { ref, style, className }, [
29
+ h(
30
+ Globe,
31
+ {
32
+ width,
33
+ height,
34
+ margin,
35
+ center,
36
+ allowDrag: true,
37
+ allowZoom,
38
+ keepNorthUp: true,
39
+ zoomScaleExtent,
40
+ ...rest,
41
+ scale,
42
+ },
43
+ [h(LandLayer), children]
44
+ ),
45
+ ]);
46
+ }
47
+
48
+ const ColumnNavigatorMap = (props) => {
49
+ const {
50
+ currentColumn,
51
+ setCurrentColumn,
52
+ children,
53
+ style,
54
+ margin = 10,
55
+ scale,
56
+ className,
57
+ showInProcessColumns = false,
58
+ ...rest
59
+ } = props;
60
+
61
+ const columnCenter = geoCentroid(currentColumn);
62
+
63
+ return h(
64
+ ResizableMapFrame,
65
+ { center: columnCenter, style, margin, scale, className },
66
+ [
67
+ children,
68
+ h(Columns, {
69
+ onChange: setCurrentColumn,
70
+ col_id: currentColumn?.properties.col_id,
71
+ ...rest,
72
+ }),
73
+ h.if(showInProcessColumns)(Columns, {
74
+ onChange: setCurrentColumn,
75
+ col_id: currentColumn?.properties.col_id,
76
+ status_code: "in process",
77
+ color: "rgba(200,150,150, 0.5)",
78
+ ...rest,
79
+ }),
80
+ h.if(currentColumn != null)(CurrentColumn, { feature: currentColumn }),
81
+ ]
82
+ );
83
+ };
84
+
85
+ export * from "./layers";
86
+ export { ColumnNavigatorMap, ResizableMapFrame };