-
Notifications
You must be signed in to change notification settings - Fork 8
/
App.tsx
120 lines (109 loc) · 4.32 KB
/
App.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import {createEffect, createResource, getOwner, JSX, lazy, runWithOwner, Show } from 'solid-js';
import { insert, render, style } from 'solid-js/web';
import { initializeMap, MapHooks } from './map/Map';
import { fetchForecastRuns } from './data/ForecastMetadata';
import {Domain, gfsModel, wrfModel} from './State';
import { BurgerButton } from './BurgerButton';
import { hooks } from "./css-hooks";
import {LayerKeys} from "./LayerKeys";
import { HelpButton } from './help/HelpButton';
import {Localized} from "./i18n";
const PeriodSelectors = lazy(() => import('./PeriodSelector').then(module => ({ default: module.PeriodSelectors })));
const App = (props: {
domain: Domain,
mapHooks: MapHooks
}): JSX.Element => {
// Update primary layer
createEffect(() => {
const url = props.domain.urlOfRasterAtCurrentHourOffset();
const projection = props.domain.state.zone.raster.proj;
const extent = props.domain.state.zone.raster.extent;
if (props.domain.state.primaryLayerEnabled) {
props.mapHooks.setPrimaryLayerSource(url, projection, extent);
} else {
props.mapHooks.hidePrimaryLayer();
}
});
// Update wind layer
createEffect(() => {
const vectorTiles = props.domain.state.zone.vectorTiles;
const url = props.domain.urlOfVectorTilesAtCurrentHourOffset();
if (props.domain.state.windLayerEnabled) {
props.mapHooks.setWindLayerSource(
url,
vectorTiles.minZoom,
vectorTiles.extent,
vectorTiles.zoomLevels - 1,
vectorTiles.tileSize
);
} else {
props.mapHooks.hideWindLayer();
}
});
createEffect(() => {
props.mapHooks.enableWindNumericalValues(props.domain.state.windNumericValuesShown);
});
// Marker when detailed view is open
createEffect(() => {
const detailedView = props.domain.state.detailedView;
if (detailedView !== undefined) {
props.mapHooks.showMarker(detailedView.latitude, detailedView.longitude);
} else {
props.mapHooks.hideMarker();
}
});
// PeriodSelectors displays the buttons to move over time. When we click on those buttons, it
// calls `onHourOffsetChanged`, which we handle by updating our `state`, which is propagated
// back to these components.
// LayersSelector displays the configuration button and manages the canvas overlay.
return <>
<style innerHTML={ hooks } />
<span style={{ position: 'absolute', top: 0, left: 0, 'z-index': 200 /* must be above the “period selector” */ }}>
<BurgerButton domain={props.domain} />
</span>
<PeriodSelectors domain={props.domain} locationClicks={props.mapHooks.locationClicks} />
<LayerKeys domain={props.domain} />
<span
style={{
position: 'absolute',
right: '.5rem',
bottom: '.5rem',
}}
>
<HelpButton domain={props.domain} overMap={true} />
</span>
</>
};
const Loader = ((props: {
mapHooks: MapHooks
}): JSX.Element => {
const owner = getOwner(); // Remember the tracking scope because it is lost when the promise callback is called
const [loadedDomain] = createResource(() =>
Promise
.all([
fetchForecastRuns(gfsModel),
fetchForecastRuns(wrfModel)
.then(runs => runs.sort((run1, run2) => run1.firstTimeStep.getTime() - run2.firstTimeStep.getTime()))
])
.then(([gfsRuns, wrfRuns]) => {
return runWithOwner(owner, () => new Domain(gfsRuns, wrfRuns));
})
.catch(error => {
console.log(error);
alert('Unable to retrieve forecast data. Try again later or contact [email protected] if the problem persists.');
return undefined
})
);
return <Show when={ loadedDomain() }>
{ domain => <App domain={domain()} mapHooks={props.mapHooks} /> }
</Show>
});
export const start = (containerElement: HTMLElement): void => {
// The map *must* be initialized before we call the other constructors
// It *must* also be mounted before we initialize it
style(containerElement, { display: 'flex', 'align-items': 'stretch', 'align-content': 'stretch' });
const mapElement = <div style={ { flex: 1 } } /> as HTMLElement;
insert(containerElement, mapElement);
const mapHooks = initializeMap(mapElement);
render(() => <Localized><Loader mapHooks={mapHooks} /></Localized>, mapElement);
};