Skip to content

Commit

Permalink
feat(web): interaction mode on beta (#507)
Browse files Browse the repository at this point in the history
Co-authored-by: KaWaite <34051327+KaWaite@users.noreply.github.com>
  • Loading branch information
keiya01 and KaWaite committed Jun 21, 2023
1 parent 4144730 commit d4bbd61
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 11 deletions.
15 changes: 14 additions & 1 deletion web/src/beta/lib/core/Crust/Plugins/api.ts
Expand Up @@ -19,7 +19,15 @@ import type { PluginInstances } from "./usePluginInstances";

export type CommonReearth = Omit<
Reearth,
"plugin" | "ui" | "modal" | "popup" | "block" | "layer" | "widget" | "clientStorage"
| "plugin"
| "ui"
| "modal"
| "popup"
| "block"
| "layer"
| "widget"
| "clientStorage"
| "interactionMode"
>;

export function exposed({
Expand Down Expand Up @@ -303,6 +311,7 @@ export function commonReearth({
tags,
camera,
clock,
interactionMode,
pluginInstances,
viewport,
selectedLayer,
Expand Down Expand Up @@ -344,6 +353,7 @@ export function commonReearth({
viewport: () => GlobalThis["reearth"]["viewport"];
camera: () => GlobalThis["reearth"]["camera"]["position"];
clock: () => GlobalThis["reearth"]["clock"];
interactionMode: () => GlobalThis["reearth"]["interactionMode"];
pluginInstances: () => PluginInstances;
selectedLayer: () => GlobalThis["reearth"]["layers"]["selected"];
selectedFeature: () => GlobalThis["reearth"]["layers"]["selectedFeature"];
Expand Down Expand Up @@ -417,6 +427,9 @@ export function commonReearth({
get clock() {
return clock?.();
},
get interactionMode() {
return interactionMode?.();
},
scene: {
get inEditor() {
return !!inEditor?.();
Expand Down
12 changes: 11 additions & 1 deletion web/src/beta/lib/core/Crust/Plugins/hooks.ts
Expand Up @@ -14,7 +14,7 @@ import {
} from "@reearth/beta/lib/core/Map";

import { commonReearth } from "./api";
import { ReearthEventType, Viewport, ViewportSize } from "./plugin_types";
import { InteractionMode, ReearthEventType, Viewport, ViewportSize } from "./plugin_types";
import { Context, Props } from "./types";
import useClientStorage from "./useClientStorage";
import usePluginInstances from "./usePluginInstances";
Expand All @@ -38,6 +38,8 @@ export default function ({
alignSystem,
floatingWidgets,
camera,
interactionMode,
overrideInteractionMode,
useExperimentalSandbox,
overrideSceneProperty,
onLayerEdit,
Expand Down Expand Up @@ -74,6 +76,12 @@ export default function ({
tick: engineRef?.tick,
};
}, [engineRef]);
const getInteractionMode = useGet(
useMemo<InteractionMode>(
() => ({ mode: interactionMode, override: overrideInteractionMode }),
[interactionMode, overrideInteractionMode],
),
);
const getPluginInstances = useGet(pluginInstances);
const getViewport = useGet(viewport as Viewport);
const getSelectedLayer = useGet(selectedLayer);
Expand Down Expand Up @@ -283,6 +291,7 @@ export default function ({
tags: getTags,
camera: getCamera,
clock: getClock,
interactionMode: getInteractionMode,
pluginInstances: getPluginInstances,
viewport: getViewport,
selectedLayer: getSelectedLayer,
Expand Down Expand Up @@ -332,6 +341,7 @@ export default function ({
getTags,
getCamera,
getClock,
getInteractionMode,
getPluginInstances,
getViewport,
getSelectedLayer,
Expand Down
7 changes: 7 additions & 0 deletions web/src/beta/lib/core/Crust/Plugins/plugin_types.ts
Expand Up @@ -23,6 +23,7 @@ import type {
} from "@reearth/beta/lib/core/Map";

import { Block } from "../Infobox";
import { InteractionModeType } from "../types";
import { Widget } from "../Widgets";

import { CommonReearth } from "./api";
Expand Down Expand Up @@ -52,6 +53,7 @@ export type Reearth = {
readonly engineName?: string;
readonly camera: Undefinable<Camera>;
readonly clock?: Clock;
readonly interactionMode?: InteractionMode;
readonly ui: UI;
readonly modal: Modal;
readonly popup: Popup;
Expand Down Expand Up @@ -169,6 +171,11 @@ export type Clock = {
readonly pause?: () => void;
};

export type InteractionMode = {
override?: (mode: InteractionModeType) => void;
mode: InteractionModeType;
};

export type PluginMessage = {
data: any;
sender: string;
Expand Down
4 changes: 3 additions & 1 deletion web/src/beta/lib/core/Crust/Plugins/types.ts
Expand Up @@ -13,7 +13,7 @@ import type {
} from "@reearth/beta/lib/core/Map";
import type { Viewport } from "@reearth/beta/lib/core/Visualizer";

import type { MapRef } from "../types";
import type { MapRef, InteractionModeType } from "../types";
import type { InternalWidget, WidgetAlignSystem } from "../Widgets";

import type { CommonReearth } from "./api";
Expand All @@ -37,6 +37,8 @@ export type Props = PropsWithChildren<{
useExperimentalSandbox?: boolean;
overrideSceneProperty: (id: string, property: any) => void;
camera?: Camera;
interactionMode: InteractionModeType;
overrideInteractionMode: (mode: InteractionModeType) => void;
onLayerEdit: (cb: (e: LayerEditEvent) => void) => void;
}>;

Expand Down
7 changes: 7 additions & 0 deletions web/src/beta/lib/core/Crust/featureFlags.ts
@@ -0,0 +1,7 @@
export const FEATURE_FLAGS = {
CAMERA_MOVE: 1 << 0,
CAMERA_ZOOM: 1 << 1,
SINGLE_SELECTION: 1 << 2,
MULTIPLE_SELECTION: 1 << 3,
SKETCH: 1 << 4,
};
10 changes: 8 additions & 2 deletions web/src/beta/lib/core/Crust/index.stories.tsx
Expand Up @@ -4,6 +4,7 @@ import { useRef } from "react";
import { engine } from "../engines/Cesium";
import Map, { Engine } from "../Map";

import { InteractionModeType, INTERACTION_MODES } from "./interactionMode";
import { MapRef } from "./types";

import Component, { Props } from ".";
Expand All @@ -13,11 +14,16 @@ export default {
parameters: { actions: { argTypesRegex: "^on.*" } },
} as Meta;

const Template: Story<Props & { engine: Engine }> = args => {
const Template: Story<Props & { engine: Engine; interactionMode: InteractionModeType }> = args => {
const ref = useRef<MapRef>(null);
return (
<>
<Map engine="a" engines={{ a: engine }} ref={ref} />
<Map
engine="a"
engines={{ a: engine }}
ref={ref}
featureFlags={INTERACTION_MODES[args.interactionMode]}
/>
<Component {...args} mapRef={ref} />
</>
);
Expand Down
17 changes: 15 additions & 2 deletions web/src/beta/lib/core/Crust/index.tsx
Expand Up @@ -11,7 +11,14 @@ import useHooks from "./hooks";
import Infobox, { Block, InfoboxProperty } from "./Infobox";
import Plugins, { type ExternalPluginProps, ModalContainer, PopupContainer } from "./Plugins";
import { usePublishTheme } from "./theme";
import type { ValueTypes, ValueType, MapRef, SceneProperty, Camera } from "./types";
import type {
ValueTypes,
ValueType,
MapRef,
SceneProperty,
Camera,
InteractionModeType,
} from "./types";
import Widgets, {
type WidgetAlignSystem as WidgetAlignSystemType,
type Alignment,
Expand All @@ -21,7 +28,7 @@ import Widgets, {
type WidgetAreaType,
} from "./Widgets";

export type { ValueTypes, ValueType } from "./types";
export type { ValueTypes, ValueType, InteractionModeType } from "./types";

export type { Block } from "./Infobox";

Expand Down Expand Up @@ -55,6 +62,8 @@ export type Props = {
overriddenClock: Clock;
viewport?: Viewport;
camera?: Camera;
interactionMode: InteractionModeType;
overrideInteractionMode: (mode: InteractionModeType) => void;
selectedComputedLayer?: ComputedLayer;
selectedComputedFeature?: ComputedFeature;
selectedFeature?: Feature;
Expand Down Expand Up @@ -122,6 +131,8 @@ export default function Crust({
overriddenClock,
viewport,
camera,
interactionMode,
overrideInteractionMode,
tags,
selectedLayerId,
selectedReason,
Expand Down Expand Up @@ -188,6 +199,8 @@ export default function Crust({
alignSystem={widgetAlignSystem}
floatingWidgets={floatingWidgets}
camera={camera}
interactionMode={interactionMode}
overrideInteractionMode={overrideInteractionMode}
useExperimentalSandbox={useExperimentalSandbox}
overrideSceneProperty={overrideSceneProperty}
onLayerEdit={onLayerEdit}>
Expand Down
12 changes: 12 additions & 0 deletions web/src/beta/lib/core/Crust/interactionMode.ts
@@ -0,0 +1,12 @@
import { FEATURE_FLAGS } from "./featureFlags";

export type InteractionModeType = "default" | "move" | "selection" | "sketch";

// If you would like enable a feature in a specific mode,
// just set the feature's flag here to that mode.
export const INTERACTION_MODES: Record<InteractionModeType, number> = {
default: FEATURE_FLAGS.CAMERA_MOVE | FEATURE_FLAGS.CAMERA_ZOOM | FEATURE_FLAGS.SINGLE_SELECTION,
move: FEATURE_FLAGS.CAMERA_MOVE | FEATURE_FLAGS.CAMERA_ZOOM,
selection: FEATURE_FLAGS.MULTIPLE_SELECTION | FEATURE_FLAGS.CAMERA_ZOOM,
sketch: FEATURE_FLAGS.SKETCH | FEATURE_FLAGS.CAMERA_ZOOM,
};
1 change: 1 addition & 0 deletions web/src/beta/lib/core/Crust/types.ts
Expand Up @@ -11,3 +11,4 @@ export type {
SceneProperty,
} from "../Map";
export type { Theme } from "./theme";
export type { InteractionModeType } from "./interactionMode";
1 change: 1 addition & 0 deletions web/src/beta/lib/core/Map/index.tsx
Expand Up @@ -6,6 +6,7 @@ import type { Engine, EngineProps } from "./types";

export * from "./types";
export { useGet, type WrappedRef, type Undefinable, useOverriddenProperty } from "./utils";
export { FEATURE_FLAGS } from "../Crust/featureFlags";

export type {
NaiveLayer,
Expand Down
1 change: 1 addition & 0 deletions web/src/beta/lib/core/Map/types/index.ts
Expand Up @@ -111,6 +111,7 @@ export type EngineProps = {
layerId?: string;
featureId?: string;
};
featureFlags: number;
layerSelectionReason?: LayerSelectionReason;
isLayerDraggable?: boolean;
isLayerDragging?: boolean;
Expand Down
20 changes: 19 additions & 1 deletion web/src/beta/lib/core/Visualizer/hooks.ts
Expand Up @@ -5,7 +5,8 @@ import { useWindowSize } from "react-use";
import { convertTime, truncMinutes } from "@reearth/beta/utils/time";
import { type DropOptions, useDrop } from "@reearth/beta/utils/use-dnd";

import type { Block, BuiltinWidgets } from "../Crust";
import type { Block, BuiltinWidgets, InteractionModeType } from "../Crust";
import { INTERACTION_MODES } from "../Crust/interactionMode";
import { getBuiltinWidgetOptions } from "../Crust/Widgets/Widget";
import type { ComputedFeature, Feature, LatLng, SelectedFeatureInfo } from "../mantle";
import type {
Expand All @@ -26,6 +27,7 @@ const viewportMobileMaxWidth = 768;
export default function useHooks({
selectedBlockId: initialSelectedBlockId,
camera: initialCamera,
interactionMode: initialInteractionMode,
sceneProperty,
isEditable,
rootLayerId,
Expand All @@ -34,11 +36,13 @@ export default function useHooks({
onLayerSelect,
onBlockSelect,
onCameraChange,
onInteractionModeChange,
onZoomToLayer,
onLayerDrop,
}: {
selectedBlockId?: string;
camera?: Camera;
interactionMode?: InteractionModeType;
isEditable?: boolean;
rootLayerId?: string;
sceneProperty?: SceneProperty;
Expand All @@ -52,6 +56,7 @@ export default function useHooks({
) => void;
onBlockSelect?: (blockId?: string) => void;
onCameraChange?: (camera: Camera) => void;
onInteractionModeChange?: (mode: InteractionModeType) => void;
onZoomToLayer?: (layerId: string | undefined) => void;
onLayerDrop?: (layerId: string, propertyKey: string, position: LatLng | undefined) => void;
}) {
Expand Down Expand Up @@ -195,6 +200,16 @@ export default function useHooks({
// camera
const [camera, changeCamera] = useValue(initialCamera, onCameraChange);

// interaction mode
const [_interactionMode, changeInteractionMode] = useValue(
initialInteractionMode,
onInteractionModeChange,
);
const interactionMode = _interactionMode || "default";

// feature flags
const featureFlags = INTERACTION_MODES[interactionMode];

// mobile
const { width } = useWindowSize();
const isMobile = width < viewportMobileMaxWidth;
Expand Down Expand Up @@ -254,6 +269,8 @@ export default function useHooks({
selectedBlock,
viewport,
camera,
interactionMode,
featureFlags,
isMobile,
overriddenSceneProperty,
overriddenClock,
Expand All @@ -264,6 +281,7 @@ export default function useHooks({
handleLayerSelect,
handleBlockSelect: selectBlock,
handleCameraChange: changeCamera,
handleInteractionModeChange: changeInteractionMode,
handleLayerDrag,
handleLayerDrop,
overrideSceneProperty,
Expand Down
10 changes: 10 additions & 0 deletions web/src/beta/lib/core/Visualizer/index.tsx
Expand Up @@ -12,6 +12,7 @@ import Crust, {
type InternalWidget,
WidgetAreaType,
BuiltinWidgets,
InteractionModeType,
} from "../Crust";
import { Tag } from "../mantle";
import Map, {
Expand Down Expand Up @@ -57,6 +58,7 @@ export type Props = {
layers?: Layer[];
clusters?: Cluster[];
camera?: Camera;
interactionMode?: InteractionModeType;
meta?: Record<string, unknown>;
style?: CSSProperties;
small?: boolean;
Expand Down Expand Up @@ -128,6 +130,7 @@ export default function Visualizer({
selectedWidgetArea,
hiddenLayers,
camera: initialCamera,
interactionMode: initialInteractionMode,
meta,
style,
pluginBaseUrl,
Expand Down Expand Up @@ -159,6 +162,8 @@ export default function Visualizer({
selectedComputedFeature,
viewport,
camera,
interactionMode,
featureFlags,
isMobile,
overriddenSceneProperty,
overriddenClock,
Expand All @@ -169,6 +174,7 @@ export default function Visualizer({
handleLayerSelect,
handleBlockSelect,
handleCameraChange,
handleInteractionModeChange,
handleLayerDrag,
handleLayerDrop,
overrideSceneProperty,
Expand All @@ -179,6 +185,7 @@ export default function Visualizer({
rootLayerId,
isEditable,
camera: initialCamera,
interactionMode: initialInteractionMode,
selectedBlockId,
sceneProperty,
zoomedLayerId,
Expand Down Expand Up @@ -211,6 +218,8 @@ export default function Visualizer({
overriddenClock={overriddenClock}
blocks={infobox?.blocks}
camera={camera}
interactionMode={interactionMode}
overrideInteractionMode={handleInteractionModeChange}
isMobile={isMobile}
selectedWidgetArea={selectedWidgetArea}
selectedComputedLayer={selectedLayer?.layer}
Expand Down Expand Up @@ -257,6 +266,7 @@ export default function Visualizer({
isLayerDraggable={isEditable}
meta={meta}
style={style}
featureFlags={featureFlags}
shouldRender={shouldRender}
// overrides={overrides} // not used for now
property={overriddenSceneProperty}
Expand Down

0 comments on commit d4bbd61

Please sign in to comment.