generated from Grigo/AndroidTemplate
fix
This commit is contained in:
+104
-29
@@ -2,6 +2,61 @@
|
||||
(function (global) {
|
||||
'use strict';
|
||||
|
||||
function niceMeterStep(span) {
|
||||
if (span <= 50) return 10;
|
||||
if (span <= 150) return 25;
|
||||
if (span <= 400) return 50;
|
||||
return 100;
|
||||
}
|
||||
|
||||
function niceMeterTicks(minD, maxD) {
|
||||
const span = Math.max(maxD - minD, 1);
|
||||
const step = niceMeterStep(span);
|
||||
const ticks = [];
|
||||
const start = Math.ceil(minD / step) * step;
|
||||
for (let d = start; d <= maxD + step * 0.01; d += step) {
|
||||
if (d >= minD - step * 0.01 && d <= maxD + step * 0.01) {
|
||||
ticks.push(d);
|
||||
}
|
||||
}
|
||||
if (!ticks.length || ticks[0] > minD + 0.5) {
|
||||
ticks.unshift(minD);
|
||||
}
|
||||
if (ticks[ticks.length - 1] < maxD - 0.5) {
|
||||
ticks.push(maxD);
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
|
||||
function drawMeterAxis(ctx, margin, plotW, plotH, h, minD, span, w) {
|
||||
const ticks = niceMeterTicks(minD, minD + span);
|
||||
const minLabelGap = 28;
|
||||
const maxLabels = Math.max(2, Math.floor(plotW / minLabelGap));
|
||||
const labelEvery = ticks.length > maxLabels
|
||||
? Math.ceil(ticks.length / maxLabels)
|
||||
: 1;
|
||||
|
||||
ctx.strokeStyle = '#2a2a3a';
|
||||
ctx.lineWidth = 1;
|
||||
ticks.forEach((d, i) => {
|
||||
const x = margin.l + ((d - minD) / span) * plotW;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, margin.t);
|
||||
ctx.lineTo(x, margin.t + plotH);
|
||||
ctx.stroke();
|
||||
|
||||
if (i % labelEvery === 0 || i === ticks.length - 1) {
|
||||
const label = `${Math.round(d)}m`;
|
||||
ctx.fillStyle = '#888';
|
||||
ctx.font = '9px system-ui';
|
||||
const tw = ctx.measureText(label).width;
|
||||
let lx = x - tw / 2;
|
||||
lx = Math.max(margin.l, Math.min(lx, margin.l + plotW - tw));
|
||||
ctx.fillText(label, lx, h - 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function drawQualityDistChart(canvas, samples, qualityColor, highlightDist) {
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
@@ -23,7 +78,7 @@
|
||||
const minD = Math.min(...dists);
|
||||
const maxD = Math.max(...dists);
|
||||
const span = Math.max(maxD - minD, 1);
|
||||
const binCount = Math.min(20, Math.max(5, Math.ceil(span / 10)));
|
||||
const binCount = Math.min(40, Math.max(8, Math.ceil(span / 5)));
|
||||
const binW = span / binCount;
|
||||
const bins = Array.from({ length: binCount }, (_, i) => ({
|
||||
min: minD + i * binW,
|
||||
@@ -37,53 +92,73 @@
|
||||
bins[idx].qualities.push(s.quality);
|
||||
}
|
||||
|
||||
const margin = { l: 36, r: 8, t: 16, b: 22 };
|
||||
const margin = { l: 36, r: 8, t: 16, b: 30 };
|
||||
const plotW = w - margin.l - margin.r;
|
||||
const plotH = h - margin.t - margin.b;
|
||||
const distBandH = Math.round(plotH * 0.25);
|
||||
const qualBandH = plotH - distBandH - 4;
|
||||
const qualTop = margin.t;
|
||||
const distTop = margin.t + qualBandH + 4;
|
||||
const axisY = margin.t + plotH;
|
||||
|
||||
ctx.strokeStyle = '#333';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(margin.l, margin.t);
|
||||
ctx.lineTo(margin.l, margin.t + plotH);
|
||||
ctx.lineTo(margin.l + plotW, margin.t + plotH);
|
||||
ctx.moveTo(margin.l, qualTop);
|
||||
ctx.lineTo(margin.l, axisY);
|
||||
ctx.lineTo(margin.l + plotW, axisY);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#888';
|
||||
ctx.font = '9px system-ui';
|
||||
ctx.fillText('0%', 2, margin.t + plotH);
|
||||
ctx.fillText('100%', 2, margin.t + 8);
|
||||
ctx.fillText(`${Math.round(minD)}m`, margin.l, h - 2);
|
||||
ctx.fillText(`${Math.round(maxD)}m`, margin.l + plotW - 24, h - 2);
|
||||
ctx.fillStyle = '#ccc';
|
||||
ctx.font = '10px system-ui';
|
||||
ctx.fillText('RX Quality vs расстояние', margin.l, margin.t - 4);
|
||||
ctx.fillText('0%', 2, distTop - 2);
|
||||
ctx.fillText('100%', 2, qualTop + 8);
|
||||
ctx.fillStyle = '#666';
|
||||
ctx.fillText('точки', 2, distTop + distBandH - 2);
|
||||
|
||||
drawMeterAxis(ctx, margin, plotW, plotH, h, minD, span, w);
|
||||
|
||||
const barW = plotW / binCount;
|
||||
let maxCount = 1;
|
||||
bins.forEach(b => {
|
||||
if (b.qualities.length > maxCount) maxCount = b.qualities.length;
|
||||
});
|
||||
|
||||
const barW = plotW / binCount * 0.75;
|
||||
bins.forEach((b, i) => {
|
||||
if (!b.qualities.length) return;
|
||||
const avg = b.qualities.reduce((a, v) => a + v, 0) / b.qualities.length;
|
||||
const cx = margin.l + (i + 0.5) / binCount * plotW;
|
||||
const barH = (avg / 100) * plotH;
|
||||
const x = cx - barW / 2;
|
||||
const y = margin.t + plotH - barH;
|
||||
const col = qualityColor ? qualityColor(avg) : '#888';
|
||||
const x = margin.l + i / binCount * plotW;
|
||||
const count = b.qualities.length;
|
||||
const highlight = highlightDist != null
|
||||
&& highlightDist >= b.min && highlightDist < b.max;
|
||||
ctx.fillStyle = col;
|
||||
ctx.globalAlpha = highlight ? 1 : 0.75;
|
||||
ctx.fillRect(x, y, barW, barH);
|
||||
ctx.globalAlpha = 1;
|
||||
if (highlight) {
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.strokeRect(x, y, barW, barH);
|
||||
|
||||
if (count === 0) {
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.08)';
|
||||
ctx.fillRect(x, distTop + distBandH - 1, barW, 1);
|
||||
} else {
|
||||
const distBarH = (count / maxCount) * distBandH;
|
||||
const intensity = 0.35 + 0.65 * (count / maxCount);
|
||||
ctx.fillStyle = `rgba(74, 85, 104, ${intensity})`;
|
||||
ctx.fillRect(x, distTop + distBandH - distBarH, barW, distBarH);
|
||||
|
||||
const avg = b.qualities.reduce((a, v) => a + v, 0) / count;
|
||||
const qualBarH = (avg / 100) * qualBandH;
|
||||
const y = qualTop + qualBandH - qualBarH;
|
||||
const col = qualityColor ? qualityColor(avg) : '#888';
|
||||
ctx.fillStyle = col;
|
||||
ctx.globalAlpha = highlight ? 1 : 0.75;
|
||||
ctx.fillRect(x, y, barW, qualBarH);
|
||||
ctx.globalAlpha = 1;
|
||||
if (highlight) {
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.strokeRect(x, y, barW, qualBarH);
|
||||
ctx.strokeRect(x, distTop + distBandH - distBarH, barW, distBarH);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.25)';
|
||||
samples.forEach(s => {
|
||||
const x = margin.l + ((s.distM - minD) / span) * plotW;
|
||||
const y = margin.t + plotH - (s.quality / 100) * plotH;
|
||||
const y = qualTop + qualBandH - (s.quality / 100) * qualBandH;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 1.5, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
Reference in New Issue
Block a user