@@ -3,259 +3,139 @@ import { useAPIResult } from "@macrostrat/ui-components";
33import {
44 MapAreaContainer ,
55 MapView ,
6+ buildInspectorStyle
67} from "@macrostrat/map-interface" ;
7- import { mapboxAccessToken , matomoToken , matomoApiURL } from "@macrostrat-web/settings" ;
8+ import { mapboxAccessToken , matomoToken , matomoApiURL , tileserverDomain } from "@macrostrat-web/settings" ;
89import { Footer } from "~/components/general" ;
910import { Divider , Spinner , Tabs , Tab } from "@blueprintjs/core" ;
1011import { useEffect , useState } from "react" ;
12+ import { mergeStyles } from "@macrostrat/mapbox-utils" ;
13+ import { useDarkMode } from "@macrostrat/ui-components" ;
1114
1215
1316export function Page ( ) {
14- const [ coords , setCoords ] = useState < Array < { latitude : number ; longitude : number } > | null > ( null ) ;
15- const today = getTodayCoords ( ) ;
16-
17- useEffect ( ( ) => {
18- ( async ( ) => {
19- const data = await getAllCoords ( ) ;
20- setCoords ( data ) ;
21- } ) ( ) ;
22- } , [ ] ) ;
23-
24- console . log ( "Coordinates:" , coords ) ;
25-
2617 return h ( 'div.main' , [
2718 h ( 'div.heatmap-page' , [
28- h ( PageHeader , { coords } ) ,
29- h (
30- Tabs ,
31- {
32- id : 'heatmap-tabs' ,
33- } ,
34- [
35- h ( Tab , { id : 'today' , title : 'Today' , panelClassName : 'today-tab-panel' , panel : h ( TodayMap , { today } ) } ) ,
36- h ( Tab , { id : 'all' , title : 'All' , panelClassName : 'all-tab-panel' , panel : h ( AllMap , { coords, today } ) } ) ,
37- ]
38- )
19+ h ( PageHeader ) ,
20+ h ( HeatMap )
3921 ] ) ,
4022 h ( Footer )
4123 ] ) ;
4224}
4325
44- function PageHeader ( { coords } ) {
45- const visitsToday = getVisitsToday ( ) ;
46-
47- const { visits, visitors } = visitsToday || { } ;
48-
49- const Visit = ! visitsToday ?
50- h ( 'p' , 'Loading visits...' ) :
51- h ( 'div.visits-today' , [
52- h ( 'h3' , `${ visits . toLocaleString ( ) } visits today` ) ,
53- h . if ( coords ?. length ) ( 'h3' , `${ coords ?. length ?. toLocaleString ( ) } visits this year` ) ,
54- ] )
55-
26+ function PageHeader ( ) {
5627 return h ( 'div.page-header' , [
5728 h ( 'h1' , 'Heatmap' ) ,
58- Visit ,
5929 h ( Divider ) ,
60- h ( 'p' , 'This is a heatmap of all the locations where Macrostrat has been accessed.' ) ,
30+ h ( 'p' , 'This is a heatmap of all the locations where Rockd has been accessed.' ) ,
6131 h ( 'p' , 'The blue markers indicate today\'s accesses, while the grey markers indicate accesses from other days.' ) ,
6232 ] ) ;
6333}
6434
65- function AllMap ( { coords, today} ) {
66- if ( ! coords || ! today ) {
67- return h ( "div.map-area-container.loading" , [
68- h ( Spinner , { size : 50 } ) ,
69- ] ) ;
70- }
71-
72- const handleMapLoaded = ( map ) => {
73- map . on ( 'load' , ( ) => {
74- // Combine coords and today coords, marking today's points
75- const allFeatures = coords . map ( ( coord ) => ( {
76- type : 'Feature' ,
77- geometry : {
78- type : 'Point' ,
79- coordinates : [ coord . longitude , coord . latitude ] ,
80- } ,
81- properties : {
82- isToday : false ,
83- } ,
84- } ) ) . concat (
85- today . map ( ( coord ) => ( {
86- type : 'Feature' ,
87- geometry : {
88- type : 'Point' ,
89- coordinates : [ coord . longitude , coord . latitude ] ,
90- } ,
91- properties : {
92- isToday : true ,
93- } ,
94- } ) )
95- ) ;
96-
97- map . addSource ( 'markers' , {
98- type : 'geojson' ,
99- data : {
100- type : 'FeatureCollection' ,
101- features : allFeatures ,
102- } ,
103- } ) ;
104-
105- // Individual points - others (grey)
106- map . addLayer ( {
107- id : 'markers-other' ,
108- type : 'circle' ,
109- source : 'markers' ,
110- filter : [ 'all' , [ '!' , [ 'has' , 'point_count' ] ] , [ '==' , [ 'get' , 'isToday' ] , false ] ] ,
111- paint : {
112- 'circle-radius' : 2 ,
113- 'circle-color' : '#888' ,
114- } ,
115- } ) ;
116-
117- // Individual points - today (blue)
118- map . addLayer ( {
119- id : 'markers-today' ,
120- type : 'circle' ,
121- source : 'markers' ,
122- filter : [ 'all' , [ '!' , [ 'has' , 'point_count' ] ] , [ '==' , [ 'get' , 'isToday' ] , true ] ] ,
123- paint : {
124- 'circle-radius' : 3 ,
125- 'circle-color' : '#007cbf' ,
126- } ,
127- } ) ;
128- } ) ;
129- } ;
35+ function todayStyle ( ) {
36+ return {
37+ sources : {
38+ today : {
39+ type : "vector" ,
40+ tiles : [ tileserverDomain + "/usage-stats/rockd/{z}/{x}/{y}?today=true" ] ,
41+ }
42+ } ,
43+ layers : [
44+ {
45+ id : 'today-points' ,
46+ type : 'circle' ,
47+ source : 'today' ,
48+ "source-layer" : "default" ,
49+ paint : {
50+ 'circle-color' : "#373ec4" ,
51+ 'circle-radius' : 4 ,
52+ }
53+ } ,
54+ ] ,
55+ } ;
56+ }
13057
131- return h ( MapInner , { handleMapLoaded } ) ;
58+ function allStyle ( ) {
59+ return {
60+ sources : {
61+ all : {
62+ type : "vector" ,
63+ tiles : [ tileserverDomain + "/usage-stats/rockd/{z}/{x}/{y}" ] ,
64+ }
65+ } ,
66+ layers : [
67+ {
68+ id : 'all-points' ,
69+ type : 'circle' ,
70+ source : 'all' ,
71+ "source-layer" : "default" ,
72+ paint : {
73+ 'circle-color' : "#838383" ,
74+ 'circle-radius' : 4 ,
75+ }
76+ } ,
77+ ] ,
78+ } ;
13279}
13380
134- function MapInner ( { handleMapLoaded} ) {
135- const style = 'mapbox://styles/mapbox/dark-v10' ;
13681
137- return h (
138- MapAreaContainer ,
139- {
140- className : "map-area-container" ,
141- } ,
82+ function HeatMap ( {
83+ mapboxToken,
84+ } : {
85+ headerElement ?: React . ReactElement ;
86+ title ?: string ;
87+ children ?: React . ReactNode ;
88+ mapboxToken ?: string ;
89+ } ) {
90+
91+ const style = useMapStyle ( ) ;
92+ if ( style == null ) return null ;
93+
94+ const mapPosition = {
95+ camera : {
96+ lat : 39 ,
97+ lng : - 98 ,
98+ altitude : 6000000 ,
99+ } ,
100+ } ;
101+
102+ return h (
103+ "div.map-container" ,
142104 [
143- h ( MapView , {
144- style,
145- mapboxToken : mapboxAccessToken ,
146- onMapLoaded : handleMapLoaded ,
147- mapPosition : {
148- camera : {
149- lat : 39 ,
150- lng : - 98 ,
151- altitude : 6000000 ,
152- } ,
153- } ,
154- } ) ,
105+ // The Map Area Container
106+ h (
107+ MapAreaContainer ,
108+ {
109+ className : 'map-area-container' ,
110+ } ,
111+ [
112+ h ( MapView , { style, mapboxToken : mapboxAccessToken , mapPosition } ) ,
113+ ]
114+ ) ,
155115 ]
156- ) ;
157- }
158-
159- function TodayMap ( { today} ) {
160- if ( ! today ) {
161- return h ( "div.map-area-container.loading" , [
162- h ( Spinner , { size : 50 } ) ,
163- ] ) ;
164- }
165-
166- const handleMapLoaded = ( map ) => {
167- map . on ( 'load' , ( ) => {
168- // Combine coords and today coords, marking today's points
169- const allFeatures = today . map ( ( coord ) => ( {
170- type : 'Feature' ,
171- geometry : {
172- type : 'Point' ,
173- coordinates : [ coord . longitude , coord . latitude ] ,
174- } ,
175- } ) )
176-
177- map . addSource ( 'markers' , {
178- type : 'geojson' ,
179- data : {
180- type : 'FeatureCollection' ,
181- features : allFeatures ,
182- } ,
183- } ) ;
184-
185- map . addLayer ( {
186- id : 'markers-today' ,
187- type : 'circle' ,
188- source : 'markers' ,
189- paint : {
190- 'circle-radius' : 3 ,
191- 'circle-color' : '#007cbf' ,
192- } ,
193- } ) ;
194- } ) ;
195- } ;
196-
197- return h ( MapInner , { handleMapLoaded } ) ;
116+ ) ;
198117}
199118
200- async function getAllCoords ( ) : Promise < Array < { latitude : number , longitude : number } > > {
201- const allCoords : Array < { latitude : number , longitude : number } > = [ ] ;
202- const pageSize = 10000 ;
203- let offset = 0 ;
204- let hasMore = true ;
205-
206- while ( hasMore ) {
207- const result = await fetch ( `${ matomoApiURL } ?${ new URLSearchParams ( {
208- date : '2025-07-01,today' ,
209- period : 'range' ,
210- filter_limit : pageSize . toString ( ) ,
211- filter_offset : offset . toString ( ) ,
212- showColumns : 'latitude,longitude' ,
213- doNotFetchActions : 'true' ,
214- module : 'API' ,
215- idSite : '1' ,
216- format : 'json' ,
217- token_auth : matomoToken ,
218- method : 'Live.getLastVisitsDetails' ,
219- } ) } `) . then ( res => res . json ( ) ) ;
220-
221- if ( Array . isArray ( result ) && result . length > 0 ) {
222- allCoords . push ( ...result ) ;
223- offset += pageSize ;
224- if ( result . length < pageSize ) {
225- hasMore = false ;
226- }
227- } else {
228- hasMore = false ;
229- }
230- }
119+ function useMapStyle ( ) {
120+ const dark = useDarkMode ( ) ;
121+ const isEnabled = dark ?. isEnabled ;
231122
232- return allCoords ;
233- }
123+ const baseStyle = isEnabled
124+ ? "mapbox://styles/mapbox/dark-v10"
125+ : "mapbox://styles/mapbox/light-v10" ;
234126
127+ const [ actualStyle , setActualStyle ] = useState ( null ) ;
128+ const overlayStyle = mergeStyles ( allStyle ( ) , todayStyle ( ) ) ;
235129
236- function getTodayCoords ( ) : Array < { latitude : number , longitude : number } > | undefined {
237- return useAPIResult ( matomoApiURL , {
238- date : 'today' ,
239- period : 'day' ,
240- filter_limit : 10000 ,
241- filter_offset : 0 ,
242- module : 'API' ,
243- format : 'json' ,
244- showColumns : 'latitude,longitude' ,
245- doNotFetchActions : true ,
246- idSite : '1' ,
247- method : 'Live.getLastVisitsDetails' ,
248- token_auth : matomoToken
249- } )
250- }
130+ // Auto select sample type
131+ useEffect ( ( ) => {
132+ buildInspectorStyle ( baseStyle , overlayStyle , {
133+ mapboxToken : mapboxAccessToken ,
134+ inDarkMode : isEnabled ,
135+ } ) . then ( ( s ) => {
136+ setActualStyle ( s ) ;
137+ } ) ;
138+ } , [ isEnabled ] ) ;
251139
252- function getVisitsToday ( ) : { visits : number , visitors : number } | undefined {
253- return useAPIResult ( matomoApiURL , {
254- method : "Live.getCounters" ,
255- lastMinutes : 1440 ,
256- module : 'API' ,
257- format : 'json' ,
258- idSite : '1' ,
259- token_auth : matomoToken
260- } ) ?. [ 0 ]
140+ return actualStyle ;
261141}
0 commit comments