feat: remove box
This commit is contained in:
parent
9b8b3ff401
commit
10c2716aeb
|
|
@ -1,12 +1,15 @@
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
|
import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
|
||||||
|
|
||||||
type ButtonProps = DetailedHTMLProps<
|
interface ButtonProps
|
||||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
extends DetailedHTMLProps<
|
||||||
HTMLButtonElement
|
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
>;
|
HTMLButtonElement
|
||||||
|
> {
|
||||||
|
isShow?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function BottomButton(props: ButtonProps) {
|
export function NextButton(props: ButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
css={css({
|
css={css({
|
||||||
|
|
@ -25,6 +28,43 @@ export function BottomButton(props: ButtonProps) {
|
||||||
outline: "rgba(240, 240, 244, 0.51) solid 0.1rem",
|
outline: "rgba(240, 240, 244, 0.51) solid 0.1rem",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
transition: "0.2s",
|
transition: "0.2s",
|
||||||
|
display: props.isShow ? "" : "none",
|
||||||
|
":hover": {
|
||||||
|
backgroundColor: "#ebeef0c2",
|
||||||
|
},
|
||||||
|
":disabled": {
|
||||||
|
backgroundColor: "#ebeef0c2",
|
||||||
|
cursor: "not-allowed",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PrevButton(props: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
css={css({
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: 9999,
|
||||||
|
left: "2rem",
|
||||||
|
bottom: "2rem",
|
||||||
|
color: "#000000",
|
||||||
|
backgroundColor: "#ffffff96",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
border: "none",
|
||||||
|
padding: "0.75rem 1.25rem",
|
||||||
|
borderRadius: "8px",
|
||||||
|
fontWeight: "300",
|
||||||
|
fontSize: "14px",
|
||||||
|
outline: "rgba(240, 240, 244, 0.51) solid 0.1rem",
|
||||||
|
cursor: "pointer",
|
||||||
|
transition: "0.2s",
|
||||||
|
display: props.isShow ? "" : "none",
|
||||||
|
|
||||||
":hover": {
|
":hover": {
|
||||||
backgroundColor: "#ebeef0c2",
|
backgroundColor: "#ebeef0c2",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,81 @@
|
||||||
export function ProcessingMap() {
|
import { css } from "@emotion/react";
|
||||||
return <p>processing</p>;
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
interface Building {
|
||||||
|
id: number;
|
||||||
|
tags: { [key: string]: string | undefined };
|
||||||
|
geometry?: { lat: number; lng: number }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BuildingHeights({ area }: { area: any }) {
|
||||||
|
const [buildings, setBuildings] = useState<Building[]>([]);
|
||||||
|
|
||||||
|
const requestBuildings = () => {
|
||||||
|
console.log(area);
|
||||||
|
const south = area[1].lat;
|
||||||
|
const west = area[1].lng;
|
||||||
|
const north = area[0].lat;
|
||||||
|
const east = area[0].lng;
|
||||||
|
console.log(south, west, north, east);
|
||||||
|
const query = `[out:json][timeout:25];(way["building"]( ${south},${west},${north},${east} );relation["building"]( ${south},${west},${north},${east} ););out body geom;`;
|
||||||
|
fetch("https://overpass-api.de/api/interpreter", {
|
||||||
|
method: "POST",
|
||||||
|
body: query,
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
const blds: Building[] = data.elements.map((element) => ({
|
||||||
|
id: element.id,
|
||||||
|
tags: element.tags,
|
||||||
|
geometry: element.geometry
|
||||||
|
? element.geometry.map((pt) => ({ lat: pt.lat, lng: pt.lon }))
|
||||||
|
: undefined,
|
||||||
|
}));
|
||||||
|
setBuildings(blds);
|
||||||
|
console.log("Building Data:", blds);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error fetching building data:", error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
css={css({
|
||||||
|
position: "relative",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<button onClick={requestBuildings}>request</button>
|
||||||
|
<ul
|
||||||
|
css={css({
|
||||||
|
overflow: "scroll",
|
||||||
|
zIndex: 999,
|
||||||
|
position: "absolute",
|
||||||
|
top: "1rem",
|
||||||
|
height: "80vh",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{buildings.map((b) => (
|
||||||
|
<li key={b.id}>
|
||||||
|
<div>Building {b.id}</div>
|
||||||
|
<div>Height: {b.tags.height || "No height info"}</div>
|
||||||
|
<div>Location/Shape:</div>
|
||||||
|
{b.geometry ? (
|
||||||
|
<ul>
|
||||||
|
{b.geometry.map((pt, index) => (
|
||||||
|
<li key={index}>
|
||||||
|
({pt.lat.toFixed(5)}, {pt.lng.toFixed(5)})
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<div>No geometry info</div>
|
||||||
|
)}
|
||||||
|
<div>Other Tags: {JSON.stringify(b.tags)}</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,13 @@ import { css } from "@emotion/react";
|
||||||
|
|
||||||
function RectangleSelector({
|
function RectangleSelector({
|
||||||
isDrag = true,
|
isDrag = true,
|
||||||
|
bounds,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: {
|
||||||
isDrag: boolean;
|
isDrag: boolean;
|
||||||
|
bounds: LatLngBounds | null;
|
||||||
onChange: (LatLngBounds: LatLngBounds) => void;
|
onChange: (LatLngBounds: LatLngBounds) => void;
|
||||||
}) {
|
}) {
|
||||||
const [bounds, setBounds] = useState<LatLngBounds | null>(null);
|
|
||||||
const [firstPoint, setFirstPoint] = useState<LatLng | null>(null);
|
const [firstPoint, setFirstPoint] = useState<LatLng | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -35,12 +36,11 @@ function RectangleSelector({
|
||||||
},
|
},
|
||||||
mousemove(e) {
|
mousemove(e) {
|
||||||
if (firstPoint) {
|
if (firstPoint) {
|
||||||
setBounds(new L.LatLngBounds(firstPoint, e.latlng));
|
onChange(new L.LatLngBounds(firstPoint, e.latlng));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mouseup(e) {
|
mouseup(e) {
|
||||||
if (firstPoint) {
|
if (firstPoint) {
|
||||||
setBounds(new L.LatLngBounds(firstPoint, e.latlng));
|
|
||||||
onChange(new L.LatLngBounds(firstPoint, e.latlng));
|
onChange(new L.LatLngBounds(firstPoint, e.latlng));
|
||||||
setFirstPoint(null);
|
setFirstPoint(null);
|
||||||
}
|
}
|
||||||
|
|
@ -51,14 +51,28 @@ function RectangleSelector({
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MapComponent({ onDone }: { onDone: (e) => void }) {
|
export function MapComponent({
|
||||||
|
onDone,
|
||||||
|
onRemove,
|
||||||
|
}: {
|
||||||
|
onDone: (e) => void;
|
||||||
|
onRemove: () => void;
|
||||||
|
}) {
|
||||||
const [isDrag, setIsDrag] = useState(true);
|
const [isDrag, setIsDrag] = useState(true);
|
||||||
|
const [bounds, setBounds] = useState<LatLngBounds | null>(null);
|
||||||
|
|
||||||
const handleClickSwitchDrag = () => {
|
const handleClickSwitchDrag = () => {
|
||||||
setIsDrag(!isDrag);
|
setIsDrag(!isDrag);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClickRemoveBox = () => {
|
||||||
|
onRemove();
|
||||||
|
setBounds(null);
|
||||||
|
setIsDrag(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleChangeDone = (e) => {
|
const handleChangeDone = (e) => {
|
||||||
|
setBounds(e);
|
||||||
onDone([e._northEast, e._southWest]);
|
onDone([e._northEast, e._southWest]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -68,40 +82,80 @@ export function MapComponent({ onDone }: { onDone: (e) => void }) {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<button
|
<div
|
||||||
css={css({
|
css={css({
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
right: "1rem",
|
right: "1rem",
|
||||||
top: "1rem",
|
top: "1rem",
|
||||||
color: "#000000",
|
display: "flex",
|
||||||
backgroundColor: "#ffffff96",
|
justifyContent: "flex-end",
|
||||||
backdropFilter: "blur(8px)",
|
gap: "0.5rem",
|
||||||
border: "none",
|
|
||||||
padding: "0.5rem 1rem",
|
|
||||||
borderRadius: "8px",
|
|
||||||
outline: "rgba(240, 240, 244, 0.51) solid 0.1rem",
|
|
||||||
cursor: "pointer",
|
|
||||||
transition: "0.2s",
|
|
||||||
":hover": {
|
|
||||||
backgroundColor: "#ebeef0c2",
|
|
||||||
},
|
|
||||||
})}
|
})}
|
||||||
onClick={handleClickSwitchDrag}
|
|
||||||
>
|
>
|
||||||
{isDrag ? "Disable" : "Enable"} Drag
|
<button
|
||||||
</button>
|
css={css({
|
||||||
|
display: isDrag ? "none" : "",
|
||||||
|
color: "#ffffff",
|
||||||
|
|
||||||
|
backgroundColor: "#ef4444",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
border: "none",
|
||||||
|
padding: "0.5rem 1rem",
|
||||||
|
borderRadius: "8px",
|
||||||
|
outline: "#ef4444c2 solid 0.1rem",
|
||||||
|
cursor: "pointer",
|
||||||
|
transition: "0.2s",
|
||||||
|
":hover": {
|
||||||
|
backgroundColor: "#ef4444",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
onClick={handleClickRemoveBox}
|
||||||
|
>
|
||||||
|
Remove Box
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
css={css({
|
||||||
|
color: isDrag ? "#ffffff" : "#000000",
|
||||||
|
|
||||||
|
backgroundColor: isDrag ? "#007bffe8" : "#ffffff96",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
border: "none",
|
||||||
|
padding: "0.5rem 1rem",
|
||||||
|
borderRadius: "8px",
|
||||||
|
outline: isDrag
|
||||||
|
? "#086ad4c2 solid 0.1rem"
|
||||||
|
: "rgba(240, 240, 244, 0.51) solid 0.1rem",
|
||||||
|
cursor: "pointer",
|
||||||
|
transition: "0.2s",
|
||||||
|
":hover": {
|
||||||
|
backgroundColor: isDrag ? "#085fbd" : "#ebeef0c2",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
onClick={handleClickSwitchDrag}
|
||||||
|
>
|
||||||
|
{isDrag ? "Select Box" : "Back to Drag"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<MapContainer
|
<MapContainer
|
||||||
center={[36.48656, 127.29064]}
|
center={[36.48656, 127.29064]}
|
||||||
zoom={13}
|
zoom={13}
|
||||||
style={{ height: "70vh", width: "100%" }}
|
style={{
|
||||||
|
height: "70vh",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<TileLayer
|
<TileLayer
|
||||||
attribution='© <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
|
attribution='© <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
/>
|
/>
|
||||||
<RectangleSelector isDrag={isDrag} onChange={handleChangeDone} />
|
<RectangleSelector
|
||||||
|
bounds={bounds}
|
||||||
|
isDrag={isDrag}
|
||||||
|
onChange={handleChangeDone}
|
||||||
|
/>
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@ body,
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,36 @@ import { Description } from "@/components/text/Description";
|
||||||
import { Column } from "@/components/flex/Column";
|
import { Column } from "@/components/flex/Column";
|
||||||
import { MapComponent } from "@/components/map/SelectMap";
|
import { MapComponent } from "@/components/map/SelectMap";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { BottomButton } from "@/components/button/BottomButton";
|
import { NextButton, PrevButton } from "@/components/button/BottomButton";
|
||||||
|
import { BuildingHeights } from "@/components/map/Processing";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [isNextButtonDisabled, setIsNextButtonDisabled] = useState(true);
|
const [isNextButtonDisabled, setIsNextButtonDisabled] = useState(true);
|
||||||
const handleDone = (e) => {
|
const [areaData, setAreaData] = useState([]);
|
||||||
console.log(e);
|
const [steps, setSteps] = useState(["front", "processing"]);
|
||||||
|
const [step, setStep] = useState(0);
|
||||||
|
|
||||||
|
const handleDone = (data) => {
|
||||||
|
setAreaData(data);
|
||||||
setIsNextButtonDisabled(false);
|
setIsNextButtonDisabled(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickNextStep = () => {};
|
const handleRemove = () => {
|
||||||
|
setAreaData([]);
|
||||||
|
setIsNextButtonDisabled(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickNextStep = () => {
|
||||||
|
setStep(step + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickPrevStep = () => {
|
||||||
|
setStep(step - 1);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={css({ height: "100%", width: "100%" })}>
|
<div css={css({ height: "100%", width: "100%" })}>
|
||||||
<FullscreenModal isOpen={true}>
|
<FullscreenModal isOpen={steps[step] == "front"}>
|
||||||
<Column gap="1rem">
|
<Column gap="1rem">
|
||||||
<Column gap="0.5rem">
|
<Column gap="0.5rem">
|
||||||
<Title>Generate 3d map</Title>
|
<Title>Generate 3d map</Title>
|
||||||
|
|
@ -27,16 +43,37 @@ function App() {
|
||||||
Tools to create 3D maps based on maps and export them in 3D format
|
Tools to create 3D maps based on maps and export them in 3D format
|
||||||
</Description>
|
</Description>
|
||||||
</Column>
|
</Column>
|
||||||
<MapComponent onDone={handleDone}></MapComponent>
|
<MapComponent
|
||||||
|
onRemove={handleRemove}
|
||||||
|
onDone={handleDone}
|
||||||
|
></MapComponent>
|
||||||
</Column>
|
</Column>
|
||||||
</FullscreenModal>
|
</FullscreenModal>
|
||||||
|
|
||||||
<BottomButton
|
<FullscreenModal isOpen={steps[step] == "processing"}>
|
||||||
|
<Column gap="1rem">
|
||||||
|
<Column gap="0.5rem">
|
||||||
|
<Title>Processing</Title>
|
||||||
|
<Description>
|
||||||
|
Tools to create 3D maps based on maps and export them in 3D format
|
||||||
|
</Description>
|
||||||
|
|
||||||
|
<BuildingHeights area={areaData} />
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
|
</FullscreenModal>
|
||||||
|
|
||||||
|
<PrevButton isShow={step != 0} onClick={handleClickPrevStep}>
|
||||||
|
Prev Step
|
||||||
|
</PrevButton>
|
||||||
|
|
||||||
|
<NextButton
|
||||||
|
isShow={true}
|
||||||
disabled={isNextButtonDisabled}
|
disabled={isNextButtonDisabled}
|
||||||
onClick={handleClickNextStep}
|
onClick={handleClickNextStep}
|
||||||
>
|
>
|
||||||
Next Step
|
Next Step
|
||||||
</BottomButton>
|
</NextButton>
|
||||||
|
|
||||||
<Space />
|
<Space />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue