import React, { useMemo, useRef, useEffect, useContext, useState } from 'react'; import { v1 as uuidv1 } from 'uuid'; import { formatPoint, ytransform } from '../../../utils/coordinates'; import { lighten } from '../../../utils/colors'; import { renderBigWig, datarange } from './utils'; import { FullBigWigProps, RenderedBigWigData } from './types'; import { ClipPath } from '../../clippath'; import { ValuedPoint } from 'utils/types'; import { BigWigData, BigZoomData } from 'bigwig-reader'; import { svgPoint } from './../../../utils/svg'; import { TooltipContext } from "../../tooltip/tooltipcontext"; /** * Shorthand for rendering a line to a point in an SVG path. * @param x the x coordinate of the destination, relative to the SVG. * @param y the y coordinate of the destination, relative to the SVG. */ function l(x: number, y: number): string { return ` L ${x} ${y}` } type Paths = { maxPath: string; minPath: string; }; /** * Represents a BigWig track rendered in full mode as at UCSC. A full BigWig uses a histogram-like * display to render signal values for basepairs or basepair bins along the chromosome. */ export const FullBigWig: React.FC = props => { const tooltipContext = useContext(TooltipContext); const [x, setX] = useState(); const mouseOver = (event: React.MouseEvent) => { if (props.svgRef) { const mousePosition = svgPoint(props.svgRef.current!, event); setX(mousePosition[0]); const rPoints = rendered.renderPoints.filter(v => v.min < Infinity && v.max > -Infinity); const point = rPoints.find( r => r.x === Math.round(mousePosition[0] - 150) ); tooltipContext.setTooltip({ show: true, x: mousePosition[0] > props.width - 60 ? (mousePosition[0] - 60) + 5: mousePosition[0] + 5, y: mousePosition[1], height: 80, width: 60, content: (
max: {formatPoint(point?.max)} min: {formatPoint(point?.min)}
) }); } }; const mouseOut = () => { tooltipContext.setTooltip({ show: false, x: 0, y: 0, content: undefined, width:0, height: 0 }); setX(undefined); }; const uuid = useRef(uuidv1()); const rendered: RenderedBigWigData = useMemo( () => ((props.data && props.data.length && (props.data[0] as ValuedPoint).x !== undefined) ? { renderPoints: props.data as ValuedPoint[], range: props.range || datarange(props.data as ValuedPoint[])} : renderBigWig(props.data as BigWigData[] | BigZoomData[] , props.width) ), [ props.data, props.width, props.domain ] ); const paths: Paths = useMemo( () => { const y = ytransform(rendered.range, props.height); const renderPoints = rendered.renderPoints.filter(v => v.min < Infinity && v.max > -Infinity); return { maxPath: renderPoints.reduce( (path, cv, ci, items) => ( path + (cv.x ? l(cv.x, y(items[ci - 1] ? items[ci - 1].max : 0)) : "") + l(cv.x, y(cv.max)) ), "M 0 " + y(0.0) + ' ') + l(props.width, y(0.0)), minPath: renderPoints.reduce( (path, cv, ci, items) => ( path + (cv.x ? l(cv.x, y(items[ci - 1] ? items[ci - 1].min : 0)) : "") + l(cv.x, y(cv.min)) ), "M 0 " + y(0.0) + ' ') + l(props.width, y(0.0)) }; }, [ rendered, props.height ]); const color = props.color || "#000000"; const lightColor = useMemo( () => props.noTransparency ? color : lighten(color, 0.5), [ props ]); useEffect( () => { props.onHeightChanged && props.onHeightChanged(props.height); }, [ props.height ]); return ( {)=> { e.persist(); mouseOver(e);}} /> } {)=> { e.persist(); mouseOver(e);}} /> } {x!==undefined && } ); } export default FullBigWig;