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

Commit

Permalink
refactor: layer clustering feature (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
issmail-basel committed Jan 17, 2022
1 parent a6466a4 commit db6e6cc
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 150 deletions.
72 changes: 9 additions & 63 deletions src/components/molecules/Visualizer/Engine/Cesium/Cluster.tsx
@@ -1,45 +1,12 @@
import { Color, Cartesian3, EntityCluster, HorizontalOrigin, VerticalOrigin } from "cesium";
import { Color, EntityCluster, HorizontalOrigin, VerticalOrigin } from "cesium";
import React, { useEffect, useMemo } from "react";
import { CustomDataSource } from "resium";

import { toCSSFont, Typography } from "@reearth/util/value";
import { toCSSFont } from "@reearth/util/value";

import { LayerStore } from "../..";
import P from "../../Primitive";
import { ClusterProps } from "../ref";

export type Props = {
property: {
default: {
clusterPixelRange: number;
clusterMinSize: number;
clusterLabelTypography?: Typography;
clusterImage?: string;
clusterImageHeight?: number;
clusterImageWidth?: number;
};
layers: { layer?: string }[];
};
pluginProperty?: { [key: string]: any };
isEditable?: boolean;
isBuilt?: boolean;
pluginBaseUrl?: string;
layers?: LayerStore;
selectedLayerId?: string;
overriddenProperties?: { [id in string]: any };
isLayerHidden?: (id: string) => boolean;
};

const Cluster: React.FC<Props> = ({
property,
pluginProperty,
isEditable,
isBuilt,
pluginBaseUrl,
layers,
selectedLayerId,
overriddenProperties,
isLayerHidden,
}) => {
const Cluster: React.FC<ClusterProps> = ({ property, children }) => {
const {
clusterPixelRange = 15,
clusterMinSize = 3,
Expand Down Expand Up @@ -82,11 +49,14 @@ const Cluster: React.FC<Props> = ({
clusterParam.label.fillColor = Color.fromCssColorString(
clusterLabelTypography.color ?? "#FFF",
);
clusterParam.label.eyeOffset = new Cartesian3(0, 0, -5);
clusterParam.billboard.show = true;
clusterParam.billboard.image = clusterImage;
clusterParam.billboard.height = clusterImageWidth;
clusterParam.billboard.width = clusterImageHeight;

// force a re-cluster with the new styling
cluster.pixelRange = 0;
cluster.pixelRange = clusterPixelRange;
});
}, [
clusterMinSize,
Expand All @@ -100,31 +70,7 @@ const Cluster: React.FC<Props> = ({

return cluster ? (
<CustomDataSource show clustering={cluster}>
{layers?.flattenLayersRaw
?.filter(
layer =>
property?.layers &&
property?.layers.some(clusterLayer => clusterLayer.layer === layer.id),
)
.map(layer =>
!layer.isVisible || !!layer.children ? null : (
<P
key={layer.id}
layer={layer}
pluginProperty={
layer.pluginId && layer.extensionId
? pluginProperty?.[`${layer.pluginId}/${layer.extensionId}`]
: undefined
}
isHidden={isLayerHidden?.(layer.id)}
isEditable={isEditable}
isBuilt={isBuilt}
isSelected={!!selectedLayerId && selectedLayerId === layer.id}
pluginBaseUrl={pluginBaseUrl}
overriddenProperties={overriddenProperties}
/>
),
)}
{children}
</CustomDataSource>
) : null;
};
Expand Down
Expand Up @@ -80,7 +80,7 @@ export default function ({ isSelected, camera }: { isSelected?: boolean; camera?
flyTo?.({ fov }, { duration: 0 });
}
// skip camera flight when selected layer was changed by storytelling widget
startTransition(!isSelected, !isSelected);
startTransition(!isSelected, storytelling.current ? !isSelected : !cameraRef.current);
}, [flyTo, startTransition, isSelected]);

const transition = useTransition(
Expand Down
5 changes: 1 addition & 4 deletions src/components/molecules/Visualizer/Engine/Cesium/index.tsx
Expand Up @@ -113,10 +113,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
? property.cameraLimiter?.cameraLimitterTargetArea?.height ?? Number.POSITIVE_INFINITY
: Number.POSITIVE_INFINITY
}></ScreenSpaceCameraController>
<Camera
onChange={handleCameraMoveEnd}
percentageChanged={property?.cameraLimiter?.cameraLimitterEnabled ? 0.2 : 0.5}
/>
<Camera onChange={handleCameraMoveEnd} percentageChanged={0.2} />

{limiterDimensions && property?.cameraLimiter?.cameraLimitterShowHelper && (
<Entity>
Expand Down
Expand Up @@ -7,6 +7,7 @@ import { delayedObject, merge } from "@reearth/util/object";
import type { Ref as EngineRef } from "..";

import builtinPrimitives from "./builtin";
import Cluster from "./Cluster";
import { getLocationFromScreenXY, flyTo, lookAt, getCamera } from "./common";

const exposed = delayedObject(Cesium);
Expand Down Expand Up @@ -84,6 +85,7 @@ export default function useEngineRef(
viewer?.scene?.camera.zoomOut(amount);
},
builtinPrimitives,
clusterComponent: Cluster,
};
}, [cesium]);

Expand Down
63 changes: 2 additions & 61 deletions src/components/molecules/Visualizer/Engine/index.tsx
Expand Up @@ -14,69 +14,10 @@ import type { Camera, LatLng } from "@reearth/util/value";
import { SelectLayerOptions } from "../Plugin/types";

import Cesium from "./Cesium";
import type { EngineRef } from "./ref";
import type { EngineRef, SceneProperty } from "./ref";

export type { OverriddenInfobox, SelectLayerOptions } from "../Plugin/types";

export type SceneProperty = {
default?: {
camera?: Camera;
terrain?: boolean;
terrainType?: "cesium" | "arcgis"; // default: cesium
terrainExaggeration?: number; // default: 1
terrainExaggerationRelativeHeight?: number; // default: 0
depthTestAgainstTerrain?: boolean;
skybox?: boolean;
bgcolor?: string;
ion?: string;
};
cameraLimiter?: {
cameraLimitterEnabled?: boolean;
cameraLimitterShowHelper?: boolean;
cameraLimitterTargetArea?: Camera;
cameraLimitterTargetWidth: number;
cameraLimitterTargetLength: number;
};
tiles?: {
id: string;
tile_type?: string;
tile_url?: string;
tile_maxLevel?: number;
tile_minLevel?: number;
}[];
terrain?: {
terrain?: boolean;
terrainType?: "cesium" | "arcgis"; // default: cesium
terrainExaggeration?: number; // default: 1
terrainExaggerationRelativeHeight?: number; // default: 0
depthTestAgainstTerrain?: boolean;
};
atmosphere?: {
enable_sun?: boolean;
enable_lighting?: boolean;
ground_atmosphere?: boolean;
sky_atmosphere?: boolean;
shadows?: boolean;
fog?: boolean;
fog_density?: number;
brightness_shift?: number;
hue_shift?: number;
surturation_shift?: number;
};
timeline?: {
animation?: boolean;
};
googleAnalytics?: {
enableGA?: boolean;
trackingId?: string;
};
theme?: {
themeType?: "light" | "dark" | "forest" | "custom";
themeTextColor?: string;
themeSelectColor?: string;
themeBackgroundColor?: string;
};
};
export type { SceneProperty, ClusterProperty, ClusterProps } from "./ref";

export type EngineProps = {
className?: string;
Expand Down
83 changes: 82 additions & 1 deletion src/components/molecules/Visualizer/Engine/ref.ts
@@ -1,4 +1,6 @@
import { LatLngHeight, Camera } from "@reearth/util/value";
import { ComponentType, ReactNode } from "react";

import { LatLngHeight, Camera, Typography } from "@reearth/util/value";

import type { Component } from "../Primitive";

Expand All @@ -14,6 +16,7 @@ export type EngineRef = {
isMarshalable?: boolean | "json" | ((target: any) => boolean | "json");
builtinPrimitives?: Record<string, Component>;
pluginApi?: any;
clusterComponent?: ComponentType<ClusterProps>;
};

export type FlyToDestination = {
Expand Down Expand Up @@ -55,3 +58,81 @@ export type CameraOptions = {
duration?: number;
easing?: (time: number) => number;
};

export type ClusterProps = {
property: ClusterProperty;
children?: ReactNode;
};

export type SceneProperty = {
default?: {
camera?: Camera;
terrain?: boolean;
terrainType?: "cesium" | "arcgis"; // default: cesium
terrainExaggeration?: number; // default: 1
terrainExaggerationRelativeHeight?: number; // default: 0
depthTestAgainstTerrain?: boolean;
skybox?: boolean;
bgcolor?: string;
ion?: string;
};
cameraLimiter?: {
cameraLimitterEnabled?: boolean;
cameraLimitterShowHelper?: boolean;
cameraLimitterTargetArea?: Camera;
cameraLimitterTargetWidth?: number;
cameraLimitterTargetLength?: number;
};
tiles?: {
id: string;
tile_type?: string;
tile_url?: string;
tile_maxLevel?: number;
tile_minLevel?: number;
}[];
terrain?: {
terrain?: boolean;
terrainType?: "cesium" | "arcgis"; // default: cesium
terrainExaggeration?: number; // default: 1
terrainExaggerationRelativeHeight?: number; // default: 0
depthTestAgainstTerrain?: boolean;
};
atmosphere?: {
enable_sun?: boolean;
enable_lighting?: boolean;
ground_atmosphere?: boolean;
sky_atmosphere?: boolean;
shadows?: boolean;
fog?: boolean;
fog_density?: number;
brightness_shift?: number;
hue_shift?: number;
surturation_shift?: number;
};
timeline?: {
animation?: boolean;
};
googleAnalytics?: {
enableGA?: boolean;
trackingId?: string;
};
theme?: {
themeType?: "light" | "dark" | "forest" | "custom";
themeTextColor?: string;
themeSelectColor?: string;
themeBackgroundColor?: string;
};
};

export type ClusterProperty = {
id: string;
default: {
clusterPixelRange: number;
clusterMinSize: number;
clusterLabelTypography?: Typography;
clusterImage?: string;
clusterImageHeight?: number;
clusterImageWidth?: number;
};
layers: { layer?: string }[];
};
53 changes: 36 additions & 17 deletions src/components/molecules/Visualizer/Layers/index.tsx
@@ -1,6 +1,6 @@
import React from "react";
import React, { ComponentType } from "react";

import Cluster from "../Engine/Cesium/Cluster";
import { ClusterProperty, ClusterProps } from "../Engine";
import P from "../Primitive";

import { LayerStore } from "./store";
Expand All @@ -9,7 +9,7 @@ export type { Layer } from "../Primitive";

export type Props = {
pluginProperty?: { [key: string]: any };
clusterProperty?: { [key: string]: any };
clusterProperty?: ClusterProperty[];
clusterLayers?: string[];
sceneProperty?: any;
isEditable?: boolean;
Expand All @@ -18,6 +18,7 @@ export type Props = {
layers?: LayerStore;
selectedLayerId?: string;
overriddenProperties?: { [id in string]: any };
clusterComponent?: ComponentType<ClusterProps>;
isLayerHidden?: (id: string) => boolean;
};

Expand All @@ -35,23 +36,41 @@ export default function Layers({
selectedLayerId,
overriddenProperties,
isLayerHidden,
clusterComponent,
}: Props): JSX.Element | null {
const Cluster = clusterComponent;

return (
<>
{clusterProperty?.map((cluster: any) => (
// TODO: NEED REFACTORING: invalid dependency flow and duplicated codes
<Cluster
key={cluster.id}
property={cluster}
layers={layers}
pluginProperty={pluginProperty}
isEditable={isEditable}
isBuilt={isBuilt}
pluginBaseUrl={pluginBaseUrl}
selectedLayerId={selectedLayerId}
overriddenProperties={overriddenProperties}
isLayerHidden={isLayerHidden}></Cluster>
))}
{Cluster &&
clusterProperty?.map(cluster => (
// TODO: NEED REFACTORING: invalid dependency flow and duplicated codes
<Cluster key={cluster.id} property={cluster}>
{layers?.flattenLayersRaw
?.filter(layer =>
cluster?.layers?.some(clusterLayer => clusterLayer.layer === layer.id),
)
.map(layer =>
!layer.isVisible || !!layer.children ? null : (
<P
key={layer.id}
layer={layer}
pluginProperty={
layer.pluginId && layer.extensionId
? pluginProperty?.[`${layer.pluginId}/${layer.extensionId}`]
: undefined
}
isHidden={isLayerHidden?.(layer.id)}
isEditable={isEditable}
isBuilt={isBuilt}
isSelected={!!selectedLayerId && selectedLayerId === layer.id}
pluginBaseUrl={pluginBaseUrl}
overriddenProperties={overriddenProperties}
/>
),
)}
</Cluster>
))}

{layers?.flattenLayersRaw
?.filter(layer => !clusterLayers?.some(clusterLayer => clusterLayer === layer.id))
Expand Down

0 comments on commit db6e6cc

Please sign in to comment.