Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
feat: port the Box layer into the reearth/core (#377)
Browse files Browse the repository at this point in the history
* feat: copy the box layer to reearth/core

* feat: copy the clipping feature logic to reearth/core

* fix: clipping type in reearth/core

* fix: import modules under reearth/core

* fixup! fix: clipping type in reearth/core

* feat: add event types

* Revert "feat: add event types"

This reverts commit f8407f4.

* feat: add onLayerEdit property to context

* fix: box event handling

* fix: timing of destroying event handler

* fix: use type import

* Update src/core/engines/Cesium/Feature/Tileset/index.tsx

Co-authored-by: rot1024 <aayhrot@gmail.com>

* refactor: move logic to hooks in tileset component

* chore: remove unnecessary console.log

* fix: pass onLayerEdit prop to context

Co-authored-by: rot1024 <aayhrot@gmail.com>
  • Loading branch information
keiya01 and rot1024 committed Dec 20, 2022
1 parent 7e18b82 commit f235f15
Show file tree
Hide file tree
Showing 20 changed files with 1,637 additions and 40 deletions.
104 changes: 104 additions & 0 deletions src/core/Map/types/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import EventTarget from "@ungap/event-target";

export type EventCallback<T extends any[] = any[]> = (...args: T) => void;
export type EventEmitter<E extends { [P in string]: any[] } = { [P in string]: any[] }> = <
T extends keyof E,
>(
type: T,
...args: E[T]
) => void;

export type Events<E extends { [P in string]: any[] } = { [P in string]: any[] }> = {
readonly on: <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => void;
readonly off: <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => void;
readonly once: <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => void;
};

export default function events<E extends { [P in string]: any[] } = { [P in string]: any[] }>(): [
Events<E>,
EventEmitter<E>,
] {
const e = new EventTarget();
const callbacks = new Map<keyof E, Map<EventCallback<E[keyof E]>, (e: Event) => void>>();
const getEventCallback = <T extends keyof E>(
type: T,
cb: EventCallback<E[T]>,
): ((e: Event) => void) => {
let ecbs = callbacks.get(type);
if (!ecbs) {
ecbs = new Map();
callbacks.set(type, ecbs);
}

let ecb = ecbs.get(cb as EventCallback);
if (!ecb) {
ecb = (e: Event): void => {
cb(...(e as CustomEvent).detail);
};
ecbs.set(cb as EventCallback, ecb);
}

return ecb;
};
const deleteEventCallback = (type: keyof E, cb: EventCallback): void => {
callbacks.get(type)?.delete(cb);
};

const on = <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => {
const ecb = getEventCallback(type, callback);
e.addEventListener(String(type), ecb);
};
const off = <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => {
const ecb = getEventCallback(type, callback);
e.removeEventListener(String(type), ecb);
deleteEventCallback(type, ecb);
};
const once = <T extends keyof E>(type: T, callback: EventCallback<E[T]>) => {
const ecb = getEventCallback(type, callback);
e.addEventListener(String(type), ecb, { once: true });
};

const events = {
get on() {
return on;
},
get off() {
return off;
},
get once() {
return once;
},
};

return [
events,
<T extends keyof E>(type: T, ...args: E[T]) =>
e.dispatchEvent(new CustomEvent(String(type), { detail: args })),
];
}

export function mergeEvents<E extends { [x: string]: any[] } = { [x: string]: any[] }>(
source: Events<E>,
dest: EventEmitter<E>,
types: (keyof E)[],
): () => void {
const cbs = types.reduce<{ [T in keyof E]: EventCallback<E[T]> }>(
(a, b) => ({
...a,
[b]: (...args: E[typeof b]) => {
dest(b, ...args);
},
}),
{} as any,
);

for (const t of Object.keys(cbs)) {
source.on(t, cbs[t]);
}

return () => {
for (const t of Object.keys(cbs)) {
source.off(t, cbs[t]);
}
};
}
8 changes: 8 additions & 0 deletions src/core/Map/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type {
Rect,
LatLngHeight,
} from "../../mantle";
export * from "./event";

export type EngineRef = {
[index in keyof MouseEventHandles]: MouseEventHandles[index];
Expand Down Expand Up @@ -82,6 +83,13 @@ export type EngineProps = {
onTick?: (clock: Date) => void;
onLayerDrag?: (layerId: string, position: LatLng) => void;
onLayerDrop?: (layerId: string, propertyKey: string, position: LatLng | undefined) => void;
onLayerEdit?: (e: LayerEditEvent) => void;
};

export type LayerEditEvent = {
layerId: string | undefined;
scale?: { width: number; length: number; height: number; location: LatLngHeight };
rotate?: { heading: number; pitch: number; roll: number };
};

export type SelectLayerOptions = {
Expand Down
73 changes: 73 additions & 0 deletions src/core/engines/Cesium/Feature/Box/Edge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ArcType, Cartesian3, Color, TranslationRotationScale } from "cesium";
import { FC, memo } from "react";
import { Entity, PolylineGraphics } from "resium";

import type { EventCallback } from "@reearth/core/Map";

import { useHooks } from "./hooks/edge";

export type EdgeEventCallback = EventCallback<
[
event: any,
edgeEvent: {
layerId: string;
index: number;
},
]
>;

export type EdgeProperties = { start: Cartesian3; end: Cartesian3; isDraggable?: boolean };

type Props = {
id: string;
index: number;
edge: EdgeProperties;
trs: TranslationRotationScale;
isHovered: boolean;
fillColor?: Color;
hoverColor?: Color;
width?: number;
onMouseDown?: EdgeEventCallback;
onMouseMove?: EdgeEventCallback;
onMouseUp?: EdgeEventCallback;
onMouseEnter?: EdgeEventCallback;
onMouseLeave?: EdgeEventCallback;
};

export const Edge: FC<Props> = memo(function EdgePresenter({
id,
index,
edge,
isHovered,
fillColor,
trs,
width,
hoverColor,
onMouseDown,
onMouseMove,
onMouseUp,
}) {
const { cbp, outlineColor } = useHooks({
id,
index,
edge,
isHovered,
fillColor,
trs,
hoverColor,
onMouseDown,
onMouseMove,
onMouseUp,
});

return (
<Entity id={id}>
<PolylineGraphics
positions={cbp}
width={width}
material={outlineColor}
arcType={ArcType.NONE}
/>
</Entity>
);
});
126 changes: 126 additions & 0 deletions src/core/engines/Cesium/Feature/Box/ScalePoints.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { ArcType, Cartesian3, Color, TranslationRotationScale } from "cesium";
import { FC, memo } from "react";
import { BoxGraphics, Entity, PolylineGraphics } from "resium";

import type { EventCallback } from "@reearth/core/Map";

import { useHooks } from "./hooks/scalePoint";

export type ScalePointProperties = {
point: Cartesian3;
oppositePoint: Cartesian3;
};

export type PointEventCallback = EventCallback<
[
event: any,
pointEvent: {
index: number;
layerId: string;
opposite: boolean;
position?: Cartesian3;
oppositePosition?: Cartesian3;
pointLocal?: Cartesian3;
},
]
>;

type Props = {
id: string;
index: number;
scalePoint: ScalePointProperties;
trs: TranslationRotationScale;
isHovered: boolean;
pointFillColor?: Color;
pointOutlineColor?: Color;
hoverPointOutlineColor?: Color;
pointOutlineWidth?: number;
axisLineColor?: Color;
axisLineWidth?: number;
dimensions?: { width: number; height: number; length: number };
visiblePoint?: boolean;
visibleAxisLine?: boolean;
onPointMouseDown?: PointEventCallback;
onPointMouseMove?: PointEventCallback;
onPointMouseUp?: PointEventCallback;
};

export const ScalePoints: FC<Props> = memo(function ScalePointsPresenter({
id,
index,
scalePoint,
isHovered,
pointFillColor,
pointOutlineColor,
hoverPointOutlineColor,
pointOutlineWidth,
axisLineColor,
axisLineWidth,
trs,
dimensions,
visiblePoint,
visibleAxisLine,
onPointMouseDown,
onPointMouseMove,
onPointMouseUp,
}) {
const {
entitiesPosition,
pointOutlineColorCb,
cesiumDimensionsCallbackProperty,
orientation,
axisColorProperty,
} = useHooks({
id,
index,
scalePoint,
isHovered,
pointOutlineColor,
hoverPointOutlineColor,
axisLineColor,
trs,
dimensions,
onPointMouseDown,
onPointMouseMove,
onPointMouseUp,
});

return (
<>
<Entity id={`${id}-${index}`} position={entitiesPosition.point} orientation={orientation}>
<BoxGraphics
show={visiblePoint}
dimensions={cesiumDimensionsCallbackProperty}
material={pointFillColor}
fill={!!pointFillColor}
outline={!!pointOutlineColor}
outlineColor={pointOutlineColorCb}
outlineWidth={pointOutlineWidth}
/>
</Entity>
<Entity
id={`${id}-opposite-${index}`}
position={entitiesPosition.oppositePoint}
orientation={orientation}>
<BoxGraphics
show={visiblePoint}
dimensions={cesiumDimensionsCallbackProperty}
material={pointFillColor}
fill={!!pointFillColor}
outline={!!pointOutlineColor}
outlineColor={pointOutlineColorCb}
outlineWidth={pointOutlineWidth}
/>
</Entity>
<Entity id={`${id}-axis-line-${index}`}>
<PolylineGraphics
positions={entitiesPosition.axisLine}
show={visibleAxisLine}
material={axisColorProperty}
width={axisLineWidth}
arcType={ArcType.NONE}
/>
</Entity>
</>
);
});
47 changes: 47 additions & 0 deletions src/core/engines/Cesium/Feature/Box/Side.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Color, Plane as CesiumPlane, TranslationRotationScale } from "cesium";
import { FC, memo } from "react";
import { Entity, PlaneGraphics } from "resium";

import { useHooks } from "./hooks/side";

export const Side: FC<{
id: string;
planeLocal: CesiumPlane;
isActive: boolean;
trs: TranslationRotationScale;
fillColor?: Color;
outlineColor?: Color;
activeOutlineColor?: Color;
fill?: boolean;
}> = memo(function SidePresenter({
id,
planeLocal,
isActive,
fill,
fillColor,
outlineColor,
activeOutlineColor,
trs,
}) {
const { cbRef, plane, dimension, orientation, outlineColorCb } = useHooks({
planeLocal,
isActive,
outlineColor,
activeOutlineColor,
trs,
});

return (
<Entity id={id} position={cbRef} orientation={orientation}>
<PlaneGraphics
plane={plane}
dimensions={dimension}
fill={fill}
material={fillColor}
outlineWidth={1}
outlineColor={outlineColorCb}
outline
/>
</Entity>
);
});
Loading

0 comments on commit f235f15

Please sign in to comment.