Markers clusterization, mobile version of map
This commit is contained in:
@@ -16,7 +16,7 @@ import GoogleMap from "./GoogleMap";
|
||||
import MarasiDriveNeighboursSliderTablet from "./MarasiDriveNeighboursSliderTablet";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
import BrochureButton from "./ui/BrochureButton";
|
||||
import { marasiDriveMapData } from "../data/mapMarasiDrive";
|
||||
import { MarasiDriveMapData } from "../data/marasiDriveMapData";
|
||||
|
||||
function AboutMarasiDrive() {
|
||||
const target = useRef<HTMLDivElement>(null);
|
||||
@@ -239,7 +239,10 @@ function AboutMarasiDrive() {
|
||||
<MarasiDriveMapCard {...card} key={card.title} />
|
||||
))}
|
||||
<div className="col-start-3 col-span-full row-start-1 row-span-full rounded-[1.667vw] overflow-hidden">
|
||||
<GoogleMap mapCenter={marasiDriveMapData.mapCenter} />
|
||||
<GoogleMap
|
||||
mapCenter={MarasiDriveMapData.defaultCenter}
|
||||
markers={MarasiDriveMapData.markers}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<MarasiDriveMapMobile />
|
||||
|
||||
@@ -1,88 +1,68 @@
|
||||
/* eslint-disable no-loss-of-precision */
|
||||
import { Map } from "@vis.gl/react-google-maps";
|
||||
import MapMarker from "./ui/MapMarker";
|
||||
import IGMapPoi from "../types/IGMapPoi";
|
||||
import MarasiMarker from "../../public/images/map/markers/marasi-drive.png";
|
||||
import MarasiPopup from "../../public/images/map/markers/popups/marasi-drive.png";
|
||||
import MarinaMarker from "../../public/images/map/markers/dubai-marina.png";
|
||||
import MarinaPopup from "../../public/images/map/markers/popups/dubai-marina.png";
|
||||
import ShopIcon from "../../public/images/map/markers/points/shop-point.svg";
|
||||
import GoogleMapMarkers from "./GoogleMapMarkers";
|
||||
import { Map, useMap } from "@vis.gl/react-google-maps";
|
||||
import { useEffect, useState } from "react";
|
||||
import GoogleMapFilterButtons from "./GoogleMapFilterButtons";
|
||||
|
||||
interface IGMapProps {
|
||||
mapCenter: google.maps.LatLngLiteral;
|
||||
defaultZoom?: number;
|
||||
markers?: IGMapPoi[];
|
||||
minZoom?: number;
|
||||
disableUI?: boolean;
|
||||
mobile?: boolean;
|
||||
mobileActive?: boolean;
|
||||
}
|
||||
|
||||
export default function GoogleMap({
|
||||
mapCenter,
|
||||
markers,
|
||||
defaultZoom = 14,
|
||||
minZoom = 10,
|
||||
disableUI = true,
|
||||
mobile = false,
|
||||
mobileActive = false,
|
||||
}: IGMapProps) {
|
||||
const [mapMarkersFilter, setMapMarkersFilter] = useState("All");
|
||||
const [isInteractale, setIsInteractale] = useState(!mobile);
|
||||
const map = useMap();
|
||||
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
|
||||
setIsInteractale(!mobile || (mobile && mobileActive));
|
||||
if (!mobileActive && mobile) {
|
||||
map.panTo(mapCenter);
|
||||
map.setZoom(defaultZoom);
|
||||
}
|
||||
}, [mobile, mobileActive, map]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mobileActive) setMapMarkersFilter("All");
|
||||
}, [mobileActive]);
|
||||
|
||||
return (
|
||||
<Map
|
||||
mapId={"30ff24bdc133c941ee0d0608"}
|
||||
defaultCenter={mapCenter}
|
||||
defaultZoom={defaultZoom}
|
||||
disableDefaultUI={disableUI}
|
||||
minZoom={minZoom}
|
||||
gestureHandling={"greedy"}
|
||||
<div
|
||||
className={`size-[100%] ${
|
||||
isInteractale ? "pointer-events-auto" : "pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
<MapMarkers />
|
||||
</Map>
|
||||
);
|
||||
}
|
||||
|
||||
function MapMarkers() {
|
||||
const marasiDriveMarker = (
|
||||
<div className="flex items-end hover:cursor-pointer">
|
||||
<img src={MarasiMarker} alt="" />
|
||||
<img className="mb-3" src={MarasiPopup} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const DubaiMarinaMarker = (
|
||||
<div className="flex items-end hover:cursor-pointer">
|
||||
<img src={MarinaMarker} alt="" />
|
||||
<img className="mb-3" src={MarinaPopup} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const shopMarker = (
|
||||
<div>
|
||||
<img src={ShopIcon} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const templateMarkers: IGMapPoi[] = [
|
||||
{
|
||||
location: { lat: 25.181504160790247, lng: 55.27565159760525 },
|
||||
customMarker: marasiDriveMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.069466431595334, lng: 55.128736429300375 },
|
||||
customMarker: DubaiMarinaMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.193476007744233, lng: 55.274782084720286 },
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.193476007744233, lng: 55.244782084720286 },
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{templateMarkers.map((poi: IGMapPoi, index: number) => (
|
||||
<MapMarker key={String(index)} location={poi.location}>
|
||||
{poi.customMarker}
|
||||
</MapMarker>
|
||||
))}
|
||||
</>
|
||||
<Map
|
||||
mapId={"30ff24bdc133c941ee0d0608"}
|
||||
defaultCenter={mapCenter}
|
||||
defaultZoom={defaultZoom}
|
||||
disableDefaultUI={true}
|
||||
minZoom={minZoom}
|
||||
gestureHandling={!mobile || mobileActive ? "greedy" : "none"}
|
||||
>
|
||||
{markers && (
|
||||
<GoogleMapMarkers data={markers} filter={mapMarkersFilter} />
|
||||
)}
|
||||
<GoogleMapFilterButtons
|
||||
mobile={mobile}
|
||||
mobileActive={mobileActive}
|
||||
currentFilter={mapMarkersFilter}
|
||||
onChange={setMapMarkersFilter}
|
||||
/>
|
||||
</Map>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { useState } from "react";
|
||||
import AllIcon from "./icons/map/AllIcon";
|
||||
import EntertainmentIcon from "./icons/map/EntertainmentIcon";
|
||||
import HotelIcon from "./icons/map/HotelIcon";
|
||||
import MallsIcon from "./icons/map/MallsIcon";
|
||||
import OtherIcon from "./icons/map/OtherIcon";
|
||||
import Button from "./ui/Button";
|
||||
|
||||
export default function GoogleMapFilterButtons({
|
||||
mobile,
|
||||
mobileActive,
|
||||
currentFilter,
|
||||
onChange,
|
||||
}: {
|
||||
mobile: boolean;
|
||||
mobileActive: boolean;
|
||||
currentFilter: string;
|
||||
onChange: (newFilter: string) => void;
|
||||
}) {
|
||||
const filters = ["All", "Hotels", "Malls", "Entertainment", "Other"];
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const buttonsVisisble = (expanded && mobile && mobileActive) || !mobile;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex gap-[0.556vw] absolute items-center bottom-[1.111vw] left-1/2 -translate-x-1/2 ${
|
||||
mobile && "flex-col"
|
||||
}`}
|
||||
>
|
||||
{buttonsVisisble &&
|
||||
filters.map((key) => (
|
||||
<Button
|
||||
key={key}
|
||||
onClick={() => onChange(key)}
|
||||
variant={key === currentFilter ? "cta" : "secondary"}
|
||||
>
|
||||
<div className="size-5">
|
||||
{key === "All" && <AllIcon />}
|
||||
{key === "Hotels" && <HotelIcon />}
|
||||
{key === "Malls" && <MallsIcon />}
|
||||
{key === "Entertainment" && <EntertainmentIcon />}
|
||||
{key === "Other" && <OtherIcon />}
|
||||
</div>
|
||||
{key}
|
||||
</Button>
|
||||
))}
|
||||
|
||||
{mobile && mobileActive && (
|
||||
<Button
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
variant={expanded ? "cta" : "secondary"}
|
||||
className="my-4"
|
||||
>
|
||||
{!expanded && (
|
||||
<div>
|
||||
<AllIcon />
|
||||
</div>
|
||||
)}
|
||||
{!expanded ? <span>Select Category</span> : <span>Apply</span>}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { useMap } from "@vis.gl/react-google-maps";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import IGMapPoi from "../types/IGMapPoi";
|
||||
import MapMarker from "./ui/MapMarker";
|
||||
import {
|
||||
MarkerClusterer,
|
||||
DefaultRenderer,
|
||||
Cluster,
|
||||
Marker,
|
||||
} from "@googlemaps/markerclusterer";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
|
||||
class CustomMarkerRenderer extends DefaultRenderer {
|
||||
render({
|
||||
count,
|
||||
position,
|
||||
}: Cluster): google.maps.marker.AdvancedMarkerElement {
|
||||
const svgElement = document.createElement("div");
|
||||
svgElement.innerHTML = `
|
||||
<svg fill="black" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="50" height="50">
|
||||
<circle cx="120" cy="120" opacity="1" r="70" />
|
||||
</svg>
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 12px; font-weight: bold;">
|
||||
${count}
|
||||
</div>`;
|
||||
|
||||
// Create the AdvancedMarkerElement
|
||||
const marker = new google.maps.marker.AdvancedMarkerElement({
|
||||
position,
|
||||
content: svgElement, // Use the custom SVG element as content
|
||||
zIndex: Math.max(1000, count),
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
|
||||
export default function GoogleMapMarkers({
|
||||
data,
|
||||
filter,
|
||||
}: {
|
||||
data: IGMapPoi[];
|
||||
filter: string;
|
||||
}) {
|
||||
const map = useMap();
|
||||
const [markers, setMarkers] = useState<{ [key: string]: Marker }>({});
|
||||
const clusterer = useRef<MarkerClusterer | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
if (!clusterer.current) {
|
||||
clusterer.current = new MarkerClusterer({
|
||||
map: map,
|
||||
renderer: new CustomMarkerRenderer(),
|
||||
});
|
||||
}
|
||||
}, [map]);
|
||||
|
||||
useEffect(() => {
|
||||
clusterer.current?.clearMarkers();
|
||||
clusterer.current?.addMarkers(Object.values(markers));
|
||||
}, [markers]);
|
||||
|
||||
const setMarkerRef = (marker: Marker | null, key: string) => {
|
||||
if (marker && markers[key]) return;
|
||||
if (!marker && !markers[key]) return;
|
||||
|
||||
setMarkers((prev) => {
|
||||
if (marker) {
|
||||
return { ...prev, [key]: marker };
|
||||
} else {
|
||||
const newMarkers = { ...prev };
|
||||
delete newMarkers[key];
|
||||
return newMarkers;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{data.map(
|
||||
(poi: IGMapPoi, index: number) =>
|
||||
(filter === poi.type || filter === "All") && (
|
||||
<MapMarker
|
||||
key={index}
|
||||
markerKey={index}
|
||||
poi={poi}
|
||||
setMarkerRef={setMarkerRef}
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
{poi.customMarker}
|
||||
</motion.div>
|
||||
</MapMarker>
|
||||
)
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,52 @@
|
||||
import { useRef } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { marasiDriveMapCards } from "../data/aboutMarasiDrive";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
import { MarasiDriveMapData } from "../data/marasiDriveMapData";
|
||||
import GoogleMap from "./GoogleMap";
|
||||
import Button from "./ui/Button";
|
||||
import FullScreenIcon from "./icons/FullScreenIcon";
|
||||
import CloseIcon from "./icons/CloseIcon";
|
||||
|
||||
function MarasiDriveMapMobile() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const mapRef = useRef<HTMLDivElement>(null);
|
||||
const [mapActive, setMapActive] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (mapActive) {
|
||||
mapRef.current?.scrollIntoView();
|
||||
window.scrollBy({
|
||||
top: -40,
|
||||
left: 0,
|
||||
behavior: "smooth",
|
||||
});
|
||||
}
|
||||
}, [mapActive]);
|
||||
|
||||
return (
|
||||
<div className="min-2xl:hidden relative flex flex-col">
|
||||
<div className="max-md:aspect-[328/544] md:max-2xl:aspect[1/1] max-2xl:mb-4">
|
||||
<img
|
||||
src="/images/about-complex/marasi-drive/map/map.png"
|
||||
alt=""
|
||||
className="object-cover size-full rounded-[6.667vw] md:max-2xl:rounded-[3.125vw]"
|
||||
<div
|
||||
ref={mapRef}
|
||||
className={`relative max-md:aspect-[328/328] scroll-mt-10 md:max-2xl:aspect[1/1] transition-all max-2xl:mb-4 overflow-clip rounded-[4.444vw] ${
|
||||
mapActive ? "h-[80vh]" : "h-[100vw]"
|
||||
}`}
|
||||
>
|
||||
<GoogleMap
|
||||
mapCenter={MarasiDriveMapData.defaultCenter}
|
||||
markers={MarasiDriveMapData.markers}
|
||||
mobileActive={mapActive}
|
||||
mobile={true}
|
||||
/>
|
||||
<Button
|
||||
className={`absolute size-[11.111vw] right-[1.111vw] ${
|
||||
mapActive ? "top-[1.111vw]" : "bottom-[1.111vw]"
|
||||
}`}
|
||||
onClick={() => setMapActive(!mapActive)}
|
||||
>
|
||||
<div className="size-[5.556vw]">
|
||||
{mapActive ? <CloseIcon /> : <FullScreenIcon />}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
ref={containerRef}
|
||||
@@ -36,7 +70,12 @@ function MarasiDriveMapMobile() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CustomScrollBar containerRef={containerRef} inlinePadding={16} trackStyle="min-2xl:hidden max-2xl:translate-y-5" thumbStyle="min-2xl:hidden"/>
|
||||
<CustomScrollBar
|
||||
containerRef={containerRef}
|
||||
inlinePadding={16}
|
||||
trackStyle="min-2xl:hidden max-2xl:translate-y-5"
|
||||
thumbStyle="min-2xl:hidden"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
const AllIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={21}
|
||||
height={20}
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M6.517 13.97h.028v.024zm0-7.952h.029v.023zm7.971 7.976h.029v.024zm-.029-7.976h.029v.023z"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default AllIcon;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
const EntertainmentIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={21}
|
||||
height={20}
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.49 6.07a.1.1 0 0 1 .186 0l1.188 3.01a.1.1 0 0 0 .056.057l3.01 1.187a.1.1 0 0 1 0 .186l-3.01 1.188a.1.1 0 0 0-.056.056l-1.188 3.01a.1.1 0 0 1-.186 0l-1.187-3.01a.1.1 0 0 0-.056-.056L3.236 10.51a.1.1 0 0 1 0-.186l3.01-1.187a.1.1 0 0 0 .057-.056zm7.13 4.882a.05.05 0 0 1 .093 0l.77 1.954a.05.05 0 0 0 .029.028l1.953.77a.05.05 0 0 1 0 .093l-1.953.77a.05.05 0 0 0-.028.029l-.77 1.953a.05.05 0 0 1-.094 0l-.77-1.953a.05.05 0 0 0-.028-.028l-1.954-.77a.05.05 0 0 1 0-.094l1.954-.77a.05.05 0 0 0 .028-.028zm-1.25-8.334a.05.05 0 0 1 .093 0l.77 1.954a.05.05 0 0 0 .029.028l1.953.77a.05.05 0 0 1 0 .093l-1.953.77a.05.05 0 0 0-.028.029l-.77 1.953a.05.05 0 0 1-.094 0l-.77-1.953a.05.05 0 0 0-.028-.028l-1.954-.77a.05.05 0 0 1 0-.094l1.954-.77a.05.05 0 0 0 .028-.028z"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default EntertainmentIcon;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
const HotelIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={21}
|
||||
height={20}
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.834 10.247h.333a1 1 0 0 1 1 1v2.19a1 1 0 0 1-1 1H4.834a1 1 0 0 1-1-1v-2.19a1 1 0 0 1 1-1h.333m10.667 0V6.882c0-.579-.448-1.048-1-1.048H10.5m5.334 4.413H10.5m-5.333 0V6.882c0-.579.448-1.048 1-1.048H10.5m-5.333 4.413H10.5m-5.833 4.19v1.397m11.667-1.397v1.397M10.5 10.247V5.834"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default HotelIcon;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
const MallsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={21}
|
||||
height={20}
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M8 6.406H6.5a1 1 0 0 0-1 1v7.428a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V7.406a1 1 0 0 0-1-1H13m-5 0v-.572a2.5 2.5 0 0 1 2.5-2.5v0a2.5 2.5 0 0 1 2.5 2.5v.572m-5 0h5"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="square"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default MallsIcon;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
const OtherIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={21}
|
||||
height={20}
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M10.5 4.166v11.667M5.45 7.086l10.104 5.834m-10.1 0 10.103-5.833"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default OtherIcon;
|
||||
@@ -1,18 +1,39 @@
|
||||
import { AdvancedMarker, Pin } from "@vis.gl/react-google-maps";
|
||||
import { AdvancedMarker, Pin, useMap } from "@vis.gl/react-google-maps";
|
||||
import type { Marker } from "@googlemaps/markerclusterer";
|
||||
import IGMapPoi from "../../types/IGMapPoi";
|
||||
|
||||
interface IGMapMarker {
|
||||
key: string;
|
||||
location: google.maps.LatLngLiteral;
|
||||
markerKey: number;
|
||||
poi: IGMapPoi;
|
||||
setMarkerRef: (marker: Marker | null, key: string) => void | undefined;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function MapMarker({ key, location, children }: IGMapMarker) {
|
||||
export default function MapMarker({
|
||||
markerKey,
|
||||
poi,
|
||||
setMarkerRef,
|
||||
children,
|
||||
}: IGMapMarker) {
|
||||
const map = useMap();
|
||||
|
||||
return (
|
||||
<AdvancedMarker key={key} position={location}>
|
||||
<AdvancedMarker
|
||||
onClick={() => {
|
||||
map?.panTo(poi.location);
|
||||
map?.setZoom(15);
|
||||
}}
|
||||
key={markerKey}
|
||||
position={poi.location}
|
||||
ref={(marker) =>
|
||||
!poi.ignoreClusterization && setMarkerRef(marker, markerKey.toString())
|
||||
}
|
||||
>
|
||||
<Pin
|
||||
background={"transparent"}
|
||||
glyphColor={"transparent"}
|
||||
borderColor={"transparent"}
|
||||
scale={poi.clickableAreaScale || 1}
|
||||
>
|
||||
{children}
|
||||
</Pin>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export const marasiDriveMapData = {
|
||||
mapCenter: { lat: 25.183476007744233, lng: 55.274782084720286 }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* eslint-disable no-loss-of-precision */
|
||||
import MarasiMarker from "../../public/images/map/markers/marasi-drive.png";
|
||||
import MarinaMarker from "../../public/images/map/markers/dubai-marina.png";
|
||||
import ShopIcon from "../../public/images/map/markers/points/shop-point.svg";
|
||||
import IGMapPoi from "../types/IGMapPoi";
|
||||
|
||||
const marasiDriveMarker = (
|
||||
<div className="flex items-end hover:cursor-pointer">
|
||||
<img src={MarasiMarker} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const DubaiMarinaMarker = (
|
||||
<div className="flex items-end hover:cursor-pointer">
|
||||
<img src={MarinaMarker} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const shopMarker = (
|
||||
<div>
|
||||
<img src={ShopIcon} alt="" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const MarasiDriveMapData: {
|
||||
defaultCenter: { lat: number; lng: number };
|
||||
markers: IGMapPoi[];
|
||||
} = {
|
||||
defaultCenter: { lat: 25.183476007744233, lng: 55.274782084720286 },
|
||||
markers: [
|
||||
{
|
||||
location: { lat: 25.223476007744233, lng: 55.274782084720286 },
|
||||
type: "Malls",
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.123476007744233, lng: 55.258782084720286 },
|
||||
type: "Malls",
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.143476007744233, lng: 55.224782084720286 },
|
||||
type: "Malls",
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.223476007744233, lng: 55.278782084720286 },
|
||||
type: "Malls",
|
||||
customMarker: shopMarker,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.181371868546396, lng: 55.27515332907251 },
|
||||
type: "Hotels",
|
||||
ignoreClusterization: true,
|
||||
customMarker: marasiDriveMarker,
|
||||
clickableAreaScale: 3,
|
||||
},
|
||||
{
|
||||
location: { lat: 25.069466431595334, lng: 55.128736429300375 },
|
||||
type: "Hotels",
|
||||
ignoreClusterization: true,
|
||||
customMarker: DubaiMarinaMarker,
|
||||
clickableAreaScale: 3,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,4 +1,9 @@
|
||||
export default interface IGMapPoi {
|
||||
location: google.maps.LatLngLiteral;
|
||||
ignoreClusterization?:boolean;
|
||||
type:"All" | "Hotels" | "Malls" | "Entertainment"| "Other";
|
||||
|
||||
// Scale multiplyer for Pin (MapMarker.tsx) component. (To match visible marker size).
|
||||
clickableAreaScale?:number;
|
||||
customMarker?: React.ReactNode;
|
||||
}
|
||||
Reference in New Issue
Block a user