@metastringfoundation/map-list 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Handler/MapComparisonControl.d.ts +7 -0
- package/dist/components/Handler/MapComparisonControl.d.ts.map +1 -0
- package/dist/components/Handler/MapComparisonControl.js +8 -0
- package/dist/components/core/button.js +1 -1
- package/dist/components/core/input.d.ts.map +1 -1
- package/dist/components/core/input.js +1 -1
- package/dist/components/dualMap/MapLayerCard.d.ts +8 -0
- package/dist/components/dualMap/MapLayerCard.d.ts.map +1 -0
- package/dist/components/dualMap/MapLayerCard.js +68 -0
- package/dist/components/dualMap/index.d.ts +2 -1
- package/dist/components/dualMap/index.d.ts.map +1 -1
- package/dist/components/dualMap/index.js +219 -56
- package/dist/components/map/compare-sidebar.d.ts +2 -0
- package/dist/components/map/compare-sidebar.d.ts.map +1 -0
- package/dist/components/map/compare-sidebar.js +34 -0
- package/dist/components/map/compare.d.ts +2 -0
- package/dist/components/map/compare.d.ts.map +1 -0
- package/dist/components/map/compare.js +42 -0
- package/dist/components/map/index.d.ts.map +1 -1
- package/dist/components/map/index.js +14 -1
- package/dist/components/map/layers/grid/index.d.ts.map +1 -1
- package/dist/components/map/layers/grid/index.js +11 -1
- package/dist/components/map/layers/index.d.ts.map +1 -1
- package/dist/components/map/layers/index.js +0 -1
- package/dist/components/map/layers/raster/index.d.ts.map +1 -1
- package/dist/components/map/layers/raster/index.js +5 -3
- package/dist/components/map/layers/vector/index.d.ts.map +1 -1
- package/dist/components/map/layers/vector/index.js +25 -2
- package/dist/components/map/search.d.ts +2 -0
- package/dist/components/map/search.d.ts.map +1 -0
- package/dist/components/map/search.js +122 -0
- package/dist/components/map-comparison/attribute-selector.d.ts +11 -0
- package/dist/components/map-comparison/attribute-selector.d.ts.map +1 -0
- package/dist/components/map-comparison/attribute-selector.js +10 -0
- package/dist/components/map-comparison/comparison-panel.d.ts +2 -0
- package/dist/components/map-comparison/comparison-panel.d.ts.map +1 -0
- package/dist/components/map-comparison/comparison-panel.js +45 -0
- package/dist/components/map-comparison/comparison-stats.d.ts +2 -0
- package/dist/components/map-comparison/comparison-stats.d.ts.map +1 -0
- package/dist/components/map-comparison/comparison-stats.js +35 -0
- package/dist/components/map-comparison/comparison-view.d.ts +2 -0
- package/dist/components/map-comparison/comparison-view.d.ts.map +1 -0
- package/dist/components/map-comparison/comparison-view.js +152 -0
- package/dist/components/map-comparison/comparison-wrapper.d.ts +8 -0
- package/dist/components/map-comparison/comparison-wrapper.d.ts.map +1 -0
- package/dist/components/map-comparison/comparison-wrapper.js +26 -0
- package/dist/components/map-comparison/index.d.ts +3 -0
- package/dist/components/map-comparison/index.d.ts.map +1 -0
- package/dist/components/map-comparison/index.js +165 -0
- package/dist/components/map-comparison/types.d.ts +30 -0
- package/dist/components/map-comparison/types.d.ts.map +1 -0
- package/dist/components/map-comparison/types.js +2 -0
- package/dist/components/map-comparison/use-map-comparison.d.ts +18 -0
- package/dist/components/map-comparison/use-map-comparison.d.ts.map +1 -0
- package/dist/components/map-comparison/use-map-comparison.js +139 -0
- package/dist/components/sidebar/common/attribute-compare-addon.d.ts +7 -0
- package/dist/components/sidebar/common/attribute-compare-addon.d.ts.map +1 -0
- package/dist/components/sidebar/common/attribute-compare-addon.js +36 -0
- package/dist/components/sidebar/common/layer-item-style.d.ts.map +1 -1
- package/dist/components/sidebar/common/layer-item-style.js +46 -1
- package/dist/components/sidebar/common/layer-item.d.ts.map +1 -1
- package/dist/components/sidebar/common/layer-item.js +1 -2
- package/dist/components/sidebar/common/opacity-handler-addon.d.ts +5 -2
- package/dist/components/sidebar/common/opacity-handler-addon.d.ts.map +1 -1
- package/dist/components/sidebar/common/opacity-handler-addon.js +101 -4
- package/dist/components/sidebar/common/style-legend.d.ts.map +1 -1
- package/dist/components/sidebar/common/style-legend.js +1 -2
- package/dist/components/sidebar/comparison/index.d.ts +4 -0
- package/dist/components/sidebar/comparison/index.d.ts.map +1 -0
- package/dist/components/sidebar/comparison/index.js +34 -0
- package/dist/components/sidebar/search/attribute-comparison.d.ts +10 -0
- package/dist/components/sidebar/search/attribute-comparison.d.ts.map +1 -0
- package/dist/components/sidebar/search/attribute-comparison.js +137 -0
- package/dist/components/sidebar/search/index.d.ts +2 -0
- package/dist/components/sidebar/search/index.d.ts.map +1 -0
- package/dist/components/sidebar/search/index.js +29 -0
- package/dist/components/sidebar/selected/index.d.ts.map +1 -1
- package/dist/components/sidebar/selected/index.js +4 -1
- package/dist/components/sidebar/tabs.js +2 -2
- package/dist/hooks/use-layers.d.ts +8 -0
- package/dist/hooks/use-layers.d.ts.map +1 -1
- package/dist/hooks/use-layers.js +101 -1
- package/dist/hooks/use-polygon-data.d.ts +34 -0
- package/dist/hooks/use-polygon-data.d.ts.map +1 -0
- package/dist/hooks/use-polygon-data.js +74 -0
- package/dist/index.css +659 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -36
- package/dist/services/naksha.d.ts.map +1 -1
- package/dist/services/naksha.js +16 -158
- package/dist/services/polygon.d.ts +36 -0
- package/dist/services/polygon.d.ts.map +1 -0
- package/dist/services/polygon.js +67 -0
- package/dist/utils/naksha.d.ts.map +1 -1
- package/dist/utils/naksha.js +4 -2
- package/package.json +16 -15
|
@@ -1,9 +1,106 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
7
|
const react_1 = require("react");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
const use_layers_1 = __importDefault(require("../../../hooks/use-layers"));
|
|
9
|
+
const OpacityHandler = ({ layerId }) => {
|
|
10
|
+
const { layer } = (0, use_layers_1.default)();
|
|
11
|
+
const contextOpacity = layer.getLayerOpacity(layerId);
|
|
12
|
+
// Local state for smooth slider interaction
|
|
13
|
+
const [localOpacity, setLocalOpacity] = (0, react_1.useState)(contextOpacity);
|
|
14
|
+
const isDraggingRef = (0, react_1.useRef)(false);
|
|
15
|
+
const rafRef = (0, react_1.useRef)(null);
|
|
16
|
+
// Sync local state with context when context changes externally (not during drag)
|
|
17
|
+
(0, react_1.useEffect)(() => {
|
|
18
|
+
if (!isDraggingRef.current) {
|
|
19
|
+
setLocalOpacity(contextOpacity);
|
|
20
|
+
}
|
|
21
|
+
}, [contextOpacity]);
|
|
22
|
+
// Use requestAnimationFrame for smooth updates
|
|
23
|
+
const updateOpacity = (0, react_1.useCallback)((value) => {
|
|
24
|
+
if (rafRef.current !== null) {
|
|
25
|
+
cancelAnimationFrame(rafRef.current);
|
|
26
|
+
}
|
|
27
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
28
|
+
layer.setLayerOpacity(layerId, value);
|
|
29
|
+
});
|
|
30
|
+
}, [layer, layerId]);
|
|
31
|
+
const handleInput = (e) => {
|
|
32
|
+
const value = Number(e.target.value);
|
|
33
|
+
setLocalOpacity(value);
|
|
34
|
+
isDraggingRef.current = true;
|
|
35
|
+
updateOpacity(value);
|
|
36
|
+
};
|
|
37
|
+
const handleMouseUp = () => {
|
|
38
|
+
// Ensure final value is set
|
|
39
|
+
if (rafRef.current !== null) {
|
|
40
|
+
cancelAnimationFrame(rafRef.current);
|
|
41
|
+
}
|
|
42
|
+
layer.setLayerOpacity(layerId, localOpacity);
|
|
43
|
+
isDraggingRef.current = false;
|
|
44
|
+
};
|
|
45
|
+
// Cleanup on unmount
|
|
46
|
+
(0, react_1.useEffect)(() => {
|
|
47
|
+
return () => {
|
|
48
|
+
if (rafRef.current !== null) {
|
|
49
|
+
cancelAnimationFrame(rafRef.current);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}, []);
|
|
53
|
+
const percentage = Math.round(localOpacity * 100);
|
|
54
|
+
const opacityPercent = localOpacity * 100;
|
|
55
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 w-full", children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1 h-6 flex items-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 h-2 rounded-lg pointer-events-none", style: {
|
|
56
|
+
background: `linear-gradient(to right, #3b82f6 0%, #3b82f6 ${opacityPercent}%, #e5e7eb ${opacityPercent}%, #e5e7eb 100%)`,
|
|
57
|
+
} }), (0, jsx_runtime_1.jsx)("input", { id: `opacity-slider-${layerId}`, type: "range", min: "0", max: "1", step: "0.01", value: localOpacity, onInput: handleInput, onChange: handleInput, onMouseUp: handleMouseUp, onTouchEnd: handleMouseUp, className: "relative w-full h-2 bg-transparent appearance-none cursor-pointer opacity-slider-input" })] }), (0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: {
|
|
58
|
+
__html: `
|
|
59
|
+
.opacity-slider-input::-webkit-slider-thumb {
|
|
60
|
+
appearance: none;
|
|
61
|
+
width: 18px;
|
|
62
|
+
height: 18px;
|
|
63
|
+
border-radius: 50%;
|
|
64
|
+
background: #3b82f6;
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
border: 2px solid white;
|
|
67
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
68
|
+
margin-top: -5px;
|
|
69
|
+
}
|
|
70
|
+
.opacity-slider-input::-webkit-slider-thumb:hover {
|
|
71
|
+
transform: scale(1.1);
|
|
72
|
+
}
|
|
73
|
+
.opacity-slider-input::-webkit-slider-thumb:active {
|
|
74
|
+
transform: scale(1.2);
|
|
75
|
+
cursor: grabbing;
|
|
76
|
+
}
|
|
77
|
+
.opacity-slider-input::-webkit-slider-runnable-track {
|
|
78
|
+
height: 8px;
|
|
79
|
+
border-radius: 4px;
|
|
80
|
+
background: transparent;
|
|
81
|
+
}
|
|
82
|
+
.opacity-slider-input::-moz-range-thumb {
|
|
83
|
+
width: 18px;
|
|
84
|
+
height: 18px;
|
|
85
|
+
border-radius: 50%;
|
|
86
|
+
background: #3b82f6;
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
border: 2px solid white;
|
|
89
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
90
|
+
}
|
|
91
|
+
.opacity-slider-input::-moz-range-thumb:hover {
|
|
92
|
+
transform: scale(1.1);
|
|
93
|
+
}
|
|
94
|
+
.opacity-slider-input::-moz-range-thumb:active {
|
|
95
|
+
transform: scale(1.2);
|
|
96
|
+
cursor: grabbing;
|
|
97
|
+
}
|
|
98
|
+
.opacity-slider-input::-moz-range-track {
|
|
99
|
+
height: 8px;
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
background: transparent;
|
|
102
|
+
}
|
|
103
|
+
`
|
|
104
|
+
} })] }));
|
|
8
105
|
};
|
|
9
|
-
exports.default =
|
|
106
|
+
exports.default = OpacityHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style-legend.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/common/style-legend.tsx"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE;;CAAA,
|
|
1
|
+
{"version":3,"file":"style-legend.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/common/style-legend.tsx"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE;;CAAA,2CA2CnC"}
|
|
@@ -11,7 +11,6 @@ const use_layers_1 = __importDefault(require("../../../hooks/use-layers"));
|
|
|
11
11
|
function StyleLegend({ item }) {
|
|
12
12
|
const [showImage, setShowImage] = (0, react_1.useState)(true);
|
|
13
13
|
const { mp } = (0, use_layers_1.default)();
|
|
14
|
-
const { t } = useT();
|
|
15
14
|
const legendStyles = (0, react_1.useMemo)(() => item?.data?.styles?.[item.data.styleIndex]?.colors?.paint?.["fill-color"]
|
|
16
15
|
?.stops ||
|
|
17
16
|
item?.data?.styles?.[item.data.styleIndex]?.colors?.paint?.["circle-color"]?.stops ||
|
|
@@ -19,5 +18,5 @@ function StyleLegend({ item }) {
|
|
|
19
18
|
const vectorLegend = () => {
|
|
20
19
|
return legendStyles.map(([title, color]) => ((0, jsx_runtime_1.jsxs)("li", { className: "flex gap-2 items-center mb-1", children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 24 24", height: "14", width: "14", focusable: "false", children: (0, jsx_runtime_1.jsx)("circle", { cx: "12", fill: color, cy: "12", r: "12", stroke: "none" }) }), (0, jsx_runtime_1.jsx)("div", { children: title })] }, color)));
|
|
21
20
|
};
|
|
22
|
-
return ((0, jsx_runtime_1.jsx)("ul", { style: { margin: 0, padding: 0 }, children: item.layerType !== "RASTER" ? (vectorLegend()) : showImage ? ((0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("img", { style: { margin: "5px" }, onError: () => setShowImage(false), src: `${mp?.geoserver?.endpoint}/wms?REQUEST=GetLegendGraphic&VERSION=1.0.0&WIDTH=20&HEIGHT=20&STRICT=false&layer=biodiv:${item.id}` }) })) : ((0, jsx_runtime_1.jsx)("div", { children:
|
|
21
|
+
return ((0, jsx_runtime_1.jsx)("ul", { style: { margin: 0, padding: 0 }, children: item.layerType !== "RASTER" ? (vectorLegend()) : showImage ? ((0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("img", { style: { margin: "5px" }, onError: () => setShowImage(false), src: `${mp?.geoserver?.endpoint}/wms?REQUEST=GetLegendGraphic&VERSION=1.0.0&WIDTH=20&HEIGHT=20&STRICT=false&layer=biodiv:${item.id}` }) })) : ((0, jsx_runtime_1.jsx)("div", { children: ("raster_style_not_found") })) }));
|
|
23
22
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/comparison/index.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,kDAoE9E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = ComparisonSidebar;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const use_layers_1 = __importDefault(require("../../../hooks/use-layers"));
|
|
9
|
+
const core_1 = require("../../core");
|
|
10
|
+
function ComparisonSidebar({ onClose }) {
|
|
11
|
+
const { layer } = (0, use_layers_1.default)();
|
|
12
|
+
const compareList = layer?.compareList || [];
|
|
13
|
+
const handleRemoveFromComparison = (id) => {
|
|
14
|
+
layer.setCompareLayer(id, false);
|
|
15
|
+
};
|
|
16
|
+
const handleClearAll = () => {
|
|
17
|
+
compareList.forEach((id) => {
|
|
18
|
+
layer.setCompareLayer(id, false);
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
// Don't show if no layers in comparison
|
|
22
|
+
if (compareList.length === 0) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "absolute md:left-4 md:bottom-4 md:max-w-sm w-full z-20 bg-white rounded-lg shadow-md overflow-hidden", style: {
|
|
26
|
+
maxHeight: "40vh",
|
|
27
|
+
height: "auto"
|
|
28
|
+
}, children: [onClose && (0, jsx_runtime_1.jsx)(core_1.CloseButton, { onClick: onClose }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", style: { maxHeight: "40vh" }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between p-4 border-b shrink-0", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-lg font-semibold text-gray-800", children: ["Comparing ", compareList.length, " ", compareList.length === 1 ? "layer" : "layers"] }), (0, jsx_runtime_1.jsx)(core_1.Button, { onClick: handleClearAll, className: "text-sm", children: "Clear All" })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto", children: (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-2 p-4", children: compareList.map((id) => {
|
|
29
|
+
const layerItem = layer.all.find((l) => l.id === id);
|
|
30
|
+
if (!layerItem)
|
|
31
|
+
return null;
|
|
32
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between p-3 bg-gray-50 rounded-md border border-gray-200 hover:bg-gray-100 transition-colors", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-medium text-gray-800", children: layerItem.title || layerItem.id }), layerItem.description && ((0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 mt-1", children: layerItem.description }))] }), (0, jsx_runtime_1.jsx)(core_1.Button, { onClick: () => handleRemoveFromComparison(id), className: "ml-2 text-red-600 hover:text-red-700", children: "Remove" })] }, id));
|
|
33
|
+
}) }) })] })] }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface AttributeComparisonProps {
|
|
2
|
+
attributeKey?: string;
|
|
3
|
+
clickedLngLat?: {
|
|
4
|
+
lng: number;
|
|
5
|
+
lat: number;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export default function AttributeComparison({ attributeKey: initialAttributeKey, clickedLngLat, }: AttributeComparisonProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=attribute-comparison.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribute-comparison.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/search/attribute-comparison.tsx"],"names":[],"mappings":"AAIA,UAAU,wBAAwB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,YAAY,EAAE,mBAA0B,EACxC,aAAa,GACd,EAAE,wBAAwB,2CAwT1B"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = AttributeComparison;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const use_layers_1 = __importDefault(require("../../../hooks/use-layers"));
|
|
10
|
+
const naksha_1 = require("../../../services/naksha");
|
|
11
|
+
function AttributeComparison({ attributeKey: initialAttributeKey = "-2", clickedLngLat, }) {
|
|
12
|
+
const { layer, mp, query } = (0, use_layers_1.default)();
|
|
13
|
+
const [attributeKey, setAttributeKey] = (0, react_1.useState)(initialAttributeKey);
|
|
14
|
+
const [comparisonData, setComparisonData] = (0, react_1.useState)([]);
|
|
15
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
16
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
17
|
+
const compareLayers = (0, react_1.useMemo)(() => {
|
|
18
|
+
if (!layer.compareList || layer.compareList.length === 0) {
|
|
19
|
+
return layer.selectedLayers || [];
|
|
20
|
+
}
|
|
21
|
+
return (layer.selectedLayers?.filter((l) => layer.compareList.includes(l.id)) ||
|
|
22
|
+
[]);
|
|
23
|
+
}, [layer.compareList, layer.selectedLayers]);
|
|
24
|
+
const fetchAttributeData = async () => {
|
|
25
|
+
if (compareLayers.length < 2) {
|
|
26
|
+
setComparisonData([]);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
setLoading(true);
|
|
30
|
+
setError(null);
|
|
31
|
+
try {
|
|
32
|
+
const lngLat = clickedLngLat || query.clickedLngLat;
|
|
33
|
+
if (!lngLat) {
|
|
34
|
+
setError("Please click on the map to select a location");
|
|
35
|
+
setLoading(false);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const dataPromises = compareLayers.map(async (currentLayer) => {
|
|
39
|
+
let attributeValue = null;
|
|
40
|
+
let allProperties = [];
|
|
41
|
+
try {
|
|
42
|
+
if (currentLayer.layerType?.toLowerCase() === "raster") {
|
|
43
|
+
const { data } = await (0, naksha_1.axGexGetRasterInfoWithLonLat)(mp.geoserver?.endpoint, mp.geoserver?.workspace, {
|
|
44
|
+
bbox: `${lngLat.lng},${lngLat.lat},${lngLat.lng},${lngLat.lat}`,
|
|
45
|
+
query_layers: `${mp.geoserver?.workspace}:${currentLayer.id}`,
|
|
46
|
+
layers: `${mp.geoserver?.workspace}:${currentLayer.id}`,
|
|
47
|
+
});
|
|
48
|
+
if (data?.features?.[0]?.properties) {
|
|
49
|
+
const props = data.features[0].properties;
|
|
50
|
+
allProperties = Object.entries(props).map(([k, v]) => [k, v]);
|
|
51
|
+
// Try multiple strategies to find the attribute
|
|
52
|
+
// 1. Direct key match
|
|
53
|
+
if (props[attributeKey] !== undefined) {
|
|
54
|
+
attributeValue = props[attributeKey];
|
|
55
|
+
}
|
|
56
|
+
// 2. Try numeric index if attributeKey is "-2"
|
|
57
|
+
else if (attributeKey === "-2") {
|
|
58
|
+
const propKeys = Object.keys(props);
|
|
59
|
+
const index = propKeys.length - 2; // -2 means second from last
|
|
60
|
+
if (index >= 0 && index < propKeys.length) {
|
|
61
|
+
attributeValue = props[propKeys[index]];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// 3. Try to find by value match (case-insensitive)
|
|
65
|
+
else {
|
|
66
|
+
const foundKey = Object.keys(props).find((k) => k.toLowerCase() === attributeKey.toLowerCase());
|
|
67
|
+
if (foundKey) {
|
|
68
|
+
attributeValue = props[foundKey];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Vector layer
|
|
75
|
+
const propertyMap = currentLayer?.data?.propertyMap || {};
|
|
76
|
+
allProperties = Object.entries(propertyMap).map(([k, v]) => [
|
|
77
|
+
v,
|
|
78
|
+
null, // Value will be fetched from clicked feature
|
|
79
|
+
]);
|
|
80
|
+
// Try multiple strategies to find the attribute
|
|
81
|
+
// 1. Direct key match in propertyMap values
|
|
82
|
+
let propertyKey = Object.keys(propertyMap).find((k) => propertyMap[k] === attributeKey);
|
|
83
|
+
// 2. Direct key match in propertyMap keys
|
|
84
|
+
if (!propertyKey && propertyMap[attributeKey]) {
|
|
85
|
+
propertyKey = attributeKey;
|
|
86
|
+
}
|
|
87
|
+
// 3. Try numeric index if attributeKey is "-2"
|
|
88
|
+
if (!propertyKey && attributeKey === "-2") {
|
|
89
|
+
const propertyKeys = Object.keys(propertyMap);
|
|
90
|
+
const index = propertyKeys.length - 2; // -2 means second from last
|
|
91
|
+
if (index >= 0 && index < propertyKeys.length) {
|
|
92
|
+
propertyKey = propertyKeys[index];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (propertyKey && layer.selectedFeatures) {
|
|
96
|
+
const feature = layer.selectedFeatures.find((f) => f.sourceLayer === currentLayer.id);
|
|
97
|
+
if (feature?.properties?.[propertyKey] !== undefined) {
|
|
98
|
+
attributeValue = feature.properties[propertyKey];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error(`Error fetching data for layer ${currentLayer.id}:`, err);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
layerId: currentLayer.id,
|
|
108
|
+
layerTitle: currentLayer.title,
|
|
109
|
+
attributeValue,
|
|
110
|
+
allProperties,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
const results = await Promise.all(dataPromises);
|
|
114
|
+
setComparisonData(results);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
setError(err.message || "Failed to fetch comparison data");
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
setLoading(false);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
(0, react_1.useEffect)(() => {
|
|
124
|
+
if (compareLayers.length >= 2 && (clickedLngLat || query.clickedLngLat)) {
|
|
125
|
+
fetchAttributeData();
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
setComparisonData([]);
|
|
129
|
+
}
|
|
130
|
+
}, [compareLayers, clickedLngLat, query.clickedLngLat, attributeKey]);
|
|
131
|
+
if (compareLayers.length < 2) {
|
|
132
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "w-full p-4 flex flex-col gap-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center py-8 text-gray-500", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-lg font-semibold mb-2", children: "No Layers Selected for Comparison" }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm", children: "Select at least 2 layers and enable comparison mode to compare attributes" })] }) }));
|
|
133
|
+
}
|
|
134
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full p-4 flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-3 mb-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-gray-800", children: "Attribute Comparison" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-sm text-gray-600 whitespace-nowrap", children: "Attribute Key:" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: attributeKey, onChange: (e) => setAttributeKey(e.target.value), className: "flex-1 px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent font-mono", placeholder: "e.g., -2, name, id" })] })] }), loading && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center py-8", children: [(0, jsx_runtime_1.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }), (0, jsx_runtime_1.jsx)("span", { className: "ml-3 text-gray-600", children: "Loading comparison data..." })] })), error && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 text-red-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold mb-1", children: "Error" }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm", children: error })] })), !loading && !error && comparisonData.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm", children: (0, jsx_runtime_1.jsx)("div", { className: "overflow-x-auto", children: (0, jsx_runtime_1.jsxs)("table", { className: "w-full", children: [(0, jsx_runtime_1.jsx)("thead", { className: "bg-gray-50 border-b border-gray-200", children: (0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider", children: "Layer" }), (0, jsx_runtime_1.jsxs)("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider", children: [attributeKey, " Value"] })] }) }), (0, jsx_runtime_1.jsx)("tbody", { className: "bg-white divide-y divide-gray-200", children: comparisonData.map((item, index) => ((0, jsx_runtime_1.jsxs)("tr", { className: `hover:bg-gray-50 transition-colors ${index % 2 === 0 ? "bg-white" : "bg-gray-50"}`, children: [(0, jsx_runtime_1.jsx)("td", { className: "px-4 py-3 text-sm font-medium text-gray-900", children: item.layerTitle }), (0, jsx_runtime_1.jsx)("td", { className: "px-4 py-3 text-sm text-gray-700", children: item.attributeValue !== null &&
|
|
135
|
+
item.attributeValue !== undefined ? ((0, jsx_runtime_1.jsx)("span", { className: "font-mono font-semibold text-blue-600", children: String(item.attributeValue) })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-gray-400 italic", children: "N/A" })) })] }, item.layerId))) })] }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: comparisonData.map((item) => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-gradient-to-br from-blue-50 to-indigo-50 border border-blue-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between mb-3", children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-semibold text-gray-800 text-sm", children: item.layerTitle }), (0, jsx_runtime_1.jsx)("div", { className: "w-2 h-2 bg-blue-500 rounded-full" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600 uppercase tracking-wide", children: attributeKey }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-blue-700", children: item.attributeValue !== null &&
|
|
136
|
+
item.attributeValue !== undefined ? (String(item.attributeValue)) : ((0, jsx_runtime_1.jsx)("span", { className: "text-gray-400 text-lg", children: "N/A" })) })] })] }, item.layerId))) }), comparisonData.some((d) => d.attributeValue !== null) && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-gray-50 border border-gray-200 rounded-lg p-4", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-sm font-semibold text-gray-700 mb-3", children: "Comparison Summary" }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 gap-4 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-gray-600", children: "Layers Compared" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-semibold text-gray-800", children: comparisonData.length })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-gray-600", children: "Valid Values" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-semibold text-green-600", children: comparisonData.filter((d) => d.attributeValue !== null).length })] })] })] }))] })), !loading && !error && comparisonData.length === 0 && ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-gray-500", children: (0, jsx_runtime_1.jsx)("div", { className: "text-sm mb-2", children: "Click on the map to compare attributes at that location" }) }))] }));
|
|
137
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/search/index.tsx"],"names":[],"mappings":"AAsBA,MAAM,CAAC,OAAO,UAAU,cAAc,4CAmDrC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = SearchTabPanel;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const core_1 = require("../../core");
|
|
7
|
+
// Darker search icon component
|
|
8
|
+
const SearchIconDark = ({ disabled = false }) => ((0, jsx_runtime_1.jsx)("svg", { fill: "none", className: `w-5 h-5 ${disabled ? "text-blue-200" : "text-white"}`, width: "24", height: "24", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }));
|
|
9
|
+
function SearchTabPanel() {
|
|
10
|
+
const [searchTerm, setSearchTerm] = (0, react_1.useState)("");
|
|
11
|
+
const handleSearchChange = (e) => {
|
|
12
|
+
setSearchTerm(e.target.value);
|
|
13
|
+
};
|
|
14
|
+
const handleSearch = () => {
|
|
15
|
+
// TODO: Implement search functionality for data within drawn polygon
|
|
16
|
+
console.log("Searching for:", searchTerm);
|
|
17
|
+
// This will search data within the polygon boundaries
|
|
18
|
+
// You can integrate with the polygon data from useMapDraw hook here
|
|
19
|
+
};
|
|
20
|
+
const handleKeyPress = (e) => {
|
|
21
|
+
if (e.key === "Enter") {
|
|
22
|
+
handleSearch();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const isDisabled = !searchTerm.trim();
|
|
26
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `w-full p-4 flex flex-col gap-4`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-3", children: [(0, jsx_runtime_1.jsx)(core_1.Input, { name: "polygon_search", label: "Search Data in Polygon", placeholder: "Enter search term...", value: searchTerm, onChange: handleSearchChange, onKeyPress: handleKeyPress }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleSearch, className: `w-full h-10 px-4 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 text-md flex align-middle items-center justify-center gap-2 font-medium transition-all duration-200 ${isDisabled
|
|
27
|
+
? "bg-blue-500 text-blue-50 cursor-not-allowed focus:ring-blue-400"
|
|
28
|
+
: "bg-blue-600 hover:bg-blue-700 text-white cursor-pointer focus:ring-blue-500 hover:shadow-md"}`, disabled: isDisabled, children: [(0, jsx_runtime_1.jsx)(SearchIconDark, { disabled: isDisabled }), (0, jsx_runtime_1.jsx)("span", { children: "Search" })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-gray-500 mt-2", children: "Draw a polygon on the map first, then search for data within it." })] }));
|
|
29
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/selected/index.tsx"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,UAAU,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/selected/index.tsx"],"names":[],"mappings":"AAOA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CA6CvC"}
|
|
@@ -14,7 +14,10 @@ function SelectedTabPanel() {
|
|
|
14
14
|
const onSortEnd = ({ oldIndex, newIndex, }) => {
|
|
15
15
|
layer.setSelectedIds((0, array_move_1.arrayMoveImmutable)(layer.selectedIds, oldIndex, newIndex));
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
const checkedCount = layer.getCheckedAttributesCount();
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto", children: (0, jsx_runtime_1.jsxs)("div", { className: `flex flex-col gap-3 w-full`, children: [layer.selectedIds.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: `p-3 pb-0 flex gap-2`, children: [(0, jsx_runtime_1.jsxs)(core_1.Button, { onClick: () => layer.clearAll(), children: ["\u2715 ", "clear"] }), checkedCount > 0 && ((0, jsx_runtime_1.jsxs)("button", { onClick: () => {
|
|
19
|
+
layer.setCompareMode(true);
|
|
20
|
+
}, className: "h-8 px-3 py-2 rounded-md focus:outline-none focus:ring cursor-pointer text-md flex align-middle items-center gap-1 bg-green-700 hover:bg-green-800 text-white", children: ["Compare", " ", (0, jsx_runtime_1.jsxs)("span", { children: ["(", checkedCount, ")"] })] }))] })), (0, jsx_runtime_1.jsx)(selected_item_list_1.SelectedItemList, { layerList: layer.selectedLayers,
|
|
18
21
|
// @ts-ignore
|
|
19
22
|
useDragHandle: true, onSortEnd: onSortEnd })] }) }));
|
|
20
23
|
}
|
|
@@ -8,8 +8,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
8
8
|
const core_1 = require("../core");
|
|
9
9
|
const index_1 = __importDefault(require("./layers/index"));
|
|
10
10
|
const selected_1 = __importDefault(require("./selected"));
|
|
11
|
-
const
|
|
11
|
+
const search_1 = __importDefault(require("./search"));
|
|
12
12
|
// @ts-ignore
|
|
13
13
|
function SidebarTabs({ onClose }) {
|
|
14
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "absolute top-0 right-0 bottom-0 left-0 md:right-auto md:top-4 md:left-4 md:bottom-4 bg-white rounded-lg shadow-md md:max-w-sm w-full z-20 overflow-hidden", children: [(0, jsx_runtime_1.jsx)(core_1.CloseButton, { onClick: onClose }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col h-full", children: (0, jsx_runtime_1.jsxs)(core_1.Tabs, { className: "flex flex-col h-full", children: [(0, jsx_runtime_1.jsxs)(core_1.TabHeader, { children: [(0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.LayersIcon, {}), children: ("layers") }), (0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.LayersIcon, {}), children: ("selected") }), (0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.
|
|
14
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "absolute top-0 right-0 bottom-0 left-0 md:right-auto md:top-4 md:left-4 md:bottom-4 bg-white rounded-lg shadow-md md:max-w-sm w-full z-20 overflow-hidden", children: [(0, jsx_runtime_1.jsx)(core_1.CloseButton, { onClick: onClose }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col h-full", children: (0, jsx_runtime_1.jsxs)(core_1.Tabs, { className: "flex flex-col h-full", children: [(0, jsx_runtime_1.jsxs)(core_1.TabHeader, { children: [(0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.LayersIcon, {}), children: ("layers") }), (0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.LayersIcon, {}), children: ("selected") }), (0, jsx_runtime_1.jsx)(core_1.IconTab, { icon: (0, jsx_runtime_1.jsx)(core_1.SearchIcon, {}), children: ("search") })] }), (0, jsx_runtime_1.jsx)(core_1.Panel, { children: (0, jsx_runtime_1.jsx)(index_1.default, {}) }), (0, jsx_runtime_1.jsx)(core_1.Panel, { children: (0, jsx_runtime_1.jsx)(selected_1.default, {}) }), (0, jsx_runtime_1.jsx)(core_1.Panel, { children: (0, jsx_runtime_1.jsx)(search_1.default, {}) })] }) })] }));
|
|
15
15
|
}
|
|
@@ -35,6 +35,14 @@ interface LayersContextProps {
|
|
|
35
35
|
setGridLegends: (g: Record<string, any>) => void;
|
|
36
36
|
compareList: string[];
|
|
37
37
|
setCompareLayer: (layerId: string, checked: boolean) => void;
|
|
38
|
+
getLayerOpacity: (layerId: string) => number;
|
|
39
|
+
setLayerOpacity: (layerId: string, opacity: number) => void;
|
|
40
|
+
checkedAttributes: Set<string>;
|
|
41
|
+
toggleAttributeCompare: (attributeKey: string) => void;
|
|
42
|
+
getCheckedAttributesCount: () => number;
|
|
43
|
+
isCompareMode: boolean;
|
|
44
|
+
setCompareMode: (value: boolean) => void;
|
|
45
|
+
fetchStyleForComparison: (layerId: string, styleIndex: number) => Promise<void>;
|
|
38
46
|
};
|
|
39
47
|
query: {
|
|
40
48
|
term: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-layers.d.ts","sourceRoot":"","sources":["../../src/hooks/use-layers.tsx"],"names":[],"mappings":"AAIA,OAAO,KAMN,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAStE,UAAU,kBAAkB;IAC1B,EAAE,EAAE,qBAAqB,CAAC;IAC1B,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE;QACL,QAAQ,CAAC,EAAE,GAAG,CAAC;QACf,WAAW,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;QAC9B,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;QACxC,GAAG,EAAE,cAAc,EAAE,CAAC;QACtB,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;QAC3C,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;QACxC,cAAc,EAAE,cAAc,EAAE,CAAC;QAEjC,QAAQ,EAAE,MAAM,IAAI,CAAC;QACrB,MAAM,EAAE,CAAC,IAAI,EAAE;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,OAAO,CAAC;YACb,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,CAAC,EAAE,OAAO,CAAC;SACjB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC3B,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC3E,gBAAgB,EAAE,GAAG,CAAC;QACtB,kBAAkB,EAAE,GAAG,CAAC;QACxB,mBAAmB,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;QACtC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;QAC9D,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QACpD,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC3C,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAEvC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QAExC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,cAAc,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"use-layers.d.ts","sourceRoot":"","sources":["../../src/hooks/use-layers.tsx"],"names":[],"mappings":"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"}
|
package/dist/hooks/use-layers.js
CHANGED
|
@@ -64,6 +64,12 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
64
64
|
const [hoverFeatures, setHoverFeatures] = (0, react_1.useState)();
|
|
65
65
|
const [selectedFeatures, setSelectedFeatures] = (0, react_1.useState)();
|
|
66
66
|
const [compareList, setCompareList] = (0, react_1.useState)((_mp && _mp.compareList) || []);
|
|
67
|
+
const [layerOpacities, setLayerOpacities] = (0, react_1.useState)({});
|
|
68
|
+
const [layerVisibilities, setLayerVisibilities] = (0, react_1.useState)({});
|
|
69
|
+
// State for tracking checked attributes for comparison (format: "layerId-styleIndex")
|
|
70
|
+
const [checkedAttributes, setCheckedAttributes] = (0, react_1.useState)(new Set());
|
|
71
|
+
// State for compare mode (showing dual map)
|
|
72
|
+
const [isCompareMode, setIsCompareMode] = (0, react_1.useState)(false);
|
|
67
73
|
const setCompareLayer = (layerId, checked) => {
|
|
68
74
|
setCompareList((prev) => {
|
|
69
75
|
if (checked)
|
|
@@ -72,6 +78,36 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
72
78
|
});
|
|
73
79
|
// optional: call mp.onCompareChange(layerId, checked) if you want callbacks
|
|
74
80
|
};
|
|
81
|
+
const toggleAttributeCompare = (attributeKey) => {
|
|
82
|
+
setCheckedAttributes((prev) => {
|
|
83
|
+
const newSet = new Set(prev);
|
|
84
|
+
if (newSet.has(attributeKey)) {
|
|
85
|
+
// Removing - always allowed
|
|
86
|
+
newSet.delete(attributeKey);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// Adding - check limit
|
|
90
|
+
if (newSet.size >= 8) {
|
|
91
|
+
alert("Maximum 8 attributes can be compared at a time");
|
|
92
|
+
return prev; // Don't add, return previous state
|
|
93
|
+
}
|
|
94
|
+
newSet.add(attributeKey);
|
|
95
|
+
}
|
|
96
|
+
return newSet;
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
const getCheckedAttributesCount = () => {
|
|
100
|
+
return checkedAttributes.size;
|
|
101
|
+
};
|
|
102
|
+
const getLayerOpacity = (layerId) => {
|
|
103
|
+
return layerOpacities[layerId] ?? 1;
|
|
104
|
+
};
|
|
105
|
+
const setLayerOpacity = (layerId, opacity) => {
|
|
106
|
+
setLayerOpacities((prev) => ({
|
|
107
|
+
...prev,
|
|
108
|
+
[layerId]: Math.max(0, Math.min(1, opacity)), // Clamp between 0 and 1
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
75
111
|
const selectedFeaturesId = (0, react_1.useMemo)(() => {
|
|
76
112
|
const meta = {};
|
|
77
113
|
for (const qr of selectedFeatures || []) {
|
|
@@ -118,11 +154,35 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
118
154
|
const layerIndex = getLayerIndexById(layerId);
|
|
119
155
|
toggleVectorLayer(layerIndex, styleIndex, false);
|
|
120
156
|
};
|
|
157
|
+
// Fetch style data for comparison without changing the active styleIndex on main map
|
|
158
|
+
const fetchStyleForComparison = async (layerId, styleIndex) => {
|
|
159
|
+
const layerIndex = getLayerIndexById(layerId);
|
|
160
|
+
const layer = layers[layerIndex];
|
|
161
|
+
if (!layer)
|
|
162
|
+
return;
|
|
163
|
+
// Get the current active styleIndex to preserve it
|
|
164
|
+
const currentStyleIndex = layer.data?.styleIndex ?? 0;
|
|
165
|
+
// Fetch the style data
|
|
166
|
+
const layerData = await (0, naksha_2.getLayerStyle)(
|
|
167
|
+
// @ts-ignore
|
|
168
|
+
layer, styleIndex, mp.nakshaApiEndpoint, mp.geoserver);
|
|
169
|
+
// Update layer data but preserve the original styleIndex so main map doesn't change
|
|
170
|
+
updateLayerById(layer.id, {
|
|
171
|
+
data: {
|
|
172
|
+
...layerData,
|
|
173
|
+
styleIndex: currentStyleIndex, // Keep the original active style
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
};
|
|
121
177
|
const onMapHover = async (e) => {
|
|
122
178
|
if (!selectedLayerIds.length || !mapl)
|
|
123
179
|
return;
|
|
124
180
|
try {
|
|
125
181
|
const lastLayerId = selectedLayerIds[0];
|
|
182
|
+
// console.log(lastLayerId , "lastLayerId")
|
|
183
|
+
// added check
|
|
184
|
+
if (!mapl?.getLayer(lastLayerId))
|
|
185
|
+
return;
|
|
126
186
|
const feats = mapl.queryRenderedFeatures(e.point, {
|
|
127
187
|
layers: [lastLayerId],
|
|
128
188
|
});
|
|
@@ -154,6 +214,16 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
154
214
|
const toggleLayer = async ({ layerId, add, styleIndex = 0, focus = true, }) => {
|
|
155
215
|
if (!add) {
|
|
156
216
|
setSelectedLayerIds(selectedLayerIds.filter((_lyrId) => layerId !== _lyrId));
|
|
217
|
+
// Remove all checked attributes for this layer when it's deselected
|
|
218
|
+
setCheckedAttributes((prev) => {
|
|
219
|
+
const newSet = new Set(prev);
|
|
220
|
+
for (const attrKey of prev) {
|
|
221
|
+
if (attrKey.startsWith(`${layerId}-`)) {
|
|
222
|
+
newSet.delete(attrKey);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return newSet;
|
|
226
|
+
});
|
|
157
227
|
return;
|
|
158
228
|
}
|
|
159
229
|
const layerIndex = getLayerIndexById(layerId);
|
|
@@ -164,7 +234,11 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
164
234
|
return updated;
|
|
165
235
|
});
|
|
166
236
|
};
|
|
167
|
-
const clearAllLayers = async () =>
|
|
237
|
+
const clearAllLayers = async () => {
|
|
238
|
+
setSelectedLayerIds([]);
|
|
239
|
+
// Clear all checked attributes when all layers are cleared
|
|
240
|
+
setCheckedAttributes(new Set());
|
|
241
|
+
};
|
|
168
242
|
const updateMP = (key, value) => {
|
|
169
243
|
setMP({ ...mp, [key]: value });
|
|
170
244
|
};
|
|
@@ -259,6 +333,24 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
259
333
|
// if it takes more then 300 selection will be discarded
|
|
260
334
|
setTimeout(featuresAtLatLng, 300);
|
|
261
335
|
}, [clickedLngLat, selectionStyle, selectedLayerIds]);
|
|
336
|
+
// Sync checkedAttributes with selectedLayers - remove attributes for unselected layers
|
|
337
|
+
(0, react_1.useEffect)(() => {
|
|
338
|
+
setCheckedAttributes((prev) => {
|
|
339
|
+
const selectedIdsSet = new Set(selectedLayerIds);
|
|
340
|
+
const newSet = new Set();
|
|
341
|
+
for (const attrKey of prev) {
|
|
342
|
+
const [layerId] = attrKey.split("-");
|
|
343
|
+
if (!layerId) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
// Only keep attributes for layers that are currently selected
|
|
347
|
+
if (selectedIdsSet.has(layerId)) {
|
|
348
|
+
newSet.add(attrKey);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return newSet;
|
|
352
|
+
});
|
|
353
|
+
}, [selectedLayerIds]);
|
|
262
354
|
return ((0, jsx_runtime_1.jsx)(LayersContext.Provider, { value: {
|
|
263
355
|
mp,
|
|
264
356
|
updateMP,
|
|
@@ -287,6 +379,14 @@ const LayersProvider = ({ mp: _mp, children }) => {
|
|
|
287
379
|
setGridLegends,
|
|
288
380
|
compareList: compareList,
|
|
289
381
|
setCompareLayer: setCompareLayer,
|
|
382
|
+
getLayerOpacity,
|
|
383
|
+
setLayerOpacity,
|
|
384
|
+
checkedAttributes: checkedAttributes,
|
|
385
|
+
toggleAttributeCompare: toggleAttributeCompare,
|
|
386
|
+
getCheckedAttributesCount: getCheckedAttributesCount,
|
|
387
|
+
isCompareMode: isCompareMode,
|
|
388
|
+
setCompareMode: setIsCompareMode,
|
|
389
|
+
fetchStyleForComparison: fetchStyleForComparison,
|
|
290
390
|
},
|
|
291
391
|
query: {
|
|
292
392
|
term: queryTermDebounced,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** GeoJSON Feature from map-draw (polygon) */
|
|
3
|
+
export type PolygonShape = {
|
|
4
|
+
id: string;
|
|
5
|
+
type: "Feature";
|
|
6
|
+
geometry: {
|
|
7
|
+
type: string;
|
|
8
|
+
coordinates: unknown;
|
|
9
|
+
};
|
|
10
|
+
properties?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
interface PolygonDataContextValue {
|
|
13
|
+
/** Current drawn polygon features from map-draw */
|
|
14
|
+
shapes: PolygonShape[];
|
|
15
|
+
/** Fetch data from backend for current polygon(s). Call after user draws and hits Search. */
|
|
16
|
+
fetchPolygonData: (searchTerm?: string) => Promise<void>;
|
|
17
|
+
/** Response data from last successful fetch */
|
|
18
|
+
polygonData: unknown;
|
|
19
|
+
/** Loading state while fetch is in progress */
|
|
20
|
+
loading: boolean;
|
|
21
|
+
/** Error message from last failed fetch */
|
|
22
|
+
error: string | null;
|
|
23
|
+
/** Clear error (e.g. when user retries or draws again) */
|
|
24
|
+
clearError: () => void;
|
|
25
|
+
}
|
|
26
|
+
export interface PolygonProviderProps {
|
|
27
|
+
/** Drawn polygon features from useMapDraw().shapes */
|
|
28
|
+
shapes: PolygonShape[];
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
export declare function PolygonProvider({ shapes, children }: PolygonProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export declare function usePolygonData(): PolygonDataContextValue;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=use-polygon-data.d.ts.map
|