// @ts-nocheck import React, { memo, useMemo } from 'react'; import tw from 'twin.macro'; import { ascending, bin, min, max, extent, scaleLinear } from 'd3'; import { getTrackBackground, Range } from 'react-range'; interface HistogramProps { shortFormat: (value: number) => string; longFormat: (value: number) => string; filtered: number[]; original: number[]; id: string; focusedValue?: number; onChange: (value: [number, number]) => void; maxWidth?: number; value?: [number, number]; } export function HtmlHistogram(props: HistogramProps) { const { filtered, original, value, focusedValue, shortFormat, longFormat, maxWidth, onChange, } = props; const height = 30; const { bins } = useMemo(() => { const maxBins = maxWidth ? Math.max(0, Math.floor(maxWidth / 6) * 0.55) : 11; let bins = bin().thresholds(maxBins)(original); if (original.length < 200) { const uniqueValues = Array.from(new Set(original)).sort(ascending); const numberOfUniqueValues = uniqueValues.length; if (numberOfUniqueValues > 1 && numberOfUniqueValues < 12) { const firstValueSpacing = uniqueValues[1] - uniqueValues[0]; const areValuesEquallySpaced = uniqueValues.find( (value, index) => index && value - uniqueValues[index - 1] !== firstValueSpacing ) === undefined; if (areValuesEquallySpaced) { bins = bin().thresholds(uniqueValues)(original); } else { if (bins.length > numberOfUniqueValues) { bins = bin().thresholds(numberOfUniqueValues)(original); } } } } return { bins }; }, [original, maxWidth, value]); const filteredBins = bins.map((bin, binIndex) => { const isLastIndex = binIndex === bins.length - 1; let newBin = filtered.filter( d => d >= bin.x0 && (d < bin.x1 || isLastIndex) ); return newBin; }); const { xScale, yScale } = useMemo(() => ({ xScale: scaleLinear() .domain([min(bins, d => d.x0), max(original)]) .range([0, 100]), yScale: scaleLinear() .domain([0, max(bins, d => d.length)]) .range([0, 100]) }), [bins, original]); const rangeValues = useMemo(() => ( value ? [xScale(value[0]), xScale(value[1])] : [0, 100] ), [xScale, value]); const focusedBinIndex = focusedValue && bins.findIndex((d, i) => { if (d.x0 <= focusedValue && d.x1 > focusedValue) { return true; } if (i === bins.length - 1 && d.x1 === focusedValue) { return true; } return false; }); const valueExtent = extent(original); const isOneValue = valueExtent[0] === valueExtent[1]; // const focusedBin = bins[focusedBinIndex]; const barWidth = 4; const barSpacing = 2; const totalBarWidth = barWidth + barSpacing; const totalWidth = filteredBins.length * totalBarWidth; let stepSize = bins.length > 1 ? xScale(bins[1].x1) - xScale(bins[0].x1) || 50 : 100; if (stepSize < 1) stepSize = 1; const isFiltered = rangeValues[0] !== 0 || rangeValues[1] !== 100; if (isOneValue) { return (
{longFormat(xScale.invert(rangeValues[0]))}
); } return (
{bins.length > 1 && ( <>
{bins.map((bin, i) => { const height = yScale(bin.length); const filteredHeight = yScale(filteredBins[i].length); return ( ); })}
)}
); } export default HtmlHistogram; const Bin = memo(({ height, filteredHeight, barWidth, barSpacing, isFocused }) => { return (
{isFocused && (
)}
) }) const BarRange = memo(({ totalWidth, stepSize, onChange, xScale, rangeValues, isFiltered, }) => { return (
{ if (newRange[0] === 0 && newRange[1] === 100) { onChange(undefined); return; } const x0 = xScale.invert(newRange[0]); const x1 = xScale.invert(newRange[1]); onChange([x0, x1]); }} renderTrack={({ props, children }) => (
{children}
)} renderThumb={({ props, isDragged }) => { return (
); }} />
) }) const Axis = memo(({ totalWidth, rangeValues, min, max, isFiltered, }) => { return (
{min}
{max}
) })