Skip to content

Commit

Permalink
feat: renterd globe
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Aug 17, 2023
1 parent e976c4b commit dfc429e
Show file tree
Hide file tree
Showing 45 changed files with 1,136 additions and 67 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-dolls-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/design-system': minor
---

Table now supports an active row with colored border.
5 changes: 5 additions & 0 deletions .changeset/hungry-baboons-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/design-system': minor
---

AppAuthedLayout now has a scroll prop.
5 changes: 5 additions & 0 deletions .changeset/nervous-dogs-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-core': minor
---

Added useTryUntil.
5 changes: 5 additions & 0 deletions .changeset/new-geckos-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

The host explorer now has an interactive map. Filtered hosts can be selected via the list or map, and hosts on the map are colored based on whether renterd is actively contracting with the host. For hosts with active contracts the size of the hosts on the map is based on renterd's used storage, for hosts without active contracts the size is based on the hosts remaining storage.
5 changes: 5 additions & 0 deletions .changeset/red-dolls-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-core': minor
---

Add useSiaCentralHosts.
5 changes: 5 additions & 0 deletions .changeset/slimy-files-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/design-system': minor
---

Fixed border issues with table.
5 changes: 5 additions & 0 deletions .changeset/thirty-countries-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/design-system': minor
---

Add box-shadow based border classes.
Binary file added apps/renterd/assets/earth-dark-contrast.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/earth-dark.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/earth-day.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/earth-night.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/earth-topology.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/map-2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/renterd/assets/night-sky.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion apps/renterd/components/Hosts/HostContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ export function HostContextMenu({
<Draggable16 />
</Button>
}
contentProps={{ align: 'start', ...contentProps }}
contentProps={{
align: 'start',
...contentProps,
onClick: (e) => {
e.stopPropagation()
},
}}
>
<div className="px-1.5 py-1">
<Text size="14" weight="medium" color="subtle">
Expand Down
224 changes: 224 additions & 0 deletions apps/renterd/components/Hosts/HostMap/Globe.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { useEffect, useRef, useCallback, useMemo } from 'react'
import { GlobeMethods } from 'react-globe.gl'
import { getHostLabel } from './utils'
import { useElementSize } from 'usehooks-ts'
import {
useSiaCentralMarketExchangeRate,
useTryUntil,
} from '@siafoundation/react-core'
import earthDarkContrast from '../../../assets/earth-dark-contrast.png'
import earthTopology from '../../../assets/earth-topology.png'
import { GlobeDyn } from './GlobeDyn'
import { HostDataWithLocation } from '../../../contexts/hosts/types'
import BigNumber from 'bignumber.js'
import { getHostStatus } from '../../../contexts/hosts/status'

export type Commands = {
moveToLocation: (
location: [number, number] | undefined,
altitude?: number
) => void
}

export const emptyCommands: Commands = {
moveToLocation: (location: [number, number], altitude?: number) => null,
}

type Props = {
activeHost?: HostDataWithLocation
hosts?: HostDataWithLocation[]
onHostClick: (publicKey: string, location: [number, number]) => void
onHostHover: (publicKey: string, location: [number, number]) => void
onMount?: (cmd: Commands) => void
}

type Route = {
distance: number
src: HostDataWithLocation
dst: HostDataWithLocation
}

export function Globe({
activeHost,
hosts,
onMount,
onHostClick,
onHostHover,
}: Props) {
const rates = useSiaCentralMarketExchangeRate({
config: {
swr: {
revalidateOnFocus: false,
},
},
})
const globeEl = useRef<GlobeMethods>(null)
const cmdRef = useRef<Commands>(emptyCommands)
const moveToLocation = useCallback(
(location: [number, number] | undefined, altitude?: number) => {
if (!location) {
return
}
globeEl.current?.pointOfView(
{
lat: location[0] - 8,
lng: location[1],
altitude: altitude || 1.5,
},
700
)
},
[]
)

useEffect(() => {
cmdRef.current.moveToLocation = moveToLocation
}, [moveToLocation])

useTryUntil(() => {
if (!globeEl.current) {
return false
}

moveToLocation(activeHost?.location || [48.8323, 2.4075], 1.5)

const directionalLight = globeEl.current
?.scene()
.children.find((obj3d) => obj3d.type === 'DirectionalLight')
if (directionalLight) {
// directionalLight.position.set(1, 1, 1)
directionalLight.intensity = 10
}
return true
})

useEffect(() => {
if (onMount) {
onMount(cmdRef.current)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

// const routes = useDecRoutes({ hosts, activeHost })
const routes = []

const [containerRef, { height, width }] = useElementSize()

const points = useMemo(() => hosts || [], [hosts])

return (
<div ref={containerRef} className="w-full h-full">
<GlobeDyn
ref={globeEl}
width={width}
height={height}
backgroundColor="rgba(0,0,0,0)"
globeImageUrl={earthDarkContrast.src}
bumpImageUrl={earthTopology.src}
// backgroundImageUrl={nightSky.src}
arcsData={routes}
atmosphereColor="rgba(0,0,0,0)"
atmosphereAltitude={0.16}
animateIn={false}
arcLabel={(r: Route) =>
getHostLabel({ host: r.dst, rates: rates.data?.rates.sc })
}
arcStartLat={(r: Route) => +r.src.location[0]}
arcStartLng={(r: Route) => +r.src.location[1]}
arcEndLat={(r: Route) => +r.dst.location[0]}
arcEndLng={(r: Route) => +r.dst.location[1]}
arcDashLength={0.75}
arcAltitude={0}
arcDashGap={0.1}
arcDashInitialGap={() => Math.random()}
arcDashAnimateTime={5000}
// arcDashAnimateTime={(route: Route) =>
// doesIncludeActiveHost(route, activeHost) ? 5000 : 0
// }
arcColor={(r: Route) =>
doesIncludeActiveHost(r, activeHost)
? [`rgba(187, 229, 201, 0.25)`, `rgba(187, 229, 201, 0.25)`]
: [`rgba(187, 229, 201, 0.10)`, `rgba(187, 229, 201, 0.10)`]
}
// onArcClick={(r: Route) => {
// selectActiveHost(r.dst.publicKey)
// }}
arcsTransitionDuration={0}
pointsData={points}
pointLat={(h: HostDataWithLocation) => h.location[0]}
pointLng={(h: HostDataWithLocation) => h.location[1]}
pointLabel={(h: HostDataWithLocation) =>
getHostLabel({ host: h, rates: rates.data?.rates.sc })
}
// pointAltitude={
// (h: HostDataWithLocation) => h.settings.remainingstorage / 1e13 / 100
// // h.publicKey === activeHost.publicKey ? 0.6 : 0.2
// }
pointAltitude={(h: HostDataWithLocation) => {
if (activeHost) {
return h.publicKey === activeHost?.publicKey
? 0.1
: h.activeContractsCount.gt(0)
? 0.1
: 0.1
}
return h.activeContractsCount.gt(0) ? 0.1 : 0.1
}}
pointsTransitionDuration={0}
pointColor={(h: HostDataWithLocation) => {
const { color } = getHostStatus(h)
if (!activeHost || h.publicKey === activeHost?.publicKey) {
return color
}
return colorWithOpacity(color, 0.2)
}}
pointRadius={(h: HostDataWithLocation) => {
let radius = 0
if (h.activeContractsCount.gt(0)) {
radius = h.activeContracts
.reduce((acc, c) => acc.plus(c.size), new BigNumber(0))
.div(1e12)
.toNumber()
}
radius = h.settings.remainingstorage / 1e13 / 3

return Math.max(radius, 0.1)
}}
onPointHover={(h: HostDataWithLocation) => {
if (!h) {
return
}
onHostHover?.(h.publicKey, h.location)
}}
onPointClick={(h: HostDataWithLocation) => {
if (!h) {
return
}
onHostClick?.(h.publicKey, h.location)
}}
pointsMerge={false}
/>
</div>
)
}

function doesIncludeActiveHost(
route: Route,
activeHost?: HostDataWithLocation
) {
if (!activeHost) {
return false
}
return (
route.dst.publicKey === activeHost.publicKey ||
route.src.publicKey === activeHost.publicKey
)
}

function colorWithOpacity(hexColor: string, opacity: number) {
const r = parseInt(hexColor.slice(1, 3), 16)
const g = parseInt(hexColor.slice(3, 5), 16)
const b = parseInt(hexColor.slice(5, 7), 16)

return `rgba(${r}, ${g}, ${b}, ${opacity})`
}
14 changes: 14 additions & 0 deletions apps/renterd/components/Hosts/HostMap/GlobeDyn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { forwardRef, MutableRefObject } from 'react'
import dynamic from 'next/dynamic'
import { GlobeMethods } from 'react-globe.gl'

const GlobeGl = dynamic(() => import('./GlobeImp'), {
ssr: false,
})

export const GlobeDyn = forwardRef(function ReactGlobe(
props: Omit<React.ComponentProps<typeof GlobeGl>, 'forwardRef'>,
ref: MutableRefObject<GlobeMethods>
) {
return <GlobeGl {...props} forwardRef={ref} />
})
11 changes: 11 additions & 0 deletions apps/renterd/components/Hosts/HostMap/GlobeImp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MutableRefObject } from 'react'
import GlobeTmpl, { GlobeMethods } from 'react-globe.gl'

const GlobeImp = ({
forwardRef,
...otherProps
}: React.ComponentProps<typeof GlobeTmpl> & {
forwardRef: MutableRefObject<GlobeMethods>
}) => <GlobeTmpl {...otherProps} ref={forwardRef} />

export default GlobeImp
Loading

0 comments on commit dfc429e

Please sign in to comment.