PromucFlow_constructor/app/client/src/widgets/OpenStreetMapWidget/component/index.tsx
Nikita Kraev 5088bd113c
Some checks failed
Merge release to pg / merge-release-to-pg (push) Waiting to run
Release Drafter / update_release_draft (push) Has been cancelled
feat: [] init
2025-11-12 22:43:13 +04:00

159 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect } from "react";
import type { WidgetProps } from "widgets/BaseWidget";
import styled from "styled-components";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import { FullScreen, useFullScreenHandle } from "react-full-screen";
import { Icon } from "@blueprintjs/core";
// Контейнер для карты с относительным позиционированием
const MapWrapper = styled.div`
position: relative;
width: 100%;
height: 100%;
`;
// Кнопка для переключения полноэкранного режима
const FullscreenButton = styled.button`
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
background: white;
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: background-color 0.2s;
&:hover {
background-color: #f0f0f0;
}
&:active {
background-color: #e0e0e0;
}
`;
// 🧩 фикс, чтобы маркеры отображались (иначе пустые иконки)
delete (L.Icon.Default.prototype as any)._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"),
iconUrl: require("leaflet/dist/images/marker-icon.png"),
shadowUrl: require("leaflet/dist/images/marker-shadow.png"),
});
// Компонент для обновления размера карты при изменении размера контейнера
function MapResizer() {
const map = useMap();
useEffect(() => {
// Обновляем размер карты при монтировании
const timer = setTimeout(() => {
map.invalidateSize();
}, 100);
return () => clearTimeout(timer);
}, [map]);
// Обновляем размер при изменении размера окна
useEffect(() => {
const handleResize = () => {
map.invalidateSize();
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, [map]);
// Обновляем размер при переключении полноэкранного режима
useEffect(() => {
const handleFullscreenChange = () => {
// Небольшая задержка, чтобы контейнер успел изменить размер
setTimeout(() => {
map.invalidateSize();
}, 200);
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
document.addEventListener("mozfullscreenchange", handleFullscreenChange);
document.addEventListener("MSFullscreenChange", handleFullscreenChange);
return () => {
document.removeEventListener("fullscreenchange", handleFullscreenChange);
document.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
document.removeEventListener("mozfullscreenchange", handleFullscreenChange);
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
};
}, [map]);
return null;
}
function OpenStreetMapComponent(props: OpenStreetMapComponentProps) {
// Получаем значения из props или используем значения по умолчанию
const centerLat = props.centerLat ?? 55.751244;
const centerLng = props.centerLng ?? 37.618423;
const zoom = props.zoom ?? 7;
const markerLat = props.markerLat ?? centerLat;
const markerLng = props.markerLng ?? centerLng;
const markerText = props.markerText ?? "Привет! Это Москва 🏙️";
const center: [number, number] = [centerLat, centerLng];
const markerPosition: [number, number] = [markerLat, markerLng];
// Хук для управления полноэкранным режимом
const fullScreenHandle = useFullScreenHandle();
return (
<MapWrapper>
<FullScreen handle={fullScreenHandle}>
<MapContainer
center={center}
zoom={zoom}
style={{ height: "500px", width: "500px" }}
>
<MapResizer />
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
/>
<Marker position={markerPosition}>
<Popup>{markerText}</Popup>
</Marker>
</MapContainer>
</FullScreen>
{/* Кнопка для переключения полноэкранного режима */}
<FullscreenButton
onClick={fullScreenHandle.active ? fullScreenHandle.exit : fullScreenHandle.enter}
title={fullScreenHandle.active ? "Выйти из полноэкранного режима" : "Развернуть на весь экран"}
>
<Icon
icon={fullScreenHandle.active ? "minimize" : "maximize"}
iconSize={16}
/>
</FullscreenButton>
</MapWrapper>
);
}
export interface OpenStreetMapComponentProps extends WidgetProps {
centerLat?: number;
centerLng?: number;
zoom?: number;
markerLat?: number;
markerLng?: number;
markerText?: string;
}
export default OpenStreetMapComponent;