UNPKG

@nafr/echo-ui

Version:

A UI library born for WAA

63 lines (62 loc) 2.7 kB
import { jsx as _jsx } from "react/jsx-runtime"; import * as d3 from 'd3'; import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'; import { useResizeObserver } from '../../../lib/hooks'; import { cn, validScaledNaN } from '../../../lib/utils'; import { useStyle } from './styles'; import { WIDTH, HEIGHT, AMPLITUDE_RANGE, LINE_COLOR, LINE_WIDTH } from './constants'; export const Oscilloscope = forwardRef((props, ref) => { const { data: _data = [], amplitudeRange = AMPLITUDE_RANGE, lineColor = LINE_COLOR, lineWidth = LINE_WIDTH, ...restProps } = props; useImperativeHandle(ref, () => oscilloscopeRef.current); const oscilloscopeRef = useRef(null); const svgRef = useRef(null); const xScale = useRef(null); const yScale = useRef(null); const dataLength = useRef(0); const dimensions = useResizeObserver(oscilloscopeRef, WIDTH, HEIGHT, () => { generateScales(); generateLine(); }); useEffect(() => { generateLine(); }, [_data]); useEffect(() => { dataLength.current = _data.length; generateScales(); }, [_data.length]); const generateScales = () => { const { width, height } = dimensions.current; xScale.current = d3.scaleLinear().domain([0, dataLength.current]).range([0, width]); yScale.current = d3.scaleLinear().domain(amplitudeRange).range([height, 0]); }; const generateLine = () => { const svg = d3.select(svgRef.current); svg.selectAll('g.echo-g-line').remove(); if (!_data.length) return; const { width, height } = dimensions.current; const g = svg .append('g') .attr('class', 'echo-g-line') .attr('width', width) .attr('height', height); // Update line generator const lineGenerator = d3 .line() .x((d) => validScaledNaN(xScale.current, d.index, -100)) .y((d) => validScaledNaN(yScale.current, d.amplitude, -100)) .curve(d3.curveNatural) .curve(d3.curveCatmullRom.alpha(0.5)); // Bind new data and apply transitions g.selectAll('path.echo-path-line') .data([_data]) .join('path') .attr('class', 'echo-path-line') .attr('d', lineGenerator) .attr('stroke', lineColor) .attr('stroke-width', lineWidth) .attr('fill', 'none'); }; const { base, svg } = useStyle(); return (_jsx("div", { ...restProps, ref: oscilloscopeRef, className: cn(base(), restProps.className), style: restProps.style, children: _jsx("svg", { ref: svgRef, className: cn(svg()) }) })); });