Skip to content

Commit

Permalink
chore(web): modify zoom level field (#808)
Browse files Browse the repository at this point in the history
Co-authored-by: nina992 <nouralali992@gmail.com>
Co-authored-by: KaWaite <34051327+KaWaite@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 28, 2023
1 parent ebf99c0 commit 1b79cfb
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 9 deletions.
51 changes: 51 additions & 0 deletions web/src/beta/components/RangeSlider/index.stories.tsx
@@ -0,0 +1,51 @@
import { useArgs } from "@storybook/preview-api";
import { Meta, StoryObj } from "@storybook/react";
import { useCallback } from "react";

import { styled } from "@reearth/services/theme";

import RangeSlider, { Props } from ".";

const meta: Meta<typeof RangeSlider> = {
component: RangeSlider,
};

type Story = StoryObj<typeof RangeSlider>;

export default meta;

export const Default: Story = (args: Props) => {
const [_, updateArgs] = useArgs();

const handleChange = useCallback((value: number[]) => updateArgs({ value: value }), [updateArgs]);

return (
<Wrapper>
<div>
<RangeSlider {...args} onChange={handleChange} />
</div>
<div>
<RangeSlider {...args} max={args.max ? 2 * args.max : undefined} onChange={handleChange} />
</div>
<div>
<RangeSlider {...args} disabled={true} onChange={handleChange} />
</div>
</Wrapper>
);
};

Default.args = {
value: [2, 50],
min: 0,
max: 100,
step: 1,
disabled: false,
};

const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 10%;
margin: 2rem;
height: 300px;
`;
86 changes: 86 additions & 0 deletions web/src/beta/components/RangeSlider/index.tsx
@@ -0,0 +1,86 @@
import RCSlider from "rc-slider";
import React, { ComponentProps } from "react";

import { styled } from "@reearth/services/theme";

import "rc-slider/assets/index.css";

const RangeSliderWithTooltip = RCSlider.createSliderWithTooltip(RCSlider.Range);

export type Props = {
min?: number;
max?: number;
} & ComponentProps<typeof RangeSliderWithTooltip>;

const calculateStep = (min?: number, max?: number, step?: number | null): number => {
if (step != undefined) {
return step;
} else if (min !== undefined && max !== undefined) {
const range = max - min;
let calculatedStep = range / 10;
if (range % calculatedStep !== 0) {
const steps = Math.ceil(range / calculatedStep);
calculatedStep = range / steps;
}
return calculatedStep;
} else {
return 1;
}
};

const RangeSlider: React.FC<Props> = ({ ...props }) => {
const calculatedStep = calculateStep(props?.min, props.max, props.step);

return (
<SliderStyled disabled={props.disabled as boolean}>
<RangeSliderWithTooltip step={calculatedStep} draggableTrack {...props} />
</SliderStyled>
);
};

const SliderStyled = styled.div<{ disabled: boolean }>`
width: 100%;
.rc-slider-disabled {
background-color: transparent;
opacity: ${({ disabled }) => (disabled ? 0.6 : 1)};
cursor: ${({ disabled }) => (disabled ? "not-allowed" : "inherit")};
}
.rc-slider-rail {
height: 8px;
}
.rc-slider-handle {
background-color: ${({ theme }) => theme.item.default};
border: ${({ theme }) => theme.primary.weak};
height: 12px;
width: 12px;
margin-top: -2px;
}
.rc-slider-track {
background-color: ${({ theme }) => theme.primary.weak};
height: 8px;
}
.rc-slider-rail {
background-color: ${({ theme }) => theme.outline.weaker};
box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.25) inset;
}
.rc-slider-tooltip-arrow {
background-color: transparent;
border-top-color: ${({ theme }) => theme.bg[2]};
bottom: 2px;
margin-left: -8px;
border-width: 9px 8px 0;
}
.rc-slider-tooltip-inner {
background-color: ${({ theme }) => theme.bg[2]};
color: ${({ theme }) => theme.content.main};
box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.25);
}
`;

export default RangeSlider;
12 changes: 12 additions & 0 deletions web/src/beta/components/fields/Property/PropertyField/index.tsx
Expand Up @@ -10,6 +10,7 @@ import ColorField from "../../ColorField";
import DateTimeField from "../../DateTimeField";
import LocationField from "../../LocationField";
import NumberField from "../../NumberField";
import RangeField from "../../RangeField";
import SelectField from "../../SelectField";
import SliderField from "../../SliderField";
import SpacingInput, { SpacingValues } from "../../SpacingInput";
Expand Down Expand Up @@ -154,6 +155,17 @@ const PropertyField: React.FC<Props> = ({
onSave={handleChange}
onFlyTo={onFlyTo}
/>
) : schema.type === "array" && schema.ui === "range" ? (
<RangeField
key={schema.id}
name={schema.name}
value={value as number[]}
defaultValue={schema.defaultValue as number[]}
min={schema.min}
max={schema.max}
description={schema.description}
onChange={handleChange}
/>
) : (
<p key={schema.id}>{schema.name} field</p>
)}
Expand Down
62 changes: 62 additions & 0 deletions web/src/beta/components/fields/RangeField/index.stories.tsx
@@ -0,0 +1,62 @@
import { useArgs } from "@storybook/preview-api";
import { Meta, StoryObj } from "@storybook/react";
import { useCallback } from "react";

import { styled } from "@reearth/services/theme";

import RangeField, { Props } from ".";

const meta: Meta<typeof RangeField> = {
component: RangeField,
};

export default meta;

type Story = StoryObj<typeof RangeField>;

export const Default: Story = (args: Props) => {
const [_, updateArgs] = useArgs();

const handleChange = useCallback(
(value: number[]) => {
updateArgs({ value: value });
},
[updateArgs],
);

return (
<Wrapper>
<div>
<RangeField {...args} onChange={handleChange} />
</div>
<div>
<RangeField
{...args}
name="Disabled"
description="Disabled field"
disabled={true}
onChange={handleChange}
/>
</div>
</Wrapper>
);
};

const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 10%;
margin: 2rem;
height: 300px;
`;

Default.args = {
name: "Slider Field",
description: "Slider field Sample description",
value: [0, 50],
min: 0,
max: 100,
step: 1,
disabled: false,
onChange: () => console.log("clicked"),
};
37 changes: 37 additions & 0 deletions web/src/beta/components/fields/RangeField/index.tsx
@@ -0,0 +1,37 @@
import { useCallback, useEffect, useState } from "react";

import Property from "@reearth/beta/components/fields";
import RangeSlider, { Props as RangeProps } from "@reearth/beta/components/RangeSlider";

export type Props = {
name?: string;
description?: string;
} & RangeProps;

const RangeField: React.FC<Props> = ({ name, description, value, onChange, ...args }: Props) => {
const [internalState, setInternalState] = useState<number[] | undefined>(value);

const handleChange = useCallback(
(value: number[]) => {
setInternalState(value);
},
[setInternalState],
);

useEffect(() => {
setInternalState(value);
}, [value]);

return (
<Property name={name} description={description}>
<RangeSlider
value={internalState}
onChange={handleChange}
onAfterChange={onChange}
{...args}
/>
</Property>
);
};

export default RangeField;
1 change: 0 additions & 1 deletion web/src/beta/features/Editor/Settings/index.tsx
Expand Up @@ -43,7 +43,6 @@ const Settings: React.FC<Props> = ({
selectedPage,
onPageUpdate,
});

const visibleItems = useMemo(() => filterVisibleItems(propertyItems), [propertyItems]);

return (
Expand Down
5 changes: 2 additions & 3 deletions web/src/beta/lib/core/Map/types/index.ts
Expand Up @@ -251,7 +251,7 @@ export type SceneProperty = {
id: string;
tile_type?: string;
tile_url?: string;
tile_zoomLevel?: number;
tile_zoomLevel?: number[];
tile_opacity?: number;
}[];
terrain?: {
Expand Down Expand Up @@ -320,8 +320,7 @@ type LegacySceneProperty = {
id: string;
tile_type?: string;
tile_url?: string;
tile_maxLevel?: number;
tile_minLevel?: number;
tile_zoomLevel?: number[];
tile_opacity?: number;
}[];
terrain?: TerrainProperty;
Expand Down
9 changes: 4 additions & 5 deletions web/src/beta/lib/core/engines/Cesium/core/Imagery.tsx
Expand Up @@ -18,8 +18,7 @@ export type Tile = {
tile_url?: string;
tile_type?: string;
tile_opacity?: number;
tile_minLevel?: number;
tile_maxLevel?: number;
tile_zoomLevel?: number[];
};

export type Props = {
Expand All @@ -45,13 +44,13 @@ export default function ImageryLayers({ tiles, cesiumIonAccessToken }: Props) {
<>
{tiles
?.map(({ id, ...tile }) => ({ ...tile, id, provider: providers[id]?.[2] }))
.map(({ id, tile_opacity: opacity, tile_minLevel: min, tile_maxLevel: max, provider }, i) =>
.map(({ id, tile_opacity: opacity, tile_zoomLevel, provider }, i) =>
provider ? (
<ImageryLayer
key={`${id}_${i}_${counter.current}`}
imageryProvider={provider}
minimumTerrainLevel={min}
maximumTerrainLevel={max}
minimumTerrainLevel={tile_zoomLevel?.[0]}
maximumTerrainLevel={tile_zoomLevel?.[1]}
alpha={opacity}
index={i}
/>
Expand Down

0 comments on commit 1b79cfb

Please sign in to comment.