Skip to content

Commit

Permalink
Merge pull request #61 from UW-Macrostrat/map-easing-demo
Browse files Browse the repository at this point in the history
Map easing demo
  • Loading branch information
davenquinn authored Nov 5, 2024
2 parents decb6a2 + 9babf07 commit e52d86a
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 26 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ jobs:

- name: Build the static website
run: |
yarn config set -H enableImmutableInstalls false
yarn install
yarn run build:storybook
yarn run build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
Expand Down
5 changes: 4 additions & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
// vite
stories: ["../packages/**/*.stories.@(mdx|js|jsx|ts|tsx)"],
stories: [
"../packages/**/*.mdx",
"../packages/**/*.stories.@(mdx|js|jsx|ts|tsx)",
],
addons: [
getAbsolutePath("@storybook/addon-links"),
getAbsolutePath("@storybook/addon-essentials"),
Expand Down
2 changes: 0 additions & 2 deletions packages/column-components/stories/base-section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import {
GrainsizeLayoutProvider,
ColumnDivision,
ColumnSurface,
ColumnLayoutContext,
} from "@macrostrat/column-components";
import { useContext } from "react";
import { BaseUnit, ColumnSpec, UnitLong } from "@macrostrat/api-types";
import { IUnit } from "@macrostrat/column-views";
import {
Expand Down
7 changes: 6 additions & 1 deletion packages/map-interface/src/main.module.sass
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
position: absolute


.context-panel-holder>:global(.bp5-card)
padding: 10px
background-color: var(--panel-background-color)

.panel-card
padding: 10px
background-color: var(--panel-background-color)
Expand Down Expand Up @@ -522,7 +526,8 @@
.spacer
flex: 1

// Shift UI around to center elements if we're in the global view

// Shift UI around to center elements if we're in the global view
@media only screen and (min-width: 768px)
.map-container.detail-panel-leave .map-view-container
margin-right: -14em
Expand Down
17 changes: 11 additions & 6 deletions packages/map-interface/stories/dev-map-page.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import h from "@macrostrat/hyper";
import type { Meta } from "@storybook/react";
import type { StoryObj } from "@storybook/react";
import { buildMacrostratStyle } from "../../mapbox-styles/src";
import * as mapboxgl from "mapbox-gl";

import { DevMapPage } from "../src";

const mapboxToken = import.meta.env.VITE_MAPBOX_API_TOKEN;

function WrappedComponent(props) {
return h(DevMapPage, { ...props, mapboxToken });
}
mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_API_TOKEN;

// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta: Meta<typeof DevMapPage> = {
title: "Map interface/Development map page",
component: WrappedComponent,
component: DevMapPage,
parameters: {
layout: "fullscreen",
docs: {
Expand All @@ -23,6 +20,14 @@ const meta: Meta<typeof DevMapPage> = {
iframeHeight: 500,
},
},
argTypes: {
mapboxToken: {
table: {
disable: true,
},
control: false,
},
},
},
};

Expand Down
22 changes: 22 additions & 0 deletions packages/map-interface/stories/map-easing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Canvas, Meta } from '@storybook/blocks';

import * as MapEasingStories from './map-easing.stories';

<Meta of={MapEasingStories} />

# Map easing

One of the most difficult interactions to get right is moving the map to a
position on click.

This example shows how to use the `useMapEaseTo` hook, which is intended to batch and sequence
updates to produce smooth animations.

<Canvas of={MapEasingStories.UseMapEaseTo} />


The following example shows an extremely basic implementation of easing, for comparative testing.



<Canvas of={MapEasingStories.BasicMapEaseTo} />
216 changes: 216 additions & 0 deletions packages/map-interface/stories/map-easing.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import h from "@macrostrat/hyper";
import type { Meta } from "@storybook/react";
import type { StoryObj } from "@storybook/react";
import { Card } from "@blueprintjs/core";
import {
FloatingNavbar,
MapAreaContainer,
MapLoadingButton,
MapView,
} from "../src";

import mapboxgl from "mapbox-gl";
import { useEffect, useState } from "react";
import {
useMapRef,
useBasicStylePair,
MapEaseToState,
useMapEaseTo,
useMapStatus,
} from "@macrostrat/mapbox-react";

mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_API_TOKEN;

type Location = { name: string } & MapEaseToState;

const locations: Location[] = [
{
name: "New York",
center: [-74.006, 40.7128],
zoom: 10,
},
{
name: "San Francisco",
center: [-122.4194, 37.7749],
},
{
name: "United States",
center: [-98.5795, 39.8283],
zoom: 3,
},
{
name: "from minimum zoom",
zoom: 0.002,
},
];

function MapEaseContainer({
children,
locationName,
nextLocation,
description,
}) {
/* We apply a custom style to the panel container when we are interacting
with the search bar, so that we can block map interactions until search
bar focus is lost.
We also apply a custom style when the infodrawer is open so we can hide
the search bar on mobile platforms
*/
const style = useBasicStylePair();

return h(
MapAreaContainer,
{
navbar: h(FloatingNavbar, {
rightElement: h(MapLoadingButton, {
large: true,
style: {
marginRight: "-5px",
},
}),
title: "Map easing",
}),
contextPanel: h(Card, [
description,
h("p", ["Viewing ", h("strong", locationName)]),
h("button", { onClick: nextLocation }, ["Next location"]),
]),
},
[
h(
MapView,
{
style,
projection: { name: "globe" },
mapPosition: null,
},
children
),
]
);
}

function MapEaseWrapper({
children,
locationName,
nextLocation,
description,
mapPosition,
}: {
children: React.ReactNode;
locationName: string;
nextLocation: () => void;
description: React.ReactNode;
mapPosition?: MapEaseToState;
}) {
/* We apply a custom style to the panel container when we are interacting
with the search bar, so that we can block map interactions until search
bar focus is lost.
We also apply a custom style when the infodrawer is open so we can hide
the search bar on mobile platforms
*/
const style = useBasicStylePair();

return h(
MapAreaContainer,
{
navbar: h(FloatingNavbar, {
rightElement: h(MapLoadingButton, {
large: true,
style: {
marginRight: "-5px",
},
}),
title: "Map easing",
}),
contextPanel: h(Card, [
description,
h("p", ["Viewing ", h("strong", locationName)]),
h("button", { onClick: nextLocation }, ["Next location"]),
]),
},
[
h(
MapView,
{
style,
projection: { name: "globe" },
mapPosition,
},
children
),
]
);
}

function BasicMapEaseToInner(props: { position: MapEaseToState }) {
const ref = useMapRef();
const { isInitialized } = useMapStatus();
const { position } = props;
useEffect(() => {
if (ref.current == null || !isInitialized) return;
console.log("Easing to", position);
ref.current.easeTo(position);
}, [ref.current, position, isInitialized]);
return null;
}

function UseMapEaseToInner({ position }: { position: MapEaseToState }) {
useMapEaseTo(position);
return null;
}

export function UseMapEaseTo() {
const [location, nextLocation] = useLocation();
const { name, ...position } = location;
return h(
MapEaseWrapper,
{
locationName: name,
nextLocation,
description: h("p", [
"This story demonstrates the ",
h("code", "useMapEaseTo"),
" hook",
]),
},
h(UseMapEaseToInner, { position })
);
}

export function BasicMapEaseTo() {
const [location, nextLocation] = useLocation();
const { name, ...position } = location;
return h(
MapEaseWrapper,
{
locationName: name,
nextLocation,
description: "This story demonstrates basic map easing",
},
h(BasicMapEaseToInner, { position })
);
}

function useLocation() {
const [ix, setIx] = useState(0);
const nextLocation = () => setIx((ix + 1) % locations.length);
return [locations[ix], nextLocation];
}

// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
title: "Mapbox React/useMapEaseTo",
component: UseMapEaseTo,
parameters: {
layout: "fullscreen",
docs: {
story: {
inline: false,
iframeHeight: 500,
},
},
},
} as Meta<typeof UseMapEaseTo>;

type Story = StoryObj<typeof UseMapEaseTo>;
Loading

0 comments on commit e52d86a

Please sign in to comment.