@macrostrat/column-views 1.0.3 → 2.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 (242) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/esm/_shared.f7eec55a.js +9 -0
  3. package/dist/esm/_shared.f7eec55a.js.map +1 -0
  4. package/dist/esm/age-axis.4a8cf5e6.js +98 -0
  5. package/dist/esm/age-axis.4a8cf5e6.js.map +1 -0
  6. package/dist/esm/age-axis.module.03773a80.css +33 -0
  7. package/dist/esm/age-axis.module.03773a80.css.map +1 -0
  8. package/dist/esm/age-axis.module.3cc91335.js +22 -0
  9. package/dist/esm/age-axis.module.3cc91335.js.map +1 -0
  10. package/dist/esm/age-model-overlay.c7226855.js +57 -0
  11. package/dist/esm/age-model-overlay.c7226855.js.map +1 -0
  12. package/dist/esm/age-model-overlay.module.5d9e78fb.css +14 -0
  13. package/dist/esm/age-model-overlay.module.5d9e78fb.css.map +1 -0
  14. package/dist/esm/age-model-overlay.module.cd985dcb.js +16 -0
  15. package/dist/esm/age-model-overlay.module.cd985dcb.js.map +1 -0
  16. package/dist/esm/base.910b80b4.js +288 -0
  17. package/dist/esm/base.910b80b4.js.map +1 -0
  18. package/dist/esm/boxes.8292cff2.js +258 -0
  19. package/dist/esm/boxes.8292cff2.js.map +1 -0
  20. package/dist/esm/boxes.module.2b5fb18e.css +26 -0
  21. package/dist/esm/boxes.module.2b5fb18e.css.map +1 -0
  22. package/dist/esm/boxes.module.4ebc7796.js +19 -0
  23. package/dist/esm/boxes.module.4ebc7796.js.map +1 -0
  24. package/dist/esm/{carbon-isotopes.3b502a9e.js → carbon-isotopes.10db8285.js} +2 -2
  25. package/dist/esm/{carbon-isotopes.3b502a9e.js.map → carbon-isotopes.10db8285.js.map} +1 -1
  26. package/dist/esm/colors.395c6db5.js +40 -0
  27. package/dist/esm/colors.395c6db5.js.map +1 -0
  28. package/dist/esm/column-correlation.c8dcfe98.js +9 -0
  29. package/dist/esm/column-correlation.c8dcfe98.js.map +1 -0
  30. package/dist/esm/column-nav.5414677c.js +55 -0
  31. package/dist/esm/column-nav.5414677c.js.map +1 -0
  32. package/dist/esm/column-navigation.37cd3245.js +9 -0
  33. package/dist/esm/column-navigation.37cd3245.js.map +1 -0
  34. package/dist/esm/column.01d68dd8.js +127 -0
  35. package/dist/esm/column.01d68dd8.js.map +1 -0
  36. package/dist/esm/{column.db058031.js → column.a25f8ebd.js} +4 -4
  37. package/dist/esm/column.a25f8ebd.js.map +1 -0
  38. package/dist/esm/column.module.1b776e15.js +46 -0
  39. package/dist/esm/column.module.1b776e15.js.map +1 -0
  40. package/dist/esm/column.module.a67a6b4c.css +159 -0
  41. package/dist/esm/column.module.a67a6b4c.css.map +1 -0
  42. package/dist/esm/composite-scale.577bf64a.js +222 -0
  43. package/dist/esm/composite-scale.577bf64a.js.map +1 -0
  44. package/dist/esm/composite.039e4798.js +163 -0
  45. package/dist/esm/composite.039e4798.js.map +1 -0
  46. package/dist/esm/{core.4db8e452.js → core.843310d3.js} +11 -12
  47. package/dist/esm/core.843310d3.js.map +1 -0
  48. package/dist/esm/core.91ede078.js +206 -0
  49. package/dist/esm/core.91ede078.js.map +1 -0
  50. package/dist/esm/correlation-chart.abd8b346.js +9 -0
  51. package/dist/esm/correlation-chart.abd8b346.js.map +1 -0
  52. package/dist/esm/data-provider.1506eb64.js.map +1 -1
  53. package/dist/esm/data-provider.f10c6d0b.js +13 -0
  54. package/dist/esm/data-provider.f10c6d0b.js.map +1 -0
  55. package/dist/esm/fetch.99aec438.js +152 -0
  56. package/dist/esm/fetch.99aec438.js.map +1 -0
  57. package/dist/esm/hash-string.285b37fb.js +39 -0
  58. package/dist/esm/hash-string.285b37fb.js.map +1 -0
  59. package/dist/esm/helpers.2f0a0cb7.js +141 -0
  60. package/dist/esm/helpers.2f0a0cb7.js.map +1 -0
  61. package/dist/esm/index.d.ts +797 -130
  62. package/dist/esm/index.d.ts.map +1 -1
  63. package/dist/esm/index.js +13 -9
  64. package/dist/esm/index.js.map +1 -1
  65. package/dist/esm/inset-map.3c18106d.js +66 -0
  66. package/dist/esm/inset-map.3c18106d.js.map +1 -0
  67. package/dist/esm/keyboard-navigation.6713401b.js +48 -0
  68. package/dist/esm/keyboard-navigation.6713401b.js.map +1 -0
  69. package/dist/esm/keyboard-navigation.a9fc80dd.js +112 -0
  70. package/dist/esm/keyboard-navigation.a9fc80dd.js.map +1 -0
  71. package/dist/esm/layers.033d3fb0.js +170 -0
  72. package/dist/esm/layers.033d3fb0.js.map +1 -0
  73. package/dist/esm/main.2e0375a5.js +221 -0
  74. package/dist/esm/main.2e0375a5.js.map +1 -0
  75. package/dist/esm/main.module.3dd9500b.css +134 -0
  76. package/dist/esm/main.module.3dd9500b.css.map +1 -0
  77. package/dist/esm/main.module.c09154b1.js +70 -0
  78. package/dist/esm/main.module.c09154b1.js.map +1 -0
  79. package/dist/esm/mapbox.cac42eed.js +167 -0
  80. package/dist/esm/mapbox.cac42eed.js.map +1 -0
  81. package/dist/esm/maps.bcdea9c1.js +11 -0
  82. package/dist/esm/maps.bcdea9c1.js.map +1 -0
  83. package/dist/esm/{names.f6a4e9a4.js → names.a8f2b452.js} +5 -5
  84. package/dist/esm/names.a8f2b452.js.map +1 -0
  85. package/dist/esm/panel.598f76a5.js +420 -0
  86. package/dist/esm/panel.598f76a5.js.map +1 -0
  87. package/dist/esm/panel.module.386166cc.js +58 -0
  88. package/dist/esm/panel.module.386166cc.js.map +1 -0
  89. package/dist/esm/panel.module.3d2ea3c6.css +111 -0
  90. package/dist/esm/panel.module.3d2ea3c6.css.map +1 -0
  91. package/dist/esm/popover.a810b7bc.js +66 -0
  92. package/dist/esm/popover.a810b7bc.js.map +1 -0
  93. package/dist/esm/popover.module.c4ba4189.js +22 -0
  94. package/dist/esm/popover.module.c4ba4189.js.map +1 -0
  95. package/dist/esm/{selection-popover.module.0a701258.css → popover.module.c4d6bfb0.css} +11 -8
  96. package/dist/esm/popover.module.c4d6bfb0.css.map +1 -0
  97. package/dist/esm/prepare-data.d4284b4a.js +125 -0
  98. package/dist/esm/prepare-data.d4284b4a.js.map +1 -0
  99. package/dist/esm/prepare-units.6c890a96.js +104 -0
  100. package/dist/esm/prepare-units.6c890a96.js.map +1 -0
  101. package/dist/esm/{resolvers.b5c82b78.js → resolvers.36013b49.js} +13 -2
  102. package/dist/esm/resolvers.36013b49.js.map +1 -0
  103. package/dist/esm/section.a34d379a.js +215 -0
  104. package/dist/esm/section.a34d379a.js.map +1 -0
  105. package/dist/esm/selection.f5b0297e.js +143 -0
  106. package/dist/esm/selection.f5b0297e.js.map +1 -0
  107. package/dist/esm/state.178ef364.js +75 -0
  108. package/dist/esm/state.178ef364.js.map +1 -0
  109. package/dist/esm/state.2952cbca.js +118 -0
  110. package/dist/esm/state.2952cbca.js.map +1 -0
  111. package/dist/esm/store.c4d7a8a4.js +52 -0
  112. package/dist/esm/store.c4d7a8a4.js.map +1 -0
  113. package/dist/esm/styles.7bc776d1.js +95 -0
  114. package/dist/esm/styles.7bc776d1.js.map +1 -0
  115. package/dist/esm/svg.4b9a96c1.js +89 -0
  116. package/dist/esm/svg.4b9a96c1.js.map +1 -0
  117. package/dist/esm/types.0f0b57c9.js +3 -0
  118. package/dist/esm/types.0f0b57c9.js.map +1 -0
  119. package/dist/esm/unit-details.071cefed.js +9 -0
  120. package/dist/esm/unit-details.071cefed.js.map +1 -0
  121. package/dist/esm/units.5a4fc058.js +98 -0
  122. package/dist/esm/units.5a4fc058.js.map +1 -0
  123. package/dist/esm/utils.d7a43a2a.js +55 -0
  124. package/dist/esm/utils.d7a43a2a.js.map +1 -0
  125. package/dist/node/index.js.map +1 -1
  126. package/package.json +24 -7
  127. package/src/age-axis.module.sass +27 -0
  128. package/src/age-axis.ts +82 -19
  129. package/src/age-model-overlay.module.sass +11 -0
  130. package/src/age-model-overlay.ts +73 -0
  131. package/src/carbon-isotopes/column.ts +4 -2
  132. package/src/carbon-isotopes/core.ts +9 -6
  133. package/src/carbon-isotopes/data-provider.ts +3 -3
  134. package/src/column.module.sass +58 -49
  135. package/src/column.ts +149 -135
  136. package/src/correlation-chart/hash-string.ts +57 -0
  137. package/src/correlation-chart/index.ts +2 -0
  138. package/src/correlation-chart/main.module.sass +122 -0
  139. package/src/correlation-chart/main.ts +305 -0
  140. package/src/correlation-chart/prepare-data.ts +217 -0
  141. package/src/correlation-chart/stories/correlation-chart.stories.ts +192 -0
  142. package/src/correlation-chart/stories/stories.module.sass +18 -0
  143. package/src/correlation-chart/unconformity-line.module.sass +8 -0
  144. package/src/correlation-chart/unconformity-line.ts +25 -0
  145. package/src/data-provider/base.ts +388 -0
  146. package/src/data-provider/column-nav.ts +53 -0
  147. package/src/data-provider/fetch.ts +231 -0
  148. package/src/data-provider/index.ts +4 -0
  149. package/src/data-provider/store.ts +72 -0
  150. package/src/index.ts +5 -3
  151. package/src/maps/_shared/index.ts +2 -0
  152. package/src/maps/_shared/inset-map.stories.ts +20 -0
  153. package/src/maps/_shared/inset-map.ts +87 -0
  154. package/src/maps/_shared/styles.ts +57 -0
  155. package/src/maps/column-correlation/column-correlation-map.stories.ts +96 -0
  156. package/src/maps/column-correlation/core.ts +225 -0
  157. package/src/maps/column-correlation/index.ts +2 -0
  158. package/src/maps/column-correlation/state.ts +192 -0
  159. package/src/maps/column-navigation/index.ts +2 -0
  160. package/src/maps/column-navigation/mapbox/column-navigation-map.stories.ts +102 -0
  161. package/src/maps/column-navigation/mapbox/index.ts +219 -0
  162. package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +119 -0
  163. package/src/maps/column-navigation/mapbox/state.ts +109 -0
  164. package/src/maps/column-navigation/svg/column-navigation-svg-map.stories.ts +46 -0
  165. package/src/{map → maps/column-navigation/svg}/index.ts +18 -6
  166. package/src/{map → maps/column-navigation/svg}/layers.ts +28 -109
  167. package/src/maps/column-navigation/utils/keyboard-navigation.ts +58 -0
  168. package/src/maps/index.ts +3 -0
  169. package/src/prepare-units/composite-scale.ts +353 -0
  170. package/src/prepare-units/helpers.ts +226 -0
  171. package/src/prepare-units/index.ts +177 -0
  172. package/src/prepare-units/utils.ts +98 -0
  173. package/src/section.ts +264 -84
  174. package/src/unit-details/index.ts +2 -215
  175. package/src/unit-details/{index.module.sass → panel.module.sass} +39 -8
  176. package/src/unit-details/panel.ts +523 -0
  177. package/src/{selection-popover.module.sass → unit-details/popover.module.sass} +4 -2
  178. package/src/unit-details/popover.ts +82 -0
  179. package/src/units/boxes.module.sass +16 -0
  180. package/src/units/boxes.ts +243 -90
  181. package/src/units/colors.ts +64 -0
  182. package/src/units/composite.ts +157 -152
  183. package/src/units/index.ts +76 -9
  184. package/src/units/names.ts +8 -4
  185. package/src/units/resolvers.ts +11 -0
  186. package/src/units/selection.ts +115 -101
  187. package/src/units/types.ts +5 -16
  188. package/dist/esm/age-axis.64c509ee.js +0 -41
  189. package/dist/esm/age-axis.64c509ee.js.map +0 -1
  190. package/dist/esm/boxes.13968b76.js +0 -164
  191. package/dist/esm/boxes.13968b76.js.map +0 -1
  192. package/dist/esm/boxes.module.28873d08.css +0 -4
  193. package/dist/esm/boxes.module.28873d08.css.map +0 -1
  194. package/dist/esm/boxes.module.605bdcd6.js +0 -13
  195. package/dist/esm/boxes.module.605bdcd6.js.map +0 -1
  196. package/dist/esm/column.8dd26e1a.js +0 -149
  197. package/dist/esm/column.8dd26e1a.js.map +0 -1
  198. package/dist/esm/column.db058031.js.map +0 -1
  199. package/dist/esm/column.module.039d872c.css +0 -151
  200. package/dist/esm/column.module.039d872c.css.map +0 -1
  201. package/dist/esm/column.module.e632868a.js +0 -19
  202. package/dist/esm/column.module.e632868a.js.map +0 -1
  203. package/dist/esm/composite.608a4ca2.js +0 -153
  204. package/dist/esm/composite.608a4ca2.js.map +0 -1
  205. package/dist/esm/core.4db8e452.js.map +0 -1
  206. package/dist/esm/helpers.8a03cfc7.js +0 -94
  207. package/dist/esm/helpers.8a03cfc7.js.map +0 -1
  208. package/dist/esm/index.module.0844afd8.css +0 -65
  209. package/dist/esm/index.module.0844afd8.css.map +0 -1
  210. package/dist/esm/index.module.24fe3a2e.js +0 -37
  211. package/dist/esm/index.module.24fe3a2e.js.map +0 -1
  212. package/dist/esm/layers.ad5fd25d.js +0 -231
  213. package/dist/esm/layers.ad5fd25d.js.map +0 -1
  214. package/dist/esm/map.7aa26f17.js +0 -82
  215. package/dist/esm/map.7aa26f17.js.map +0 -1
  216. package/dist/esm/names.f6a4e9a4.js.map +0 -1
  217. package/dist/esm/providers.cd1e652f.js +0 -25
  218. package/dist/esm/providers.cd1e652f.js.map +0 -1
  219. package/dist/esm/resolvers.b5c82b78.js.map +0 -1
  220. package/dist/esm/section.cc1b1100.js +0 -118
  221. package/dist/esm/section.cc1b1100.js.map +0 -1
  222. package/dist/esm/selection-popover.17d1bd55.js +0 -60
  223. package/dist/esm/selection-popover.17d1bd55.js.map +0 -1
  224. package/dist/esm/selection-popover.module.0a701258.css.map +0 -1
  225. package/dist/esm/selection-popover.module.e22f5183.js +0 -22
  226. package/dist/esm/selection-popover.module.e22f5183.js.map +0 -1
  227. package/dist/esm/selection.bbf26d0e.js +0 -117
  228. package/dist/esm/selection.bbf26d0e.js.map +0 -1
  229. package/dist/esm/store.25eaa168.js +0 -18
  230. package/dist/esm/store.25eaa168.js.map +0 -1
  231. package/dist/esm/types.f016e032.js +0 -18
  232. package/dist/esm/types.f016e032.js.map +0 -1
  233. package/dist/esm/unit-details.56ff8b70.js +0 -209
  234. package/dist/esm/unit-details.56ff8b70.js.map +0 -1
  235. package/dist/esm/units.361088d4.js +0 -42
  236. package/dist/esm/units.361088d4.js.map +0 -1
  237. package/src/helpers.ts +0 -133
  238. package/src/providers.ts +0 -34
  239. package/src/selection-popover.ts +0 -71
  240. package/src/store.ts +0 -12
  241. package/src/units/units.scss +0 -16
  242. /package/src/{map → maps/column-navigation/svg}/animated.ts +0 -0
@@ -0,0 +1,523 @@
1
+ import hyper from "@macrostrat/hyper";
2
+ import styles from "./panel.module.sass";
3
+ import { JSONView } from "@macrostrat/ui-components";
4
+ import { Button, ButtonGroup } from "@blueprintjs/core";
5
+ import { ReactNode, useMemo, useState } from "react";
6
+ import {
7
+ DataField,
8
+ EnvironmentsList,
9
+ IntervalShort,
10
+ IntervalTag,
11
+ ItemList,
12
+ LithologyList,
13
+ LithologyTagFeature,
14
+ Parenthetical,
15
+ Value,
16
+ } from "@macrostrat/data-components";
17
+ import { useMacrostratData, useMacrostratDefs } from "../data-provider";
18
+ import { Environment, UnitLong, UnitLongFull } from "@macrostrat/api-types";
19
+ import { defaultNameFunction } from "../units/names";
20
+ import classNames from "classnames";
21
+
22
+ const h = hyper.styled(styles);
23
+
24
+ export function UnitDetailsPanel({
25
+ unit,
26
+ onClose,
27
+ className,
28
+ features = new Set<UnitDetailsFeature>([
29
+ UnitDetailsFeature.AdjacentUnits,
30
+ UnitDetailsFeature.OutcropType,
31
+ UnitDetailsFeature.JSONToggle,
32
+ UnitDetailsFeature.DepthRange,
33
+ ]),
34
+ lithologyFeatures,
35
+ actions,
36
+ selectUnit,
37
+ columnUnits,
38
+ }: {
39
+ unit: any;
40
+ onClose?: any;
41
+ showLithologyProportions?: boolean;
42
+ className?: string;
43
+ actions?: ReactNode;
44
+ features?: Set<UnitDetailsFeature>;
45
+ lithologyFeatures?: Set<LithologyTagFeature>;
46
+ columnUnits?: UnitLong[];
47
+ selectUnit?: (unitID: number) => void;
48
+ }) {
49
+ const [showJSON, setShowJSON] = useState(false);
50
+
51
+ let content = null;
52
+ if (showJSON) {
53
+ content = h(JSONView, { data: unit, showRoot: false });
54
+ } else {
55
+ content = h(UnitDetailsContent, { unit, features, lithologyFeatures });
56
+ }
57
+
58
+ let title = defaultNameFunction(unit);
59
+
60
+ let hiddenActions = null;
61
+ if (features.has(UnitDetailsFeature.JSONToggle)) {
62
+ hiddenActions = h(Button, {
63
+ icon: "code",
64
+ small: true,
65
+ minimal: true,
66
+ key: "json-view-toggle",
67
+ className: classNames("json-view-toggle", { enabled: setShowJSON }),
68
+ onClick(evt) {
69
+ setShowJSON(!showJSON);
70
+ evt.stopPropagation();
71
+ },
72
+ });
73
+ }
74
+
75
+ return h("div.unit-details-panel", { className }, [
76
+ h(LegendPanelHeader, {
77
+ onClose,
78
+ title,
79
+ id: unit.unit_id,
80
+ actions,
81
+ hiddenActions,
82
+ }),
83
+ h("div.unit-details-content-holder", content),
84
+ ]);
85
+ }
86
+
87
+ export function LegendPanelHeader({
88
+ title,
89
+ id,
90
+ onClose,
91
+ actions = null,
92
+ hiddenActions,
93
+ }: {
94
+ title?: string | null;
95
+ id?: number | null;
96
+ onClose?: () => void;
97
+ actions?: ReactNode | null;
98
+ hiddenActions?: ReactNode | null;
99
+ }) {
100
+ return h("header.legend-panel-header", [
101
+ h("div.title-container", [
102
+ h.if(title != null)("h3", title),
103
+ h.if(hiddenActions != null)("div.hidden-actions", hiddenActions),
104
+ ]),
105
+ h("div.spacer"),
106
+ h.if(id != null)("code", id),
107
+ h.if(actions != null)(ButtonGroup, { minimal: true }, actions),
108
+ h.if(onClose != null)(Button, {
109
+ icon: "cross",
110
+ minimal: true,
111
+ small: true,
112
+ onClick() {
113
+ onClose();
114
+ },
115
+ }),
116
+ ]);
117
+ }
118
+
119
+ export enum UnitDetailsFeature {
120
+ AdjacentUnits = "adjacent-units",
121
+ Color = "color",
122
+ OutcropType = "outcrop-type",
123
+ JSONToggle = "json-toggle",
124
+ DepthRange = "depth-range",
125
+ }
126
+
127
+ function UnitDetailsContent({
128
+ unit,
129
+ selectUnit,
130
+ columnUnits,
131
+ lithologyFeatures = new Set([
132
+ LithologyTagFeature.Proportion,
133
+ LithologyTagFeature.Attributes,
134
+ ]),
135
+ features = new Set<UnitDetailsFeature>([
136
+ UnitDetailsFeature.AdjacentUnits,
137
+ UnitDetailsFeature.OutcropType,
138
+ ]),
139
+ }: {
140
+ unit: UnitLong;
141
+ selectUnit?: (unitID: number) => void;
142
+ columnUnits?: UnitLong[];
143
+ lithologyFeatures?: Set<LithologyTagFeature>;
144
+ features?: Set<UnitDetailsFeature>;
145
+ }) {
146
+ const lithMap = useMacrostratDefs("lithologies");
147
+ const envMap = useMacrostratDefs("environments");
148
+
149
+ const environments = enhanceEnvironments(unit.environ, envMap);
150
+ const lithologies = enhanceLithologies(unit.lith ?? [], lithMap);
151
+
152
+ // Create a lookup table of units if provided
153
+ const columnUnitsMap = useMemo(() => {
154
+ const map = new Map<number, UnitLong>();
155
+ for (const colUnit of columnUnits ?? []) {
156
+ map.set(colUnit.unit_id, colUnit);
157
+ }
158
+ return map;
159
+ }, [columnUnits]);
160
+
161
+ let outcropField = null;
162
+ if (features.has(UnitDetailsFeature.OutcropType)) {
163
+ // Determine outcrop type
164
+ let outcrop = unit.outcrop;
165
+ if (outcrop == "both") {
166
+ outcrop = "surface and subsurface";
167
+ }
168
+ outcropField = h(DataField, {
169
+ label: "Outcrop",
170
+ value: outcrop,
171
+ });
172
+ }
173
+
174
+ let thicknessOrHeightRange = null;
175
+ const [thickness, thicknessUnit] = getThickness(unit);
176
+ // Proxy for actual heights in t_pos and b_pos
177
+ if (
178
+ features.has(UnitDetailsFeature.DepthRange) &&
179
+ unit.t_pos != null &&
180
+ unit.b_pos != null &&
181
+ unit.min_thick == unit.max_thick && // We have an actual fixed height
182
+ unit.min_thick != 0 // Not a zero thickness
183
+ ) {
184
+ const label = unit.t_pos < unit.b_pos ? "Depth" : "Height";
185
+ const u1 = "m";
186
+
187
+ thicknessOrHeightRange = h(DataField, {
188
+ unit: u1,
189
+ label,
190
+ value: formatRange(unit.b_pos, unit.t_pos),
191
+ children: h(
192
+ Parenthetical,
193
+ h(Value, { value: thickness, unit: thicknessUnit })
194
+ ),
195
+ });
196
+ }
197
+ thicknessOrHeightRange ??= h(DataField, {
198
+ label: "Thickness",
199
+ value: thickness,
200
+ unit: thicknessUnit,
201
+ });
202
+
203
+ /** We are trying to move away from passing the "color" parameter in the API */
204
+ let colorSwatch: ReactNode = null;
205
+ if ("color" in unit) {
206
+ const unit1 = unit as UnitLongFull;
207
+ colorSwatch = h("div.color-swatch", {
208
+ style: { backgroundColor: unit1.color },
209
+ });
210
+ }
211
+
212
+ return h("div.unit-details-content", [
213
+ thicknessOrHeightRange,
214
+ h(LithologyList, {
215
+ label: "Lithology",
216
+ lithologies,
217
+ features: lithologyFeatures,
218
+ }),
219
+ h(AgeField, { unit }, [
220
+ h(Parenthetical, h(Duration, { value: unit.b_age - unit.t_age })),
221
+ h(IntervalProportions, { unit }),
222
+ ]),
223
+ h(EnvironmentsList, { environments }),
224
+ h.if(unit.strat_name_id != null)(
225
+ DataField,
226
+ {
227
+ label: "Stratigraphic name",
228
+ },
229
+ h("span.strat-name-id", unit.strat_name_id)
230
+ ),
231
+ outcropField,
232
+ h.if(features.has(UnitDetailsFeature.AdjacentUnits))([
233
+ h(
234
+ DataField,
235
+ { label: "Above" },
236
+ h(UnitIDList, { units: unit.units_above, selectUnit })
237
+ ),
238
+ h(
239
+ DataField,
240
+ { label: "Below" },
241
+ h(UnitIDList, { units: unit.units_below, selectUnit })
242
+ ),
243
+ ]),
244
+ colorSwatch,
245
+ h(
246
+ DataField,
247
+ { label: "Source", inline: true },
248
+ h(BibInfo, { refs: unit.refs })
249
+ ),
250
+ ]);
251
+ }
252
+
253
+ function getThickness(unit): [string, string] {
254
+ let minThickness = unit.min_thick ?? 0;
255
+ let maxThickness = unit.max_thick ?? unit.min_thick ?? 0;
256
+ let _unit = "m";
257
+
258
+ if (minThickness == 0 && maxThickness == 0) {
259
+ return ["Unknown", null];
260
+ }
261
+
262
+ if (minThickness < 0.8 && maxThickness < 1.2) {
263
+ // Convert to cm
264
+ minThickness = minThickness * 100;
265
+ maxThickness = maxThickness * 100;
266
+ _unit = "cm";
267
+ } else if (minThickness > 800 && maxThickness > 1200) {
268
+ // Convert to km
269
+ minThickness = minThickness / 1000;
270
+ maxThickness = maxThickness / 1000;
271
+ _unit = "km";
272
+ }
273
+
274
+ if (minThickness == maxThickness) {
275
+ return [formatSignificance(minThickness), _unit];
276
+ }
277
+
278
+ return [formatRange(minThickness, maxThickness), _unit];
279
+ }
280
+
281
+ function ThicknessField({ unit, label = "Thickness" }) {
282
+ const [value, thicknessUnit] = getThickness(unit);
283
+ return h(DataField, {
284
+ label,
285
+ value,
286
+ unit: thicknessUnit,
287
+ });
288
+ }
289
+
290
+ function BibInfo({ refs }) {
291
+ const refData = useMacrostratData("refs", refs);
292
+
293
+ if (refData == null || refData.length === 0) {
294
+ return null;
295
+ }
296
+
297
+ if (refData.length == 1) {
298
+ return h(Citation, { data: refData[0], tag: "span" });
299
+ }
300
+
301
+ return h(
302
+ "ul.refs",
303
+ refData.map((data, i) => h(Citation, { data, tag: "li", key: i }))
304
+ );
305
+ }
306
+
307
+ function Citation({ data, tag = "p" }) {
308
+ return h(tag, { className: "citation" }, [
309
+ h("span.authors", data.author),
310
+ ", ",
311
+ h("span.year", data.pub_year),
312
+ ", ",
313
+ h("span.title", data.ref),
314
+ ]);
315
+ }
316
+
317
+ function AgeField({ unit, children }) {
318
+ const [b_age, t_age, _unit] = getAgeRange(unit);
319
+
320
+ return h(
321
+ DataField,
322
+ {
323
+ label: "Age",
324
+ value: formatRange(b_age, t_age),
325
+ unit: _unit,
326
+ },
327
+ children
328
+ );
329
+ }
330
+
331
+ function getAgeRange(_unit) {
332
+ let b_age = _unit.b_age;
333
+ let t_age = _unit.t_age;
334
+ let unit = "Ma";
335
+
336
+ if (b_age < 0.8 && t_age < 1.2) {
337
+ b_age *= 1000;
338
+ t_age *= 1000;
339
+ unit = "ka";
340
+ } else if (b_age > 800 && t_age > 1200) {
341
+ b_age /= 1000;
342
+ t_age /= 1000;
343
+ unit = "Ga";
344
+ }
345
+
346
+ return [b_age, t_age, unit];
347
+ }
348
+
349
+ export function Duration({
350
+ value,
351
+ maximumFractionDigits = 2,
352
+ minimumFractionDigits = 0,
353
+ }) {
354
+ let unit = "Myr";
355
+ if (value < 0.8) {
356
+ unit = "kyr";
357
+ value *= 1000;
358
+ if (value < 5) {
359
+ unit = "yr";
360
+ value *= 1000;
361
+ }
362
+ } else if (value > 1000) {
363
+ unit = "Gyr";
364
+ value /= 1000;
365
+ }
366
+
367
+ let _value = value.toLocaleString("en-US", {
368
+ maximumFractionDigits,
369
+ minimumFractionDigits,
370
+ });
371
+
372
+ return h(Value, { value: _value, unit });
373
+ }
374
+
375
+ function enhanceEnvironments(
376
+ environments: Partial<Environment>[],
377
+ envMap: Map<number, Environment>
378
+ ) {
379
+ return environments.map((env) => {
380
+ return {
381
+ ...(envMap?.get(env.environ_id) ?? {}),
382
+ ...env,
383
+ };
384
+ });
385
+ }
386
+
387
+ function enhanceLithologies(
388
+ lithologies: Partial<UnitLong["lith"]>,
389
+ lithMap: Map<number, any>
390
+ ) {
391
+ return lithologies.map((lith) => {
392
+ return {
393
+ ...(lithMap?.get(lith.lith_id) ?? {}), // get lithology details
394
+ ...lith, // override with the unit's specific lithology data
395
+ };
396
+ });
397
+ }
398
+
399
+ function UnitIDList({ units, selectUnit }) {
400
+ const u1 = units.filter((d) => d != 0);
401
+
402
+ if (u1.length === 0) {
403
+ return h("span.no-units", "None");
404
+ }
405
+
406
+ let tag = "span";
407
+ if (selectUnit != null) {
408
+ tag = "a";
409
+ }
410
+
411
+ return h(
412
+ ItemList,
413
+ { className: "unit-id-list" },
414
+ u1.map((unit) => {
415
+ return h(
416
+ tag,
417
+
418
+ {
419
+ className: "unit-id",
420
+ onClick() {
421
+ selectUnit?.(unit.id);
422
+ },
423
+ key: unit.id,
424
+ },
425
+ unit
426
+ );
427
+ })
428
+ );
429
+ }
430
+
431
+ function IntervalProportions({ unit }) {
432
+ const i0 = unit.b_int_id;
433
+ const i1 = unit.t_int_id;
434
+ let b_prop = unit.b_prop ?? 0;
435
+ let t_prop = unit.t_prop ?? 1;
436
+
437
+ const intervalMap = useMacrostratDefs("intervals");
438
+ const int0 = intervalMap?.get(i0) ?? {};
439
+
440
+ const interval0: IntervalShort = {
441
+ ...int0,
442
+ id: i0,
443
+ name: unit.b_int_name,
444
+ };
445
+
446
+ let p0: ReactNode = null;
447
+ const int1 = intervalMap?.get(i1) ?? {};
448
+ const p1: ReactNode = h(Proportion, { value: t_prop });
449
+
450
+ if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {
451
+ // We have a single interval with undefined proportions
452
+ p0 = h(Proportion, { value: b_prop });
453
+ }
454
+
455
+ if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {
456
+ p0 = h("span.joint-proportion", [p0, h("span.sep", "to"), p1]);
457
+ }
458
+
459
+ return h("div.interval-proportions", [
460
+ h(IntervalTag, {
461
+ interval: interval0,
462
+ prefix: p0,
463
+ }),
464
+ h.if(i0 != i1)("span.discourage-break", [
465
+ h("span.sep", "to"),
466
+ h(IntervalTag, {
467
+ interval: {
468
+ ...int1,
469
+ id: i1,
470
+ name: unit.t_int_name,
471
+ },
472
+ prefix: p1,
473
+ }),
474
+ ]),
475
+ ]);
476
+ }
477
+
478
+ const formatProportion = (d) => {
479
+ if (d == null) return null;
480
+ return d.toFixed(1);
481
+ };
482
+
483
+ function Proportion({ value }) {
484
+ let content = null;
485
+ if (value == 0) {
486
+ content = "base";
487
+ } else if (value == 1) {
488
+ content = "top";
489
+ } else {
490
+ content = formatProportion(value * 100) + "%";
491
+ }
492
+
493
+ return h("span.proportion", content);
494
+ }
495
+
496
+ function formatRange(min, max, precision = null) {
497
+ if (min == null || max == null) return null;
498
+ if (min === max) {
499
+ return min.toFixed(precision);
500
+ }
501
+
502
+ return `${formatSignificance(min, precision)}–${formatSignificance(
503
+ max,
504
+ precision
505
+ )}`;
506
+ }
507
+
508
+ function formatSignificance(value, precision = null) {
509
+ // Format to preserve a reasonable number of significant figures
510
+ // this could be done with an easier algorithm, probably:
511
+
512
+ if (precision == null) {
513
+ return value.toLocaleString();
514
+ }
515
+ if (precision >= 0) {
516
+ return value.toFixed(precision);
517
+ }
518
+ if (precision < 0) {
519
+ return (
520
+ (value / Math.pow(10, -precision)).toFixed(0) + "0".repeat(-precision)
521
+ );
522
+ }
523
+ }
@@ -13,10 +13,12 @@
13
13
  pointer-events: none
14
14
  outline: 2px solid #f22
15
15
 
16
- .legend-panel-outer
16
+ :global(.bp5-popover-content)
17
+ overflow: hidden
18
+
19
+ .legend-panel
17
20
  width: 25em
18
21
  max-height: 60vh
19
- overflow-y: scroll
20
22
  background-color: var(--panel-background-color)
21
23
 
22
24
  .legend-info-panel
@@ -0,0 +1,82 @@
1
+ import hyper from "@macrostrat/hyper";
2
+ import { Popover } from "@blueprintjs/core";
3
+ import styles from "./popover.module.sass";
4
+ import { useSelectedUnit, useUnitSelectionStore } from "../units";
5
+ import { UnitDetailsPanel } from "./panel";
6
+
7
+ const h = hyper.styled(styles);
8
+
9
+ export function UnitDetailsPopover({
10
+ style,
11
+ children,
12
+ viewportPadding = 20,
13
+ }: {
14
+ style: object;
15
+ viewportPadding?: number;
16
+ children: React.ReactNode;
17
+ }) {
18
+ const content = h(InteractionBarrier, children);
19
+
20
+ return h(
21
+ "div.popover-main",
22
+ {
23
+ style,
24
+ },
25
+ h(
26
+ Popover,
27
+ // @ts-ignore
28
+ {
29
+ content,
30
+ isOpen: true,
31
+ usePortal: false,
32
+ position: "right",
33
+ modifiers: {
34
+ preventOverflow: { options: { padding: viewportPadding } },
35
+ },
36
+ },
37
+ h("span.popover-target")
38
+ )
39
+ );
40
+ }
41
+
42
+ function InteractionBarrier({ children }) {
43
+ return h(
44
+ "div",
45
+ {
46
+ onClick(e) {
47
+ // Stop events from leaking to the parent
48
+ e.stopPropagation();
49
+ },
50
+ },
51
+ children
52
+ );
53
+ }
54
+
55
+ export function UnitSelectionPopover() {
56
+ const unit = useSelectedUnit();
57
+ const position = useUnitSelectionStore((state) => state.overlayPosition);
58
+ if (unit == null) {
59
+ return null;
60
+ }
61
+
62
+ return h(
63
+ "div.unit-popover-container",
64
+ h(
65
+ UnitDetailsPopover,
66
+ {
67
+ style: {
68
+ position: "absolute",
69
+ top: position?.y ?? 0,
70
+ width: position?.width ?? 100,
71
+ left: position?.x ?? 0,
72
+ height: position?.height ?? 100,
73
+ },
74
+ },
75
+ h(UnitDetailsPanel, {
76
+ unit,
77
+ showLithologyProportions: true,
78
+ className: "legend-panel",
79
+ })
80
+ )
81
+ );
82
+ }
@@ -1,3 +1,19 @@
1
1
  .unit-label-container
2
2
  pointer-events: none
3
3
 
4
+ .labeled-unit
5
+ --column-unit-background-internal: var(--column-unit-background-color, var(--column-background-color))
6
+ :global(.unit-overlay)
7
+ font-size: 10px
8
+ font-style: italic
9
+ display: flex
10
+ align-items: center
11
+ justify-content: center
12
+
13
+ :global(.unit-label)
14
+ display: block
15
+ color: var(--column-text-color)
16
+ text-shadow: 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal), 0px 0px 4px var(--column-unit-background-internal)
17
+
18
+ .background
19
+ fill: var(--column-unit-background-internal, transparent)