This repository has been archived by the owner on May 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#conditions-gp | added import files for Road Continditions, comments …
…to be added and dependencies fixed #3
- Loading branch information
1 parent
61dd64a
commit e68aaa3
Showing
24 changed files
with
826 additions
and
17,838 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
|
||
import { FC, useEffect, useMemo, useState } from 'react'; | ||
import { LeafletEvent, Polyline } from 'leaflet' | ||
import { HotlineOptions, useCustomHotline } from 'react-leaflet-hotline'; | ||
|
||
import { useGraph } from '../../../context/GraphContext'; | ||
|
||
import { Condition, Node, WayId } from '../../../models/path'; | ||
|
||
import DistRenderer from '../../../assets/hotline/DistRenderer'; | ||
import { DistData } from '../../../assets/hotline/hotline'; | ||
import HoverHotPolyline from '../../../assets/hotline/HoverHotPolyline'; | ||
import { HotlineEventFn, HotlineEventHandlers } from 'react-leaflet-hotline/lib/types'; | ||
import useZoom from '../Hooks/useZoom'; | ||
import { useHoverContext } from "../../../context/GraphHoverContext"; | ||
|
||
|
||
const getLat = (n: Node) => n.lat; | ||
const getLng = (n: Node) => n.lng; | ||
const getVal = (n: Node) => n.way_dist; | ||
const getWeight = (z: number | undefined) => z === undefined ? 0 : Math.max(z > 8 ? z - 6 : z - 5, 2) | ||
|
||
interface IDistHotline { | ||
way_ids: WayId[]; | ||
geometry: Node[][]; | ||
conditions: Condition[][]; | ||
options?: HotlineOptions, | ||
eventHandlers?: HotlineEventHandlers; | ||
} | ||
|
||
const handler = (eventHandlers: HotlineEventHandlers | undefined, event: keyof HotlineEventHandlers, opacity: number) => { | ||
return (e: LeafletEvent, i: number, p: Polyline<any, any>) => { | ||
p.setStyle( { opacity } ) | ||
if ( eventHandlers && eventHandlers[event] !== undefined ) | ||
(eventHandlers[event] as HotlineEventFn)(e, i, p); | ||
} | ||
} | ||
|
||
const DistHotline: FC<IDistHotline> = ( { way_ids, geometry, conditions, options, eventHandlers } ) => { | ||
|
||
const { dotHover } = useHoverContext() | ||
const zoom = useZoom() | ||
|
||
const opts = useMemo( () => ({ | ||
...options, weight: getWeight(zoom) | ||
}), [options, zoom] ) | ||
|
||
const handlers: HotlineEventHandlers = useMemo( () => ({ | ||
...eventHandlers, | ||
mouseover: handler(eventHandlers, 'mouseover', 0.5), | ||
mouseout: handler(eventHandlers, 'mouseout', 0), | ||
}), [eventHandlers] ) | ||
|
||
const { hotline } = useCustomHotline<Node, DistData>( | ||
DistRenderer, HoverHotPolyline, | ||
{ data: geometry, getLat, getLng, getVal, options: opts, eventHandlers: handlers }, | ||
way_ids, conditions | ||
); | ||
|
||
useEffect( () => { | ||
if ( hotline === undefined ) return; | ||
(hotline as HoverHotPolyline<Node, DistData>).setHover(dotHover) | ||
}, [dotHover]) | ||
|
||
return null; | ||
} | ||
|
||
|
||
export default DistHotline; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { FC, MouseEvent, useState } from "react"; | ||
import { Gradient } from "react-gradient-hook"; | ||
import { CursorOptions } from "react-gradient-hook/lib/types"; | ||
import { useMap } from "react-leaflet"; | ||
import { Palette } from "react-leaflet-hotline"; | ||
|
||
import '../../css/palette.css' | ||
|
||
interface IPaletteEditor { | ||
width: number | undefined; | ||
defaultPalette?: Palette; | ||
cursorOptions?: CursorOptions; | ||
onChange?: (palette: Palette) => void; | ||
} | ||
|
||
const PaletteEditor: FC<IPaletteEditor> = ( { width, defaultPalette, cursorOptions, onChange } ) => { | ||
|
||
const [show, setShow] = useState<boolean>(false) | ||
|
||
const toggleAppear = () => setShow(prev => !prev) | ||
|
||
if ( width === undefined || width === 0 ) return null; | ||
|
||
return ( | ||
<div className={`palette-wrapper ${show ? 'palette-show' : ''}`} style={{width: `${width}px`}} > | ||
<div className="palette-container"> | ||
<Gradient defaultColors={defaultPalette} cursorOptions={cursorOptions} onChange={onChange}/> | ||
</div> | ||
<div className='palette-hover' onClick={toggleAppear}>🎨</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default PaletteEditor; |
97 changes: 97 additions & 0 deletions
97
frontend/src/Components/RoadConditions/ConditionsGraph.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { FC, useCallback, useEffect, useMemo, useRef } from "react"; | ||
import { ChartData, Chart, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, ActiveElement, ChartEvent, ChartOptions, ChartTypeRegistry, Plugin } from "chart.js"; | ||
import { Color, Palette } from "react-leaflet-hotline"; | ||
import { Line } from "react-chartjs-2"; | ||
|
||
import { ConditionType } from "../../models/graph"; | ||
|
||
Chart.register( CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend ); | ||
|
||
const options = ({name, min, max}: ConditionType): ChartOptions<'line'> => ({ | ||
responsive: true, | ||
maintainAspectRatio: false, | ||
plugins: { | ||
legend: { | ||
position: 'top' as const, | ||
labels: { color: 'white' }, | ||
}, | ||
}, | ||
scales: { | ||
x: { | ||
title: { | ||
display: true, | ||
text: 'distance (m)' | ||
}, | ||
ticks: { | ||
maxTicksLimit: 30, | ||
stepSize: 200, | ||
callback: (tick: string | number) => Math.round(parseFloat(tick.toString())) | ||
} | ||
}, | ||
y: { | ||
title: { | ||
display: true, | ||
text: name | ||
}, | ||
min: min, | ||
max: max | ||
} | ||
} | ||
}); | ||
|
||
interface Props { | ||
type: ConditionType; | ||
data: ChartData<"line", number[], number> | undefined | ||
palette: Palette; | ||
} | ||
|
||
const ConditionsGraph: FC<Props> = ( { type, data, palette } ) => { | ||
|
||
const ref = useRef<Chart<"line", number[], number>>(null) | ||
|
||
const addPaletteChart = (palette: Palette) => (chart: Chart<keyof ChartTypeRegistry, number[], unknown>) => { | ||
const dataset = chart.data.datasets[0]; | ||
const gradient = chart.ctx.createLinearGradient(0, chart.chartArea.bottom, 0, 0); | ||
console.log(...palette); | ||
palette.forEach( (c: Color) => { | ||
gradient.addColorStop(c.t, `rgb(${c.r}, ${c.g}, ${c.b})`); | ||
}) | ||
dataset.borderColor = gradient; | ||
dataset.backgroundColor = gradient; | ||
} | ||
|
||
useEffect( () => { | ||
if (ref.current === null ) return; | ||
const chart = ref.current; | ||
addPaletteChart(palette)(chart) | ||
chart.update() | ||
}, [ref, data, palette]) | ||
|
||
// attach events to the graph options | ||
const graphOptions: ChartOptions<'line'> = useMemo( () => ({ | ||
...options(type), | ||
onClick: (event: ChartEvent, elts: ActiveElement[], chart: Chart<keyof ChartTypeRegistry, number[], unknown>) => { | ||
if ( elts.length === 0 ) return; | ||
const elt = elts[0] // doesnt work if multiple datasets | ||
const pointIndex = elt.index | ||
console.log(pointIndex, event, elts); | ||
} | ||
}), [] ) | ||
|
||
const plugins: Plugin<"line">[] = [ { | ||
id: 'id', | ||
} ] | ||
|
||
return ( | ||
<div className="road-conditions-graph"> | ||
{ data && <Line | ||
ref={ref} | ||
data={data} | ||
options={graphOptions} | ||
plugins={plugins} /> | ||
} | ||
</div> | ||
) | ||
} | ||
|
||
export default ConditionsGraph; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
|
||
import { FC, useCallback, useEffect, useMemo, useState } from 'react'; | ||
import { TRGB } from 'react-gradient-hook/lib/types'; | ||
import { HotlineOptions } from 'react-leaflet-hotline'; | ||
import { HotlineEventHandlers } from 'react-leaflet-hotline/lib/types'; | ||
import { useGraph } from '../../context/GraphContext'; | ||
import { WaysConditions } from '../../models/path'; | ||
import { getWaysConditions } from '../../queries/conditions'; | ||
import useZoom from '../Map/Hooks/useZoom'; | ||
import DistHotline from '../Map/Renderers/DistHotline'; | ||
|
||
interface IWays { | ||
palette: TRGB[] | ||
type: string; | ||
onClick?: (way_id: string, way_length: number) => void; | ||
} | ||
|
||
const Ways: FC<IWays> = ( { palette, type, onClick } ) => { | ||
|
||
const zoom = useZoom(); | ||
const { minY, maxY } = useGraph() | ||
|
||
const [ways, setWays] = useState<WaysConditions>() | ||
|
||
const options = useMemo<HotlineOptions>( () => ({ | ||
palette, min: minY, max: maxY | ||
} ), [palette, minY, maxY] ) | ||
|
||
const handlers = useMemo<HotlineEventHandlers>( () => ({ | ||
click: (_, i) => { | ||
if ( ways && onClick ) | ||
onClick(ways.way_ids[i], ways.way_lengths[i]) | ||
}, | ||
}), [ways] ) | ||
|
||
useEffect( () => { | ||
if ( zoom === undefined ) return; | ||
const z = Math.max(0, zoom - 12) | ||
getWaysConditions(type, z, (data: WaysConditions) => { | ||
console.log(data) | ||
setWays( data ) | ||
} ) | ||
}, [zoom] ) | ||
|
||
return ( | ||
<> | ||
{ ways | ||
? <DistHotline | ||
way_ids={ways.way_ids} | ||
geometry={ways.geometry} | ||
conditions={ways.conditions} | ||
options={options} | ||
eventHandlers={handlers}/> | ||
: null | ||
} | ||
</> | ||
) | ||
} | ||
|
||
export default Ways; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
|
||
import { Selection } from "d3" | ||
import { FC } from "react" | ||
import { Color } from "react-leaflet-hotline"; | ||
import { Bounds } from "../../models/path"; | ||
|
||
// SVG | ||
export type SVG = d3.Selection<SVGGElement, unknown, null, undefined> | ||
export type SVGLayer = d3.Selection<d3.BaseType, unknown, null, undefined> | ||
|
||
// Axis | ||
export interface IAxis { | ||
svg: SVG; | ||
axis: Axis | undefined, | ||
width: number; | ||
height: number; | ||
zoom: number; | ||
absolute?: boolean; | ||
time?: boolean; | ||
} | ||
export type ReactAxis = FC<IAxis>; | ||
export type Axis = d3.ScaleLinear<number, number, never> | ||
export type GraphAxis = [Axis, Axis] | ||
|
||
// Data format | ||
export type GraphPoint = { | ||
x: number, | ||
y: number, | ||
lat: number, | ||
lng: number } // [number, number] | ||
|
||
export type GraphData = GraphPoint[] | ||
|
||
export interface Plot { | ||
data: GraphData | ||
bounds?: Bounds; | ||
label: string; | ||
} | ||
|
||
// Events | ||
export interface DotHover { | ||
label: string; | ||
point: GraphPoint | ||
} | ||
|
||
// Options | ||
export interface PathOptions { | ||
stroke?: string; | ||
strokeWidth?: number; | ||
} | ||
|
||
export interface DotsOptions { | ||
radius?: number; | ||
opacity?: number; | ||
fill?: string; | ||
} | ||
|
||
// Palette - Gradient | ||
export type Gradient = Selection<SVGStopElement, Color, SVGLinearGradientElement, unknown> | ||
|
||
// MinMax | ||
export type MinMax = [number, number] | ||
export type AddMinMaxFunc = (label: string, bounds: Required<Bounds>) => void | ||
export type RemMinMaxFunc = (label: string) => void | ||
|
||
// Callback | ||
export type D3Callback = (event: any, d: GraphPoint) => void |
Oops, something went wrong.