/* Interactive stylized sector map — pan via plots, zoom, layers, hover, select. */ (function () { const { useState, useMemo } = React; const Icon = window.Icon; // Generate a plausible plot layout: blocks of plots separated by roads. function buildPlots(seed) { const rng = (() => { let s = seed; return () => { s = (s * 9301 + 49297) % 233280; return s / 233280; }; })(); const blocks = [ { code: 'A', x: 40, y: 40, cols: 6, rows: 3 }, { code: 'B', x: 40, y: 230, cols: 6, rows: 3 }, { code: 'C', x: 470, y: 40, cols: 5, rows: 3 }, { code: 'D', x: 470, y: 230, cols: 5, rows: 4 }, ]; const pw = 58, ph = 50, gap = 6; const plots = []; blocks.forEach(b => { for (let r = 0; r < b.rows; r++) for (let c = 0; c < b.cols; c++) { const n = r * b.cols + c + 1; const types = ['res', 'res', 'res', 'comm', 'inst', 'park']; const t = rng() < 0.08 ? 'park' : rng() < 0.12 ? 'comm' : rng() < 0.08 ? 'inst' : 'res'; plots.push({ id: b.code + '-' + n, block: b.code, x: b.x + c * (pw + gap), y: b.y + r * (ph + gap), w: pw, h: ph, type: t, }); } }); return plots; } const TYPE = { res: { fill: '#ffffff', label: 'Residential', sw: '#cbd8e8' }, comm: { fill: '#fff2dc', label: 'Commercial', sw: '#f0d49a' }, inst: { fill: '#e7eeff', label: 'Institutional', sw: '#bcd0f5' }, park: { fill: '#e3f6ec', label: 'Green / Park', sw: '#b6e6cd' }, }; function SectorMap({ sectorName = 'Sector 18', myPlot = 'B-47', height = 460, compact }) { const plots = useMemo(() => buildPlots(sectorName.length * 137 + 7), [sectorName]); const [zoom, setZoom] = useState(1); const [sel, setSel] = useState(null); const [hover, setHover] = useState(null); const [layers, setLayers] = useState({ satellite: false, master: false, infra: true }); const [search, setSearch] = useState(''); // map myPlot to an existing plot id; fall back to one in the same block, then a default const mine = plots.find(p => p.id === myPlot) || (myPlot && plots.find(p => p.block === myPlot.split('-')[0])) || plots[14]; const matched = search ? plots.find(p => p.id.toLowerCase() === search.toLowerCase()) : null; const W = 760, H = 480; return (
{/* toolbar */}
{sectorName}
{ setSearch(e.target.value); const m = plots.find(p => p.id.toLowerCase() === e.target.value.toLowerCase()); if (m) setSel(m.id); }} />
{[['satellite', 'layers', 'Satellite'], ['master', 'grid', 'Master Plan'], ['infra', 'building', 'Infrastructure']].map(([k, ic, l]) => ( ))}
{/* map canvas */}
{/* land base */} {/* greens / blocks bg when satellite */} {layers.satellite && plots.filter(p => p.type === 'park').map(p => )} {/* roads */} {/* master plan grid overlay */} {layers.master && Array.from({ length: 20 }).map((_, i) => ( ))} {/* plots */} {plots.map(p => { const t = TYPE[p.type]; const isMine = p.id === mine.id; const isSel = sel === p.id; const isHover = hover === p.id; const isMatch = matched && matched.id === p.id; let fill = layers.satellite ? (p.type === 'park' ? '#356b4e' : '#cdd9e6') : t.fill; if (isMine) fill = 'var(--emerald-500)'; if (isSel || isMatch) fill = 'var(--blue-500)'; return ( setHover(p.id)} onMouseLeave={() => setHover(null)} onClick={() => setSel(p.id)}> {p.id} ); })} {/* my plot pulse */}
{/* legend */} {!compact && (
Legend
{[['Your Plot', 'var(--emerald-500)'], ['Selected', 'var(--blue-500)'], ['Residential', '#fff'], ['Commercial', '#fff2dc'], ['Green / Park', '#e3f6ec']].map(([l, c]) => (
{l}
))}
)} {/* zoom controls */}
{/* selected plot tooltip */} {sel && (() => { const p = plots.find(x => x.id === sel); const isMine = p.id === mine.id; return (
Plot {p.id}
{TYPE[p.type].label} · Block {p.block}
Area{p.type === 'comm' ? '450' : '300'} sq.m
Status{isMine ? Yours : Allotted}
); })()}
); } window.SectorMap = SectorMap; })();