Skip to content

Commit

Permalink
refactor(web): add layer from resource (#1212)
Browse files Browse the repository at this point in the history
Co-authored-by: airslice <[email protected]>
  • Loading branch information
mkumbobeaty and airslice authored Nov 8, 2024
1 parent cf1bd0e commit 3016a71
Show file tree
Hide file tree
Showing 13 changed files with 493 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ const CSV: FC<DataProps> = ({ sceneId, onSubmit, onClose }) => {
</InputGroup>
)}
<Warning>
<Icon icon="lightBulb" color={theme.warning.main} size="large" />
<IconWrapper
icon="lightBulb"
color={theme.warning.main}
size="normal"
/>
<TextWrapper>
{t(
"Visualizer currently only supports CSV point data. Please specify the column names for latitude and longitude in your data below."
Expand Down Expand Up @@ -157,6 +161,11 @@ const TextWrapper = styled("div")(({ theme }) => ({
fontWeight: theme.fonts.weight.regular
}));

const IconWrapper = styled(Icon)(() => ({
flexGrow: 0,
flexShrink: 0
}));

const CoordinateWrapper = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.small,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useT } from "@reearth/services/i18n";
import { useState, useMemo, useCallback } from "react";

import { DataProps, DataSourceOptType, SourceType } from "..";
import { generateTitle } from "../util";

export default ({ sceneId, onClose, onSubmit }: DataProps) => {
const t = useT();

const [sourceType, setSourceType] = useState<SourceType>("local");

const [value, setValue] = useState("");
const [layerName, setLayerName] = useState("");
const dataSourceTypeOptions: DataSourceOptType = useMemo(
() => [
{ label: t("From Assets"), value: "local" },
{ label: t("From Web"), value: "url" },
{ label: t("From Value"), value: "value" }
],
[t]
);

const handleSubmit = () => {
let encodeUrl = undefined;

if (sourceType === "value" && value !== "") {
encodeUrl = "data:text/plain;charset=UTF-8," + encodeURIComponent(value);
}

onSubmit({
layerType: "simple",
sceneId,
title: generateTitle(value, layerName),
visible: true,
config: {
data: {
url: sourceType === "value" ? encodeUrl : value || undefined,
type: "czml",
}
}
});
onClose();
};

const handleValueChange = useCallback((value?: string, name?: string) => {
setValue(value || "");
setLayerName(name || "");
}, []);

const handleDataSourceTypeChange = useCallback((newValue: string) => {
setSourceType(newValue as SourceType);
setValue("");
}, []);

return {
value,
dataSourceTypeOptions,
sourceType,
handleValueChange,
handleDataSourceTypeChange,
handleSubmit
};
};
124 changes: 124 additions & 0 deletions web/src/beta/features/Editor/Map/DataSourceLayerCreator/CZML/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import {
InputGroup,
SubmitWrapper,
Wrapper,
InputsWrapper,
ContentWrapper
} from "@reearth/beta/features/Editor/Map/shared/SharedComponent";
import {
RadioGroup,
Button,
TextInput,
TextArea,
Icon
} from "@reearth/beta/lib/reearth-ui";
import { AssetField } from "@reearth/beta/ui/fields";
import { useT } from "@reearth/services/i18n";
import { styled, useTheme } from "@reearth/services/theme";
import { FC } from "react";

import { DataProps } from "..";

import useHooks from "./hooks";

const CZML: FC<DataProps> = ({ sceneId, onSubmit, onClose }) => {
const t = useT();

const {
value,
sourceType,
dataSourceTypeOptions,
handleValueChange,
handleDataSourceTypeChange,
handleSubmit
} = useHooks({ sceneId, onSubmit, onClose });

const theme = useTheme();
return (
<Wrapper>
<ContentWrapper>
<Warning>
<IconWrapper
icon="lightBulb"
color={theme.warning.main}
size="normal"
/>
<TextWrapper>
{t(
"Support for the CZML format is currently experimental and remains somewhat unstable, with certain features not yet fully supported. We advise using it with caution."
)}
</TextWrapper>
</Warning>
<InputGroup label={t("Source Type")}>
<RadioGroup
value={sourceType}
options={dataSourceTypeOptions}
onChange={handleDataSourceTypeChange}
/>
</InputGroup>

{sourceType === "local" && (
<InputsWrapper>
<AssetField
inputMethod="asset"
title={t("Asset")}
value={value}
assetsTypes={["czml"]}
onChange={handleValueChange}
/>
</InputsWrapper>
)}
{sourceType === "url" && (
<InputGroup label={t("Resource URL")}>
<InputsWrapper>
<TextInput
placeholder={t("Input Text")}
value={value}
onChange={handleValueChange}
/>
</InputsWrapper>
</InputGroup>
)}
{sourceType === "value" && (
<InputGroup label={t("Value")}>
<InputsWrapper>
<TextArea
placeholder={t("Input data here")}
rows={8}
value={value}
onChange={handleValueChange}
/>
</InputsWrapper>
</InputGroup>
)}
</ContentWrapper>
<SubmitWrapper>
<Button
title={t("Add to Layer")}
appearance="primary"
onClick={handleSubmit}
disabled={!value}
/>
</SubmitWrapper>
</Wrapper>
);
};

const Warning = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.small,
alignItems: "center"
}));

const IconWrapper = styled(Icon)(() => ({
flexGrow: 0,
flexShrink: 0
}));

const TextWrapper = styled("div")(({ theme }) => ({
color: theme.warning.main,
fontSize: theme.fonts.sizes.body,
fontWeight: theme.fonts.weight.regular
}));

export default CZML;
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { GisType } from "@reearth/beta/features/AssetsManager/constants";
import { DataType } from "@reearth/core";
import { useT } from "@reearth/services/i18n";
import { useState, useMemo, useCallback } from "react";

Expand All @@ -10,7 +8,6 @@ export default ({ sceneId, onClose, onSubmit }: DataProps) => {
const t = useT();

const [sourceType, setSourceType] = useState<SourceType>("local");
const [fileFormat, setFileFormat] = useState<GisType>("geojson");

const [value, setValue] = useState("");
const [layerName, setLayerName] = useState("");
Expand All @@ -24,42 +21,26 @@ export default ({ sceneId, onClose, onSubmit }: DataProps) => {
[t]
);

const fileFormatOptions = [
{
value: "geojson",
label: "GeoJSON"
},
{
value: "kml",
label: "KML"
},
{
value: "czml",
label: "CZML"
}
];

const isValidExtension = useCallback(() => {
if (sourceType === "url" || sourceType === "local") {
const extension = value.split(".").pop()?.toLowerCase();
return extension === fileFormat.toLowerCase();
}
return true;
}, [value, fileFormat, sourceType]);
const isValidGeoJSON = (json: any): boolean => {

Check warning on line 24 in web/src/beta/features/Editor/Map/DataSourceLayerCreator/GeoJSON/hooks.tsx

View workflow job for this annotation

GitHub Actions / ci-web / ci

Unexpected any. Specify a different type
return (
json &&
typeof json === "object" &&
(json.type === "FeatureCollection" || json.type === "Feature")
);
};

const handleSubmit = () => {
const handleSubmit = useCallback(() => {
let parsedValue = null;

if (sourceType === "value" && value !== "") {
if (fileFormat === "geojson") {
try {
parsedValue = JSON.parse(value);
} catch (_error) {
parsedValue = value;
try {
parsedValue = JSON.parse(value);
if (!isValidGeoJSON(parsedValue)) {
throw new Error(t("Invalid GeoJSON format"));
}
} else {
parsedValue =
"data:text/plain;charset=UTF-8," + encodeURIComponent(value);
} catch (error) {
console.error("GeoJSON parsing error:", error);
throw new Error(t("Please enter valid GeoJSON"));
}
}

Expand All @@ -73,10 +54,8 @@ export default ({ sceneId, onClose, onSubmit }: DataProps) => {
url:
(sourceType === "url" || sourceType === "local") && value !== ""
? value
: fileFormat === "czml" || fileFormat === "kml"
? parsedValue
: undefined,
type: fileFormat.toLowerCase() as DataType,
: undefined,
type: "geojson",
value: parsedValue,
geojson: {
useAsResource: prioritizePerformance
Expand All @@ -85,36 +64,34 @@ export default ({ sceneId, onClose, onSubmit }: DataProps) => {
}
});
onClose();
};
}, [
layerName,
onClose,
onSubmit,
prioritizePerformance,
sceneId,
sourceType,
t,
value
]);

const handleValueChange = useCallback((value?: string, name?: string) => {
setValue(value || "");
setLayerName(name || "");
}, []);

const handleFileFormatChange = useCallback((value: string | string[]) => {
setFileFormat(value as GisType);
}, []);

const handleDataSourceTypeChange = useCallback((newValue: string) => {
setSourceType(newValue as SourceType);
setValue("");
}, []);

const assetsTypes = useMemo(() => [fileFormat], [fileFormat]);

return {
value,
dataSourceTypeOptions,
fileFormatOptions,
fileFormat,
assetsTypes,
sourceType,
prioritizePerformance,
setPrioritizePerformance,
isValidExtension,
handleValueChange,
handleFileFormatChange,
handleDataSourceTypeChange,
handleSubmit
};
Expand Down
Loading

0 comments on commit 3016a71

Please sign in to comment.