Skip to content

Commit

Permalink
vector data layers (#93)
Browse files Browse the repository at this point in the history
* 1. resolve conflicts
2. fix bug that change raster map will cover vector data layer

* resolve "Delete `␍` prettier/prettier" problem

* 1. refine the data structure in rasterMenu component
2. complete vector data dynamic update function, so vector data list will uncheck all layers and automatically update to corresponding list when we change the raster map.
  • Loading branch information
yiyanw authored Aug 13, 2022
1 parent b379c6a commit 78f75cb
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 42 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint", "prettier"],
"rules": { "prettier/prettier": ["error"] }
"rules": { "prettier/prettier": ["error", {
"endOfLine": "auto"
}] }
}
22 changes: 12 additions & 10 deletions src/components/RasterMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
import './RasterMenu.scss'
import { chevronBack, chevronForward } from 'ionicons/icons'
import { useRecoilState } from 'recoil'
import { isRasterMenuShow } from '../functions/atoms'
import {
currentRasterMapIndexState,
isRasterMenuShow,
} from '../functions/atoms'
import rasterMaps from '../functions/rasterMaps'
import { cesiumViewer } from '../pages/Main'
import { WebMapTileServiceImageryProvider } from 'cesium'
Expand All @@ -33,7 +36,9 @@ export const RasterMenu: React.FC<ContainerProps> = ({
isViewerLoading,
isCesiumViewerReady,
}) => {
const [isSelectedList, setIsSelectedList] = useState([] as boolean[])
const [currentRasterMapIndex, setCurrentRasterMapIndex] = useRecoilState(
currentRasterMapIndexState
)
const [isShow, setIsShow] = useRecoilState(isRasterMenuShow)

const [present, dismiss] = useIonLoading()
Expand All @@ -55,9 +60,11 @@ export const RasterMenu: React.FC<ContainerProps> = ({
optionList.push(
<IonCard
key={'raster-menu-element-' + i}
className={isSelectedList[i] ? 'selected-opt' : 'unselected-opt'}
className={
currentRasterMapIndex === i ? 'selected-opt' : 'unselected-opt'
}
onClick={async (e) => {
if (!isSelectedList[i]) {
if (currentRasterMapIndex !== i) {
select(i)
await present({ message: 'Loading...' })
switchLayer(rasterMaps[i].layer)
Expand Down Expand Up @@ -85,12 +92,7 @@ export const RasterMenu: React.FC<ContainerProps> = ({

// select the target one and unselect rest all
const select = (index: number) => {
let temp = [...isSelectedList]
for (let i = 0; i < isSelectedList.length; i++) {
temp[i] = false
}
temp[index] = true
setIsSelectedList(temp)
setCurrentRasterMapIndex(index)
}

return (
Expand Down
145 changes: 114 additions & 31 deletions src/components/VectorDataLayerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ import {
IonToolbar,
useIonLoading,
} from '@ionic/react'
import { vectorData } from '../functions/DataLoader'
import React, { useEffect } from 'react'
import {
createCesiumImageryProvider,
vectorData,
} from '../functions/DataLoader'
import React, { useEffect, useState } from 'react'
import { timeout } from 'workbox-core/_private'
import { useRecoilState } from 'recoil'
import { isVectorMenuShow } from '../functions/atoms'
import { useRecoilState, useRecoilValue } from 'recoil'
import {
currentRasterMapIndexState,
isVectorMenuShow,
rasterMapState,
} from '../functions/atoms'
import { WebMapTileServiceImageryProvider } from 'cesium'
import { cesiumViewer } from '../pages/Main'
import { gplates_coastlines } from '../functions/DataLoader'
import rasterMaps from '../functions/rasterMaps'

interface ContainerProps {
checkedVectorData: { [key: string]: WebMapTileServiceImageryProvider }
Expand All @@ -37,20 +43,88 @@ export const VectorDataLayerMenu: React.FC<ContainerProps> = ({
}) => {
const [isShow, setIsShow] = useRecoilState(isVectorMenuShow)
const [present, dismiss] = useIonLoading()
const currentRasterMapIndex = useRecoilValue(currentRasterMapIndexState)
const [checkboxList, setCheckBoxList] = useState(new Map<String, boolean>())
const [vecDataProviderMap, setVecDataProviderMap] = useState(vectorData)
const rasterMapInfo = useRecoilValue(rasterMapState)

const getVecInfoByRaster = async (rasterModel: String) => {
let response = await (
await fetch(
'https://gws.gplates.org/mobile/get_vector_layers?model=' + rasterModel
)
).json()
let vecDataMap: {
[key: string]: WebMapTileServiceImageryProvider
} = {}
for (let key in response) {
vecDataMap[key] = createCesiumImageryProvider(
response[key].url,
response[key].layer
)
}
return vecDataMap
}

function removeAllVectorLayer() {
for (let layer in checkedVectorData) {
let curLayer = checkedVectorData[layer]
removeLayer(curLayer)
}
setVectorData({})
}

function updateVectorDataInformation(
checkedFunction: (input: number) => boolean
) {
let model
if (rasterMaps[currentRasterMapIndex] != undefined) {
model = rasterMaps[currentRasterMapIndex].model
} else {
// default invoking
model = rasterMapInfo[currentRasterMapIndex].model
}
if (model === undefined) {
// no model info, no update
return
}
removeAllVectorLayer()
getVecInfoByRaster(model).then((vecDataMap) => {
setVecDataProviderMap(vecDataMap)
const tempCheckboxList: Map<string, boolean> = new Map()
const vectorDataName = Object.keys(vecDataMap)
for (let i = 0; i < vectorDataName.length; i++) {
// initially load coastlines vector data for Geology
// i == 0 means coastlines for Geology
tempCheckboxList.set(vectorDataName[i], checkedFunction(i))
}
setCheckBoxList(tempCheckboxList)
})
}

// update to corresponding vector layer when raster map changes
useEffect(() => {
updateVectorDataInformation((idx) => false)
}, [currentRasterMapIndex])

// initializing
useEffect(() => {
updateVectorDataInformation((idx) => {
return idx == 0
})
}, [])

const waitUntilLoaded = async () => {
await timeout(500)
await timeout(100)
while (!isViewerLoading()) {
await timeout(500)
}
}

const onCheckBoxChange = async (val: any) => {
const name: string = val.detail.value
const isChecked = val.detail.checked

// check or uncheck target vector layer
const checkLayer = (name: string, isChecked: boolean) => {
if (isChecked) {
checkedVectorData[name] = addLayer(vectorData[name])
checkedVectorData[name] = addLayer(vecDataProviderMap[name])
setVectorData(checkedVectorData)
} else {
removeLayer(checkedVectorData[name])
Expand All @@ -59,14 +133,35 @@ export const VectorDataLayerMenu: React.FC<ContainerProps> = ({
}
}

const checkboxList: any[] = []
const vectorDataName = Object.keys(vectorData)
for (let i = 0; i < vectorDataName.length; i++) {
checkboxList.push({
val: vectorDataName[i],
isChecked: vectorDataName[i] in checkedVectorData,
const onCheckBoxChange = (val: any) => {
const name: string = val.detail.value
const isChecked = val.detail.checked
checkboxList.set(name, isChecked)
setCheckBoxList(checkboxList)
checkLayer(name, isChecked)
}

const generateCheckList = () => {
let count = 0
let checkList: JSX.Element[] = []
checkboxList.forEach((isChecked, name, map) => {
checkList.push(
<IonItem key={count}>
<IonLabel>{name}</IonLabel>
<IonCheckbox
slot="end"
value={name}
checked={isChecked}
onIonChange={onCheckBoxChange}
/>
</IonItem>
)
count += 1
})

return checkList
}

return (
<IonModal isOpen={isShow} animated backdropDismiss={false}>
<IonToolbar>
Expand All @@ -86,19 +181,7 @@ export const VectorDataLayerMenu: React.FC<ContainerProps> = ({
</IonButton>
</IonButtons>
</IonToolbar>
<IonContent>
{checkboxList.map(({ val, isChecked }, i) => (
<IonItem key={i}>
<IonLabel>{val}</IonLabel>
<IonCheckbox
slot="end"
value={val}
checked={isChecked}
onIonChange={onCheckBoxChange}
/>
</IonItem>
))}
</IonContent>
<IonContent>{generateCheckList()}</IonContent>
</IonModal>
)
}
4 changes: 4 additions & 0 deletions src/functions/atoms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export const rasterMapState = atom<RasterCfg[]>({
key: 'rasterMapState',
default: failSafeRasterMaps,
})
export const currentRasterMapIndexState = atom({
key: 'currentRasterMapIndexState',
default: 0,
})

// Settings menu path: Ionic's Nav component is not available under React yet, so we have to build our own solution
export const settingsPath = atom({ key: 'settingsPath', default: 'root' })
3 changes: 3 additions & 0 deletions src/functions/rasterMaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ export const failSafeRasterMaps = [
title: 'Geology',
subTitle: 'present day',
icon: 'assets/raster_menu/geology-256x256.png',
model: 'MULLER2019',
},
{
layer: rasterData['agegrid'],
title: 'Agegrid',
subTitle: 'present day',
icon: 'assets/raster_menu/agegrid-256x256.png',
model: 'SETON2012',
},
{
layer: rasterData['topography'],
title: 'Topography',
subTitle: 'present day',
icon: 'assets/raster_menu/topography-256x256.png',
model: 'MERDITH2021',
},
]

Expand Down

0 comments on commit 78f75cb

Please sign in to comment.