1
- import { useState , useEffect } from "react" ;
1
+ import { useState } from "react" ;
2
2
import {
3
3
Map as GLMap ,
4
4
NavigationControl ,
5
5
useControl ,
6
6
} from "react-map-gl/maplibre" ;
7
7
import { TileLayer } from "@deck.gl/geo-layers" ;
8
- import type { _TileLoadProps } from "@deck.gl/geo-layers" ;
8
+ import type { _TileLoadProps , TileIndex } from "@deck.gl/geo-layers" ;
9
9
10
10
import { MapboxOverlay as DeckOverlay } from "@deck.gl/mapbox" ;
11
11
12
12
import ZarrReader from "./zarr" ;
13
13
import NumericDataAnimationLayer from "@/layers/NumericDataAnimationLayer" ;
14
- import type { NumericDataPickingInfo } from "@/layers/NumericDataLayer/types" ;
15
14
import Panel from "@/components/Panel" ;
16
15
import Description from "@/components/Description" ;
17
16
import Dropdown from "@/components/ui/Dropdown" ;
18
17
import RangeSlider from "@/components/ui/RangeSlider" ;
19
18
import SingleSlider from "@/components/ui/Slider" ;
20
- import CheckBox from "@/components/ui/Checkbox" ;
19
+ import PlayButton from "@/components/ui/PlayButton" ;
20
+
21
+ import { usePausableAnimation } from "@/components/ui/utils" ;
21
22
22
23
import "maplibre-gl/dist/maplibre-gl.css" ;
23
24
import "./App.css" ;
@@ -45,7 +46,7 @@ const zarrReader = await ZarrReader.initialize({
45
46
} ) ;
46
47
47
48
const timestampUnit = 1 ;
48
- const maxTimestamp = 2 ;
49
+ const maxTimestamp = 4 ;
49
50
50
51
const quickCache = new Map ( ) ;
51
52
@@ -56,6 +57,24 @@ function DeckGLOverlay(props) {
56
57
return null ;
57
58
}
58
59
60
+ async function fetchOneTimeStamp ( {
61
+ timestamp,
62
+ index,
63
+ } : {
64
+ timestamp : number ;
65
+ index : TileIndex ;
66
+ } ) {
67
+ const { x, y, z } = index ;
68
+ const keyName = `tile${ timestamp } ${ x } ${ y } ${ z } ` ;
69
+ if ( quickCache . get ( keyName ) ) return quickCache . get ( keyName ) ;
70
+ const chunkData = await zarrReader . getTileData ( {
71
+ ...index ,
72
+ timestamp,
73
+ } ) ;
74
+ quickCache . set ( keyName , chunkData ) ;
75
+ return chunkData ;
76
+ }
77
+ const SPEED = 0.02 ;
59
78
function App ( ) {
60
79
const [ selectedColormap , setSelectedColormap ] = useState < string > ( "viridis" ) ;
61
80
const [ minMax , setMinMax ] = useState < { min : number ; max : number } > (
@@ -67,18 +86,12 @@ function App() {
67
86
Math . floor ( timestamp + timestampUnit ) ,
68
87
maxTimestamp
69
88
) ;
70
- const [ showTooltip , setShowTooltip ] = useState < boolean > ( false ) ;
71
89
72
- async function fetchOneTimeStamp ( { timestamp, index } ) {
73
- const { x, y, z } = index ;
74
- const keyName = `tile${ timestamp } ${ x } ${ y } ${ z } ` ;
75
- const chunkData = await zarrReader . getTileData ( {
76
- ...index ,
77
- timestamp,
78
- } ) ;
79
- quickCache . set ( keyName , chunkData ) ;
80
- return chunkData ;
81
- }
90
+ const { isRunning, toggleAnimation } = usePausableAnimation ( ( ) => {
91
+ // Pass on a function to the setter of the state
92
+ // to make sure we always have the latest state
93
+ setTimestamp ( ( prev ) => ( prev + SPEED ) % maxTimestamp ) ;
94
+ } ) ;
82
95
83
96
async function getTileData ( { index, signal } : _TileLoadProps ) {
84
97
if ( signal ?. aborted ) {
@@ -89,45 +102,33 @@ function App() {
89
102
90
103
const { min, max } = scale ;
91
104
const { x, y, z } = index ;
92
- let chunkDataStart ;
93
- let chunkDataEnd ;
105
+
94
106
const timestampKeyStart = `tile${ timestampStart } ${ x } ${ y } ${ z } ` ;
95
107
const timestampKeyEnd = `tile${ timestampEnd } ${ x } ${ y } ${ z } ` ;
96
- // Make it synchronous when there the value is cached
108
+ // Make it synchronous when there are values cached
97
109
if ( quickCache . get ( timestampKeyStart ) && quickCache . get ( timestampKeyEnd ) ) {
98
110
return {
99
- imageDataStart : quickCache . get ( timestampKeyStart ) ,
100
- imageDataEnd : quickCache . get ( timestampKeyEnd ) ,
111
+ imageDataFrom : quickCache . get ( timestampKeyStart ) ,
112
+ imageDataTo : quickCache . get ( timestampKeyEnd ) ,
101
113
min,
102
114
max,
103
115
} ;
104
116
}
105
117
106
- const oneMoreStamp = Math . min ( timestampEnd + 1 , maxTimestamp ) ;
107
- await fetchOneTimeStamp ( { timestamp : oneMoreStamp , index } ) ;
108
-
109
- if ( ! quickCache . get ( timestampKeyStart ) ) {
110
- chunkDataStart = await fetchOneTimeStamp ( {
111
- index,
112
- timestamp : timestampStart ,
113
- } ) ;
114
- } else {
115
- chunkDataStart = quickCache . get ( timestampKeyStart ) ;
116
- }
118
+ const chunkDataStart = await fetchOneTimeStamp ( {
119
+ index,
120
+ timestamp : timestampStart ,
121
+ } ) ;
117
122
118
- if ( ! quickCache . get ( timestampKeyEnd ) ) {
119
- chunkDataEnd = await fetchOneTimeStamp ( {
120
- index,
121
- timestamp : timestampEnd ,
122
- } ) ;
123
- } else {
124
- chunkDataEnd = quickCache . get ( timestampKeyEnd ) ;
125
- }
123
+ const chunkDataEnd = await fetchOneTimeStamp ( {
124
+ index,
125
+ timestamp : timestampEnd ,
126
+ } ) ;
126
127
127
128
if ( chunkDataStart && chunkDataEnd ) {
128
129
return {
129
- imageDataStart : chunkDataStart ,
130
- imageDataEnd : chunkDataEnd ,
130
+ imageDataFrom : chunkDataStart ,
131
+ imageDataTo : chunkDataEnd ,
131
132
min,
132
133
max,
133
134
} ;
@@ -157,20 +158,20 @@ function App() {
157
158
// onViewportLoad: null,
158
159
// refinementStrategy: 'best-available',
159
160
updateTriggers : {
160
- getTileData : [ timestampStart , timestampEnd ] ,
161
+ getTileData : [ timestampStart ] ,
161
162
renderSubLayers : [ selectedColormap , minMax , timestamp ] ,
162
163
} ,
163
164
renderSubLayers : ( props ) => {
164
- const { imageDataStart , imageDataEnd } = props . data ;
165
+ const { imageDataFrom , imageDataTo } = props . data ;
165
166
const { boundingBox } = props . tile ;
166
167
return new NumericDataAnimationLayer ( props , {
167
168
data : undefined ,
168
169
colormap_image : `/colormaps/${ selectedColormap } .png` ,
169
170
min : minMax . min ,
170
171
max : minMax . max ,
171
- imageDataStart ,
172
- imageDataEnd ,
173
- timestamp : timestamp - timestampStart ,
172
+ imageDataFrom ,
173
+ imageDataTo ,
174
+ step : timestamp - timestampStart ,
174
175
tileSize : zarrReader . tileSize ,
175
176
bounds : [
176
177
boundingBox [ 0 ] [ 0 ] ,
@@ -201,9 +202,6 @@ function App() {
201
202
202
203
const deckProps = {
203
204
layers,
204
- getTooltip : ( info : NumericDataPickingInfo ) => {
205
- return showTooltip ? info . dataValue && `${ info . dataValue } ` : null ;
206
- } ,
207
205
} ;
208
206
209
207
return (
@@ -226,11 +224,13 @@ function App() {
226
224
/>
227
225
228
226
< SingleSlider
229
- minMax = { [ 0 , 2 ] }
230
- step = { 0.02 }
227
+ minMax = { [ 0 , maxTimestamp ] }
228
+ step = { SPEED }
229
+ currentValue = { timestamp }
231
230
label = "Timestamp"
232
231
onValueChange = { setTimestamp }
233
232
/>
233
+ < PlayButton onPlay = { isRunning } onClick = { toggleAnimation } />
234
234
</ Panel >
235
235
</ >
236
236
) ;
0 commit comments