@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.
- package/CHANGELOG.md +14 -0
- package/README.md +3 -0
- package/dist/age-axis.7ce58d66.js +41 -0
- package/dist/age-axis.7ce58d66.js.map +1 -0
- package/dist/boxes.6d3192e6.js +164 -0
- package/dist/boxes.6d3192e6.js.map +1 -0
- package/dist/boxes.module.998ff312.js +13 -0
- package/dist/boxes.module.998ff312.js.map +1 -0
- package/dist/boxes.module.dd631fe3.css +4 -0
- package/dist/boxes.module.dd631fe3.css.map +1 -0
- package/dist/carbon-isotopes.6d9bddcf.js +11 -0
- package/dist/carbon-isotopes.6d9bddcf.js.map +1 -0
- package/dist/column.e35a471f.js +149 -0
- package/dist/column.e35a471f.js.map +1 -0
- package/dist/column.e901b5d4.js +117 -0
- package/dist/column.e901b5d4.js.map +1 -0
- package/dist/column.module.2e29259c.js +22 -0
- package/dist/column.module.2e29259c.js.map +1 -0
- package/dist/column.module.35184ea7.css +157 -0
- package/dist/column.module.35184ea7.css.map +1 -0
- package/dist/column.module.35ba04e7.js +34 -0
- package/dist/column.module.35ba04e7.js.map +1 -0
- package/dist/column.module.c9df6edf.css +138 -0
- package/dist/column.module.c9df6edf.css.map +1 -0
- package/dist/composite.494beffc.js +153 -0
- package/dist/composite.494beffc.js.map +1 -0
- package/dist/composite.module.5cc0e747.css +4 -0
- package/dist/composite.module.5cc0e747.css.map +1 -0
- package/dist/composite.module.6359deba.js +13 -0
- package/dist/composite.module.6359deba.js.map +1 -0
- package/dist/core.f3824dd8.js +89 -0
- package/dist/core.f3824dd8.js.map +1 -0
- package/dist/data-area.f9bb9ad9.js +86 -0
- package/dist/data-area.f9bb9ad9.js.map +1 -0
- package/dist/data-provider.61ef7f9a.js +25 -0
- package/dist/data-provider.61ef7f9a.js.map +1 -0
- package/dist/helpers.2af05ee4.js +94 -0
- package/dist/helpers.2af05ee4.js.map +1 -0
- package/dist/index.d.ts +363 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/index.module.8fad0020.js +37 -0
- package/dist/index.module.8fad0020.js.map +1 -0
- package/dist/index.module.de76feb2.css +65 -0
- package/dist/index.module.de76feb2.css.map +1 -0
- package/dist/isotopes-column.b5442b4d.js +163 -0
- package/dist/isotopes-column.b5442b4d.js.map +1 -0
- package/dist/layers.946aaa37.js +231 -0
- package/dist/layers.946aaa37.js.map +1 -0
- package/dist/map.e782010f.js +82 -0
- package/dist/map.e782010f.js.map +1 -0
- package/dist/names.ab14789e.js +65 -0
- package/dist/names.ab14789e.js.map +1 -0
- package/dist/providers.abcb2cbe.js +25 -0
- package/dist/providers.abcb2cbe.js.map +1 -0
- package/dist/resolvers.2949c4c0.js +83 -0
- package/dist/resolvers.2949c4c0.js.map +1 -0
- package/dist/section.6f6fc929.js +118 -0
- package/dist/section.6f6fc929.js.map +1 -0
- package/dist/selection-popover.7e008544.js +60 -0
- package/dist/selection-popover.7e008544.js.map +1 -0
- package/dist/selection-popover.module.2732ebc0.css +34 -0
- package/dist/selection-popover.module.2732ebc0.css.map +1 -0
- package/dist/selection-popover.module.fdbfb40e.js +22 -0
- package/dist/selection-popover.module.fdbfb40e.js.map +1 -0
- package/dist/selection.add9f8b0.js +117 -0
- package/dist/selection.add9f8b0.js.map +1 -0
- package/dist/store.c5271371.js +18 -0
- package/dist/store.c5271371.js.map +1 -0
- package/dist/types.ff938b22.js +18 -0
- package/dist/types.ff938b22.js.map +1 -0
- package/dist/unit-details.0c1edd00.js +209 -0
- package/dist/unit-details.0c1edd00.js.map +1 -0
- package/dist/units.5ec6a44c.js +42 -0
- package/dist/units.5ec6a44c.js.map +1 -0
- package/package.json +66 -0
- package/src/age-axis.ts +42 -0
- package/src/carbon-isotopes/column.module.sass +136 -0
- package/src/carbon-isotopes/column.ts +131 -0
- package/src/carbon-isotopes/core.ts +78 -0
- package/src/carbon-isotopes/data-area.ts +96 -0
- package/src/carbon-isotopes/data-provider.ts +19 -0
- package/src/carbon-isotopes/index.ts +3 -0
- package/src/carbon-isotopes/isotopes-column.ts +214 -0
- package/src/column.module.sass +114 -0
- package/src/column.ts +185 -0
- package/src/helpers.ts +133 -0
- package/src/index.ts +7 -0
- package/src/map/animated.ts +78 -0
- package/src/map/index.ts +86 -0
- package/src/map/layers.ts +316 -0
- package/src/providers.ts +34 -0
- package/src/section.ts +129 -0
- package/src/selection-popover.module.sass +27 -0
- package/src/selection-popover.ts +71 -0
- package/src/store.ts +12 -0
- package/src/unit-details/index.module.sass +51 -0
- package/src/unit-details/index.ts +215 -0
- package/src/units/boxes.module.sass +3 -0
- package/src/units/boxes.ts +221 -0
- package/src/units/composite.module.sass +2 -0
- package/src/units/composite.ts +266 -0
- package/src/units/index.ts +36 -0
- package/src/units/names.ts +118 -0
- package/src/units/resolvers.ts +111 -0
- package/src/units/selection.ts +167 -0
- package/src/units/types.ts +26 -0
- package/src/units/units.scss +16 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
@use "sass:color"
|
|
2
|
+
|
|
3
|
+
.column-ui
|
|
4
|
+
width: 100vw
|
|
5
|
+
height: 100vh
|
|
6
|
+
overflow-y: scroll
|
|
7
|
+
display: flex
|
|
8
|
+
flex-direction: row
|
|
9
|
+
|
|
10
|
+
.column-view
|
|
11
|
+
flex-grow: 1
|
|
12
|
+
padding: 1em
|
|
13
|
+
max-height: 100vh
|
|
14
|
+
overflow-y: scroll
|
|
15
|
+
h1
|
|
16
|
+
font-size: 1.2em
|
|
17
|
+
margin-bottom: 0.2em
|
|
18
|
+
padding-left: 35px
|
|
19
|
+
|
|
20
|
+
// Column
|
|
21
|
+
.column
|
|
22
|
+
margin-bottom: 1em
|
|
23
|
+
display: flex
|
|
24
|
+
flex-direction: row
|
|
25
|
+
.age-axis-label
|
|
26
|
+
writing-mode: vertical-lr
|
|
27
|
+
transform: rotate(180deg)
|
|
28
|
+
font-size: 12px
|
|
29
|
+
text-align: center
|
|
30
|
+
position: sticky
|
|
31
|
+
top: 0
|
|
32
|
+
max-height: 100vh
|
|
33
|
+
|
|
34
|
+
:global
|
|
35
|
+
.tick text
|
|
36
|
+
text-anchor: middle
|
|
37
|
+
font-weight: 400 !important
|
|
38
|
+
transform: rotate(-90deg) translate(8px,-12px)
|
|
39
|
+
|
|
40
|
+
rect.unit
|
|
41
|
+
stroke: black
|
|
42
|
+
stroke-width: 1px
|
|
43
|
+
|
|
44
|
+
g.lithology-column use.frame
|
|
45
|
+
stroke: black
|
|
46
|
+
stroke-width: 1.5px !important
|
|
47
|
+
pointer-events: none
|
|
48
|
+
|
|
49
|
+
g.isotopes-column
|
|
50
|
+
rect.underlay
|
|
51
|
+
fill: transparent
|
|
52
|
+
|
|
53
|
+
.col-note-label
|
|
54
|
+
font-size: 10px
|
|
55
|
+
margin-top: 3px
|
|
56
|
+
padding: 2px 2px 2px 3px
|
|
57
|
+
line-height: 9px
|
|
58
|
+
border-left: none !important
|
|
59
|
+
|
|
60
|
+
g.height-range
|
|
61
|
+
display: none
|
|
62
|
+
|
|
63
|
+
.note-inner
|
|
64
|
+
border: none
|
|
65
|
+
|
|
66
|
+
.frame rect
|
|
67
|
+
fill: transparent
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
.bp5-dark
|
|
72
|
+
.column :global
|
|
73
|
+
.lithology-column .frame
|
|
74
|
+
stroke: white
|
|
75
|
+
g.inner
|
|
76
|
+
rect.unit
|
|
77
|
+
filter: invert(100%)
|
|
78
|
+
g.lithology-column use.frame
|
|
79
|
+
stroke: white
|
|
80
|
+
.note
|
|
81
|
+
line, path.col-note-link
|
|
82
|
+
stroke: white
|
|
83
|
+
.y.axis .tick line
|
|
84
|
+
stroke: white
|
|
85
|
+
|
|
86
|
+
.column-nav
|
|
87
|
+
position: sticky
|
|
88
|
+
top: 2.2em
|
|
89
|
+
h3
|
|
90
|
+
color: #444
|
|
91
|
+
margin-bottom: 0.3em
|
|
92
|
+
|
|
93
|
+
.default-buttons
|
|
94
|
+
width: 100%
|
|
95
|
+
margin: 0 -10px
|
|
96
|
+
|
|
97
|
+
div.map-column
|
|
98
|
+
width: 600px
|
|
99
|
+
height: 100vh
|
|
100
|
+
display: flex
|
|
101
|
+
flex-direction: column
|
|
102
|
+
|
|
103
|
+
:global
|
|
104
|
+
.map-area
|
|
105
|
+
flex-grow: 1
|
|
106
|
+
|
|
107
|
+
.map-placeholder
|
|
108
|
+
position: relative
|
|
109
|
+
|
|
110
|
+
.macrostrat-map
|
|
111
|
+
.graticule
|
|
112
|
+
stroke-dasharray: inherit
|
|
113
|
+
stroke: color.adjust(#AFE6F0, $lightness: -5%)
|
|
114
|
+
.neatline
|
|
115
|
+
stroke-width: 1.5px
|
|
116
|
+
|
|
117
|
+
.context-map
|
|
118
|
+
position: absolute
|
|
119
|
+
top: 0
|
|
120
|
+
right: 0
|
|
121
|
+
width: 250px
|
|
122
|
+
height: 250px
|
|
123
|
+
cursor: pointer
|
|
124
|
+
z-index: 100
|
|
125
|
+
&.expanded
|
|
126
|
+
cursor: inherit
|
|
127
|
+
.columns path:hover
|
|
128
|
+
stroke: rgba(255,0,0,.4) !important
|
|
129
|
+
|
|
130
|
+
.close-button
|
|
131
|
+
position: absolute
|
|
132
|
+
top: 1em
|
|
133
|
+
right: 1em
|
|
134
|
+
|
|
135
|
+
.land
|
|
136
|
+
background-color: rgb(233, 252, 234)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import hyper from "@macrostrat/hyper";
|
|
2
|
+
import { group } from "d3-array";
|
|
3
|
+
import { useAPIResult } from "@macrostrat/ui-components";
|
|
4
|
+
import {
|
|
5
|
+
ColumnSVG,
|
|
6
|
+
ColumnAxis,
|
|
7
|
+
ColumnContext,
|
|
8
|
+
} from "@macrostrat/column-components";
|
|
9
|
+
import { SimpleUnitsColumn, IUnit, ColumnArgs } from "../units";
|
|
10
|
+
import { useContext } from "react";
|
|
11
|
+
import { IsotopesColumn } from "./isotopes-column";
|
|
12
|
+
import { MacrostratColumnProvider } from "../providers";
|
|
13
|
+
import styles from "./column.module.sass";
|
|
14
|
+
|
|
15
|
+
const h = hyper.styled(styles);
|
|
16
|
+
|
|
17
|
+
interface IColumnProps {
|
|
18
|
+
data: IUnit[];
|
|
19
|
+
pixelScale?: number;
|
|
20
|
+
isOldestColumn: boolean;
|
|
21
|
+
range?: [number, number];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const AgeAxis = ({ ticks }) => {
|
|
25
|
+
const { pixelHeight } = useContext(ColumnContext);
|
|
26
|
+
// A tick roughly every 40 pixels
|
|
27
|
+
let v = Math.max(Math.round(pixelHeight / 40), 1);
|
|
28
|
+
|
|
29
|
+
return h(ColumnAxis, {
|
|
30
|
+
ticks: v,
|
|
31
|
+
showDomain: false,
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const Section = (props: IColumnProps) => {
|
|
36
|
+
// Section with "squishy" time scale
|
|
37
|
+
const {
|
|
38
|
+
data,
|
|
39
|
+
isOldestColumn = true,
|
|
40
|
+
range = [data[data.length - 1].b_age, data[0].t_age],
|
|
41
|
+
} = props;
|
|
42
|
+
let { pixelScale } = props;
|
|
43
|
+
|
|
44
|
+
const notesOffset = 100;
|
|
45
|
+
|
|
46
|
+
if (!pixelScale) {
|
|
47
|
+
// Make up a pixel scale
|
|
48
|
+
const dAge = range[0] - range[1];
|
|
49
|
+
const targetHeight = 50 * data.length;
|
|
50
|
+
pixelScale = Math.ceil(targetHeight / dAge);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return h(
|
|
54
|
+
MacrostratColumnProvider,
|
|
55
|
+
{
|
|
56
|
+
divisions: data,
|
|
57
|
+
range,
|
|
58
|
+
pixelsPerMeter: pixelScale, // Actually pixels per myr
|
|
59
|
+
},
|
|
60
|
+
[
|
|
61
|
+
h(
|
|
62
|
+
ColumnSVG,
|
|
63
|
+
{
|
|
64
|
+
width: 650,
|
|
65
|
+
padding: 20,
|
|
66
|
+
paddingTop: 5,
|
|
67
|
+
paddingBottom: 25,
|
|
68
|
+
},
|
|
69
|
+
[
|
|
70
|
+
h(AgeAxis),
|
|
71
|
+
h(SimpleUnitsColumn, {
|
|
72
|
+
width: 400,
|
|
73
|
+
columnWidth: 90,
|
|
74
|
+
}),
|
|
75
|
+
h(IsotopesColumn, {
|
|
76
|
+
parameter: "D13C",
|
|
77
|
+
label: "δ¹³C",
|
|
78
|
+
width: 100,
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
nTicks: 4,
|
|
81
|
+
showAxis: isOldestColumn,
|
|
82
|
+
transform: "translate(250,0)",
|
|
83
|
+
}),
|
|
84
|
+
h(IsotopesColumn, {
|
|
85
|
+
parameter: "D18O",
|
|
86
|
+
label: "δ¹⁸O",
|
|
87
|
+
color: "red",
|
|
88
|
+
domain: [-40, 0],
|
|
89
|
+
width: 100,
|
|
90
|
+
// @ts-ignore
|
|
91
|
+
nTicks: 4,
|
|
92
|
+
showAxis: isOldestColumn,
|
|
93
|
+
transform: "translate(370,0)",
|
|
94
|
+
}),
|
|
95
|
+
]
|
|
96
|
+
),
|
|
97
|
+
]
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function Column(props: Omit<IColumnProps, "data"> & { params: ColumnArgs }) {
|
|
102
|
+
const { params } = props;
|
|
103
|
+
const data: IUnit[] = useAPIResult("/units", {
|
|
104
|
+
all: true,
|
|
105
|
+
...params,
|
|
106
|
+
response: "long",
|
|
107
|
+
});
|
|
108
|
+
if (data == null) return null;
|
|
109
|
+
|
|
110
|
+
let sectionGroups = Array.from(group(data, (d) => d.section_id));
|
|
111
|
+
|
|
112
|
+
//sectionGroups.sort((a, b) => a.t_age - b.t_age);
|
|
113
|
+
|
|
114
|
+
return h("div.column", [
|
|
115
|
+
h("div.age-axis-label", "Age (Ma)"),
|
|
116
|
+
h(
|
|
117
|
+
"div.main-column",
|
|
118
|
+
sectionGroups.map(([id, values], i) => {
|
|
119
|
+
return h(`div.section-${id}`, [
|
|
120
|
+
h(Section, {
|
|
121
|
+
data: values,
|
|
122
|
+
isOldestColumn: i == sectionGroups.length - 1,
|
|
123
|
+
}),
|
|
124
|
+
]);
|
|
125
|
+
})
|
|
126
|
+
),
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { Section, IColumnProps };
|
|
131
|
+
export default Column;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import hyper from "@macrostrat/hyper";
|
|
2
|
+
import styles from "./column.module.sass";
|
|
3
|
+
|
|
4
|
+
import { useAPIResult } from "@macrostrat/ui-components";
|
|
5
|
+
import BaseColumn from "./column";
|
|
6
|
+
import { ColumnNavigatorMap, MeasurementsLayer } from "../map";
|
|
7
|
+
import { MeasurementDataProvider } from "./data-provider";
|
|
8
|
+
import { MacrostratAPIProvider } from "../providers";
|
|
9
|
+
import { ColumnArgs, useColumnNav } from "../units";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import { FeatureCollection } from "geojson";
|
|
12
|
+
|
|
13
|
+
const h = hyper.styled(styles);
|
|
14
|
+
|
|
15
|
+
const ColumnTitle = (props) => {
|
|
16
|
+
return h.if(props.data != null)("h1", props.data?.col_name);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const defaultArgs: ColumnArgs = {
|
|
20
|
+
col_id: 2192,
|
|
21
|
+
//unit_id: null,
|
|
22
|
+
project_id: 10,
|
|
23
|
+
status_code: "in process",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function CarbonIsotopesColumn(columnArgs) {
|
|
27
|
+
return h(
|
|
28
|
+
MacrostratAPIProvider,
|
|
29
|
+
h(MeasurementDataProvider, columnArgs, [
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
h(BaseColumn, { params: columnArgs }),
|
|
32
|
+
])
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function ColumnManager() {
|
|
37
|
+
const [columnArgs, setCurrentColumn] = useColumnNav(defaultArgs);
|
|
38
|
+
const { col_id, ...projectParams } = columnArgs;
|
|
39
|
+
|
|
40
|
+
const colParams = useMemo(
|
|
41
|
+
() => ({ ...columnArgs, format: "geojson" }),
|
|
42
|
+
[columnArgs]
|
|
43
|
+
);
|
|
44
|
+
const res: FeatureCollection = useAPIResult("/columns", colParams);
|
|
45
|
+
const columnFeature = res?.features[0];
|
|
46
|
+
|
|
47
|
+
return h(MeasurementDataProvider, columnArgs, [
|
|
48
|
+
h("div.column-ui", [
|
|
49
|
+
h("div.column-view", [
|
|
50
|
+
h(ColumnTitle, { data: columnFeature?.properties }),
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
h(BaseColumn, { params: columnArgs }),
|
|
53
|
+
]),
|
|
54
|
+
h("div.map-column", [
|
|
55
|
+
h(
|
|
56
|
+
ColumnNavigatorMap,
|
|
57
|
+
{
|
|
58
|
+
currentColumn: columnFeature,
|
|
59
|
+
setCurrentColumn,
|
|
60
|
+
margin: 0,
|
|
61
|
+
...projectParams,
|
|
62
|
+
},
|
|
63
|
+
h(MeasurementsLayer, {
|
|
64
|
+
...projectParams,
|
|
65
|
+
style: {
|
|
66
|
+
fill: "dodgerblue",
|
|
67
|
+
stroke: "blue",
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
),
|
|
71
|
+
]),
|
|
72
|
+
]),
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function CarbonIsotopesApp() {
|
|
77
|
+
return h(MacrostratAPIProvider, h(ColumnManager));
|
|
78
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { line } from "d3-shape";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
import h from "@macrostrat/hyper";
|
|
4
|
+
import { ColumnLayoutContext } from "@macrostrat/column-components";
|
|
5
|
+
|
|
6
|
+
const inDomain = (scale, num) => {
|
|
7
|
+
const domain = scale.domain();
|
|
8
|
+
return domain[0] < num < domain[1];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const createPointLocator = function (opts) {
|
|
12
|
+
const { xScale, scale, getHeight, ...rest } = opts;
|
|
13
|
+
return function (d, s = 0) {
|
|
14
|
+
const height = getHeight(d);
|
|
15
|
+
if (!inDomain(scale, height)) return null;
|
|
16
|
+
return [xScale(d.value), scale(height)];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const IsotopesDataContext = createContext(null);
|
|
21
|
+
|
|
22
|
+
export interface DataAreaProps {
|
|
23
|
+
clipY: boolean;
|
|
24
|
+
parameter: string;
|
|
25
|
+
corrected: boolean;
|
|
26
|
+
system: string;
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
getHeight?: Function;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const IsotopesDataArea = function (props: DataAreaProps) {
|
|
32
|
+
const { xScale, scale } = useContext(ColumnLayoutContext) ?? {};
|
|
33
|
+
|
|
34
|
+
let { corrected, system, children, getHeight, clipY } = props;
|
|
35
|
+
if (getHeight == null) {
|
|
36
|
+
getHeight = function (d) {
|
|
37
|
+
if (d.height == null) {
|
|
38
|
+
console.log(d);
|
|
39
|
+
}
|
|
40
|
+
return d.height;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Handlers for creating points and lines
|
|
45
|
+
const pointLocator = createPointLocator({
|
|
46
|
+
xScale,
|
|
47
|
+
scale,
|
|
48
|
+
corrected,
|
|
49
|
+
system,
|
|
50
|
+
getHeight,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let column = "avg_" + system;
|
|
54
|
+
if (corrected) {
|
|
55
|
+
column += "_corr";
|
|
56
|
+
}
|
|
57
|
+
const lineLocator = line()
|
|
58
|
+
.x((d) => xScale(d[column]))
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
.y((d) => scale(d.height));
|
|
61
|
+
|
|
62
|
+
const value = { pointLocator, lineLocator, corrected, system, clipY };
|
|
63
|
+
return h(IsotopesDataContext.Provider, { value }, h("g.data", children));
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
IsotopesDataArea.defaultProps = { clipY: false };
|
|
67
|
+
|
|
68
|
+
const IsotopeDataPoint = function (props) {
|
|
69
|
+
const { pointLocator } = useContext(IsotopesDataContext);
|
|
70
|
+
const { datum, strokeWidth, ...rest } = props;
|
|
71
|
+
const loc = pointLocator(datum);
|
|
72
|
+
if (loc == null) return null;
|
|
73
|
+
const [cx, cy] = loc;
|
|
74
|
+
|
|
75
|
+
return h("circle", {
|
|
76
|
+
key: datum.sample_id,
|
|
77
|
+
cx,
|
|
78
|
+
cy,
|
|
79
|
+
r: 2,
|
|
80
|
+
...rest,
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const IsotopeDataLine = function (props) {
|
|
85
|
+
const { values: lineValues, ...rest } = props;
|
|
86
|
+
const { lineLocator } = useContext(IsotopesDataContext);
|
|
87
|
+
return h("path", {
|
|
88
|
+
d: lineLocator(lineValues),
|
|
89
|
+
fill: "transparent",
|
|
90
|
+
...rest,
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const useDataLocator = () => useContext(IsotopesDataContext);
|
|
95
|
+
|
|
96
|
+
export { IsotopesDataArea, IsotopeDataPoint, IsotopeDataLine, useDataLocator };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import h from "@macrostrat/hyper";
|
|
2
|
+
import { useContext, createContext } from "react";
|
|
3
|
+
import { useAPIResult } from "@macrostrat/ui-components";
|
|
4
|
+
|
|
5
|
+
const MeasurementDataContext = createContext(null);
|
|
6
|
+
|
|
7
|
+
function MeasurementDataProvider(props) {
|
|
8
|
+
const { children, ...params } = props;
|
|
9
|
+
const res = useAPIResult("/measurements", {
|
|
10
|
+
...params,
|
|
11
|
+
show_values: true,
|
|
12
|
+
response: "long"
|
|
13
|
+
});
|
|
14
|
+
return h(MeasurementDataContext.Provider, { value: res, children });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const useMeasurementData = () => useContext(MeasurementDataContext);
|
|
18
|
+
|
|
19
|
+
export { MeasurementDataProvider, useMeasurementData, MeasurementDataContext };
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { format } from "d3-format";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import h from "@macrostrat/hyper";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
import { AxisBottom } from "@visx/axis";
|
|
6
|
+
import { useMeasurementData } from "./data-provider";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
IsotopesDataArea,
|
|
10
|
+
useDataLocator,
|
|
11
|
+
IsotopeDataPoint,
|
|
12
|
+
} from "./data-area";
|
|
13
|
+
import { referenceMeasuresToColumn } from "@macrostrat/stratigraphy-utils";
|
|
14
|
+
import {
|
|
15
|
+
CrossAxisLayoutProvider,
|
|
16
|
+
ColumnLayoutContext,
|
|
17
|
+
useColumnDivisions,
|
|
18
|
+
} from "@macrostrat/column-components";
|
|
19
|
+
import { BaseUnit } from "@macrostrat/api-types";
|
|
20
|
+
import { AxisProps } from "@visx/axis/lib/axis/Axis";
|
|
21
|
+
|
|
22
|
+
const fmt = format(".1f");
|
|
23
|
+
|
|
24
|
+
type IsotopesTextProps = {
|
|
25
|
+
datum: any;
|
|
26
|
+
text: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function IsotopeText({ datum, text, ...rest }: IsotopesTextProps) {
|
|
30
|
+
const { pointLocator } = useDataLocator();
|
|
31
|
+
const [x, y] = pointLocator(datum);
|
|
32
|
+
return h(
|
|
33
|
+
"text",
|
|
34
|
+
{
|
|
35
|
+
x,
|
|
36
|
+
y,
|
|
37
|
+
...rest,
|
|
38
|
+
},
|
|
39
|
+
text
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function ColumnScale(props) {
|
|
44
|
+
const {
|
|
45
|
+
label,
|
|
46
|
+
showAxis = true,
|
|
47
|
+
nTicks = 6,
|
|
48
|
+
tickValues: _tickVals,
|
|
49
|
+
...rest
|
|
50
|
+
} = props;
|
|
51
|
+
const { xScale, pixelHeight, width } = useContext(ColumnLayoutContext);
|
|
52
|
+
|
|
53
|
+
const tickValues = _tickVals ?? xScale.ticks(nTicks);
|
|
54
|
+
|
|
55
|
+
return h("g.scale.isotope-scale-axis", [
|
|
56
|
+
h(
|
|
57
|
+
"g.scale-lines",
|
|
58
|
+
tickValues.map((value) => {
|
|
59
|
+
const strokeDasharray = value == 0 ? null : "2 6";
|
|
60
|
+
return h(ScaleLine, { value, stroke: "#ddd", strokeDasharray });
|
|
61
|
+
})
|
|
62
|
+
),
|
|
63
|
+
h.if(showAxis)([
|
|
64
|
+
h("rect.underlay", {
|
|
65
|
+
x: 0,
|
|
66
|
+
y: pixelHeight,
|
|
67
|
+
width,
|
|
68
|
+
height: 30,
|
|
69
|
+
}),
|
|
70
|
+
h(AxisBottom, {
|
|
71
|
+
scale: xScale,
|
|
72
|
+
tickLength: 3,
|
|
73
|
+
tickValues,
|
|
74
|
+
...rest,
|
|
75
|
+
top: pixelHeight,
|
|
76
|
+
tickLabelProps(tickValue, i) {
|
|
77
|
+
// Compensate for negative sign
|
|
78
|
+
let dx;
|
|
79
|
+
if (tickValue < 0) {
|
|
80
|
+
dx = -2;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
dy: "-1px",
|
|
84
|
+
dx,
|
|
85
|
+
fontSize: 10,
|
|
86
|
+
textAnchor: "middle",
|
|
87
|
+
fill: "#aaa",
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
labelOffset: 0,
|
|
91
|
+
label,
|
|
92
|
+
}),
|
|
93
|
+
]),
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface ScaleLineProps {
|
|
98
|
+
value: number;
|
|
99
|
+
className?: string;
|
|
100
|
+
labelBottom?: boolean;
|
|
101
|
+
labelOffset?: number;
|
|
102
|
+
strokeDasharray?: string;
|
|
103
|
+
stroke?: string | number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function ScaleLine(props: ScaleLineProps) {
|
|
107
|
+
let { value, className, labelBottom, labelOffset, ...rest } = props;
|
|
108
|
+
if (labelBottom == null) {
|
|
109
|
+
labelBottom = false;
|
|
110
|
+
}
|
|
111
|
+
if (labelOffset == null) {
|
|
112
|
+
labelOffset = 12;
|
|
113
|
+
}
|
|
114
|
+
const { xScale, pixelHeight } = useContext(ColumnLayoutContext);
|
|
115
|
+
const x = xScale(value);
|
|
116
|
+
const transform = `translate(${x})`;
|
|
117
|
+
className = classNames(className, { zero: value === 0 });
|
|
118
|
+
return h("g.tick", { transform, className, key: value }, [
|
|
119
|
+
h("line", { x0: 0, x1: 0, y0: 0, y1: pixelHeight, ...rest }),
|
|
120
|
+
h.if(labelBottom)("text", { y: pixelHeight + labelOffset }, `${value}`),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function unnestPoints(measures) {
|
|
125
|
+
let points = [];
|
|
126
|
+
for (const meas of measures) {
|
|
127
|
+
const vals = meas.measure_value.map((d, i) => {
|
|
128
|
+
return {
|
|
129
|
+
value: d,
|
|
130
|
+
age: meas.measure_age[i],
|
|
131
|
+
position: meas.measure_position[i],
|
|
132
|
+
unit_id: meas.unit_id,
|
|
133
|
+
sample_id: meas.sample_no[i],
|
|
134
|
+
measurement: meas.measurement,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
Array.prototype.push.apply(points, vals);
|
|
138
|
+
}
|
|
139
|
+
return points;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface IsotopesDatasetProps {
|
|
143
|
+
color: string;
|
|
144
|
+
parameter: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface IsotopeColumnProps extends IsotopesDatasetProps {
|
|
148
|
+
width: number;
|
|
149
|
+
tickValues?: number[];
|
|
150
|
+
label: string;
|
|
151
|
+
domain: [number, number];
|
|
152
|
+
transform?: string;
|
|
153
|
+
getHeight?: Function;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function IsotopesDataset(props) {
|
|
157
|
+
const { parameter, color = "dodgerblue" } = props;
|
|
158
|
+
const divisions: BaseUnit[] = useColumnDivisions() as any;
|
|
159
|
+
const measures = useMeasurementData() ?? [];
|
|
160
|
+
const refMeasures = referenceMeasuresToColumn(divisions, measures).filter(
|
|
161
|
+
(d) => d.measurement == parameter
|
|
162
|
+
);
|
|
163
|
+
const points = unnestPoints(refMeasures);
|
|
164
|
+
|
|
165
|
+
return h(
|
|
166
|
+
IsotopesDataArea,
|
|
167
|
+
{
|
|
168
|
+
getHeight(d) {
|
|
169
|
+
return d.age;
|
|
170
|
+
},
|
|
171
|
+
} as any,
|
|
172
|
+
h(
|
|
173
|
+
"g.data-points",
|
|
174
|
+
points.map((d) => {
|
|
175
|
+
return h(IsotopeDataPoint, {
|
|
176
|
+
datum: d,
|
|
177
|
+
fill: color,
|
|
178
|
+
});
|
|
179
|
+
})
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function IsotopesColumn(
|
|
185
|
+
props: IsotopeColumnProps & { children?: React.ReactNode } & AxisProps<any>
|
|
186
|
+
) {
|
|
187
|
+
const {
|
|
188
|
+
width = 120,
|
|
189
|
+
domain = [-14, 6],
|
|
190
|
+
parameter,
|
|
191
|
+
label,
|
|
192
|
+
color = "dodgerblue",
|
|
193
|
+
children = null,
|
|
194
|
+
transform,
|
|
195
|
+
getHeight,
|
|
196
|
+
...rest
|
|
197
|
+
} = props;
|
|
198
|
+
|
|
199
|
+
let _children: any = children;
|
|
200
|
+
if (children == null && parameter != null) {
|
|
201
|
+
_children = h(IsotopesDataset, { parameter, color, getHeight });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return h(
|
|
205
|
+
CrossAxisLayoutProvider,
|
|
206
|
+
{ width, domain },
|
|
207
|
+
h("g.isotopes-column", { className: parameter, transform }, [
|
|
208
|
+
h(ColumnScale, { label: label ?? parameter, ...rest }),
|
|
209
|
+
_children,
|
|
210
|
+
])
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export { IsotopesColumn, IsotopesDataset };
|