Spaces:
Runtime error
Runtime error
Commit
·
1d6d0dd
1
Parent(s):
c2a5a36
Add option for scientific/normal numerical representations
Browse files- frontend/src/components/Map.js +36 -4
- frontend/src/utils/mapUtils.js +14 -8
frontend/src/components/Map.js
CHANGED
@@ -68,6 +68,8 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
68 |
const [polygonArea, setPolygonArea] = useState(null);
|
69 |
const [areaUnit, setAreaUnit] = useState('sqm'); // 'sqm', 'sqkm', 'ha', 'acres', 'sqmi'
|
70 |
|
|
|
|
|
71 |
const handleMouseDown = (e) => {
|
72 |
isDragging.current = true;
|
73 |
startX.current = e.clientX;
|
@@ -434,7 +436,12 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
434 |
boxShadow: 'none',
|
435 |
padding: 0
|
436 |
}}>
|
437 |
-
{geoDistance
|
|
|
|
|
|
|
|
|
|
|
438 |
</span>
|
439 |
</Tooltip>
|
440 |
)}
|
@@ -461,7 +468,7 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
461 |
icon={L.divIcon({
|
462 |
className: 'area-label',
|
463 |
html: polygonArea !== null
|
464 |
-
? `<div style="background:rgba(255,255,255,0.8);padding:2px 6px;border-radius:4px;color:#1976d2;font-weight:600;">${formatArea(polygonArea, areaUnit)}</div>`
|
465 |
: '',
|
466 |
iconSize: [100, 24],
|
467 |
iconAnchor: [50, 12]
|
@@ -619,9 +626,23 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
619 |
<option value="mi">Miles</option>
|
620 |
</select>
|
621 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
622 |
{geoDistance !== null && (
|
623 |
<div style={{ fontSize: 20, fontWeight: 600, color: '#1976d2' }}>
|
624 |
-
{
|
|
|
|
|
|
|
625 |
</div>
|
626 |
)}
|
627 |
<button
|
@@ -668,7 +689,7 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
668 |
</div>
|
669 |
{polygonArea !== null && (
|
670 |
<div style={{ fontSize: 20, fontWeight: 600, color: '#1976d2' }}>
|
671 |
-
{formatArea(polygonArea, areaUnit)}
|
672 |
</div>
|
673 |
)}
|
674 |
<button
|
@@ -703,6 +724,17 @@ const Map = ( { onMapClick, searchQuery, contentType } ) => {
|
|
703 |
<option value="mi2">mi²</option>
|
704 |
</select>
|
705 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
706 |
</>
|
707 |
)}
|
708 |
</div>
|
|
|
68 |
const [polygonArea, setPolygonArea] = useState(null);
|
69 |
const [areaUnit, setAreaUnit] = useState('sqm'); // 'sqm', 'sqkm', 'ha', 'acres', 'sqmi'
|
70 |
|
71 |
+
const [numberFormat, setNumberFormat] = useState('normal'); // 'normal' | 'scientific'
|
72 |
+
|
73 |
const handleMouseDown = (e) => {
|
74 |
isDragging.current = true;
|
75 |
startX.current = e.clientX;
|
|
|
436 |
boxShadow: 'none',
|
437 |
padding: 0
|
438 |
}}>
|
439 |
+
{geoDistance !== null
|
440 |
+
? (numberFormat === 'scientific'
|
441 |
+
? geoDistance.toExponential(2)
|
442 |
+
: geoDistance.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })
|
443 |
+
) + ' ' + geoUnit
|
444 |
+
: ''}
|
445 |
</span>
|
446 |
</Tooltip>
|
447 |
)}
|
|
|
468 |
icon={L.divIcon({
|
469 |
className: 'area-label',
|
470 |
html: polygonArea !== null
|
471 |
+
? `<div style="background:rgba(255,255,255,0.8);padding:2px 6px;border-radius:4px;color:#1976d2;font-weight:600;">${formatArea(polygonArea, areaUnit, numberFormat)}</div>`
|
472 |
: '',
|
473 |
iconSize: [100, 24],
|
474 |
iconAnchor: [50, 12]
|
|
|
626 |
<option value="mi">Miles</option>
|
627 |
</select>
|
628 |
</div>
|
629 |
+
<div>
|
630 |
+
<label style={{ fontWeight: 500, marginRight: 8 }}>Number format:</label>
|
631 |
+
<select
|
632 |
+
value={numberFormat}
|
633 |
+
onChange={e => setNumberFormat(e.target.value)}
|
634 |
+
style={{ padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
|
635 |
+
>
|
636 |
+
<option value="normal">Normal</option>
|
637 |
+
<option value="scientific">Scientific</option>
|
638 |
+
</select>
|
639 |
+
</div>
|
640 |
{geoDistance !== null && (
|
641 |
<div style={{ fontSize: 20, fontWeight: 600, color: '#1976d2' }}>
|
642 |
+
{numberFormat === 'scientific'
|
643 |
+
? geoDistance.toExponential(2)
|
644 |
+
: geoDistance.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })
|
645 |
+
}
|
646 |
</div>
|
647 |
)}
|
648 |
<button
|
|
|
689 |
</div>
|
690 |
{polygonArea !== null && (
|
691 |
<div style={{ fontSize: 20, fontWeight: 600, color: '#1976d2' }}>
|
692 |
+
{formatArea(polygonArea, areaUnit, numberFormat)}
|
693 |
</div>
|
694 |
)}
|
695 |
<button
|
|
|
724 |
<option value="mi2">mi²</option>
|
725 |
</select>
|
726 |
</div>
|
727 |
+
<div>
|
728 |
+
<label style={{ fontWeight: 500, marginRight: 8 }}>Number format:</label>
|
729 |
+
<select
|
730 |
+
value={numberFormat}
|
731 |
+
onChange={e => setNumberFormat(e.target.value)}
|
732 |
+
style={{ padding: '4px 8px', borderRadius: 4, border: '1px solid #ccc' }}
|
733 |
+
>
|
734 |
+
<option value="normal">Normal</option>
|
735 |
+
<option value="scientific">Scientific</option>
|
736 |
+
</select>
|
737 |
+
</div>
|
738 |
</>
|
739 |
)}
|
740 |
</div>
|
frontend/src/utils/mapUtils.js
CHANGED
@@ -110,25 +110,31 @@ function getPolygonCentroid(points) {
|
|
110 |
return [x / n, y / n];
|
111 |
}
|
112 |
|
113 |
-
function formatArea(area, unit = 'sqm') {
|
114 |
|
115 |
if (typeof area !== 'number' || isNaN(area)) {
|
116 |
return 'Invalid area';
|
117 |
}
|
118 |
-
|
119 |
switch (unit) {
|
120 |
case "km2":
|
121 |
-
|
|
|
122 |
case "ha":
|
123 |
-
|
|
|
124 |
case "sqm":
|
125 |
-
|
|
|
126 |
case "acres":
|
127 |
-
|
|
|
128 |
case "mi2":
|
129 |
-
|
|
|
130 |
default:
|
131 |
-
|
|
|
132 |
}
|
133 |
}
|
134 |
|
|
|
110 |
return [x / n, y / n];
|
111 |
}
|
112 |
|
113 |
+
function formatArea(area, unit = 'sqm', format = "normal") {
|
114 |
|
115 |
if (typeof area !== 'number' || isNaN(area)) {
|
116 |
return 'Invalid area';
|
117 |
}
|
118 |
+
let value;
|
119 |
switch (unit) {
|
120 |
case "km2":
|
121 |
+
value = area / 1e6;
|
122 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' km²';
|
123 |
case "ha":
|
124 |
+
value = area / 1e4;
|
125 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' ha';
|
126 |
case "sqm":
|
127 |
+
value = area;
|
128 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m²';
|
129 |
case "acres":
|
130 |
+
value = area / 4046.8564224;
|
131 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' acres';
|
132 |
case "mi2":
|
133 |
+
value = area / 2589988.110336;
|
134 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' mi²';
|
135 |
default:
|
136 |
+
value = area;
|
137 |
+
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m²';
|
138 |
}
|
139 |
}
|
140 |
|