Синхронизировать пользовательские цвета в MapboxJavascript

Форум по Javascript
Ответить
Anonymous
 Синхронизировать пользовательские цвета в Mapbox

Сообщение 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 из -за ограничения символов.


Подробнее здесь: https://stackoverflow.com/questions/796 ... -in-mapbox
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»