Я работаю над функцией в моем приложении Next.js 15, в котором пользователи должны нарисовать область на карте с различными инструментами, а когда пользователь заканчивает рисование, он добавляет, что область остается на карте, а также добавляет ряд некоторых элементов в списке области в левой части страницы. В ряду у меня есть пользовательский цветовой сборщик с собственной цветовой паллеткой. Я хочу, чтобы, когда пользователь финишна, он также добавляет цвет в область Дрю, и когда пользователь изменяет цвет определенной области, он также изменит цвет области на карте."use client";
import type React from "react";
import { useState, useMemo, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import {
Check,
MoreVertical,
Pencil,
Eye,
Trash2,
ArrowUpDown,
} from "lucide-react";
import CollectionAreaMap from "./collection-area-map";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import ColorPicker, { COLOR_PALETTE } from "./color-picker";
// Define the excluded color (grey with pattern)
const EXCLUDED_COLOR = { color: "#808080" };
interface CollectionArea {
id: number;
name: string;
fee: string;
enabled: boolean;
color: string;
featureId?: string; // Store the mapbox feature ID associated with this area
}
type SortDirection = "asc" | "desc" | null;
type SortField = "name" | "fee" | null;
export default function CollectionTerritoriesPage() {
const [isEditMode, setIsEditMode] = useState(true);
const [territoryName, setTerritoryName] = useState(
"Matlock 30 miles Collection Territory"
);
const [territoryDescription, setTerritoryDescription] = useState("");
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [areaToDelete, setAreaToDelete] = useState(null);
const [sortField, setSortField] = useState(null);
const [sortDirection, setSortDirection] = useState(null);
const [focusedAreaId, setFocusedAreaId] = useState(null);
// Initialize with an empty collection areas array
const [collectionAreas, setCollectionAreas] = useState([]);
const nextIdRef = useRef(1);
// Add this ref to store the deleteFeature function from the map component
const deleteFeatureRef = useRef void) | null>(null);
// Sort the collection areas based on the current sort field and direction
const sortedCollectionAreas = useMemo(() => {
if (!sortField || !sortDirection) {
return [...collectionAreas];
}
return [...collectionAreas].sort((a, b) => {
if (sortField === "name") {
return sortDirection === "asc"
? a.name.localeCompare(b.name)
: b.name.localeCompare(a.name);
} else if (sortField === "fee") {
const feeA = Number.parseInt(a.fee) || 0;
const feeB = Number.parseInt(b.fee) || 0;
return sortDirection === "asc" ? feeA - feeB : feeB - feeA;
}
return 0;
});
}, [collectionAreas, sortField, sortDirection]);
// Update nextIdRef whenever areas change
useEffect(() => {
if (collectionAreas.length > 0) {
const maxId = Math.max(...collectionAreas.map((area) => area.id));
nextIdRef.current = maxId + 1;
} else {
nextIdRef.current = 1;
}
}, [collectionAreas]);
const toggleEditMode = () => {
setIsEditMode(!isEditMode);
};
const toggleAreaEnabled = (id: number) => {
setCollectionAreas(
collectionAreas.map((area) =>
area.id === id ? { ...area, enabled: !area.enabled } : area
)
);
};
const handleSort = (field: SortField) => {
if (sortField === field) {
// Toggle direction if same field
setSortDirection(sortDirection === "asc" ? "desc" : "asc");
} else {
// Set new field and default to ascending
setSortField(field);
setSortDirection("asc");
}
};
const updateAreaName = (id: number, name: string) => {
// Check if name is unique
const isDuplicate = collectionAreas.some(
(area) => area.id !== id && area.name === name
);
if (isDuplicate) {
alert("Area name must be unique within the territory");
return;
}
setCollectionAreas(
collectionAreas.map((area) => (area.id === id ? { ...area, name } : area))
);
};
const updateAreaFee = (id: number, fee: string) => {
// Validate fee (3-digit integer)
if (fee !== "" && !/^\d{1,3}$/.test(fee)) {
return;
}
setCollectionAreas(
collectionAreas.map((area) => (area.id === id ? { ...area, fee } : area))
);
};
const updateAreaColor = (id: number, color: string) => {
setCollectionAreas(
collectionAreas.map((area) =>
area.id === id ? { ...area, color } : area
)
);
};
const deleteArea = (area: CollectionArea) => {
setAreaToDelete(area);
setDeleteDialogOpen(true);
};
// Updated to delete from map as well
const confirmDeleteArea = () => {
if (areaToDelete) {
// Get the feature ID associated with this area
const featureId = areaToDelete.featureId;
// Remove the area from the state
setCollectionAreas(
collectionAreas.filter((area) => area.id !== areaToDelete.id)
);
// If there's a feature ID and we have a delete function, delete it from the map
if (featureId && deleteFeatureRef.current) {
deleteFeatureRef.current(featureId);
}
setDeleteDialogOpen(false);
setAreaToDelete(null);
}
};
// Handler for when an area is drawn on the map
const handleAreaDrawn = (feature: any) => {
const nextId = nextIdRef.current;
// Get a color from the palette based on the ID
const nextColorIndex = nextId % COLOR_PALETTE.length;
// Create a new area object
const newArea: CollectionArea = {
id: nextId,
name: `Area ${nextId}`,
fee: "",
enabled: true,
color: COLOR_PALETTE[nextColorIndex].color,
featureId: feature.id, // Store the feature ID for reference
};
// Log for debugging
console.log(`Adding new area with ID ${nextId}, featureId: ${feature.id}`);
// Update the state with the new area
setCollectionAreas((prev) => [...prev, newArea]);
// Automatically focus the newly created area
setFocusedAreaId(nextId);
return newArea;
};
const focusArea = (id: number) => {
setFocusedAreaId(id === focusedAreaId ? null : id);
};
return (
{/* Collection Areas Panel */}
Collection Areas
{/* "Add Area" button has been removed as requested */}
{collectionAreas.length === 0 ? (
{isEditMode ? (
No areas added yet. Draw an area on the map to add your first
collection area.
) : (
No collection areas defined.
)}
) : (
className="font-medium text-sm text-gray-600 flex items-center cursor-pointer"
onClick={() => handleSort("name")}
>
Name
className="font-medium text-sm text-gray-600 text-right flex items-center justify-end cursor-pointer"
onClick={() => handleSort("fee")}
>
Fee
Enable
{sortedCollectionAreas.map((area) => (
{isEditMode ? (
updateAreaColor(area.id, color)
}
disabled={!area.enabled}
/>
) : (
className="w-4 h-4 rounded-sm"
style={{
backgroundColor: area.enabled
? area.color
: EXCLUDED_COLOR.color,
}}
>
)}
{isEditMode ? (
updateAreaName(area.id, e.target.value)
}
className="h-8 text-sm"
maxLength={20}
disabled={!area.enabled}
/>
) : (
{area.name}
)}
{isEditMode ? (
area.enabled ? (
updateAreaFee(area.id, e.target.value)
}
className="h-8 text-sm w-20"
placeholder="0"
/>
) : null
) : area.enabled ? (
`£${area.fee}`
) : (
"Excluded"
)}
toggleAreaEnabled(area.id)}
className="data-[state=checked]:bg-blue-500"
disabled={!isEditMode}
/>
focusArea(area.id)}>
Focus
{isEditMode && (
deleteArea(area)}
className="text-red-600"
>
Delete
)}
))}
)}
{/* Collection Territory Info (only visible in edit mode) */}
{isEditMode && (
Collection Territory Info
Name
setTerritoryName(e.target.value)}
maxLength={30}
/>
Description
setTerritoryDescription(e.target.value)}
maxLength={200}
/>
)}
{/* Map Container */}
{
// Store the delete function from the map component
deleteFeatureRef.current = deleteFeatureFunction;
}}
/>
{/* Floating Button */}
{isEditMode ? (
Done editing
) : (
Edit
)}
{/* Delete Confirmation Dialog */}
Delete Area
Are you sure you want to delete {areaToDelete?.name}?
setDeleteDialogOpen(false)}
>
Cancel
Delete
);
}
< /code>
Я попробовал разные подходы, но не смог решить эту проблему при синхронизации этих цветов. Если кто -нибудь знает, как исправить это просто направить меня, и я сам реализую. Я не могу добавить компонент AREAMAP из -за ограничения символов.
Подробнее здесь: https://stackoverflow.com/questions/796 ... -in-mapbox
Синхронизировать пользовательские цвета в Mapbox ⇐ Javascript
Форум по Javascript
-
Anonymous
1746202185
Anonymous
Я работаю над функцией в моем приложении Next.js 15, в котором пользователи должны нарисовать область на карте с различными инструментами, а когда пользователь заканчивает рисование, он добавляет, что область остается на карте, а также добавляет ряд некоторых элементов в списке области в левой части страницы. В ряду у меня есть пользовательский цветовой сборщик с собственной цветовой паллеткой. Я хочу, чтобы, когда пользователь финишна, он также добавляет цвет в область Дрю, и когда пользователь изменяет цвет определенной области, он также изменит цвет области на карте."use client";
import type React from "react";
import { useState, useMemo, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import {
Check,
MoreVertical,
Pencil,
Eye,
Trash2,
ArrowUpDown,
} from "lucide-react";
import CollectionAreaMap from "./collection-area-map";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import ColorPicker, { COLOR_PALETTE } from "./color-picker";
// Define the excluded color (grey with pattern)
const EXCLUDED_COLOR = { color: "#808080" };
interface CollectionArea {
id: number;
name: string;
fee: string;
enabled: boolean;
color: string;
featureId?: string; // Store the mapbox feature ID associated with this area
}
type SortDirection = "asc" | "desc" | null;
type SortField = "name" | "fee" | null;
export default function CollectionTerritoriesPage() {
const [isEditMode, setIsEditMode] = useState(true);
const [territoryName, setTerritoryName] = useState(
"Matlock 30 miles Collection Territory"
);
const [territoryDescription, setTerritoryDescription] = useState("");
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [areaToDelete, setAreaToDelete] = useState(null);
const [sortField, setSortField] = useState(null);
const [sortDirection, setSortDirection] = useState(null);
const [focusedAreaId, setFocusedAreaId] = useState(null);
// Initialize with an empty collection areas array
const [collectionAreas, setCollectionAreas] = useState([]);
const nextIdRef = useRef(1);
// Add this ref to store the deleteFeature function from the map component
const deleteFeatureRef = useRef void) | null>(null);
// Sort the collection areas based on the current sort field and direction
const sortedCollectionAreas = useMemo(() => {
if (!sortField || !sortDirection) {
return [...collectionAreas];
}
return [...collectionAreas].sort((a, b) => {
if (sortField === "name") {
return sortDirection === "asc"
? a.name.localeCompare(b.name)
: b.name.localeCompare(a.name);
} else if (sortField === "fee") {
const feeA = Number.parseInt(a.fee) || 0;
const feeB = Number.parseInt(b.fee) || 0;
return sortDirection === "asc" ? feeA - feeB : feeB - feeA;
}
return 0;
});
}, [collectionAreas, sortField, sortDirection]);
// Update nextIdRef whenever areas change
useEffect(() => {
if (collectionAreas.length > 0) {
const maxId = Math.max(...collectionAreas.map((area) => area.id));
nextIdRef.current = maxId + 1;
} else {
nextIdRef.current = 1;
}
}, [collectionAreas]);
const toggleEditMode = () => {
setIsEditMode(!isEditMode);
};
const toggleAreaEnabled = (id: number) => {
setCollectionAreas(
collectionAreas.map((area) =>
area.id === id ? { ...area, enabled: !area.enabled } : area
)
);
};
const handleSort = (field: SortField) => {
if (sortField === field) {
// Toggle direction if same field
setSortDirection(sortDirection === "asc" ? "desc" : "asc");
} else {
// Set new field and default to ascending
setSortField(field);
setSortDirection("asc");
}
};
const updateAreaName = (id: number, name: string) => {
// Check if name is unique
const isDuplicate = collectionAreas.some(
(area) => area.id !== id && area.name === name
);
if (isDuplicate) {
alert("Area name must be unique within the territory");
return;
}
setCollectionAreas(
collectionAreas.map((area) => (area.id === id ? { ...area, name } : area))
);
};
const updateAreaFee = (id: number, fee: string) => {
// Validate fee (3-digit integer)
if (fee !== "" && !/^\d{1,3}$/.test(fee)) {
return;
}
setCollectionAreas(
collectionAreas.map((area) => (area.id === id ? { ...area, fee } : area))
);
};
const updateAreaColor = (id: number, color: string) => {
setCollectionAreas(
collectionAreas.map((area) =>
area.id === id ? { ...area, color } : area
)
);
};
const deleteArea = (area: CollectionArea) => {
setAreaToDelete(area);
setDeleteDialogOpen(true);
};
// Updated to delete from map as well
const confirmDeleteArea = () => {
if (areaToDelete) {
// Get the feature ID associated with this area
const featureId = areaToDelete.featureId;
// Remove the area from the state
setCollectionAreas(
collectionAreas.filter((area) => area.id !== areaToDelete.id)
);
// If there's a feature ID and we have a delete function, delete it from the map
if (featureId && deleteFeatureRef.current) {
deleteFeatureRef.current(featureId);
}
setDeleteDialogOpen(false);
setAreaToDelete(null);
}
};
// Handler for when an area is drawn on the map
const handleAreaDrawn = (feature: any) => {
const nextId = nextIdRef.current;
// Get a color from the palette based on the ID
const nextColorIndex = nextId % COLOR_PALETTE.length;
// Create a new area object
const newArea: CollectionArea = {
id: nextId,
name: `Area ${nextId}`,
fee: "",
enabled: true,
color: COLOR_PALETTE[nextColorIndex].color,
featureId: feature.id, // Store the feature ID for reference
};
// Log for debugging
console.log(`Adding new area with ID ${nextId}, featureId: ${feature.id}`);
// Update the state with the new area
setCollectionAreas((prev) => [...prev, newArea]);
// Automatically focus the newly created area
setFocusedAreaId(nextId);
return newArea;
};
const focusArea = (id: number) => {
setFocusedAreaId(id === focusedAreaId ? null : id);
};
return (
{/* Collection Areas Panel */}
Collection Areas
{/* "Add Area" button has been removed as requested */}
{collectionAreas.length === 0 ? (
{isEditMode ? (
No areas added yet. Draw an area on the map to add your first
collection area.
) : (
No collection areas defined.
)}
) : (
className="font-medium text-sm text-gray-600 flex items-center cursor-pointer"
onClick={() => handleSort("name")}
>
Name
className="font-medium text-sm text-gray-600 text-right flex items-center justify-end cursor-pointer"
onClick={() => handleSort("fee")}
>
Fee
Enable
{sortedCollectionAreas.map((area) => (
{isEditMode ? (
updateAreaColor(area.id, color)
}
disabled={!area.enabled}
/>
) : (
className="w-4 h-4 rounded-sm"
style={{
backgroundColor: area.enabled
? area.color
: EXCLUDED_COLOR.color,
}}
>
)}
{isEditMode ? (
updateAreaName(area.id, e.target.value)
}
className="h-8 text-sm"
maxLength={20}
disabled={!area.enabled}
/>
) : (
{area.name}
)}
{isEditMode ? (
area.enabled ? (
updateAreaFee(area.id, e.target.value)
}
className="h-8 text-sm w-20"
placeholder="0"
/>
) : null
) : area.enabled ? (
`£${area.fee}`
) : (
"Excluded"
)}
toggleAreaEnabled(area.id)}
className="data-[state=checked]:bg-blue-500"
disabled={!isEditMode}
/>
focusArea(area.id)}>
Focus
{isEditMode && (
deleteArea(area)}
className="text-red-600"
>
Delete
)}
))}
)}
{/* Collection Territory Info (only visible in edit mode) */}
{isEditMode && (
Collection Territory Info
Name
setTerritoryName(e.target.value)}
maxLength={30}
/>
Description
setTerritoryDescription(e.target.value)}
maxLength={200}
/>
)}
{/* Map Container */}
{
// Store the delete function from the map component
deleteFeatureRef.current = deleteFeatureFunction;
}}
/>
{/* Floating Button */}
{isEditMode ? (
Done editing
) : (
Edit
)}
{/* Delete Confirmation Dialog */}
Delete Area
Are you sure you want to delete {areaToDelete?.name}?
setDeleteDialogOpen(false)}
>
Cancel
Delete
);
}
< /code>
Я попробовал разные подходы, но не смог решить эту проблему при синхронизации этих цветов. Если кто -нибудь знает, как исправить это просто направить меня, и я сам реализую. Я не могу добавить компонент AREAMAP из -за ограничения символов.
Подробнее здесь: [url]https://stackoverflow.com/questions/79603732/sync-custom-colors-in-mapbox[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия