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

Add TOI zoom behavior #908

Merged
merged 5 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions app/scripts/components/exploration/atoms/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export const zoomTransformAtom = atom<ZoomTransformPlain>({
k: 1
});

//. TOI test
export const zoomBehaviorAtom = atom<any>(undefined);


// Width of the whole timeline item. Set via a size observer and then used to
// compute the different element sizes.
export const timelineWidthAtom = atom<number | undefined>(undefined);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect } from 'react';
import { useAtomValue } from 'jotai';
import { useAtomValue, useAtom } from 'jotai';
import styled, { css } from 'styled-components';
import { MapRef } from 'react-map-gl';
import { glsp, themeVal } from '@devseed-ui/theme-provider';
Expand All @@ -11,7 +11,15 @@ import {
} from '@devseed-ui/collecticons';
import { timelineDatasetsAtom } from '../../atoms/datasets';
import { selectedIntervalAtom } from '../../atoms/dates';
// import { applyTransform, isEqualTransform, rescaleX } from './timeline-utils';
import { rescaleX } from '$components/exploration/components/timeline/timeline-utils';
import useMaps from '$components/common/map/hooks/use-maps';
import {
timelineSizesAtom,
timelineWidthAtom,
zoomTransformAtom
} from '$components/exploration/atoms/timeline';
import { useScales } from '../../hooks/scales-hooks';

import useAois from '$components/common/map/controls/hooks/use-aois';
import { calcFeatCollArea } from '$components/common/aoi/utils';
Expand All @@ -21,6 +29,7 @@ import useThemedControl from '$components/common/map/controls/hooks/use-themed-c
import { getZoomFromBbox } from '$components/common/map/utils';
import { AoIFeature } from '$components/common/map/types';
import { ShortcutCode } from '$styles/shortcut-code';
import { RIGHT_AXIS_SPACE } from '$components/exploration/constants'

const AnalysisMessageWrapper = styled.div.attrs({
'data-tour': 'analysis-message'
Expand Down Expand Up @@ -84,14 +93,19 @@ const MessageControls = styled.div`
gap: ${glsp(0.5)};
`;

export function AnalysisMessage({ mainMap }: { mainMap: MapRef | undefined }) {
export function AnalysisMessage({ mainMap, zoomTOI }: { mainMap: MapRef | undefined }) {
const { isObsolete, setObsolete, isAnalyzing } = useAnalysisController();

const datasets = useAtomValue(timelineDatasetsAtom);
const datasetIds = datasets.map((d) => d.data.id);

const timelineWidth = useAtomValue(timelineWidthAtom);
const { main, scaled} = useScales();
const [zoomTransform, setZoomTransform] = useAtom(zoomTransformAtom);

const { features } = useAois();
const selectedInterval = useAtomValue(selectedIntervalAtom);

const dateLabel =
selectedInterval &&
formatDateRange(selectedInterval.start, selectedInterval.end);
Expand All @@ -102,7 +116,10 @@ export function AnalysisMessage({ mainMap }: { mainMap: MapRef | undefined }) {
setObsolete();
}, [setObsolete, features]);



const analysisCallback = useCallback(() => {
// Fit AOI
const bboxToFit = bbox({
type: 'FeatureCollection',
features: selectedFeatures
Expand All @@ -112,7 +129,18 @@ export function AnalysisMessage({ mainMap }: { mainMap: MapRef | undefined }) {
center:[ (bboxToFit[2] + bboxToFit[0])/2, (bboxToFit[3] + bboxToFit[1])/2],
zoom
});
}, [selectedFeatures, mainMap]);

// Fit TOI
if (!main || !timelineWidth || !zoomTOI ) return
const widthToFit = (timelineWidth - RIGHT_AXIS_SPACE) * 0.8
const startPoint = (timelineWidth - RIGHT_AXIS_SPACE) * 0.05
const new_k = widthToFit/(main(selectedInterval.end) - main(selectedInterval.start));
const new_x = startPoint - new_k * main(selectedInterval.start);


zoomTOI(new_x, new_k);

}, [selectedFeatures, mainMap, main, timelineWidth, zoomTOI, selectedInterval]);

if (isAnalyzing) {
return (
Expand All @@ -138,9 +166,10 @@ export function AnalysisMessage({ mainMap }: { mainMap: MapRef | undefined }) {
}
}

export function AnalysisMessageControl() {
export function AnalysisMessageControl(props) {
const { main } = useMaps();
useThemedControl(() => <AnalysisMessage mainMap={main} />, { position: 'top-left' });
const { zoomTOI } = props;
useThemedControl(() => <AnalysisMessage mainMap={main} zoomTOI={zoomTOI} />, { position: 'top-left' });

return null;
}
Expand Down
5 changes: 3 additions & 2 deletions app/scripts/components/exploration/components/map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import DrawControl from '$components/common/map/controls/aoi';
import CustomAoIControl from '$components/common/map/controls/aoi/custom-aoi-control';
import { usePreviousValue } from '$utils/use-effect-previous';

export function ExplorationMap() {
export function ExplorationMap(props) {
const { zoomTOI } = props;
const [projection, setProjection] = useState(projectionDefault);

const {
Expand Down Expand Up @@ -144,7 +145,7 @@ export function ExplorationMap() {
comparing && 'Analysis is not possible when comparing dates'
}
/>
<AnalysisMessageControl />
<AnalysisMessageControl zoomTOI={zoomTOI} />
<GeocoderControl />
<MapOptionsControl
projection={projection}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ import { timelineDatasetsAtom } from '$components/exploration/atoms/datasets';
import {
timelineSizesAtom,
timelineWidthAtom,
zoomTransformAtom
zoomTransformAtom,
zoomBehaviorAtom
} from '$components/exploration/atoms/timeline';
import { useTimelineDatasetsDomain } from '$components/exploration/atoms/hooks';
import { RIGHT_AXIS_SPACE } from '$components/exploration/constants';
Expand Down Expand Up @@ -168,7 +169,7 @@ const getIntervalFromDate = (selectedDay: Date, dataDomain: [Date, Date]) => {
};

export default function Timeline(props: TimelineProps) {
const { onDatasetAddClick } = props;
const { onDatasetAddClick, setZoomTOIFunc } = props;

// Refs for non react based interactions.
// The interaction rect is used to capture the different d3 events for the
Expand Down Expand Up @@ -200,7 +201,7 @@ export default function Timeline(props: TimelineProps) {
const [selectedInterval, setSelectedInterval] = useAtom(selectedIntervalAtom);

const { setObsolete, runAnalysis, isAnalyzing } = useAnalysisController();

const [zoomTransform, setZoomTransform] = useAtom(zoomTransformAtom);
const { features } = useAois();

useEffect(() => {
Expand All @@ -216,13 +217,15 @@ export default function Timeline(props: TimelineProps) {
[width]
);

const [zoomTransform, setZoomTransform] = useAtom(zoomTransformAtom);

// Calculate min and max scale factors, such has each day has a minimum of 2px
// and a maximum of 100px.
const { k0, k1 } = useScaleFactors();
const { scaled: xScaled, main: xMain } = useScales();

// const zoomBehavior = useZoomBehavior({k0, k1, translateExtent, datasetsContainerRef})
// console.log(zoomBehavior)
// console.log(typeof zoomBehavior)
// setZoomBehaviorAtom(zoomBehavior(datasetsContainerRef));
hanbyul-here marked this conversation as resolved.
Show resolved Hide resolved
// Create the zoom behavior needed for the timeline interactions.
const zoomBehavior = useMemo(() => {
return zoom()
Expand Down Expand Up @@ -371,7 +374,24 @@ export default function Timeline(props: TimelineProps) {
applyTransform(zoomBehavior, select(interactionRef.current), 0, 0, k0);
}, [prevSuccessDatasetsCount, successDatasetsCount, k0, zoomBehavior]);

const onControlsZoom = useCallback(
const onTOIZoom = useCallback(()=> (newX, newK) => {
if (!newX || ! newK) return;
applyTransform(
zoomBehavior,
select(interactionRef.current),
newX,
0,
newK
);
},[interactionRef.current, zoomBehavior])

// Pass onTOIZoom up to the parent component when it's defined or changed
useEffect(() => {
if (!onTOIZoom) return
setZoomTOIFunc(onTOIZoom);
}, [onTOIZoom, setZoomTOIFunc]);

const onControlsZoom = useCallback(
(zoomV) => {
if (!interactionRef.current || !xMain || !xScaled || !selectedDay) return;

Expand Down
6 changes: 4 additions & 2 deletions app/scripts/components/exploration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ function Exploration() {

const setUrl = useSetAtom(urlAtom);
const { reset: resetAnalysisController } = useAnalysisController();

const [zoomTOIFunc, setZoomTOIFunc] = useState(() => {});
// Reset atoms when leaving the page.
useEffect(() => {
return () => {
Expand All @@ -105,11 +107,11 @@ function Exploration() {
<Container>
<PanelGroup direction='vertical' className='panel-wrapper'>
<Panel maxSize={75} className='panel'>
<ExplorationMap />
<ExplorationMap zoomTOI={zoomTOIFunc} />
</Panel>
<PanelResizeHandle className='resize-handle' />
<Panel maxSize={75} className='panel panel-timeline'>
<Timeline onDatasetAddClick={openModal} />
<Timeline onDatasetAddClick={openModal} setZoomTOIFunc={setZoomTOIFunc}/>
</Panel>
</PanelGroup>
</Container>
Expand Down