Skip to content

Commit

Permalink
Merge branch 'correlation-updates'
Browse files Browse the repository at this point in the history
* correlation-updates:
  Some more updates to focus state controls
  Updated focus state management
  Allow easy overriding of unit selection
  Adjust spacing
  Removed on-click handler
  Allow map focus state to track map resize
  Add the ability to disable section neatline
  Added some types
  Export another variable
  Fix ease to handler
  More helpers for map components
  Added new, more flexible easeTo command
  Some bounds fitting
  • Loading branch information
davenquinn committed Jul 13, 2024
2 parents 5c40988 + 1d5cdfc commit 2767227
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 35 deletions.
21 changes: 13 additions & 8 deletions packages/column-components/src/lithology/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Component, useContext } from "react";
import h from "react-hyperscript";
import h from "@macrostrat/hyper";
import classNames from "classnames";
import T from "prop-types";
import {
Expand Down Expand Up @@ -321,15 +321,17 @@ interface LithologyColumnProps {
width: number;
left?: number;
children?: React.ReactNode;
clipToFrame?: boolean;
}

function LithologyColumn(props: LithologyColumnProps) {
const { left = 0, shiftY = 0.5, width, children } = props;
export function LithologyColumn(props: LithologyColumnProps) {
const { left = 0, shiftY = 0.5, width, children, clipToFrame = true } = props;

const transform = left != null ? `translate(${left} ${shiftY})` : null;

return h(ColumnLayoutProvider, { width }, [
h(
let inner: React.ReactNode;
if (clipToFrame) {
inner = h(
ClipToFrame,
{
className: "lithology-column",
Expand All @@ -338,8 +340,12 @@ function LithologyColumn(props: LithologyColumnProps) {
frame: SimpleFrame,
},
children
),
]);
);
} else {
inner = h("g.lithology-column", { transform }, children);
}

return h(ColumnLayoutProvider, { width }, inner);
}

const simplifiedResolveID = function (d) {
Expand Down Expand Up @@ -388,7 +394,6 @@ export * from "./patterns";
export * from "./column-patterns";
export {
ParameterIntervals,
LithologyColumn,
LithologyBoxes,
GeneralizedSectionColumn,
defaultResolveID,
Expand Down
1 change: 1 addition & 0 deletions packages/column-views/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import styles from "./column.module.scss";
import { CompositeUnitsColumn, TrackedLabeledUnit } from "./units";
import { IUnit } from "./units/types";
export * from "./units";
export * from "./age-axis";

import { ColumnAxisType } from "@macrostrat/column-components";

Expand Down
23 changes: 11 additions & 12 deletions packages/column-views/src/units/composite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,20 @@ function LabelTrackerProvider(props) {
);
}

type BaseUnitProps =
| {
width: number;
showLabels: false;
columnWidth?: number;
}
| {
width: number;
columnWidth: number;
showLabels: true;
};
type BaseUnitProps = {
width: number;
showLabels: boolean;
columnWidth?: number;
clipToFrame?: boolean;
};

type ICompositeUnitProps = BaseUnitProps & {
gutterWidth?: number;
labelOffset?: number;
nameForDivision?: (division: BaseUnit) => string;
children?: React.ReactNode;
unitComponent?: React.FC<any>;
unitComponentProps?: any;
};

function TrackedLabeledUnit({
Expand Down Expand Up @@ -107,6 +104,7 @@ function _BaseUnitsColumn(
width: number;
unitComponent?: React.FC<any>;
unitComponentProps?: any;
clipToFrame?: boolean;
}>
) {
/*
Expand All @@ -118,11 +116,12 @@ function _BaseUnitsColumn(
children,
unitComponent = TrackedLabeledUnit,
unitComponentProps,
clipToFrame,
...rest
} = props;

return h(LabelTrackerProvider, [
h(LithologyColumn, { width }, [
h(LithologyColumn, { width, clipToFrame }, [
h(UnitBoxes, {
unitComponent,
unitComponentProps,
Expand Down
37 changes: 33 additions & 4 deletions packages/column-views/src/units/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ const DispatchContext = createContext<UnitSelectDispatch | null>(null);

export function useUnitSelector(u: BaseUnit | null) {
const dispatch = useContext(DispatchContext);
return () => {
return (evt: Event) => {
dispatch?.(u);
evt.stopPropagation();
};
}

Expand All @@ -31,16 +32,44 @@ export function useSelectedUnit() {
return useContext(UnitSelectionContext);
}

export function UnitSelectionProvider<BaseUnit>(props: {
interface UnitSelectionProps<T extends BaseUnit> {
children: React.ReactNode;
unit: T | null;
setUnit: Dispatch<SetStateAction<T>>;
}

export function UnitSelectionProvider<T extends BaseUnit>(
props: Partial<UnitSelectionProps<T>>
) {
const { unit, setUnit, children } = props;

if (unit == null && setUnit == null) {
return h(StatefulUnitSelectionProvider, props);
}

return h(BaseUnitSelectionProvider, { unit, setUnit }, children);
}

function StatefulUnitSelectionProvider<T extends BaseUnit>(props: {
children: React.ReactNode;
}) {
const [unit, setUnit] = useState<BaseUnit | null>(null);
const { children } = props;
const [unit, setUnit] = useState<T | null>(null);

return h(BaseUnitSelectionProvider, { children, unit, setUnit });
}

function BaseUnitSelectionProvider<T extends BaseUnit>({
children,
unit,
setUnit,
}: UnitSelectionProps<T>) {
const value = useMemo(() => unit, [unit?.unit_id]);

return h(
DispatchContext.Provider,
{ value: setUnit },
h(UnitSelectionContext.Provider, { value }, props.children)
h(UnitSelectionContext.Provider, { value }, children)
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/map-interface/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
useMapRef,
useMapEaseToCenter,
useMapEaseTo,
useMapDispatch,
useMapStatus,
} from "@macrostrat/mapbox-react";
Expand Down Expand Up @@ -67,7 +67,7 @@ export function MapPaddingManager({
});

// Ideally, we would not have to do this when we know the infobox is loaded
useMapEaseToCenter(infoMarkerPosition, padding);
useMapEaseTo({ center: infoMarkerPosition, padding });

return null;
}
Expand Down
115 changes: 111 additions & 4 deletions packages/mapbox-react/src/focus-state.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
/* Reporters and buttons for evaluating a feature's focus on the map. */
import { Intent, Button } from "@blueprintjs/core";
import { useMapRef } from "./context";
import { useMapRef, useMapStatus } from "./context";
import classNames from "classnames";
import { useState, useRef, useEffect } from "react";
import bbox from "@turf/bbox";
import styles from "./main.module.scss";
import hyper from "@macrostrat/hyper";
import mapboxgl from "mapbox-gl";
import mapboxgl, {
LngLatBoundsLike,
LngLatLike,
PaddingOptions,
} from "mapbox-gl";
import centroid from "@turf/centroid";

const h = hyper.styled(styles);
Expand Down Expand Up @@ -48,6 +52,10 @@ export function intentForFocusState(pos: PositionFocusState): Intent {
}
}

/**
* Ease the map to a center position with optional padding.
* @deprecated Use useMapEaseTo instead
*/
export function useMapEaseToCenter(position, padding) {
const mapRef = useMapRef();

Expand All @@ -57,7 +65,7 @@ export function useMapEaseToCenter(position, padding) {
useEffect(() => {
const map = mapRef.current;
if (map == null) return;
let opts = null;
let opts: mapboxgl.FlyToOptions = null;
if (position != prevPosition.current) {
opts ??= {};
opts.center = position;
Expand All @@ -80,7 +88,106 @@ export function useMapEaseToCenter(position, padding) {
prevPosition.current = position;
prevPadding.current = padding;
});
}, [position, padding]);
}, [position, padding, mapRef.current]);
}

/**
* Ease the map to a set of bounds, with optional padding.
* @deprecated Use useMapEaseTo instead
*/
export function useMapEaseToBounds(
bounds: LngLatBoundsLike,
padding: PaddingOptions | number = 0
) {
const mapRef = useMapRef();

const prevPosition = useRef<any>(null);
const prevPadding = useRef<any>(null);
// Handle map position easing (for both map padding and markers)
useEffect(() => {
const map = mapRef.current;
if (map == null) return;
if (bounds == prevPosition.current || padding == prevPadding.current) {
return;
}
let opts: mapboxgl.FlyToOptions = {
padding,
duration: prevPadding.current == null ? 0 : 800,
};

map.fitBounds(bounds, opts);
map.once("moveend", () => {
/* Waiting until moveend to update the refs allows us to
batch overlapping movements together, which increases UI
smoothness when, e.g., flying to new panels */
prevPosition.current = bounds;
prevPadding.current = padding;
});
}, [bounds, padding, mapRef.current]);
}

type MapEaseToProps = {
bounds?: LngLatBoundsLike;
padding?: PaddingOptions | number;
center?: LngLatLike;
zoom?: number;
duration?: number;
trackResize?: boolean;
};

export function useMapEaseTo(props: MapEaseToProps) {
const mapRef = useMapRef();
const {
bounds,
padding,
center,
zoom,
duration = 800,
trackResize = false,
} = props;
const initialized = useRef<boolean>(false);
const [resizeCounter, setResizeCounter] = useState(0);

useEffect(() => {
const map = mapRef.current;
if (map == null) return;

let opts: mapboxgl.FlyToOptions = {
padding,
duration: initialized.current ? duration : 0,
};

if (bounds != null) {
map.fitBounds(bounds, opts);
} else if (center != null || zoom != null || padding != null) {
let props = { ...opts };
if (center != null) {
props.center = center;
}
if (zoom != null) {
props.zoom = zoom;
}
map.flyTo(props);
}

map.once("moveend", () => {
initialized.current = true;
});
}, [bounds, padding, center, zoom, mapRef.current, resizeCounter]);

useEffect(() => {
const map = mapRef.current;
if (map == null) return;
if (props.trackResize) {
const cb = () => {
setResizeCounter((x) => x + 1);
};
map.on("resize", cb);
return () => {
map.off("resize", cb);
};
}
}, [trackResize, mapRef.current]);
}

function greatCircleDistance(
Expand Down
19 changes: 18 additions & 1 deletion packages/mapbox-react/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { RefObject, useEffect } from "react";
import mapboxgl from "mapbox-gl";
import { toggleMapLabelVisibility } from "@macrostrat/mapbox-utils";
import { useMapRef, useMapStatus } from "./context";
import {useCallback} from "react";

/** A newer and more flexible version of useMapConditionalStyle */
export function useMapStyleOperator(
Expand All @@ -28,7 +29,7 @@ export function useMapStyleOperator(
* Apply conditional style logic depending on a state value or object.
* The operator function can operate on the Map and the state, and is applied on state changes
* and on style load events.
* @deprecated Use useMapStyleCallback instead
* @deprecated Use useMapStyleOperator instead
*/
export function useMapConditionalStyle<T = any>(
mapRef: RefObject<mapboxgl.Map>,
Expand Down Expand Up @@ -63,3 +64,19 @@ export function useMapLabelVisibility(
_toggleMapLabels
);
}

export function useMapClickHandler(
fn: (e: mapboxgl.MapMouseEvent) => void,
deps: any[]
) {
const clickFn = useCallback(fn, deps);
useMapStyleOperator(
(map) => {
map.on("click", clickFn);
return () => {
map.off("click", clickFn);
};
},
[clickFn]
);
}
1 change: 1 addition & 0 deletions packages/mapbox-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./position";
export * from "./preprocess-styles";
export * from "./utils";
export * from "./view-info";
export * from "./style-helpers";
16 changes: 16 additions & 0 deletions packages/mapbox-utils/src/style-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FeatureCollection } from "geojson";
import {GeoJSONSource} from "mapbox-gl";

export function setGeoJSON(
map: mapboxgl.Map,
sourceID: string,
data: FeatureCollection
) {
let source = map.getSource(sourceID) as GeoJSONSource | null;
if (source == null) {
map.addSource(sourceID, { type: "geojson", data });
} else {
source.setData(data);
}
}

Loading

0 comments on commit 2767227

Please sign in to comment.