diff --git a/src/components/icons/WalkHereIcon.tsx b/src/components/icons/WalkHereIcon.tsx new file mode 100644 index 0000000..4ef933c --- /dev/null +++ b/src/components/icons/WalkHereIcon.tsx @@ -0,0 +1,28 @@ +const WalkHereIcon = () => { + return ( + + + + + + ); +}; + +export default WalkHereIcon; diff --git a/src/components/virtualTour/LabelMarker.tsx b/src/components/virtualTour/LabelMarker.tsx new file mode 100644 index 0000000..0d25830 --- /dev/null +++ b/src/components/virtualTour/LabelMarker.tsx @@ -0,0 +1,40 @@ +import { Html } from "@react-three/drei"; +import { IAppartmentSphere, ISphereLink } from "../../types/apartmentSphere"; +import WalkHereIcon from "../icons/WalkHereIcon"; +import useSphere from "../../store/useSphere"; + +interface LaberlMarkerProps { + sphereLink: ISphereLink; + apartment: IAppartmentSphere; +} + +const LabelMarker = ({ sphereLink, apartment }: LaberlMarkerProps) => { + const { setSelectedSphere } = useSphere(); + + const handleOnClick = () => { + const moveToShpere = apartment.spheres.find( + (sph) => sph.id === sphereLink.id + ); + if (moveToShpere) { + setSelectedSphere(moveToShpere); + } + }; + + return ( + <> + { + +
console.log(sphereLink.id)} + onClick={handleOnClick} + > + +
+ + } + + ); +}; + +export default LabelMarker; diff --git a/src/components/virtualTour/SphereTour.tsx b/src/components/virtualTour/SphereTour.tsx index faea3b0..2328fd0 100644 --- a/src/components/virtualTour/SphereTour.tsx +++ b/src/components/virtualTour/SphereTour.tsx @@ -1,13 +1,13 @@ import { Sphere, useTexture } from "@react-three/drei"; import { useEffect, useRef } from "react"; import { BackSide, MeshBasicMaterial } from "three"; -import { IAppartmentSphere } from "../../types/apartmentSphere"; +import { ISphere } from "../../types/apartmentSphere"; import gsap from "gsap"; // import gsap from "gsap"; interface SphereTourProps { - sphere: IAppartmentSphere; - selectedSphere: IAppartmentSphere; + sphere: ISphere; + selectedSphere: ISphere; } const SphereTour = ({ sphere, selectedSphere }: SphereTourProps) => { diff --git a/src/components/virtualTour/VirtualTourWrapper.tsx b/src/components/virtualTour/VirtualTourWrapper.tsx index 2265f33..42e35fa 100644 --- a/src/components/virtualTour/VirtualTourWrapper.tsx +++ b/src/components/virtualTour/VirtualTourWrapper.tsx @@ -1,32 +1,32 @@ -import { OrbitControls, Html, useTexture } from "@react-three/drei"; -import { Suspense, useEffect, useRef, useState } from "react"; +import { OrbitControls, Html } from "@react-three/drei"; +import { Suspense, useEffect, useRef } from "react"; import { OrbitControls as OrbitControlsImpl } from "three-stdlib"; -import { useParams } from "react-router-dom"; import useCompass from "../../store/useCompass"; import SphereTour from "./SphereTour"; -import { spheres } from "../../consts/spheres"; +import { IAppartmentSphere } from "../../types/apartmentSphere"; import useSphere from "../../store/useSphere"; +import LabelMarker from "./LabelMarker"; +// import { spheres } from "../../consts/spheres"; -const VirtualTourWrapper = () => { +interface VirtualTourWrapperProps { + appartment: IAppartmentSphere; +} + +const VirtualTourWrapper = ({ appartment }: VirtualTourWrapperProps) => { const orbitRef = useRef(null); - const { setCurrentCompassRotate, currentCompassRotate } = useCompass(); - const { id } = useParams(); - const [startRotatingPos, setStartRotatingPos] = useState(0); + const { setCurrentCompassRotate } = useCompass(); const { selectedSphere, setSelectedSphere } = useSphere(); - // const [selectedSphere, setSelectedSphere] = useState( - // spheres[1] - // ); + useEffect(() => { - setSelectedSphere(spheres[0]); + setSelectedSphere(appartment.spheres[0]); }, []); const handleOnRotating = () => { const radian = orbitRef.current?.getAzimuthalAngle(); if (radian) { const currentCompasDegrees = (radian * 180) / Math.PI + 180; - const compassOffsetDegres = startRotatingPos - currentCompasDegrees; - setCurrentCompassRotate(currentCompassRotate + compassOffsetDegres); + setCurrentCompassRotate(currentCompasDegrees); } }; @@ -38,12 +38,23 @@ const VirtualTourWrapper = () => { } > - {spheres.map((sphere) => ( - - ))} + {appartment.spheres.map((sphere) => { + const isLabelContains = + selectedSphere && sphere.id === selectedSphere.id; + + return ( + <> + {isLabelContains && + sphere.links.map((sphereLink) => ( + + ))} + + + ); + })} { // onStart={(e) => console.log("e", e)} // onChange={(e) => console.log("e", e?.target)} onChange={handleOnRotating} - target={[-14.16, 0, 24.11]} + target={appartment.spheres[0].position} /> ); diff --git a/src/consts/spheres.ts b/src/consts/spheres.ts deleted file mode 100644 index 9ee68ed..0000000 --- a/src/consts/spheres.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IAppartmentSphere } from "../types/apartmentSphere"; - -const spheres: IAppartmentSphere[] = [ - { - id: "1", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-01.webp", - roomType: "room 1", - }, - { - id: "2", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-02.webp", - roomType: "room 2", - }, - { - id: "3", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-03.webp", - roomType: "room 3", - }, - { - id: "4", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-04.webp", - roomType: "room 4", - }, - { - id: "5", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-05.webp", - roomType: "room 5", - }, - { - id: "6", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-06.webp", - roomType: "room 6", - }, - { - id: "7", - sphereImage: "/images/virtual-tour/studio1/Studio1_w-12_13_sp-07.webp", - roomType: "room 7", - }, -]; - -export { spheres }; diff --git a/src/data/appartment.json b/src/data/appartment.json new file mode 100644 index 0000000..735a9fa --- /dev/null +++ b/src/data/appartment.json @@ -0,0 +1,123 @@ +[ + { + "id": "appartments-studio-1", + "spheres": [ + { + "id": "studio-1_sp-01", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-01.webp", + "roomType": "room 1", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-02", + "type": "default", + "labelPosition": [-15.16, 0, 44.11] + }, + { + "id": "studio-1_sp-03", + "type": "default", + "labelPosition": [-0.16, 0, 24.11] + } + ] + }, + { + "id": "studio-1_sp-02", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-02.webp", + "roomType": "room 2", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-01", + "type": "default", + "labelPosition": [-12.16, 0, 5.11] + } + ] + }, + { + "id": "studio-1_sp-03", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-03.webp", + "roomType": "room 3", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-04", + "type": "default", + "labelPosition": [-0.16, 0, 24.11] + }, + { + "id": "studio-1_sp-01", + "type": "default", + "labelPosition": [-45, 0, 24.11] + } + ] + }, + { + "id": "studio-1_sp-04", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-04.webp", + "roomType": "room 4", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-05", + "type": "default", + "labelPosition": [-0.16, 0, 21.11] + }, + { + "id": "studio-1_sp-03", + "type": "default", + "labelPosition": [-45, 0, 24.11] + } + ] + }, + { + "id": "studio-1_sp-05", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-05.webp", + "roomType": "room 5", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-06", + "type": "default", + "labelPosition": [-0.16, 0, 24.11] + }, + { + "id": "studio-1_sp-04", + "type": "default", + "labelPosition": [-45, 0, 27.11] + } + ] + }, + { + "id": "studio-1_sp-06", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-06.webp", + "roomType": "room 6", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-07", + "type": "default", + "labelPosition": [-0.16, 0, 40.11] + }, + { + "id": "studio-1_sp-05", + "type": "default", + "labelPosition": [-45, 0, 27.11] + } + ] + }, + { + "id": "studio-1_sp-07", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-07.webp", + "roomType": "room 7", + "position": [-14.16, 0, 24.11], + "links": [ + { + "id": "studio-1_sp-06", + "type": "default", + "labelPosition": [-45, 0, 5.11] + } + ] + } + ] + } +] diff --git a/src/data/appartments-studio-1.json b/src/data/appartments-studio-1.json index 1c06a76..7c69878 100644 --- a/src/data/appartments-studio-1.json +++ b/src/data/appartments-studio-1.json @@ -1,77 +1,57 @@ [ { - "id": "studio-1-sp-01", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-01.webp", - "position": [-23.12, 0, -13.4], - "mapPosition": [97.61, 281.92], - "links": [ - { "toId": "Dvor_16", "label": "" }, - { "toId": "Dvor_17", "label": "Детская площадка" } - ] - }, - { - "id": "studio-1-sp-02", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-02.webp", + "id": "studio-1_sp-01", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-01.webp", + "roomType": "room 1", "position": [-14.16, 0, 24.11], - "mapPosition": [39.57, 347.47], "links": [ - { "toId": "Dvor_16", "label": "" }, - { "toId": "Dvor_2", "label": "" }, - { "toId": "Hall_1", "label": "Лобби" } + { + "id": "studio-1_sp-02", + "type": "default", + "labelPosition": [-15.16, 0, 24.11] + } ] }, { - "id": "studio-1-sp-03", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-03.webp", - "position": [-22.27, 0, 19.69], - "mapPosition": [36.26, 327.64], - "links": [ - { "toId": "Dvor_1", "label": "" }, - { "toId": "Dvor_14", "label": "" } - ] + "id": "studio-1_sp-02", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-02.webp", + "roomType": "room 2", + "position": [-14.16, 0, 24.11], + "links": [] }, { - "id": "studio-1-sp-04", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-04.webp", - "position": [-52.03, 0, -3.63], - "mapPosition": [41.11, 241.29], - "links": [ - { "toId": "Dvor_15", "label": "" }, - { "toId": "Dvor_4", "label": "" }, - { "toId": "Dvor_9", "label": "Детская площадка" } - ] + "id": "studio-1_sp-03", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-03.webp", + "roomType": "room 3", + "position": [-14.16, 0, 24.11], + "links": [] }, { - "id": "studio-1-sp-05", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-05.webp", - "position": [-50.6, 0, -15.06], - "mapPosition": [64.39, 228.91], - "links": [ - { "toId": "Dvor_9", "label": "Детская площадка" }, - { "toId": "Dvor_5", "label": "" }, - { "toId": "Dvor_3", "label": "" }, - { "toId": "Dvor_6", "label": "Детская площадка" } - ] + "id": "studio-1_sp-04", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-04.webp", + "roomType": "room 4", + "position": [-14.16, 0, 24.11], + "links": [] }, { - "id": "studio-1-sp-06", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-06.webp", - "position": [-34.36, 0, -4.72], - "mapPosition": [66.41, 273.23], - "links": [ - { "toId": "Dvor_4", "label": "" }, - { "toId": "Dvor_17", "label": "Детская площадка" } - ] + "id": "studio-1_sp-05", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-05.webp", + "roomType": "room 5", + "position": [-14.16, 0, 24.11], + "links": [] }, { - "id": "studio-1-sp-07", - "src": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-07.webp", - "position": [-40.94, 0, -23.93], - "mapPosition": [93.88, 235.03], - "links": [ - { "toId": "Dvor_17", "label": "Детская площадка" }, - { "toId": "Dvor_7", "label": "" }, - { "toId": "Dvor_4", "label": "" } - ] + "id": "studio-1_sp-06", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-06.webp", + "roomType": "room 6", + "position": [-14.16, 0, 24.11], + "links": [] + }, + { + "id": "studio-1_sp-07", + "sphereImage": "/images/virtual-tour/studio1/Studio1_w-12_13_sp-07.webp", + "roomType": "room 7", + "position": [-14.16, 0, 24.11], + "links": [] } ] diff --git a/src/pages/VirtualTour.tsx b/src/pages/VirtualTour.tsx index 54519db..87b1575 100644 --- a/src/pages/VirtualTour.tsx +++ b/src/pages/VirtualTour.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Canvas } from "@react-three/fiber"; import VirtualTourWrapper from "../components/virtualTour/VirtualTourWrapper"; import Button from "../components/Button"; @@ -6,22 +6,37 @@ import HeartIcon from "../components/icons/Heart"; import ChevronDownIcon from "../components/icons/ChevronDownIcon"; import ButtomPanelCompass from "../components/ButtomPanelCompass"; import BookingIcon from "../components/icons/BookingIcon"; -import { spheres } from "../consts/spheres"; -import { IAppartmentSphere } from "../types/apartmentSphere"; +import { IAppartmentSphere, ISphere } from "../types/apartmentSphere"; import useSphere from "../store/useSphere"; +import { useParams } from "react-router-dom"; +import _appartment from "../data/appartment.json"; + +const appartments = _appartment as IAppartmentSphere[]; const VirtualTour = () => { const [isActive, setIsActive] = useState(false); + const [currentAppartment, setCurrentAppartment] = + useState(null); const { setSelectedSphere } = useSphere(); + const { appartmentTypeId } = useParams(); const handleOnShowClick = () => { setIsActive((prev) => !prev); }; - const handleOnLabelClick = (sphere: IAppartmentSphere) => { + const handleOnLabelClick = (sphere: ISphere) => { setSelectedSphere(sphere); }; + useEffect(() => { + const _currentAppartment = appartments.find( + (app) => app.id === appartmentTypeId + ); + if (_currentAppartment) { + setCurrentAppartment(_currentAppartment); + } + }, [appartmentTypeId]); + return (
@@ -83,17 +98,18 @@ const VirtualTour = () => {
- {spheres.map((sphere) => { - return ( -
handleOnLabelClick(sphere)} - className="bg-[#F3F3F2] font-semibold text-[#0D1922] text-caption-s py-0.5 px-2 w-fit rounded-full cursor-pointer pointer-events-auto select-none" - key={sphere.id} - > - {sphere.roomType} -
- ); - })} + {currentAppartment && + currentAppartment.spheres.map((sphere) => { + return ( +
handleOnLabelClick(sphere)} + className="bg-[#F3F3F2] font-semibold text-[#0D1922] text-caption-s py-0.5 px-2 w-fit rounded-full cursor-pointer pointer-events-auto select-none" + key={sphere.id} + > + {sphere.roomType} +
+ ); + })}
{
- + {currentAppartment && ( + + )}
diff --git a/src/store/useSphere.tsx b/src/store/useSphere.tsx index 65df788..a1e8a4e 100644 --- a/src/store/useSphere.tsx +++ b/src/store/useSphere.tsx @@ -1,9 +1,9 @@ import { create } from "zustand"; -import { IAppartmentSphere } from "../types/apartmentSphere"; +import { ISphere } from "../types/apartmentSphere"; interface SequenceStore { - selectedSphere: null | IAppartmentSphere; - setSelectedSphere: (sphere: null | IAppartmentSphere) => void; + selectedSphere: null | ISphere; + setSelectedSphere: (sphere: null | ISphere) => void; } const useSphere = create((set) => ({ diff --git a/src/types/apartmentSphere.ts b/src/types/apartmentSphere.ts index 6dfdeea..b66950d 100644 --- a/src/types/apartmentSphere.ts +++ b/src/types/apartmentSphere.ts @@ -1,7 +1,20 @@ -interface IAppartmentSphere { +interface ISphereLink { + id: string; + type: string; + labelPosition: [number, number, number]; +} + +interface ISphere { id: string; sphereImage: string; roomType: string; + position: [number, number, number]; + links: ISphereLink[]; } -export type { IAppartmentSphere }; +interface IAppartmentSphere { + id: string; + spheres: ISphere[]; +} + +export type { ISphere, IAppartmentSphere, ISphereLink };