Files
sthlm-mesh/static/js/status/position-precision-chart.js
2025-04-19 22:13:33 +02:00

147 lines
5.1 KiB
JavaScript

function getPositionPrecisionInMeters(positionPrecision) {
switch(positionPrecision){
case 2: return 5976446;
case 3: return 2988223;
case 4: return 1494111;
case 5: return 747055;
case 6: return 373527;
case 7: return 186763;
case 8: return 93381;
case 9: return 46690;
case 10: return 23345;
case 11: return 11672; // Android LOW_PRECISION
case 12: return 5836;
case 13: return 2918;
case 14: return 1459;
case 15: return 729;
case 16: return 364; // Android MED_PRECISION
case 17: return 182;
case 18: return 91;
case 19: return 45;
case 20: return 22;
case 21: return 11;
case 22: return 5;
case 23: return 2;
case 24: return 1;
case 32: return 0; // Android HIGH_PRECISION
}
return null;
}
function getPositionColor(positionPrecision) {
switch(positionPrecision){
case 2: return 'rgb(196, 36, 18)';
case 3: return 'rgb(196, 36, 18)';
case 4: return 'rgb(196, 36, 18)';
case 5: return 'rgb(196, 36, 18)';
case 6: return 'rgb(196, 36, 18)';
case 7: return 'rgb(196, 36, 18)';
case 8: return 'rgb(196, 36, 18)';
case 9: return 'rgb(196, 36, 18)';
case 10: return 'rgb(196, 36, 18)';
case 11: return 'rgb(196, 36, 18)'; // Android LOW_PRECISION
case 12: return 'rgb(196, 36, 18)';
case 13: return 'rgb(212, 74, 58)'; // Default +/- 3km
case 14: return 'rgb(242, 161, 67)';
case 15: return 'rgb(229, 189, 82)';
case 16: return 'rgb(195, 208, 98)'; // Android MED_PRECISION
case 17: return 'rgb(157, 195, 91)'; //182
case 18: return 'rgb(118, 182, 84)';
case 19: return 'rgb(79, 170, 77)'; //45
case 20: return 'rgb(41, 156, 70)';
case 21: return 'rgb(41, 156, 70)';
case 22: return 'rgb(41, 156, 70)';
case 23: return 'rgb(41, 156, 70)';
case 24: return 'rgb(41, 156, 70)';
case 32: return 'rgb(41, 156, 70)'; // Android HIGH_PRECISION
}
return 'rgb(200, 200, 200)';
}
function formatPositionPrecision(positionPrecision) {
// get position precision in meters
const positionPrecisionInMeters = getPositionPrecisionInMeters(positionPrecision);
if(positionPrecisionInMeters == null){
return "?";
}
// format kilometers
if(positionPrecisionInMeters > 1000){
const positionPrecisionInKilometers = Math.ceil(positionPrecisionInMeters / 1000);
return `±${positionPrecisionInKilometers}km`;
}
// format meters
return `±${positionPrecisionInMeters}m`;
}
async function positionPrecisionGraph() {
const canvas = document.getElementById('positionPrecisionChart');
const ctx = canvas.getContext('2d');
// Show "Loading..." message
ctx.font = '16px Arial';
ctx.fillStyle = 'gray';
ctx.textAlign = 'center';
ctx.fillText('Loading data...', canvas.width / 2, canvas.height / 2);
try {
await fetchNodes();
const countsByPrecision = {};
// Filter out nodes without position_precision
const nodesWithPoistion = nodes.filter(node => node.position_precision != null);
// Count how many nodes fall into each precision value
for (const node of nodesWithPoistion) {
const precision = node.position_precision
countsByPrecision[precision] = (countsByPrecision[precision] || 0) + 1;
}
// Convert to array of { precision, count }
const statsArray = Object.entries(countsByPrecision).map(([precision, count]) => ({
precision: parseInt(precision, 10),
count
}));
// Sort by precision descending
const sorted = statsArray.sort((a, b) => b.precision - a.precision);
const labels = sorted.map(entry => formatPositionPrecision(entry.precision));
const counts = sorted.map(entry => entry.count);
const backgroundColors = sorted.map(entry => getPositionColor(entry.precision));
const chartContainer = document.getElementById('positionPrecisionContainer');
chartContainer.style.height = `${labels.length * 35 + 50}px`;
new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Position Precision',
data: counts,
backgroundColor: backgroundColors,
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
barPercentage: 0.8,
indexAxis: 'y',
y: { ticks: { autoSkip: false, font: { size: 12 } } },
plugins: { legend: { display: false } }
}
});
} catch(error) {
console.error('Error fetching data:', error);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'red';
ctx.fillText('Error loading data', canvas.width / 2, canvas.height / 2);
}
}
positionPrecisionGraph();