Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor deployments and events section #710

Merged
merged 5 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { TimelineChart } from "./timeline-chart"
export { DeploymentMap } from "./map"
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react"
import PropTypes from "prop-types"
import styled from "styled-components"

import Map from "../map"
import Source from "../map/source"
Expand All @@ -12,27 +13,71 @@ import {
getStaticIcons,
getIconColors,
} from "../../utils/platform-colors"
import { useFetch } from "@custom-react-hooks/use-fetch"
import { CaseiLogoIcon } from "../../icons"
import { GlobeMap } from "../map/globe-map"
import { MapLegend } from "./map-legend"
import { MapViewControl } from "./map-view-control"
import bbox from "@turf/bbox"

export function DeploymentMap({
geojson,
const MapErrorMsg = styled.div`
background: rgba(255, 255, 255, 0.1);
padding: 1rem;
margin-bottom: 2rem;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
> h4 {
font-size: 1.2rem;
margin: 0;
}
`

const MapLoading = styled.div`
background-color: #111;
height: 500px;
text-align: center;
align-content: center;
`

export const DeploymentMap = ({
campaignName,
deployments,
bounds,
selectedDeployment,
}) {
const MAP_STYLE_ID = "devseed/clx25ggbv076o01ql8k8m03k8"
const geojsonBbox = bbox(geojson)
}) => {
const {
data: geojson,
error: geojsonError,
loading: geojsonLoading,
} = useFetch(`/casei/flight-tracks/${replaceSlashes(campaignName)}.geojson`)
const geojsonBbox = !!geojson && bbox(geojson)
const [enable3DView, setEnable3DView] = useState(
// if the geojson crosses the 80º or -80º latitude, enables 3D view by default
geojsonBbox[1] < -80 || geojsonBbox[3] > 80
)
const platforms = getUniquePlatforms(
deployments.flatMap(d => d.collectionPeriods)
).map(i => ({ name: i.item.shortname, type: i.item.platformType.shortname }))
const names = platforms.map(i => i.name)
const platformNames = platforms.map(i => i.name)
const platformsWithData = geojson?.features.map(
f => f.properties.platform_name
)
const [selectedPlatforms, setSelectedPlatforms] = useState([])
// Set all platforms as selected after the geojson is loaded
useEffect(() => {
if (!geojsonLoading && !selectedPlatforms.length) {
setSelectedPlatforms(
platformNames
.filter((name, index) => platformNames.indexOf(name) === index)
.filter(name => platformsWithData?.includes(name))
)
}
}, [selectedPlatforms, geojsonLoading])

const MAP_STYLE_ID = "devseed/clx25ggbv076o01ql8k8m03k8"
const activeDeploymentPlatforms = getUniquePlatforms(
deployments
.filter(d =>
Expand All @@ -42,9 +87,6 @@ export function DeploymentMap({
)
.map(i => ({ name: i.item.shortname, type: i.item.platformType.shortname }))
.map(i => i.name)
const platformsWithData = geojson.features.map(
f => f.properties.platform_name
)
let movingPlatforms = platforms
.filter(platform =>
["Jet", "Prop", "UAV", "Ships/Boats"].includes(platform.type)
Expand All @@ -55,11 +97,22 @@ export function DeploymentMap({
movingPlatforms.filter((i, index) => movingPlatforms.indexOf(i) === index)
)

const [selectedPlatforms, setSelectedPlatforms] = useState(
names
.filter((name, index) => names.indexOf(name) === index)
.filter(name => platformsWithData.includes(name))
)
if (geojsonError) {
return (
<MapErrorMsg>
<CaseiLogoIcon size="tiny" />
<h4>Flight path data is not yet available for this campaign.</h4>
</MapErrorMsg>
)
}

if (geojsonLoading) {
return (
<MapLoading>
<span className="loader"></span>
</MapLoading>
)
}

return (
<>
Expand Down Expand Up @@ -113,7 +166,7 @@ export function DeploymentMap({
}

DeploymentMap.propTypes = {
geojson: PropTypes.object,
campaignName: PropTypes.string,
deployments: PropTypes.array,
bounds: PropTypes.array,
selectedDeployment: PropTypes.object,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ import * as d3 from "d3"
import styled from "styled-components"

import { Axis } from "./axis"
import { useFetch } from "@custom-react-hooks/use-fetch"
import { NEGATIVE, POSITIVE } from "../../utils/constants"
import { colors } from "../../theme"
import { useChartDimensions } from "../../utils/use-chart-dimensions"
import { occlusion } from "./occlusion"
import { Deployment } from "./deployment"
import { Disclosure } from "@reach/disclosure"
import { DeploymentPanel } from "./deployment-panel"
import { DeploymentMap } from "./map"
import { replaceSlashes } from "../../utils/helpers"
import { CaseiLogoIcon } from "../../icons"

const chartSettings = {
marginTop: 1,
Expand All @@ -40,7 +36,11 @@ export const Swatch = styled.div`
background-color: ${({ color }) => color};
`

export const TimelineChart = ({ deployments, bounds, campaignName }) => {
export const TimelineChart = ({
deployments,
selectedDeployment,
setSelectedDeployment,
}) => {
const [containerRef, dms] = useChartDimensions(chartSettings)

const minDateString = d3
Expand Down Expand Up @@ -83,15 +83,9 @@ export const TimelineChart = ({ deployments, bounds, campaignName }) => {

const isFirstRun = useRef(true)
const tooltipRef = useRef(null)
const [selectedDeployment, setSelectedDeployment] = useState(null)
const [hoveredDeployment, setHoveredDeployment] = useState(null)
const [count, setCount] = useState(1)
const [priority, setPriority] = useState({})
const {
data: geojson,
error: geojsonError,
loading: geojsonLoading,
} = useFetch(`/casei/flight-tracks/${replaceSlashes(campaignName)}.geojson`)

const [tooltip, setTooltip] = useState({ x: null, y: null })
const [tooltipContent, setTooltipContent] = useState(null)
Expand Down Expand Up @@ -130,25 +124,6 @@ export const TimelineChart = ({ deployments, bounds, campaignName }) => {

return (
<Disclosure open={!!selectedDeployment}>
{geojsonError && (
<MapErrorMsg>
<CaseiLogoIcon size="tiny" />
<h4>Flight path data is not yet available for this campaign.</h4>
</MapErrorMsg>
)}
{geojsonLoading && (
<MapLoading>
<span className="loader"></span>
</MapLoading>
)}
{geojson && !geojsonError && !geojsonLoading && (
<DeploymentMap
geojson={geojson}
deployments={deployments}
bounds={bounds}
selectedDeployment={selectedDeployment}
/>
)}
<div
ref={containerRef}
css={`
Expand Down Expand Up @@ -340,28 +315,6 @@ TimelineChart.propTypes = {
),
})
),
bounds: PropTypes.array,
campaignName: PropTypes.string.isRequired,
selectedDeployment: PropTypes.object,
setSelectedDeployment: PropTypes.func,
}

const MapErrorMsg = styled.div`
background: rgba(255, 255, 255, 0.1);
padding: 1rem;
margin-bottom: 2rem;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
> h4 {
font-size: 1.2rem;
margin: 0;
}
`

const MapLoading = styled.div`
background-color: #111;
height: 500px;
text-align: center;
align-content: center;
`
4 changes: 2 additions & 2 deletions src/templates/campaign/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import InpageNav from "../../components/inpage-nav"
import OverviewSection from "./overview-section"
import FocusSection from "./focus-section"
import PlatformSection from "./platform-section"
import TimelineSection from "./timeline-section"
import DeploymentEventsSection from "./timeline-section"
import DataSection from "../../components/data-section"
import ProgramInfoSection from "./program-info-section"
// import OtherResourcesSection from "./other-resources-section"
Expand Down Expand Up @@ -89,7 +89,7 @@ const CampaignTemplate = ({ data: { campaign }, path }) => {
},
deployment: {
nav: "Deployment & Events",
component: TimelineSection,
component: DeploymentEventsSection,
props: {
campaignName: campaign.shortname,
deployments: campaign.deployments,
Expand Down
21 changes: 14 additions & 7 deletions src/templates/campaign/timeline-section.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
/* eslint-disable react/prop-types */
import React from "react"
import React, { useState } from "react"
import PropTypes from "prop-types"
import { graphql } from "gatsby"

import { Section, SectionHeader, SectionContent } from "../../components/layout"
import { TimelineChart } from "../../components/timeline"
import { DeploymentMap, TimelineChart } from "../../components/deployments"

const TimelineSection = ({ id, deployments, bounds, campaignName }) => {
const DeploymentEventsSection = ({ id, deployments, bounds, campaignName }) => {
const [selectedDeployment, setSelectedDeployment] = useState(null)
return (
<Section id={id}>
<SectionHeader headline="Deployment & Events" id={id} />
<SectionContent>
<DeploymentMap
campaignName={campaignName}
deployments={deployments}
bounds={bounds}
selectedDeployment={selectedDeployment}
/>
<TimelineChart
{...{ deployments }}
bounds={bounds}
campaignName={campaignName}
selectedDeployment={selectedDeployment}
setSelectedDeployment={setSelectedDeployment}
/>
</SectionContent>
</Section>
Expand Down Expand Up @@ -49,7 +56,7 @@ export const deploymentFields = graphql`
}
`

TimelineSection.propTypes = {
DeploymentEventsSection.propTypes = {
id: PropTypes.string.isRequired,
campaignName: PropTypes.string.isRequired,
deployments: PropTypes.arrayOf(
Expand Down Expand Up @@ -77,4 +84,4 @@ TimelineSection.propTypes = {
bounds: PropTypes.array,
}

export default TimelineSection
export default DeploymentEventsSection
Loading