Estoy tratando de representar el histograma con js canvas, funciona bien, pero tengo algunos problemas con el borde visible cuando uso fillRect . Sé que se debe a que el ancho del cubo es un punto flotante en lugar de un número entero, pero redondear el ancho de mi cubo a un número entero daría como resultado que sea demasiado grande o demasiado pequeño (depende de la cantidad de cubos). Entonces mi pregunta es, ¿hay alguna solución para deshacerse de este borde?
// problem with bucket width being floating point const bucketWidth = (Math.round(((desiredHistogramWidth / (data.buckets.length - 1))) * 100) / 100) for (let i = 0; i < data.buckets.length - 1; ++i) { ctx.fillStyle = `rgb(${colors[i][0]}, ${colors[i][1]}, ${colors[i][2]})`; const x = histogramXOffset + i * bucketWidth; ctx.fillRect(x, histogramHeight, bucketWidth, -data.buckets[i] * heightPixelRatio); ctx.fillRect(x, histogramHeight + 20, bucketWidth, 20); }Este tipo de comportamiento se puede observar en este ejemplo reproducible mínimo cuando el ancho del depósito es de punto flotante.
const data = [ 1034, 783, 700, 699, 212, 123, 300, 323, 344, 344, 434, 344, 434, 434, 0, 0 ]; const canvas = document.getElementById('histogram'); const ctx = canvas.getContext('2d'); const [ width, height ] = [ canvas.clientWidth, canvas.clientHeight ] ctx.canvas.width = width; ctx.canvas.height = height; const max = Math.max(...data); const heightPixelRatio = ((height) / max); const bucketWidth = Math.round(width / (data.length) * 100) / 100 console.log(bucketWidth) for (let i = 0; i < data.length; ++i) { ctx.fillStyle = '#000'; const x = i * bucketWidth; ctx.fillRect(x, height, bucketWidth, -data[i] * heightPixelRatio); } .histogram { width: 600px; height: 800px; background: #ebecd2; } <canvas id="histogram" class="histogram"></canvas>Qué tal algo como esto:
const data = [ 1034, 783, 700, 699, 212, 123, 300, 323, 344, 344, 434, 344, 434, 434, 100, 200 ]; const canvas = document.getElementById('histogram'); const ctx = canvas.getContext('2d'); canvas.width = canvas.height = 180; const heightRatio = canvas.height / Math.max(...data); const bucketWidth = canvas.width / data.length for (let i = 0; i < data.length; ++i) { ctx.fillRect( i * bucketWidth, canvas.height, bucketWidth + 0.5, -data[i] * heightRatio ); } <canvas id="histogram" ></canvas>Puntos clave:
canvas.width / data.lengthfillRect hacemos bucketWidth + 0.5 agregando una pequeña cantidadOtra opción que estaba experimentando es solo llenar una vez:
const data = [ 1034, 783, 700, 680, 212, 123, 300, 323, 354, 340, 434, 344, 444, 430, 100, 200 ]; const canvas = document.getElementById('histogram'); const ctx = canvas.getContext('2d'); canvas.width = canvas.height = 180; const heightRatio = canvas.height / Math.max(...data); const bucketWidth = canvas.width / data.length for (let i = 0; i < data.length; ++i) { ctx.rect( i * bucketWidth, canvas.height, bucketWidth, -data[i] * heightRatio ); } ctx.fill() <canvas id="histogram" ></canvas> Para casos con una gran cantidad de cubos, simplemente no puede mostrarlos todos a la vez, debe haber un botón siguiente o crear algún tipo de desplazamiento lateral infinito, no hay muchas opciones.
Un valor de 0.01 no puede ser un ancho de bucketWidth válido que simplemente no mostrará nada