import React, { useState, useEffect } from "react";
const sldHeader = `
`;
const sldFooter = ``;
const singleColorSLD = (color, geometryType) => `
${sldHeader}
layer
${symbolizer(geometryType, color)}
${sldFooter}
`;
const uniqueValueSLD = (column, rules, geometryType) => `
${sldHeader}
layer
${rules.map(r => `
${column}
${r.value}
${symbolizer(geometryType, r.color)}
`).join("")}
${sldFooter}
`;
const globalIconSLD = (iconCode) => `
${sldHeader}
layer
image/png
10
${sldFooter}
`;
const symbolizer = (geometryType, color) => {
if (geometryType.toUpperCase() === "POINT" || geometryType.toUpperCase() === "MULTIPOINT") {
return `
circle
${color}
#000000
2
10
`;
}
if (geometryType === "line") {
return `
${color}
2
`;
}
return `
${color}
0.5
#232323
`;
};
// const randomColor = () =>
// "#" + Math.floor(Math.random() * 16777215).toString(16);
const randomColor = () => {
let color = "#000000"
while (color === "#000000") {
color =
"#" + Math.floor(Math.random() * 16777215)
.toString(16)
.padStart(6, "0")
}
return color
}
const CustomLayerStyle = ({ data = [], geometryType, onSubmit, onChange }) => {
const [columns, setColumns] = useState([]);
const [selectedStyle, setSelectedStyle] = useState("single");
// STYLE STATE
const [singleColor, setSingleColor] = useState("#3388ff");
const [uniqueColumn, setUniqueColumn] = useState("");
const [uniqueRules, setUniqueRules] = useState([]);
const [randomRules, setRandomRules] = useState([]);
const [propColumn, setPropColumn] = useState("");
const [propMin, setPropMin] = useState(3);
const [propMax, setPropMax] = useState(12);
const [iconMode, setIconMode] = useState("global"); // global | per-feature
const [iconGlobal, setIconGlobal] = useState("");
const [iconRules, setIconRules] = useState([]);
// Extract columns
useEffect(() => {
if (data.length > 0) {
const keys = Object.keys(data[0]).filter((k) => k !== "geometry");
setColumns(keys);
}
}, [data]);
useEffect(() => {
onChange({
type: selectedStyle,
color: singleColor,
unique: uniqueRules,
random: randomRules,
proportional: { propColumn, propMin, propMax }
});
}, [selectedStyle, singleColor, uniqueRules, randomRules, propColumn, propMin, propMax]);
// Handle unique value column selection
const generateUniqueRules = (column) => {
const values = [...new Set(data.map((d) => d[column]))];
const rules = values.map((v) => ({
value: v,
color: randomColor(),
}));
setUniqueRules(rules);
};
// Handle random per row
const generateRandomRules = () => {
const rules = data.map((row) => ({
id: row.id,
color: randomColor(),
}));
setRandomRules(rules);
};
// Handle icon rules
const generateIconRules = () => {
const rules = data.map((row) => ({
id: row.id,
iconUrl: "",
}));
setIconRules(rules);
};
async function generateBase64(iconUrl) {
const response = await fetch(iconUrl, {
mode: "cors",
});
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
// Final Submit
const submit = async () => {
let xml = "";
if (selectedStyle === "single") {
xml = singleColorSLD(singleColor, geometryType);
}
if (selectedStyle === "unique_value") {
xml = uniqueValueSLD(uniqueColumn, uniqueRules, geometryType);
}
if (selectedStyle === "icon") {
// const iconCode = await generateBase64('https://cdn-icons-png.flaticon.com/512/0/614.png')
const iconCode = 'https://cdn-icons-png.flaticon.com/512/0/614.png'
xml = globalIconSLD(iconCode);
}
// xml = ``
onSubmit({
styleType: "sld",
sldContent: xml
});
};
return (
🎨 Pengaturan Styling Data Spasial
{/* PILIH STYLE */}
{/* ---------------- SINGLE COLOR ---------------- */}
{selectedStyle === "single" && (
setSingleColor(e.target.value)}
/>
)}
{/* ---------------- UNIQUE VALUE ---------------- */}
{selectedStyle === "unique_value" && (
{/* RULE LIST */}
{uniqueRules.map((r, i) => (
))}
)}
{/* ---------------- RANDOM COLOR ---------------- */}
{selectedStyle === "random" && (
{randomRules.map((r, i) => (
ID {r.id}
{
const copy = [...randomRules];
copy[i].color = e.target.value;
setRandomRules(copy);
}}
/>
))}
)}
{/* ---------------- PROPORTIONAL ---------------- */}
{selectedStyle === "proportional" && (
)}
{/* ---------------- ICON PER FEATURE ---------------- */}
{selectedStyle === "icon" && geometryType === "Point" && (
setIconGlobal(e.target.value)}
/>
)}
);
};
export default CustomLayerStyle;