Skip to content

Commit

Permalink
climbing: Add RouteDistribution (#285)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvaclavik authored Apr 3, 2024
1 parent 482037c commit 6ddff1f
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 34 deletions.
2 changes: 2 additions & 0 deletions src/components/FeaturePanel/Climbing/ClimbingPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { StarButton } from '../ImageSection/StarButton';
import { OsmError } from '../OsmError';
import { Properties } from '../Properties/Properties';
import { PoiDescription } from '../ImageSection/PoiDescription';
import { RouteDistribution } from './RouteDistribution';

const ThumbnailContainer = styled.div<{ height: number }>`
width: 100%;
Expand Down Expand Up @@ -144,6 +145,7 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => {

<OsmError />

<RouteDistribution />
<RouteList />

<div style={{ padding: '35px 15px 5px' }}>
Expand Down
12 changes: 10 additions & 2 deletions src/components/FeaturePanel/Climbing/ClimbingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { getCommonsImageUrl } from '../../../services/images/getWikiImage';
import { Guide } from './Guide';
import { ControlPanel } from './Editor/ControlPanel';
import { useScrollShadow } from './utils/useScrollShadow';
import { RouteDistribution } from './RouteDistribution';

const Container = styled.div`
position: relative;
Expand Down Expand Up @@ -139,6 +140,13 @@ const BackgroundContainer = styled.div<{
height: 100%;
`;

const MainContent = () => (
<>
<RouteList isEditable />
<RouteDistribution />
</>
);

export const ClimbingView = ({ photoIndex }: { photoIndex?: number }) => {
const {
imageSize,
Expand Down Expand Up @@ -329,13 +337,13 @@ export const ClimbingView = ({ photoIndex }: { photoIndex?: number }) => {
<ShadowContainer>
<ShadowTop backgroundColor={theme.palette.background.paper} />
<BottomPanel onScroll={onScroll} ref={scrollElementRef}>
<RouteList isEditable />
<MainContent />
</BottomPanel>
<ShadowBottom backgroundColor={theme.palette.background.paper} />
</ShadowContainer>
</SplitPane>
) : (
<RouteList isEditable />
<MainContent />
)}
</Container>
);
Expand Down
7 changes: 7 additions & 0 deletions src/components/FeaturePanel/Climbing/ContentContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from 'styled-components';

export const ContentContainer = styled.div`
width: 100%;
max-width: 800px;
margin: 0 auto;
`;
36 changes: 36 additions & 0 deletions src/components/FeaturePanel/Climbing/PanelLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import styled from 'styled-components';
import { ContentContainer } from './ContentContainer';

type PanelLabelProps = {
children: React.ReactNode;
addition?: React.ReactNode;
};

export const Container = styled.div`
border-bottom: solid 1px ${({ theme }) => theme.palette.divider};
padding: 20px 10px 4px;
`;

export const InnerContainer = styled.div`
display: flex;
justify-content: space-between;
`;
export const Title = styled.div`
font-weight: bold;
color: ${({ theme }) => theme.palette.secondary.main};
`;
export const Addition = styled.div`
color: ${({ theme }) => theme.palette.secondary.main};
`;

export const PanelLabel = ({ children, addition }: PanelLabelProps) => (
<Container>
<ContentContainer>
<InnerContainer>
<Title>{children}</Title>
<Addition>{addition}</Addition>
</InnerContainer>
</ContentContainer>
</Container>
);
127 changes: 127 additions & 0 deletions src/components/FeaturePanel/Climbing/RouteDistribution.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import styled from 'styled-components';
import React from 'react';
import { useClimbingContext } from './contexts/ClimbingContext';
import {
convertGrade,
getDifficultyColor,
getGradeSystemName,
} from './utils/routeGrade';
import { PanelLabel } from './PanelLabel';
import { ContentContainer } from './ContentContainer';

const MAX_HEIGHT = 100;
const GRADE_SYSTEM = 'uiaa';

const Container = styled.div`
margin: 16px 12px 12px;
`;

const Items = styled.div`
display: flex;
align-items: flex-end;
gap: 4px;
`;

const NumberOfRoutes = styled.div`
text-align: center;
font-size: 9px;
`;
const Column = styled.div``;
const DifficultyLevel = styled.div<{ isActive: boolean }>`
text-align: center;
color: ${({ color, isActive, theme }) =>
isActive ? color : theme.palette.secondary.main};
font-weight: bold;
font-size: 11px;
`;

const Chart = styled.div<{ ratio: number; color: string }>`
height: ${({ ratio }) => MAX_HEIGHT * ratio}px;
background-color: ${({ color, theme, ratio }) =>
ratio === 0 ? theme.palette.secondary.main : color};
width: 24px;
border-radius: 2px;
`;

const getGroupingLabel = (label: string) => String(parseFloat(label));

export const RouteDistribution = () => {
const { routes, gradeTable } = useClimbingContext();
if (routes.length === 0) return null;

const prepareOccurrenceStructure = () =>
gradeTable?.[GRADE_SYSTEM].reduce<{ [grade: string]: number }>(
(acc, grade) => ({
...acc,
[getGroupingLabel(grade)]: 0,
}),
{},
);

const getOccurrences = () => {
const structure = prepareOccurrenceStructure();
return routes.reduce((acc, route) => {
if (!route.difficulty) return acc;
const convertedGrade = convertGrade(
gradeTable,
route.difficulty.gradeSystem,
GRADE_SYSTEM,
route.difficulty.grade,
);
const newGrade = getGroupingLabel(convertedGrade);
if (!structure) return {};
const updatedKey = Object.keys(structure).find((grade) => {
if (grade === newGrade) return true;
return false;
});
if (updatedKey === undefined) return acc;
return { ...acc, [updatedKey]: acc[updatedKey] + 1 };
}, structure);
};

const routeOccurrences = getOccurrences();

if (!routeOccurrences) return null;

const heightsRatios = Object.keys(routeOccurrences).map((key) => ({
grade: key,
ratio: routeOccurrences[key] / routes.length,
}));

return (
<>
<PanelLabel addition={getGradeSystemName(GRADE_SYSTEM)}>
Routes distribution
</PanelLabel>
<Container>
<ContentContainer>
<Items>
{heightsRatios.map((heightRatioItem) => {
const color = getDifficultyColor(gradeTable, {
gradeSystem: 'uiaa',
grade: heightRatioItem.grade,
});
const numberOfRoutesKey = Object.keys(routeOccurrences).find(
(key) => key === heightRatioItem.grade,
);
const numberOfRoutes = routeOccurrences[numberOfRoutesKey];
const isColumnActive = numberOfRoutes > 0;
return (
<Column>
{numberOfRoutes > 0 && (
<NumberOfRoutes>{numberOfRoutes}x</NumberOfRoutes>
)}
<Chart color={color} ratio={heightRatioItem.ratio} />

<DifficultyLevel color={color} isActive={isColumnActive}>
{heightRatioItem.grade}
</DifficultyLevel>
</Column>
);
})}
</Items>
</ContentContainer>
</Container>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const ExpandedRowContainer = styled.div<{ isExpanded?: boolean }>`
transition: all 0.1s ease-in-out;
min-height: 0;
overflow: hidden;
margin-left: 26px;
`;

const Value = styled.div``;
Expand Down
61 changes: 34 additions & 27 deletions src/components/FeaturePanel/Climbing/RouteList/RouteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { RouteListDndContent } from './RouteListDndContent';
import { addElementToArray, deleteFromArray } from '../utils/array';
import { getCsvGradeData } from '../utils/routeGrade';
import { invertedBoltCodeMap } from '../utils/boltCodes';
import { PanelLabel } from '../PanelLabel';
import { ContentContainer } from '../ContentContainer';

const Container = styled.div`
padding-bottom: 20px;
Expand All @@ -32,6 +34,8 @@ export const RouteList = ({ isEditable }: { isEditable?: boolean }) => {
showDebugMenu,
} = useClimbingContext();

if (routes.length === 0) return null;

React.useEffect(() => {
if (!gradeTable) setGradeTable(getCsvGradeData());
}, []);
Expand Down Expand Up @@ -120,36 +124,39 @@ export const RouteList = ({ isEditable }: { isEditable?: boolean }) => {

return (
<Container>
<PanelLabel addition={`${routes.length} routes`}>Routes</PanelLabel>
{/* {arePointerEventsDisabled ? 'NONE' : 'ALL'} */}
{routes.length !== 0 && <RouteListDndContent isEditable={isEditable} />}
{!isEditMode && isEditable && (
<ButtonContainer>
<Button
onClick={handleEdit}
color="primary"
variant="outlined"
endIcon={<EditIcon />}
>
Edit routes
</Button>
</ButtonContainer>
)}
{showDebugMenu && (
<>
<br />
<ButtonGroup variant="contained" size="small" color="primary">
<Button size="small" onClick={getRoutesCsv}>
export OSM
</Button>
<Button size="small" onClick={getRoutesJson}>
export JSON
</Button>
<Button size="small" onClick={mockRoutes}>
Mock
<ContentContainer>
{!isEditMode && isEditable && (
<ButtonContainer>
<Button
onClick={handleEdit}
color="primary"
variant="outlined"
endIcon={<EditIcon />}
>
Edit routes
</Button>
</ButtonGroup>
</>
)}
</ButtonContainer>
)}
{showDebugMenu && (
<>
<br />
<ButtonGroup variant="contained" size="small" color="primary">
<Button size="small" onClick={getRoutesCsv}>
export OSM
</Button>
<Button size="small" onClick={getRoutesJson}>
export JSON
</Button>
<Button size="small" onClick={mockRoutes}>
Mock
</Button>
</ButtonGroup>
</>
)}
</ContentContainer>
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ type Item = {
content: React.ReactNode;
};

const Container = styled.div`
width: 100%;
margin: 0 auto;
`;

const MaxWidthContainer = styled.div`
width: 100%;
max-width: 800px;
Expand All @@ -17,10 +22,7 @@ const MaxWidthContainer = styled.div`
justify-content: center;
flex-direction: row;
`;
const Container = styled.div`
width: 100%;
margin: 0 auto;
`;

const RowWithDragHandler = styled.div<{ isDraggedOver: boolean }>`
cursor: pointer;
display: flex;
Expand All @@ -32,7 +34,7 @@ const RowWithDragHandler = styled.div<{ isDraggedOver: boolean }>`
isSelected ? theme.palette.action.selected : 'transparent'};
position: relative;
font-size: 16px;
border-top: solid 1px ${({ theme }) => theme.palette.divider};
border-top: dotted 1px ${({ theme }) => theme.palette.divider};
z-index: ${({ isSelected }) => (isSelected ? '2' : 'auto')};
`;
const DragHandler = styled.div`
Expand Down
1 change: 1 addition & 0 deletions src/components/FeaturePanel/Climbing/utils/gradeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,5 @@ export const gradeColors = {
'13+': { light: '#9C0101', dark: '#690000' },
'13+/14-': { light: '#9C0101', dark: '#690000' },
'14-': { light: '#9C0101', dark: '#690000' },
'14': { light: '#9C0101', dark: '#690000' },
};

0 comments on commit 6ddff1f

Please sign in to comment.