From 520e1cb3f1fe5cecaba6f869ae3c34bc47d7bb84 Mon Sep 17 00:00:00 2001 From: JIANG Date: Tue, 10 Mar 2026 11:04:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E9=A1=B9=E7=9B=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package_back.json | 58 ------ src/app/(main)/health-risk-analysis/page.tsx | 6 +- .../burst-location/page.tsx | 4 +- .../loading.tsx | 0 .../page.tsx | 6 +- .../loading.tsx | 0 .../page.tsx | 4 +- .../dma-leak-detection/page.tsx | 4 +- .../loading.tsx | 0 .../page.tsx | 4 +- .../monitoring-place-optimization/page.tsx | 4 +- .../network-partition-optimization/page.tsx | 4 +- src/app/(main)/network-simulation/page.tsx | 10 +- src/app/(main)/scada-data-cleaning/page.tsx | 8 +- src/app/_refine_context.tsx | 6 +- .../olmap/BurstLocation/LocationResults.tsx | 2 +- .../AnalysisParameters.tsx | 2 +- .../BurstPipeAnalysisPanel.tsx | 0 .../LocationResults.tsx | 2 +- .../SchemeQuery.tsx | 4 +- .../ValveIsolation.tsx | 2 +- .../types.ts | 0 .../AnalysisParameters.tsx | 2 +- .../ContaminantSimulation/SchemeQuery.tsx | 4 +- .../WaterQualityPanel.tsx | 2 +- .../DMALeakDetectionPanel.tsx | 4 +- .../FlushingAnalysis/AnalysisParameters.tsx | 2 +- .../olmap/FlushingAnalysis/SchemeQuery.tsx | 4 +- .../olmap/HealthRiskAnalysis/Timeline.tsx | 4 +- .../SchemeQuery.tsx | 2 +- .../ZonePropsPanel.tsx | 2 +- .../olmap/{ => SCADA}/SCADADataPanel.tsx | 0 .../olmap/{ => SCADA}/SCADADeviceList.tsx | 2 +- .../olmap/core}/Controls/BaseLayers.tsx | 0 .../olmap/core}/Controls/DrawPanel.tsx | 0 .../olmap/core}/Controls/HistoryDataPanel.tsx | 0 .../olmap/core}/Controls/LayerControl.tsx | 0 .../olmap/core}/Controls/PropertyPanel.tsx | 0 .../olmap/core}/Controls/ScaleLine.tsx | 0 .../olmap/core}/Controls/StyleEditorPanel.tsx | 0 .../olmap/core}/Controls/StyleLegend.tsx | 0 .../olmap/core}/Controls/Timeline.tsx | 0 .../olmap/core}/Controls/Toolbar.tsx | 0 .../olmap/core}/Controls/Zoom.tsx | 0 .../olmap/core}/MapComponent.tsx | 0 .../olmap/core}/MapTools.tsx | 0 src/utils/breaks_classification.js | 181 ------------------ src/utils/breaks_classification.ts | 136 +++++++++++++ src/utils/parseColor.js | 35 ---- src/utils/parseColor.test.js | 21 -- src/utils/parseColor.test.ts | 25 +++ src/utils/parseColor.ts | 31 +++ 52 files changed, 242 insertions(+), 345 deletions(-) delete mode 100644 package_back.json rename src/app/(main)/hydraulic-simulation/{pipe-burst-analysis => burst-simulation}/loading.tsx (100%) rename src/app/(main)/hydraulic-simulation/{pipe-burst-analysis => burst-simulation}/page.tsx (55%) rename src/app/(main)/hydraulic-simulation/{pipe-flushing => contaminant-simulation}/loading.tsx (100%) rename src/app/(main)/hydraulic-simulation/{water-quality-simulation => contaminant-simulation}/page.tsx (74%) rename src/app/(main)/hydraulic-simulation/{water-quality-simulation => flushing-analysis}/loading.tsx (100%) rename src/app/(main)/hydraulic-simulation/{pipe-flushing => flushing-analysis}/page.tsx (74%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/AnalysisParameters.tsx (99%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/BurstPipeAnalysisPanel.tsx (100%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/LocationResults.tsx (99%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/SchemeQuery.tsx (99%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/ValveIsolation.tsx (99%) rename src/components/olmap/{BurstPipeAnalysis => BurstSimulation}/types.ts (100%) rename src/components/olmap/{ => SCADA}/SCADADataPanel.tsx (100%) rename src/components/olmap/{ => SCADA}/SCADADeviceList.tsx (99%) rename src/{app/OlMap => components/olmap/core}/Controls/BaseLayers.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/DrawPanel.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/HistoryDataPanel.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/LayerControl.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/PropertyPanel.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/ScaleLine.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/StyleEditorPanel.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/StyleLegend.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/Timeline.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/Toolbar.tsx (100%) rename src/{app/OlMap => components/olmap/core}/Controls/Zoom.tsx (100%) rename src/{app/OlMap => components/olmap/core}/MapComponent.tsx (100%) rename src/{app/OlMap => components/olmap/core}/MapTools.tsx (100%) delete mode 100644 src/utils/breaks_classification.js create mode 100644 src/utils/breaks_classification.ts delete mode 100644 src/utils/parseColor.js delete mode 100644 src/utils/parseColor.test.js create mode 100644 src/utils/parseColor.test.ts create mode 100644 src/utils/parseColor.ts diff --git a/package_back.json b/package_back.json deleted file mode 100644 index 0a8c876..0000000 --- a/package_back.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "tjwater-app", - "version": "0.1.0", - "private": true, - "engines": { - "node": ">=20" - }, - "scripts": { - "dev": "cross-env NODE_OPTIONS=--max_old_space_size=4096 refine dev", - "build": "refine build", - "start": "refine start", - "lint": "next lint", - "refine": "refine" - }, - "dependencies": { - "@emotion/react": "^11.8.2", - "@emotion/styled": "^11.8.1", - "@mui/icons-material": "^6.1.6", - "@mui/lab": "^6.0.0-beta.14", - "@mui/material": "^6.1.7", - "@mui/x-data-grid": "^7.22.2", - "@refinedev/cli": "^2.16.48", - "@refinedev/core": "^5.0.0", - "@refinedev/devtools": "^2.0.1", - "@refinedev/kbar": "^2.0.0", - "@refinedev/mui": "^7.0.0", - "@refinedev/nextjs-router": "^7.0.0", - "@refinedev/react-hook-form": "^5.0.0", - "@refinedev/simple-rest": "^6.0.0", - "@tailwindcss/postcss": "^4.1.13", - "@turf/turf": "^7.2.0", - "clsx": "^2.1.1", - "deck.gl": "^9.1.14", - "js-cookie": "^3.0.5", - "next": "^15.2.4", - "next-auth": "^4.24.5", - "ol": "^10.6.1", - "postcss": "^8.5.6", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-icons": "^5.5.0", - "tailwindcss": "^4.1.13" - }, - "devDependencies": { - "@svgr/webpack": "^8.1.0", - "@types/js-cookie": "^3.0.6", - "@types/node": "^20", - "@types/react": "^19.1.0", - "@types/react-dom": "^19.1.0", - "cross-env": "^7.0.3", - "eslint": "^8", - "eslint-config-next": "^15.0.3", - "typescript": "^5.8.3" - }, - "refine": { - "projectId": "4LwOCL-BBaV29-qUYMAJ" - } -} diff --git a/src/app/(main)/health-risk-analysis/page.tsx b/src/app/(main)/health-risk-analysis/page.tsx index 67881f7..f6c014d 100644 --- a/src/app/(main)/health-risk-analysis/page.tsx +++ b/src/app/(main)/health-risk-analysis/page.tsx @@ -1,12 +1,12 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; +import MapComponent from "@components/olmap/core/MapComponent"; import Timeline from "@components/olmap/HealthRiskAnalysis/Timeline"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import { HealthRiskProvider } from "@components/olmap/HealthRiskAnalysis/HealthRiskContext"; import HealthRiskStatistics from "@components/olmap/HealthRiskAnalysis/HealthRiskStatistics"; import PredictDataPanel from "@components/olmap/HealthRiskAnalysis/PredictDataPanel"; -import StyleLegend from "@app/OlMap/Controls/StyleLegend"; +import StyleLegend from "@components/olmap/core/Controls/StyleLegend"; import { RAINBOW_COLORS, RISK_BREAKS, diff --git a/src/app/(main)/hydraulic-simulation/burst-location/page.tsx b/src/app/(main)/hydraulic-simulation/burst-location/page.tsx index f8e01cd..977ef8e 100644 --- a/src/app/(main)/hydraulic-simulation/burst-location/page.tsx +++ b/src/app/(main)/hydraulic-simulation/burst-location/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import BurstLocationPanel from "@/components/olmap/BurstLocation/BurstLocationPanel"; export default function Home() { diff --git a/src/app/(main)/hydraulic-simulation/pipe-burst-analysis/loading.tsx b/src/app/(main)/hydraulic-simulation/burst-simulation/loading.tsx similarity index 100% rename from src/app/(main)/hydraulic-simulation/pipe-burst-analysis/loading.tsx rename to src/app/(main)/hydraulic-simulation/burst-simulation/loading.tsx diff --git a/src/app/(main)/hydraulic-simulation/pipe-burst-analysis/page.tsx b/src/app/(main)/hydraulic-simulation/burst-simulation/page.tsx similarity index 55% rename from src/app/(main)/hydraulic-simulation/pipe-burst-analysis/page.tsx rename to src/app/(main)/hydraulic-simulation/burst-simulation/page.tsx index 0942860..8078cf7 100644 --- a/src/app/(main)/hydraulic-simulation/pipe-burst-analysis/page.tsx +++ b/src/app/(main)/hydraulic-simulation/burst-simulation/page.tsx @@ -1,8 +1,8 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; -import BurstPipeAnalysisPanel from "@/components/olmap/BurstPipeAnalysis/BurstPipeAnalysisPanel"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; +import BurstPipeAnalysisPanel from "@/components/olmap/BurstSimulation/BurstPipeAnalysisPanel"; export default function Home() { return ( diff --git a/src/app/(main)/hydraulic-simulation/pipe-flushing/loading.tsx b/src/app/(main)/hydraulic-simulation/contaminant-simulation/loading.tsx similarity index 100% rename from src/app/(main)/hydraulic-simulation/pipe-flushing/loading.tsx rename to src/app/(main)/hydraulic-simulation/contaminant-simulation/loading.tsx diff --git a/src/app/(main)/hydraulic-simulation/water-quality-simulation/page.tsx b/src/app/(main)/hydraulic-simulation/contaminant-simulation/page.tsx similarity index 74% rename from src/app/(main)/hydraulic-simulation/water-quality-simulation/page.tsx rename to src/app/(main)/hydraulic-simulation/contaminant-simulation/page.tsx index 6929b05..2c3d499 100644 --- a/src/app/(main)/hydraulic-simulation/water-quality-simulation/page.tsx +++ b/src/app/(main)/hydraulic-simulation/contaminant-simulation/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import WaterQualityPanel from "@/components/olmap/ContaminantSimulation/WaterQualityPanel"; export default function Home() { diff --git a/src/app/(main)/hydraulic-simulation/dma-leak-detection/page.tsx b/src/app/(main)/hydraulic-simulation/dma-leak-detection/page.tsx index fc90a12..68fc86a 100644 --- a/src/app/(main)/hydraulic-simulation/dma-leak-detection/page.tsx +++ b/src/app/(main)/hydraulic-simulation/dma-leak-detection/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import DMALeakDetectionPanel from "@/components/olmap/DMALeakDetection/DMALeakDetectionPanel"; export default function Home() { diff --git a/src/app/(main)/hydraulic-simulation/water-quality-simulation/loading.tsx b/src/app/(main)/hydraulic-simulation/flushing-analysis/loading.tsx similarity index 100% rename from src/app/(main)/hydraulic-simulation/water-quality-simulation/loading.tsx rename to src/app/(main)/hydraulic-simulation/flushing-analysis/loading.tsx diff --git a/src/app/(main)/hydraulic-simulation/pipe-flushing/page.tsx b/src/app/(main)/hydraulic-simulation/flushing-analysis/page.tsx similarity index 74% rename from src/app/(main)/hydraulic-simulation/pipe-flushing/page.tsx rename to src/app/(main)/hydraulic-simulation/flushing-analysis/page.tsx index a0dcf6e..05e45cb 100644 --- a/src/app/(main)/hydraulic-simulation/pipe-flushing/page.tsx +++ b/src/app/(main)/hydraulic-simulation/flushing-analysis/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import FlushingAnalysisPanel from "@/components/olmap/FlushingAnalysis/FlushingAnalysisPanel"; export default function Home() { diff --git a/src/app/(main)/monitoring-place-optimization/page.tsx b/src/app/(main)/monitoring-place-optimization/page.tsx index ef51c2c..8ce7202 100644 --- a/src/app/(main)/monitoring-place-optimization/page.tsx +++ b/src/app/(main)/monitoring-place-optimization/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import MonitoringPlaceOptimizationPanel from "@components/olmap/MonitoringPlaceOptimization/MonitoringPlaceOptimizationPanel"; export default function Home() { return ( diff --git a/src/app/(main)/network-partition-optimization/page.tsx b/src/app/(main)/network-partition-optimization/page.tsx index ddf0a80..07aa7aa 100644 --- a/src/app/(main)/network-partition-optimization/page.tsx +++ b/src/app/(main)/network-partition-optimization/page.tsx @@ -1,7 +1,7 @@ "use client"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; import ZonePropsPanel from "@components/olmap/NetworkPartitionOptimization/ZonePropsPanel"; export default function Home() { return ( diff --git a/src/app/(main)/network-simulation/page.tsx b/src/app/(main)/network-simulation/page.tsx index d454bea..18ec7c7 100644 --- a/src/app/(main)/network-simulation/page.tsx +++ b/src/app/(main)/network-simulation/page.tsx @@ -1,12 +1,12 @@ "use client"; import { useCallback, useState } from "react"; -import MapComponent from "@app/OlMap/MapComponent"; -import Timeline from "@app/OlMap/Controls/Timeline"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import Timeline from "@components/olmap/core/Controls/Timeline"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; -import SCADADeviceList from "@components/olmap/SCADADeviceList"; -import SCADADataPanel from "@components/olmap/SCADADataPanel"; +import SCADADeviceList from "@components/olmap/SCADA/SCADADeviceList"; +import SCADADataPanel from "@components/olmap/SCADA/SCADADataPanel"; export default function Home() { const [selectedDeviceIds, setSelectedDeviceIds] = useState([]); diff --git a/src/app/(main)/scada-data-cleaning/page.tsx b/src/app/(main)/scada-data-cleaning/page.tsx index 2258ee8..8458924 100644 --- a/src/app/(main)/scada-data-cleaning/page.tsx +++ b/src/app/(main)/scada-data-cleaning/page.tsx @@ -1,11 +1,11 @@ "use client"; import { useCallback, useState } from "react"; -import MapComponent from "@app/OlMap/MapComponent"; -import MapToolbar from "@app/OlMap/Controls/Toolbar"; +import MapComponent from "@components/olmap/core/MapComponent"; +import MapToolbar from "@components/olmap/core/Controls/Toolbar"; -import SCADADeviceList from "@components/olmap/SCADADeviceList"; -import SCADADataPanel from "@components/olmap/SCADADataPanel"; +import SCADADeviceList from "@components/olmap/SCADA/SCADADeviceList"; +import SCADADataPanel from "@components/olmap/SCADA/SCADADataPanel"; export default function Home() { const [selectedDeviceIds, setSelectedDeviceIds] = useState([]); diff --git a/src/app/_refine_context.tsx b/src/app/_refine_context.tsx index 4d75a3b..ecd54d9 100644 --- a/src/app/_refine_context.tsx +++ b/src/app/_refine_context.tsx @@ -177,7 +177,7 @@ const App = (props: React.PropsWithChildren) => { }, { name: "爆管模拟", - list: "/hydraulic-simulation/pipe-burst-analysis", + list: "/hydraulic-simulation/burst-simulation", meta: { parent: "Hydraulic Simulation", icon: , @@ -204,7 +204,7 @@ const App = (props: React.PropsWithChildren) => { }, { name: "水质模拟", - list: "/hydraulic-simulation/water-quality-simulation", + list: "/hydraulic-simulation/contaminant-simulation", meta: { parent: "Hydraulic Simulation", icon: , @@ -213,7 +213,7 @@ const App = (props: React.PropsWithChildren) => { }, { name: "管道冲洗", - list: "/hydraulic-simulation/pipe-flushing", + list: "/hydraulic-simulation/flushing-analysis", meta: { parent: "Hydraulic Simulation", icon: , diff --git a/src/components/olmap/BurstLocation/LocationResults.tsx b/src/components/olmap/BurstLocation/LocationResults.tsx index f344e86..d000c99 100644 --- a/src/components/olmap/BurstLocation/LocationResults.tsx +++ b/src/components/olmap/BurstLocation/LocationResults.tsx @@ -20,7 +20,7 @@ import { Map as MapIcon, } from "@mui/icons-material"; import dayjs from "dayjs"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; import { GeoJSON } from "ol/format"; import Feature from "ol/Feature"; diff --git a/src/components/olmap/BurstPipeAnalysis/AnalysisParameters.tsx b/src/components/olmap/BurstSimulation/AnalysisParameters.tsx similarity index 99% rename from src/components/olmap/BurstPipeAnalysis/AnalysisParameters.tsx rename to src/components/olmap/BurstSimulation/AnalysisParameters.tsx index 7e242c0..5482313 100644 --- a/src/components/olmap/BurstPipeAnalysis/AnalysisParameters.tsx +++ b/src/components/olmap/BurstSimulation/AnalysisParameters.tsx @@ -16,7 +16,7 @@ import { zhCN as pickerZhCN } from "@mui/x-date-pickers/locales"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import "dayjs/locale/zh-cn"; // 引入中文包 import dayjs, { Dayjs } from "dayjs"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Style, Stroke, Icon } from "ol/style"; diff --git a/src/components/olmap/BurstPipeAnalysis/BurstPipeAnalysisPanel.tsx b/src/components/olmap/BurstSimulation/BurstPipeAnalysisPanel.tsx similarity index 100% rename from src/components/olmap/BurstPipeAnalysis/BurstPipeAnalysisPanel.tsx rename to src/components/olmap/BurstSimulation/BurstPipeAnalysisPanel.tsx diff --git a/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx b/src/components/olmap/BurstSimulation/LocationResults.tsx similarity index 99% rename from src/components/olmap/BurstPipeAnalysis/LocationResults.tsx rename to src/components/olmap/BurstSimulation/LocationResults.tsx index 84f05f8..6f5efcf 100644 --- a/src/components/olmap/BurstPipeAnalysis/LocationResults.tsx +++ b/src/components/olmap/BurstSimulation/LocationResults.tsx @@ -13,7 +13,7 @@ import { LocationOn as LocationIcon, } from "@mui/icons-material"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; diff --git a/src/components/olmap/BurstPipeAnalysis/SchemeQuery.tsx b/src/components/olmap/BurstSimulation/SchemeQuery.tsx similarity index 99% rename from src/components/olmap/BurstPipeAnalysis/SchemeQuery.tsx rename to src/components/olmap/BurstSimulation/SchemeQuery.tsx index b1c5e6b..6256d16 100644 --- a/src/components/olmap/BurstPipeAnalysis/SchemeQuery.tsx +++ b/src/components/olmap/BurstSimulation/SchemeQuery.tsx @@ -32,7 +32,7 @@ import { config, NETWORK_NAME } from "@config/config"; import { useNotification } from "@refinedev/core"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; -import { useData, useMap } from "@app/OlMap/MapComponent"; +import { useData, useMap } from "@components/olmap/core/MapComponent"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; @@ -48,7 +48,7 @@ import { } from "@turf/turf"; import { Point } from "ol/geom"; import { toLonLat } from "ol/proj"; -import Timeline from "@app/OlMap/Controls/Timeline"; +import Timeline from "@components/olmap/core/Controls/Timeline"; import { SchemaItem, SchemeRecord } from "./types"; interface SchemeQueryProps { diff --git a/src/components/olmap/BurstPipeAnalysis/ValveIsolation.tsx b/src/components/olmap/BurstSimulation/ValveIsolation.tsx similarity index 99% rename from src/components/olmap/BurstPipeAnalysis/ValveIsolation.tsx rename to src/components/olmap/BurstSimulation/ValveIsolation.tsx index 7553bbc..def9331 100644 --- a/src/components/olmap/BurstPipeAnalysis/ValveIsolation.tsx +++ b/src/components/olmap/BurstSimulation/ValveIsolation.tsx @@ -35,7 +35,7 @@ import { queryFeaturesByIds, handleMapClickSelectFeatures, } from "@/utils/mapQueryService"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; diff --git a/src/components/olmap/BurstPipeAnalysis/types.ts b/src/components/olmap/BurstSimulation/types.ts similarity index 100% rename from src/components/olmap/BurstPipeAnalysis/types.ts rename to src/components/olmap/BurstSimulation/types.ts diff --git a/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx b/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx index ee58be3..8303e65 100644 --- a/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx +++ b/src/components/olmap/ContaminantSimulation/AnalysisParameters.tsx @@ -19,7 +19,7 @@ import dayjs, { Dayjs } from "dayjs"; import { useNotification } from "@refinedev/core"; import { api } from "@/lib/api"; import { config, NETWORK_NAME } from "@/config/config"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Style, Stroke, Fill, Circle as CircleStyle, Icon } from "ol/style"; diff --git a/src/components/olmap/ContaminantSimulation/SchemeQuery.tsx b/src/components/olmap/ContaminantSimulation/SchemeQuery.tsx index 21d29fd..ccef88d 100644 --- a/src/components/olmap/ContaminantSimulation/SchemeQuery.tsx +++ b/src/components/olmap/ContaminantSimulation/SchemeQuery.tsx @@ -30,14 +30,14 @@ import moment from "moment"; import { useNotification } from "@refinedev/core"; import { config, NETWORK_NAME } from "@config/config"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; -import { useData, useMap } from "@app/OlMap/MapComponent"; +import { useData, useMap } from "@components/olmap/core/MapComponent"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Style, Icon, Circle, Fill, Stroke } from "ol/style"; import Feature from "ol/Feature"; import { bbox, featureCollection } from "@turf/turf"; -import Timeline from "@app/OlMap/Controls/Timeline"; +import Timeline from "@components/olmap/core/Controls/Timeline"; import { ContaminantSchemaItem, ContaminantSchemeRecord } from "./types"; interface SchemeQueryProps { diff --git a/src/components/olmap/ContaminantSimulation/WaterQualityPanel.tsx b/src/components/olmap/ContaminantSimulation/WaterQualityPanel.tsx index 43c7023..d7ba9e4 100644 --- a/src/components/olmap/ContaminantSimulation/WaterQualityPanel.tsx +++ b/src/components/olmap/ContaminantSimulation/WaterQualityPanel.tsx @@ -19,7 +19,7 @@ import { } from "@mui/icons-material"; import ContaminantAnalysisParameters from "./AnalysisParameters"; import ContaminantSchemeQuery from "./SchemeQuery"; -import { useData } from "@app/OlMap/MapComponent"; +import { useData } from "@components/olmap/core/MapComponent"; interface WaterQualityPanelProps { open?: boolean; diff --git a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx index 24b9e4c..9dd5fd3 100644 --- a/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx +++ b/src/components/olmap/DMALeakDetection/DMALeakDetectionPanel.tsx @@ -21,8 +21,8 @@ import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile"; import VectorTileSource from "ol/source/VectorTile"; import { VectorTile } from "ol"; import { FlatStyleLike } from "ol/style/flat"; -import { useMap } from "@app/OlMap/MapComponent"; -import StyleLegend from "@app/OlMap/Controls/StyleLegend"; +import { useMap } from "@components/olmap/core/MapComponent"; +import StyleLegend from "@components/olmap/core/Controls/StyleLegend"; import AnalysisParameters from "./AnalysisParameters"; import SchemeQuery from "./SchemeQuery"; import RecognitionResults from "./RecognitionResults"; diff --git a/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx b/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx index 32e2f8f..40dbb9f 100644 --- a/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx +++ b/src/components/olmap/FlushingAnalysis/AnalysisParameters.tsx @@ -18,7 +18,7 @@ import { zhCN as pickerZhCN } from "@mui/x-date-pickers/locales"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import "dayjs/locale/zh-cn"; import dayjs, { Dayjs } from "dayjs"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import { Style, Stroke, Fill, Circle as CircleStyle } from "ol/style"; diff --git a/src/components/olmap/FlushingAnalysis/SchemeQuery.tsx b/src/components/olmap/FlushingAnalysis/SchemeQuery.tsx index 2d2d7f2..b37a35a 100644 --- a/src/components/olmap/FlushingAnalysis/SchemeQuery.tsx +++ b/src/components/olmap/FlushingAnalysis/SchemeQuery.tsx @@ -30,7 +30,7 @@ import { api } from "@/lib/api"; import moment from "moment"; import { config, NETWORK_NAME } from "@config/config"; import { useNotification } from "@refinedev/core"; -import { useData, useMap } from "@app/OlMap/MapComponent"; +import { useData, useMap } from "@components/olmap/core/MapComponent"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; @@ -38,7 +38,7 @@ import VectorSource from "ol/source/Vector"; import { Style, Icon, Circle, Fill, Stroke } from "ol/style"; import Feature, { FeatureLike } from "ol/Feature"; import { bbox, featureCollection } from "@turf/turf"; -import Timeline from "@app/OlMap/Controls/Timeline"; +import Timeline from "@components/olmap/core/Controls/Timeline"; import { SchemeRecord, SchemaItem } from "./types"; import { FLOW_DISPLAY_UNIT } from "@utils/units"; diff --git a/src/components/olmap/HealthRiskAnalysis/Timeline.tsx b/src/components/olmap/HealthRiskAnalysis/Timeline.tsx index 13ff443..8c4a561 100644 --- a/src/components/olmap/HealthRiskAnalysis/Timeline.tsx +++ b/src/components/olmap/HealthRiskAnalysis/Timeline.tsx @@ -27,10 +27,10 @@ import dayjs from "dayjs"; import { PlayArrow, Pause, Stop, Refresh } from "@mui/icons-material"; import { TbArrowBackUp, TbArrowForwardUp } from "react-icons/tb"; import { FiSkipBack, FiSkipForward } from "react-icons/fi"; -import { useData } from "../../../app/OlMap/MapComponent"; +import { useData } from "@components/olmap/core/MapComponent"; import { config, NETWORK_NAME } from "@/config/config"; import { apiFetch } from "@/lib/apiFetch"; -import { useMap } from "../../../app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { useHealthRisk } from "./HealthRiskContext"; import { PredictionResult, diff --git a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx index 25560d0..23198b4 100644 --- a/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx +++ b/src/components/olmap/MonitoringPlaceOptimization/SchemeQuery.tsx @@ -28,7 +28,7 @@ import { api } from "@/lib/api"; import moment from "moment"; import { config, NETWORK_NAME } from "@config/config"; import { useNotification } from "@refinedev/core"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { queryFeaturesByIds } from "@/utils/mapQueryService"; import { GeoJSON } from "ol/format"; import VectorLayer from "ol/layer/Vector"; diff --git a/src/components/olmap/NetworkPartitionOptimization/ZonePropsPanel.tsx b/src/components/olmap/NetworkPartitionOptimization/ZonePropsPanel.tsx index 6052313..32d43ab 100644 --- a/src/components/olmap/NetworkPartitionOptimization/ZonePropsPanel.tsx +++ b/src/components/olmap/NetworkPartitionOptimization/ZonePropsPanel.tsx @@ -6,7 +6,7 @@ import Fill from "ol/style/Fill"; import { Stroke } from "ol/style"; import GeoJson from "ol/format/GeoJSON"; import config from "@config/config"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { useProject } from "@/contexts/ProjectContext"; interface PropertyItem { diff --git a/src/components/olmap/SCADADataPanel.tsx b/src/components/olmap/SCADA/SCADADataPanel.tsx similarity index 100% rename from src/components/olmap/SCADADataPanel.tsx rename to src/components/olmap/SCADA/SCADADataPanel.tsx diff --git a/src/components/olmap/SCADADeviceList.tsx b/src/components/olmap/SCADA/SCADADeviceList.tsx similarity index 99% rename from src/components/olmap/SCADADeviceList.tsx rename to src/components/olmap/SCADA/SCADADeviceList.tsx index c8fdd1e..9626b1c 100644 --- a/src/components/olmap/SCADADeviceList.tsx +++ b/src/components/olmap/SCADA/SCADADeviceList.tsx @@ -52,7 +52,7 @@ import { api } from "@/lib/api"; import { useGetIdentity } from "@refinedev/core"; import config from "@/config/config"; -import { useMap } from "@app/OlMap/MapComponent"; +import { useMap } from "@components/olmap/core/MapComponent"; import { useProject } from "@/contexts/ProjectContext"; import { GeoJSON } from "ol/format"; import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService"; diff --git a/src/app/OlMap/Controls/BaseLayers.tsx b/src/components/olmap/core/Controls/BaseLayers.tsx similarity index 100% rename from src/app/OlMap/Controls/BaseLayers.tsx rename to src/components/olmap/core/Controls/BaseLayers.tsx diff --git a/src/app/OlMap/Controls/DrawPanel.tsx b/src/components/olmap/core/Controls/DrawPanel.tsx similarity index 100% rename from src/app/OlMap/Controls/DrawPanel.tsx rename to src/components/olmap/core/Controls/DrawPanel.tsx diff --git a/src/app/OlMap/Controls/HistoryDataPanel.tsx b/src/components/olmap/core/Controls/HistoryDataPanel.tsx similarity index 100% rename from src/app/OlMap/Controls/HistoryDataPanel.tsx rename to src/components/olmap/core/Controls/HistoryDataPanel.tsx diff --git a/src/app/OlMap/Controls/LayerControl.tsx b/src/components/olmap/core/Controls/LayerControl.tsx similarity index 100% rename from src/app/OlMap/Controls/LayerControl.tsx rename to src/components/olmap/core/Controls/LayerControl.tsx diff --git a/src/app/OlMap/Controls/PropertyPanel.tsx b/src/components/olmap/core/Controls/PropertyPanel.tsx similarity index 100% rename from src/app/OlMap/Controls/PropertyPanel.tsx rename to src/components/olmap/core/Controls/PropertyPanel.tsx diff --git a/src/app/OlMap/Controls/ScaleLine.tsx b/src/components/olmap/core/Controls/ScaleLine.tsx similarity index 100% rename from src/app/OlMap/Controls/ScaleLine.tsx rename to src/components/olmap/core/Controls/ScaleLine.tsx diff --git a/src/app/OlMap/Controls/StyleEditorPanel.tsx b/src/components/olmap/core/Controls/StyleEditorPanel.tsx similarity index 100% rename from src/app/OlMap/Controls/StyleEditorPanel.tsx rename to src/components/olmap/core/Controls/StyleEditorPanel.tsx diff --git a/src/app/OlMap/Controls/StyleLegend.tsx b/src/components/olmap/core/Controls/StyleLegend.tsx similarity index 100% rename from src/app/OlMap/Controls/StyleLegend.tsx rename to src/components/olmap/core/Controls/StyleLegend.tsx diff --git a/src/app/OlMap/Controls/Timeline.tsx b/src/components/olmap/core/Controls/Timeline.tsx similarity index 100% rename from src/app/OlMap/Controls/Timeline.tsx rename to src/components/olmap/core/Controls/Timeline.tsx diff --git a/src/app/OlMap/Controls/Toolbar.tsx b/src/components/olmap/core/Controls/Toolbar.tsx similarity index 100% rename from src/app/OlMap/Controls/Toolbar.tsx rename to src/components/olmap/core/Controls/Toolbar.tsx diff --git a/src/app/OlMap/Controls/Zoom.tsx b/src/components/olmap/core/Controls/Zoom.tsx similarity index 100% rename from src/app/OlMap/Controls/Zoom.tsx rename to src/components/olmap/core/Controls/Zoom.tsx diff --git a/src/app/OlMap/MapComponent.tsx b/src/components/olmap/core/MapComponent.tsx similarity index 100% rename from src/app/OlMap/MapComponent.tsx rename to src/components/olmap/core/MapComponent.tsx diff --git a/src/app/OlMap/MapTools.tsx b/src/components/olmap/core/MapTools.tsx similarity index 100% rename from src/app/OlMap/MapTools.tsx rename to src/components/olmap/core/MapTools.tsx diff --git a/src/utils/breaks_classification.js b/src/utils/breaks_classification.js deleted file mode 100644 index 5be3974..0000000 --- a/src/utils/breaks_classification.js +++ /dev/null @@ -1,181 +0,0 @@ -/** - * 优雅分段分类 - 类似QGIS的Pretty Breaks - * 生成"好看"、易读的断点数值 - * @param {number[]} data - 数据数组 - * @param {number} n_classes - 分类数量 - * @returns {number[]} 断点数组 - */ -function prettyBreaksClassification(data, n_classes) { - if (data.length === 0) return []; - - // const min_val = Math.min(...data); - // const max_val = Math.max(...data); - // const min_val = data.reduce((min, val) => Math.min(min, val), Infinity); - // 保证最小值不小于0 - const min_val = Math.max(data.reduce((min, val) => Math.min(min, val), Infinity), 0); - const max_val = data.reduce((max, val) => Math.max(max, val), -Infinity); - const data_range = max_val - min_val; - - // 计算基础间隔 - const raw_interval = data_range / n_classes; - - // 寻找"优雅"的间隔 - const magnitude = 10 ** Math.floor(Math.log10(raw_interval)); - const normalized = raw_interval / magnitude; - - // 选择最接近的优雅数字 - let nice_interval; - if (normalized <= 1) { - nice_interval = magnitude; - } else if (normalized <= 2) { - nice_interval = 2 * magnitude; - } else if (normalized <= 5) { - nice_interval = 5 * magnitude; - } else { - nice_interval = 10 * magnitude; - } - - // 计算优雅的起始点 - const nice_min = Math.floor(min_val / nice_interval) * nice_interval; - const nice_max = Math.ceil(max_val / nice_interval) * nice_interval; - - // 生成断点 - const breaks = []; - let current = nice_min; - while (current <= nice_max && breaks.length < n_classes + 1) { - breaks.push(current); - current += nice_interval; - } - - // 确保包含最大值 - if (breaks.length === 0 || breaks[breaks.length - 1] < max_val) { - breaks.push(nice_max); - } - - // 调整为n_classes个区间 - if (breaks.length > n_classes + 1) { - breaks.splice(n_classes + 1); - } - - return breaks; -} - -/** - * 计算类内方差 - * @param {number[]} data - 排序后的数据数组 - * @param {number} start - 起始索引 - * @param {number} end - 结束索引 - * @returns {number} 类内方差 - */ -function variance(data, start, end) { - if (start >= end) return 0; - const mean = data.slice(start, end + 1).reduce((a, b) => a + b, 0) / (end - start + 1); - return data.slice(start, end + 1).reduce((sum, val) => sum + (val - mean) ** 2, 0); -} - -/** - * Jenks自然断点分类算法 - * @param {number[]} data - 数据数组 - * @param {number} n_classes - 分类数量 - * @returns {number[]} 断点数组 - */ -function jenks_breaks_jenkspy(data, n_classes) { - if (data.length === 0) return []; - if (n_classes >= data.length) return data.slice().sort((a, b) => a - b); - - const sortedData = data.slice().sort((a, b) => a - b); - const n = sortedData.length; - const k = n_classes; - - // 初始化矩阵 - const lowerClassLimits = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); - const varianceCombinations = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); - - for (let i = 1; i <= n; i++) { - lowerClassLimits[i][1] = 1; - varianceCombinations[i][1] = variance(sortedData, 0, i - 1); - for (let j = 2; j <= k; j++) { - varianceCombinations[i][j] = Infinity; - } - } - - // 动态规划 - for (let l = 2; l <= k; l++) { - for (let m = l; m <= n; m++) { - for (let i = l - 1; i < m; i++) { - const v = varianceCombinations[i][l - 1] + variance(sortedData, i, m - 1); - if (v < varianceCombinations[m][l]) { - varianceCombinations[m][l] = v; - lowerClassLimits[m][l] = i; - } - } - } - } - - // 回溯找到断点 - const breaks = []; - let current = n; - for (let j = k; j >= 1; j--) { - breaks.unshift(sortedData[lowerClassLimits[current][j] - 1] || sortedData[0]); - current = lowerClassLimits[current][j]; - } - breaks.push(sortedData[n - 1]); - - return breaks; -} - -/** - * 使用分层采样优化的Jenks算法 - * 确保采样数据能代表原数据的分布 - * @param {number[]} data - 数据数组 - * @param {number} n_classes - 分类数量 - * @param {number} sample_size - 采样大小,默认10000 - * @returns {number[]} 断点数组 - */ -function jenks_with_stratified_sampling(data, n_classes, sample_size = 10000) { - if (data.length <= sample_size) { - return jenks_breaks_jenkspy(data, n_classes); - } - - // 对数据排序 - const sorted_data = data.slice().sort((a, b) => a - b); - - // 计算采样间隔 - const interval = sorted_data.length / sample_size; - - // 分层采样 - const sampled_data = []; - for (let i = 0; i < sample_size; i++) { - const index = Math.floor(i * interval); - if (index < sorted_data.length) { - sampled_data.push(sorted_data[index]); - } - } - - return jenks_breaks_jenkspy(sampled_data, n_classes); -} - -/** - * 根据指定的方法计算数据的分类断点。 - * @param {Array} data - 要分类的数值数据数组。 - * @param {number} segments - 要创建的段数或类别数。 - * @param {string} classificationMethod - 要使用的分类方法。支持的值:"pretty_breaks" 或 "jenks_optimized"。 - * @returns {Array} 分类的断点数组。如果数据为空或无效,则返回空数组。 - */ -function calculateClassification( - data, - segments, - classificationMethod -) { - if (!data || data.length === 0) { - return []; - } - if (classificationMethod === "pretty_breaks") { - return prettyBreaksClassification(data, segments); - } - if (classificationMethod === "jenks_optimized") { - return jenks_with_stratified_sampling(data, segments); - } -} - -module.exports = { prettyBreaksClassification, jenks_breaks_jenkspy, jenks_with_stratified_sampling, calculateClassification }; \ No newline at end of file diff --git a/src/utils/breaks_classification.ts b/src/utils/breaks_classification.ts new file mode 100644 index 0000000..ba98b6e --- /dev/null +++ b/src/utils/breaks_classification.ts @@ -0,0 +1,136 @@ +export function prettyBreaksClassification( + data: number[], + nClasses: number +): number[] { + if (data.length === 0) return []; + + const minVal = Math.max(data.reduce((min, val) => Math.min(min, val), Infinity), 0); + const maxVal = data.reduce((max, val) => Math.max(max, val), -Infinity); + const dataRange = maxVal - minVal; + const rawInterval = dataRange / nClasses; + + const magnitude = 10 ** Math.floor(Math.log10(rawInterval)); + const normalized = rawInterval / magnitude; + + let niceInterval: number; + if (normalized <= 1) { + niceInterval = magnitude; + } else if (normalized <= 2) { + niceInterval = 2 * magnitude; + } else if (normalized <= 5) { + niceInterval = 5 * magnitude; + } else { + niceInterval = 10 * magnitude; + } + + const niceMin = Math.floor(minVal / niceInterval) * niceInterval; + const niceMax = Math.ceil(maxVal / niceInterval) * niceInterval; + + const breaks: number[] = []; + let current = niceMin; + while (current <= niceMax && breaks.length < nClasses + 1) { + breaks.push(current); + current += niceInterval; + } + + if (breaks.length === 0 || breaks[breaks.length - 1] < maxVal) { + breaks.push(niceMax); + } + + if (breaks.length > nClasses + 1) { + breaks.splice(nClasses + 1); + } + + return breaks; +} + +function variance(data: number[], start: number, end: number): number { + if (start >= end) return 0; + const mean = data.slice(start, end + 1).reduce((a, b) => a + b, 0) / (end - start + 1); + return data.slice(start, end + 1).reduce((sum, val) => sum + (val - mean) ** 2, 0); +} + +export function jenks_breaks_jenkspy(data: number[], nClasses: number): number[] { + if (data.length === 0) return []; + if (nClasses >= data.length) return data.slice().sort((a, b) => a - b); + + const sortedData = data.slice().sort((a, b) => a - b); + const n = sortedData.length; + const k = nClasses; + + const lowerClassLimits = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); + const varianceCombinations = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); + + for (let i = 1; i <= n; i++) { + lowerClassLimits[i][1] = 1; + varianceCombinations[i][1] = variance(sortedData, 0, i - 1); + for (let j = 2; j <= k; j++) { + varianceCombinations[i][j] = Infinity; + } + } + + for (let l = 2; l <= k; l++) { + for (let m = l; m <= n; m++) { + for (let i = l - 1; i < m; i++) { + const v = varianceCombinations[i][l - 1] + variance(sortedData, i, m - 1); + if (v < varianceCombinations[m][l]) { + varianceCombinations[m][l] = v; + lowerClassLimits[m][l] = i; + } + } + } + } + + const breaks: number[] = []; + let current = n; + for (let j = k; j >= 1; j--) { + breaks.unshift(sortedData[lowerClassLimits[current][j] - 1] || sortedData[0]); + current = lowerClassLimits[current][j]; + } + breaks.push(sortedData[n - 1]); + + return breaks; +} + +export function jenks_with_stratified_sampling( + data: number[], + nClasses: number, + sampleSize = 10000 +): number[] { + if (data.length <= sampleSize) { + return jenks_breaks_jenkspy(data, nClasses); + } + + const sortedData = data.slice().sort((a, b) => a - b); + const interval = sortedData.length / sampleSize; + + const sampledData: number[] = []; + for (let i = 0; i < sampleSize; i++) { + const index = Math.floor(i * interval); + if (index < sortedData.length) { + sampledData.push(sortedData[index]); + } + } + + return jenks_breaks_jenkspy(sampledData, nClasses); +} + +export function calculateClassification( + data: number[], + segments: number, + classificationMethod: string +): number[] { + if (!data || data.length === 0) { + return []; + } + + if (classificationMethod === "pretty_breaks") { + return prettyBreaksClassification(data, segments); + } + + if (classificationMethod === "jenks_optimized") { + return jenks_with_stratified_sampling(data, segments); + } + + return []; +} diff --git a/src/utils/parseColor.js b/src/utils/parseColor.js deleted file mode 100644 index 89b0206..0000000 --- a/src/utils/parseColor.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * 将颜色字符串解析为包含红色、绿色、蓝色和 alpha 分量的对象。 - * 支持 rgba、rgb 和十六进制颜色格式。对于 rgba 和 rgb,提取 r、g、b 和 a(如果未提供,则默认为 1)。 - * 对于十六进制(例如 #RRGGBB),提取 r、g、b。(e.g., "rgba(255, 0, 0, 0.5)", "rgb(255, 0, 0)", or "#FF0000"). - * @param {string} color - 要解析的颜色字符串(例如 "rgba(255, 0, 0, 0.5)"、"rgb(255, 0, 0)" 或 "#FF0000")。 - * @returns {{r: number, g: number, b: number, a?: number}} 包含颜色分量的对象: - * - r: 红色分量 (0-255) - * - g: 绿色分量 (0-255) - * - b: 蓝色分量 (0-255) - * - a: Alpha 分量 (0-1),如果未指定则默认为 1 - **/ -function parseColor(color) { - // 解析 rgba 格式的颜色 - const match = color.match( - /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/ - ); - if (match) { - return { - r: parseInt(match[1], 10), - g: parseInt(match[2], 10), - b: parseInt(match[3], 10), - // 如果没有 alpha 值,默认为 1 - a: match[4] ? parseFloat(match[4]) : 1, - }; - } - // 如果还是十六进制格式,保持原来的解析方式 - const hex = color.replace("#", ""); - return { - r: parseInt(hex.slice(0, 2), 16), - g: parseInt(hex.slice(2, 4), 16), - b: parseInt(hex.slice(4, 6), 16), - }; -} - -module.exports = { parseColor }; \ No newline at end of file diff --git a/src/utils/parseColor.test.js b/src/utils/parseColor.test.js deleted file mode 100644 index 3d95a87..0000000 --- a/src/utils/parseColor.test.js +++ /dev/null @@ -1,21 +0,0 @@ -const { parseColor } = require('./parseColor'); - -describe('parseColor', () => { - it('should parse hex color', () => { - expect(parseColor('#FF0000')).toEqual({ r: 255, g: 0, b: 0 }); - expect(parseColor('00FF00')).toEqual({ r: 0, g: 255, b: 0 }); - }); - - it('should parse rgb color', () => { - expect(parseColor('rgb(0, 0, 255)')).toEqual({ r: 0, g: 0, b: 255, a: 1 }); - }); - - it('should parse rgba color', () => { - expect(parseColor('rgba(0, 0, 255, 0.5)')).toEqual({ r: 0, g: 0, b: 255, a: 0.5 }); - }); - - it('should default alpha to 1 if not provided in rgba-like pattern', () => { - // The regex supports optional alpha - expect(parseColor('rgba(0, 0, 255)')).toEqual({ r: 0, g: 0, b: 255, a: 1 }); - }); -}); diff --git a/src/utils/parseColor.test.ts b/src/utils/parseColor.test.ts new file mode 100644 index 0000000..09b4b10 --- /dev/null +++ b/src/utils/parseColor.test.ts @@ -0,0 +1,25 @@ +import { parseColor } from "./parseColor"; + +describe("parseColor", () => { + it("should parse hex color", () => { + expect(parseColor("#FF0000")).toEqual({ r: 255, g: 0, b: 0 }); + expect(parseColor("00FF00")).toEqual({ r: 0, g: 255, b: 0 }); + }); + + it("should parse rgb color", () => { + expect(parseColor("rgb(0, 0, 255)")).toEqual({ r: 0, g: 0, b: 255, a: 1 }); + }); + + it("should parse rgba color", () => { + expect(parseColor("rgba(0, 0, 255, 0.5)")).toEqual({ + r: 0, + g: 0, + b: 255, + a: 0.5, + }); + }); + + it("should default alpha to 1 if not provided in rgba-like pattern", () => { + expect(parseColor("rgba(0, 0, 255)")).toEqual({ r: 0, g: 0, b: 255, a: 1 }); + }); +}); diff --git a/src/utils/parseColor.ts b/src/utils/parseColor.ts new file mode 100644 index 0000000..cecc343 --- /dev/null +++ b/src/utils/parseColor.ts @@ -0,0 +1,31 @@ +export interface ParsedColor { + r: number; + g: number; + b: number; + a?: number; +} + +/** + * 将颜色字符串解析为包含红色、绿色、蓝色和 alpha 分量的对象。 + */ +export function parseColor(color: string): ParsedColor { + const match = color.match( + /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/ + ); + + if (match) { + return { + r: parseInt(match[1], 10), + g: parseInt(match[2], 10), + b: parseInt(match[3], 10), + a: match[4] ? parseFloat(match[4]) : 1, + }; + } + + const hex = color.replace("#", ""); + return { + r: parseInt(hex.slice(0, 2), 16), + g: parseInt(hex.slice(2, 4), 16), + b: parseInt(hex.slice(4, 6), 16), + }; +}