622 lines
21 KiB
TypeScript
622 lines
21 KiB
TypeScript
"use client";
|
|
import { config } from "@/config/config";
|
|
import React, {
|
|
createContext,
|
|
useContext,
|
|
useState,
|
|
useEffect,
|
|
useRef,
|
|
} from "react";
|
|
import { Map as OlMap, VectorTile } from "ol";
|
|
import View from "ol/View.js";
|
|
import "ol/ol.css";
|
|
import MapTools from "./MapTools";
|
|
|
|
import { Layer } from "ol/layer"; // 保留导入,但用于继承
|
|
import VectorTileSource from "ol/source/VectorTile";
|
|
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
|
import MVT from "ol/format/MVT";
|
|
import { FlatStyleLike } from "ol/style/flat";
|
|
import { toLonLat } from "ol/proj";
|
|
import { center } from "@turf/center";
|
|
import { bearing } from "@turf/turf";
|
|
import { Deck } from "@deck.gl/core";
|
|
import { TextLayer } from "@deck.gl/layers";
|
|
import { TripsLayer } from "@deck.gl/geo-layers";
|
|
import { CollisionFilterExtension } from "@deck.gl/extensions";
|
|
|
|
interface MapComponentProps {
|
|
children?: React.ReactNode;
|
|
}
|
|
interface DataContextType {
|
|
currentJunctionCalData?: any[]; // 当前计算结果
|
|
setCurrentJunctionCalData?: React.Dispatch<React.SetStateAction<any[]>>;
|
|
currentPipeCalData?: any[]; // 当前计算结果
|
|
setCurrentPipeCalData?: React.Dispatch<React.SetStateAction<any[]>>;
|
|
showJunctionText?: boolean; // 是否显示节点文本
|
|
showPipeText?: boolean; // 是否显示管道文本
|
|
setShowJunctionText?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
setShowPipeText?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
junctionText: string;
|
|
pipeText: string;
|
|
setJunctionText?: React.Dispatch<React.SetStateAction<string>>;
|
|
setPipeText?: React.Dispatch<React.SetStateAction<string>>;
|
|
}
|
|
|
|
// 创建自定义Layer类来包装deck.gl
|
|
class DeckLayer extends Layer {
|
|
private deck: Deck;
|
|
|
|
constructor(deckInstance: Deck) {
|
|
super({});
|
|
this.deck = deckInstance;
|
|
}
|
|
|
|
render(frameState: any): HTMLElement {
|
|
const { size, viewState } = frameState;
|
|
const [width, height] = size;
|
|
const [longitude, latitude] = toLonLat(viewState.center);
|
|
const zoom = viewState.zoom - 1; // 调整 zoom 以匹配
|
|
const bearing = (-viewState.rotation * 180) / Math.PI;
|
|
const deckViewState = { bearing, longitude, latitude, zoom };
|
|
this.deck.setProps({ width, height, viewState: deckViewState });
|
|
this.deck.redraw();
|
|
// 返回deck.gl的canvas元素
|
|
return document.getElementById("deck-canvas") as HTMLElement;
|
|
}
|
|
}
|
|
// 跨组件传递
|
|
const MapContext = createContext<OlMap | undefined>(undefined);
|
|
const DataContext = createContext<DataContextType | undefined>(undefined);
|
|
|
|
const extent = config.mapExtent;
|
|
const mapUrl = config.mapUrl;
|
|
|
|
// 添加防抖函数
|
|
function debounce<F extends (...args: any[]) => any>(func: F, waitFor: number) {
|
|
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
return (...args: Parameters<F>): void => {
|
|
if (timeout !== null) {
|
|
clearTimeout(timeout);
|
|
}
|
|
timeout = setTimeout(() => func(...args), waitFor);
|
|
};
|
|
}
|
|
|
|
export const useMap = () => {
|
|
return useContext(MapContext);
|
|
};
|
|
export const useData = () => {
|
|
return useContext(DataContext);
|
|
};
|
|
|
|
const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|
const mapRef = useRef<HTMLDivElement | null>(null);
|
|
const deckRef = useRef<Deck | null>(null);
|
|
|
|
const [map, setMap] = useState<OlMap>();
|
|
// currentCalData 用于存储当前计算结果
|
|
const [currentJunctionCalData, setCurrentJunctionCalData] = useState<any[]>(
|
|
[]
|
|
);
|
|
const [currentPipeCalData, setCurrentPipeCalData] = useState<any[]>([]);
|
|
// junctionData 和 pipeData 分别缓存瓦片解析后节点和管道的数据,用于 deck.gl 定位、标签渲染
|
|
const [junctionData, setJunctionDataState] = useState<any[]>([]);
|
|
const [pipeData, setPipeDataState] = useState<any[]>([]);
|
|
const junctionDataIds = useRef(new Set<string>());
|
|
const pipeDataIds = useRef(new Set<string>());
|
|
const tileJunctionDataBuffer = useRef<any[]>([]);
|
|
const tilePipeDataBuffer = useRef<any[]>([]);
|
|
|
|
const [showJunctionText, setShowJunctionText] = useState(false); // 控制节点文本显示
|
|
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
|
|
const [showJunctionTextLayer, setShowJunctionTextLayer] = useState(true); // 控制节点文本图层显示
|
|
const [showPipeTextLayer, setShowPipeTextLayer] = useState(true); // 控制管道文本图层显示
|
|
const [junctionText, setJunctionText] = useState("pressure");
|
|
const [pipeText, setPipeText] = useState("flow");
|
|
const flowAnimation = useRef(false); // 添加动画控制标志
|
|
const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别
|
|
// 防抖更新函数
|
|
const debouncedUpdateData = useRef(
|
|
debounce(() => {
|
|
if (tileJunctionDataBuffer.current.length > 0) {
|
|
setJunctionData(tileJunctionDataBuffer.current);
|
|
tileJunctionDataBuffer.current = [];
|
|
}
|
|
if (tilePipeDataBuffer.current.length > 0) {
|
|
setPipeData(tilePipeDataBuffer.current);
|
|
tilePipeDataBuffer.current = [];
|
|
}
|
|
}, 100)
|
|
);
|
|
|
|
const setJunctionData = (newData: any[]) => {
|
|
const uniqueNewData = newData.filter((item) => {
|
|
if (!item || !item.id) return false;
|
|
if (!junctionDataIds.current.has(item.id)) {
|
|
junctionDataIds.current.add(item.id);
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
if (uniqueNewData.length > 0) {
|
|
setJunctionDataState((prev) => [...prev, ...uniqueNewData]);
|
|
}
|
|
};
|
|
const setPipeData = (newData: any[]) => {
|
|
const uniqueNewData = newData.filter((item) => {
|
|
if (!item || !item.id) return false;
|
|
if (!pipeDataIds.current.has(item.id)) {
|
|
pipeDataIds.current.add(item.id);
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
if (uniqueNewData.length > 0) {
|
|
setPipeDataState((prev) => [...prev, ...uniqueNewData]);
|
|
}
|
|
};
|
|
const defaultFlatStyle: FlatStyleLike = {
|
|
"stroke-width": 3,
|
|
"stroke-color": "rgba(51, 153, 204, 0.9)",
|
|
"circle-fill-color": "rgba(255,255,255,0.4)",
|
|
"circle-stroke-color": "rgba(255,255,255,0.9)",
|
|
"circle-radius": [
|
|
"interpolate",
|
|
["linear"],
|
|
["zoom"],
|
|
12,
|
|
1, // 在缩放级别 12 时,圆形半径为 1px
|
|
24,
|
|
12, // 在缩放级别 24 时,圆形半径为 12px
|
|
],
|
|
};
|
|
// 矢量瓦片数据源和图层
|
|
const junctionSource = new VectorTileSource({
|
|
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_junctions_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
|
format: new MVT(),
|
|
projection: "EPSG:3857",
|
|
});
|
|
const pipeSource = new VectorTileSource({
|
|
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_pipes_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
|
format: new MVT(),
|
|
projection: "EPSG:3857",
|
|
});
|
|
// WebGL 渲染优化显示
|
|
const junctionLayer = new WebGLVectorTileLayer({
|
|
source: junctionSource as any, // 使用 WebGL 渲染
|
|
style: defaultFlatStyle,
|
|
extent: extent, // 设置图层范围
|
|
maxZoom: 24,
|
|
minZoom: 12,
|
|
properties: {
|
|
name: "节点图层", // 设置图层名称
|
|
value: "junctions",
|
|
type: "point",
|
|
properties: [
|
|
// { name: "需求量", value: "demand" },
|
|
// { name: "海拔高度", value: "elevation" },
|
|
{ name: "实际需求量", value: "actualdemand" },
|
|
{ name: "水头", value: "head" },
|
|
{ name: "压力", value: "pressure" },
|
|
{ name: "水质", value: "quality" },
|
|
],
|
|
},
|
|
});
|
|
const pipeLayer = new WebGLVectorTileLayer({
|
|
source: pipeSource as any, // 使用 WebGL 渲染
|
|
style: defaultFlatStyle,
|
|
extent: extent, // 设置图层范围
|
|
maxZoom: 24,
|
|
minZoom: 12,
|
|
properties: {
|
|
name: "管道图层", // 设置图层名称
|
|
value: "pipes",
|
|
type: "linestring",
|
|
properties: [
|
|
// { name: "直径", value: "diameter" },
|
|
// { name: "粗糙度", value: "roughness" },
|
|
// { name: "局部损失", value: "minor_loss" },
|
|
{ name: "流量", value: "flow" },
|
|
{ name: "摩阻系数", value: "friction" },
|
|
{ name: "水头损失", value: "headloss" },
|
|
{ name: "水质", value: "quality" },
|
|
{ name: "反应速率", value: "reaction" },
|
|
{ name: "设置值", value: "setting" },
|
|
{ name: "状态", value: "status" },
|
|
{ name: "流速", value: "velocity" },
|
|
],
|
|
},
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!mapRef.current) return;
|
|
// 缓存 junction、pipe 数据,提供给 deck.gl 显示标签使用
|
|
junctionSource.on("tileloadend", (event) => {
|
|
try {
|
|
if (event.tile instanceof VectorTile) {
|
|
const renderFeatures = event.tile.getFeatures();
|
|
const data = new Map();
|
|
|
|
renderFeatures.forEach((renderFeature) => {
|
|
const props = renderFeature.getProperties();
|
|
const featureId = props.id;
|
|
if (featureId && !junctionDataIds.current.has(featureId)) {
|
|
const geometry = renderFeature.getGeometry();
|
|
if (geometry) {
|
|
const coordinates = geometry.getFlatCoordinates();
|
|
const coordWGS84 = toLonLat(coordinates);
|
|
data.set(featureId, {
|
|
id: featureId,
|
|
position: coordWGS84,
|
|
elevation: props.elevation || 0,
|
|
demand: props.demand || 0,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
const uniqueData = Array.from(data.values());
|
|
if (uniqueData.length > 0) {
|
|
tileJunctionDataBuffer.current.push(...uniqueData);
|
|
debouncedUpdateData.current();
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Junction tile load error:", error);
|
|
}
|
|
});
|
|
pipeSource.on("tileloadend", (event) => {
|
|
try {
|
|
if (event.tile instanceof VectorTile) {
|
|
const renderFeatures = event.tile.getFeatures();
|
|
const data = new Map();
|
|
|
|
renderFeatures.forEach((renderFeature) => {
|
|
try {
|
|
const props = renderFeature.getProperties();
|
|
const featureId = props.id;
|
|
if (featureId && !pipeDataIds.current.has(featureId)) {
|
|
const geometry = renderFeature.getGeometry();
|
|
if (geometry) {
|
|
const flatCoordinates = geometry.getFlatCoordinates();
|
|
const stride = geometry.getStride(); // 获取步长,通常为 2
|
|
// 重建为 LineString GeoJSON 格式的 coordinates: [[x1, y1], [x2, y2], ...]
|
|
const lineCoords = [];
|
|
for (let i = 0; i < flatCoordinates.length; i += stride) {
|
|
lineCoords.push([
|
|
flatCoordinates[i],
|
|
flatCoordinates[i + 1],
|
|
]);
|
|
}
|
|
const lineCoordsWGS84 = lineCoords.map((coord) => {
|
|
const [lon, lat] = toLonLat(coord);
|
|
return [lon, lat];
|
|
});
|
|
// 计算中点
|
|
const midPoint = center({
|
|
type: "LineString",
|
|
coordinates: lineCoordsWGS84,
|
|
}).geometry.coordinates;
|
|
// 计算角度
|
|
let lineAngle = bearing(
|
|
lineCoordsWGS84[0],
|
|
lineCoordsWGS84[lineCoordsWGS84.length - 1]
|
|
);
|
|
lineAngle = -lineAngle + 90;
|
|
if (lineAngle < -90 || lineAngle > 90) {
|
|
lineAngle += 180;
|
|
}
|
|
|
|
// 计算时间戳(可选)
|
|
const numSegments = lineCoordsWGS84.length - 1;
|
|
const timestamps = [0];
|
|
if (numSegments > 0) {
|
|
for (let i = 1; i <= numSegments; i++) {
|
|
timestamps.push((i / numSegments) * 10);
|
|
}
|
|
}
|
|
|
|
data.set(featureId, {
|
|
id: featureId,
|
|
diameter: props.diameter || 0,
|
|
path: lineCoordsWGS84, // 使用重建后的坐标
|
|
position: midPoint,
|
|
angle: lineAngle,
|
|
timestamps,
|
|
});
|
|
}
|
|
}
|
|
} catch (geomError) {
|
|
console.error("Geometry calculation error:", geomError);
|
|
}
|
|
});
|
|
|
|
const uniqueData = Array.from(data.values());
|
|
if (uniqueData.length > 0) {
|
|
tilePipeDataBuffer.current.push(...uniqueData);
|
|
debouncedUpdateData.current();
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Pipe tile load error:", error);
|
|
}
|
|
});
|
|
// 更新标签可见性状态
|
|
// 监听 junctionLayer 的 visible 变化
|
|
const handleJunctionVisibilityChange = () => {
|
|
const isVisible = junctionLayer.getVisible();
|
|
setShowJunctionTextLayer(isVisible);
|
|
};
|
|
// 监听 pipeLayer 的 visible 变化
|
|
const handlePipeVisibilityChange = () => {
|
|
const isVisible = pipeLayer.getVisible();
|
|
setShowPipeTextLayer(isVisible);
|
|
};
|
|
// 添加事件监听器
|
|
junctionLayer.on("change:visible", handleJunctionVisibilityChange);
|
|
pipeLayer.on("change:visible", handlePipeVisibilityChange);
|
|
|
|
const map = new OlMap({
|
|
target: mapRef.current,
|
|
view: new View({
|
|
projection: "EPSG:3857",
|
|
}),
|
|
// 图层依面、线、点、标注次序添加
|
|
layers: [pipeLayer, junctionLayer],
|
|
controls: [],
|
|
});
|
|
setMap(map);
|
|
map.getView().fit(extent, {
|
|
padding: [50, 50, 50, 50], // 添加一些内边距
|
|
duration: 1000, // 动画持续时间
|
|
});
|
|
// 监听缩放变化
|
|
map.getView().on("change", () => {
|
|
setTimeout(() => {
|
|
const zoom = map.getView().getZoom() || 0;
|
|
setCurrentZoom(zoom);
|
|
}, 0);
|
|
});
|
|
// 初始化 deck.gl
|
|
const deck = new Deck({
|
|
initialViewState: {
|
|
longitude: 0,
|
|
latitude: 0,
|
|
zoom: 1,
|
|
},
|
|
canvas: "deck-canvas",
|
|
controller: false, // 由 OpenLayers 控制视图
|
|
layers: [],
|
|
});
|
|
deckRef.current = deck;
|
|
const deckLayer = new DeckLayer(deck);
|
|
// deckLayer.setZIndex(1000); // 确保在最上层
|
|
map.addLayer(deckLayer);
|
|
|
|
// 清理函数
|
|
return () => {
|
|
junctionLayer.un("change:visible", handleJunctionVisibilityChange);
|
|
pipeLayer.un("change:visible", handlePipeVisibilityChange);
|
|
map.setTarget(undefined);
|
|
map.dispose();
|
|
deck.finalize();
|
|
};
|
|
}, []);
|
|
|
|
// 当数据变化时,更新 deck.gl 图层
|
|
useEffect(() => {
|
|
const deck = deckRef.current;
|
|
if (!deck) return; // 如果 deck 实例还未创建,则退出
|
|
const newLayers = [
|
|
new TextLayer({
|
|
id: "junctionTextLayer",
|
|
zIndex: 10,
|
|
data: showJunctionText ? junctionData : [],
|
|
getPosition: (d: any) => d.position,
|
|
fontFamily: "Monaco, monospace",
|
|
getText: (d: any) =>
|
|
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
|
getSize: 12,
|
|
getColor: [150, 150, 255],
|
|
getAngle: 0,
|
|
getTextAnchor: "middle",
|
|
getAlignmentBaseline: "center",
|
|
getPixelOffset: [0, -10],
|
|
visible:
|
|
showJunctionTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
|
extensions: [new CollisionFilterExtension()],
|
|
collisionTestProps: {
|
|
sizeScale: 2, // 增加碰撞检测的尺寸以提供更大间距
|
|
},
|
|
fontSettings: {
|
|
sdf: true,
|
|
fontSize: 64, // 字体图集大小,默认 64
|
|
buffer: 6, // 字符间距缓冲,默认 4
|
|
radius: 12, // SDF 半径,默认 12
|
|
cutoff: 0.25, // 控制字符粗细,默认 0.25
|
|
smoothing: 0.1, // 边缘平滑度,默认 0.1
|
|
},
|
|
outlineWidth: 10,
|
|
outlineColor: [255, 255, 255, 255],
|
|
}),
|
|
new TextLayer({
|
|
id: "pipeTextLayer",
|
|
zIndex: 10,
|
|
data: showPipeText ? pipeData : [],
|
|
getPosition: (d: any) => d.position,
|
|
fontFamily: "Monaco, monospace",
|
|
getText: (d: any) =>
|
|
d[pipeText] ? (d[pipeText] as number).toFixed(3) : "",
|
|
getSize: 14,
|
|
getColor: [120, 128, 181],
|
|
getAngle: (d: any) => d.angle || 0,
|
|
getPixelOffset: [0, -8],
|
|
getTextAnchor: "middle",
|
|
getAlignmentBaseline: "bottom",
|
|
visible: showPipeTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
|
extensions: [new CollisionFilterExtension()],
|
|
collisionTestProps: {
|
|
sizeScale: 2, // 增加碰撞检测的尺寸以提供更大间距
|
|
},
|
|
fontSettings: {
|
|
sdf: true,
|
|
fontSize: 64, // 字体图集大小,默认 64
|
|
buffer: 6, // 字符间距缓冲,默认 4
|
|
radius: 12, // SDF 半径,默认 12
|
|
cutoff: 0.25, // 控制字符粗细,默认 0.25
|
|
smoothing: 0.1, // 边缘平滑度,默认 0.1
|
|
},
|
|
outlineWidth: 10,
|
|
outlineColor: [255, 255, 255, 255],
|
|
}),
|
|
];
|
|
deck.setProps({ layers: newLayers });
|
|
|
|
// 动画循环
|
|
const animate = () => {
|
|
if (!deck || !flowAnimation.current) return; // 添加检查,防止空数据或停止旧循环
|
|
// 动画总时长(秒)
|
|
if (pipeData.length === 0) {
|
|
requestAnimationFrame(animate);
|
|
return;
|
|
}
|
|
const animationDuration = 10;
|
|
// 缓冲时间(秒)
|
|
const bufferTime = 2;
|
|
// 完整循环周期
|
|
const loopLength = animationDuration + bufferTime;
|
|
// 确保时间范围与你的时间戳数据匹配
|
|
const currentTime = (Date.now() / 1000) % loopLength; // (0,12) 之间循环
|
|
// console.log("Current Time:", currentTime);
|
|
const waterflowLayer = new TripsLayer({
|
|
id: "waterflowLayer",
|
|
data: pipeData,
|
|
getPath: (d) => (flowAnimation.current ? d.path : []),
|
|
getTimestamps: (d) => {
|
|
return d.timestamps; // 这些应该是与 currentTime 匹配的数值
|
|
},
|
|
getColor: [0, 220, 255],
|
|
opacity: 0.8,
|
|
visible: currentZoom >= 12 && currentZoom <= 24,
|
|
widthMinPixels: 5,
|
|
jointRounded: true, // 拐角变圆
|
|
// capRounded: true, // 端点变圆
|
|
trailLength: 2, // 水流尾迹淡出时间
|
|
currentTime: currentTime,
|
|
});
|
|
|
|
// 获取当前除 waterflowLayer 之外的所有图层
|
|
const otherLayers = deck.props.layers.filter(
|
|
(layer: any) => layer && layer.id !== "waterflowLayer"
|
|
);
|
|
|
|
deck.setProps({
|
|
layers: [...otherLayers, waterflowLayer],
|
|
});
|
|
|
|
// 继续请求动画帧,每帧执行一次函数
|
|
requestAnimationFrame(animate);
|
|
};
|
|
animate();
|
|
}, [
|
|
flowAnimation,
|
|
junctionData,
|
|
pipeData,
|
|
currentZoom,
|
|
showJunctionText,
|
|
showPipeText,
|
|
showJunctionTextLayer,
|
|
showPipeTextLayer,
|
|
junctionText,
|
|
pipeText,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (pipeText === "flow") {
|
|
flowAnimation.current = true;
|
|
} else {
|
|
flowAnimation.current = false;
|
|
}
|
|
}, [pipeText]);
|
|
// 计算值更新时,更新 junctionData 和 pipeData
|
|
useEffect(() => {
|
|
const junctionProperties = junctionText;
|
|
const pipeProperties = pipeText;
|
|
|
|
// 将 nodeRecords 转换为 Map 以提高查找效率
|
|
const nodeMap: Map<string, any> = new Map(
|
|
currentJunctionCalData.map((r: any) => [r.ID, r])
|
|
);
|
|
// 将 linkRecords 转换为 Map 以提高查找效率
|
|
const linkMap: Map<string, any> = new Map(
|
|
currentPipeCalData.map((r: any) => [r.ID, r])
|
|
);
|
|
|
|
// 更新junctionData
|
|
setJunctionDataState((prev: any[]) =>
|
|
prev.map((j) => {
|
|
const record = nodeMap.get(j.id);
|
|
if (record) {
|
|
return {
|
|
...j,
|
|
[junctionProperties]: record.value,
|
|
};
|
|
}
|
|
return j;
|
|
})
|
|
);
|
|
|
|
// 更新pipeData
|
|
setPipeDataState((prev: any[]) =>
|
|
prev.map((p) => {
|
|
const record = linkMap.get(p.id);
|
|
if (record) {
|
|
return {
|
|
...p,
|
|
flowFlag: pipeProperties === "flow" && record.value < 0 ? -1 : 1,
|
|
path:
|
|
pipeProperties === "flow" && record.value < 0 && p.flowFlag > 0
|
|
? [...p.path].reverse()
|
|
: p.path,
|
|
[pipeProperties]: record.value,
|
|
};
|
|
}
|
|
return p;
|
|
})
|
|
);
|
|
}, [currentJunctionCalData, currentPipeCalData]);
|
|
return (
|
|
<>
|
|
<DataContext.Provider
|
|
value={{
|
|
currentJunctionCalData,
|
|
setCurrentJunctionCalData,
|
|
currentPipeCalData,
|
|
setCurrentPipeCalData,
|
|
setShowJunctionText,
|
|
setShowPipeText,
|
|
setJunctionText,
|
|
setPipeText,
|
|
showJunctionText,
|
|
showPipeText,
|
|
junctionText,
|
|
pipeText,
|
|
}}
|
|
>
|
|
<MapContext.Provider value={map}>
|
|
<div className="relative w-full h-full">
|
|
<div ref={mapRef} className="w-full h-full"></div>
|
|
<MapTools />
|
|
{children}
|
|
</div>
|
|
<canvas id="deck-canvas" />
|
|
</MapContext.Provider>
|
|
</DataContext.Provider>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default MapComponent;
|