import React, { useEffect, useState } from 'react'; import { BamTrackProps } from './types'; import { parseRawIndexRefData, BamIndexRefData, BamAlignment, blocksForRange, CigarOp } from 'bigwig-reader'; import { EmptyTrack } from '../empty'; import { StackedTracks } from '../../browser'; import { isReactElement } from '../../../utils'; import { BamRect } from '../bam/types'; const BamTrack: React.FC = props => { const [refId, setRefId] = useState(); const [indexRefData, setIndexRefData] = useState(); const [bamData, setBamData] = useState(); useEffect(()=>{ const fetchBamData = async () => { if(!indexRefData) return; let bamData = '', d = true; try { let response = await fetch(props.endpoint+'/bam', { method: 'post', body: JSON.stringify({bamUrl: props.track.bamUrl, refId: refId, chr: props.track.chr, start: props.track.start, end: props.track.end, chunks: blocksForRange(indexRefData, props.track.start, props.track.end),}), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); const reader = response && response.body && response.body.getReader(); while(d) { const { done, value } = await reader!.read(); const val = new TextDecoder('utf-8').decode(value); bamData += val; if (done) { d = false; console.log('done reading bam'); } } const bamResData = JSON.parse(bamData); setBamData(bamResData); } catch(e){ console.log(e) } } fetchBamData() },[indexRefData, props.track.start, props.track.end, props.track.chr]) useEffect(()=>{ const fetchBamIndexData = async () =>{ if (refId===undefined) return; try { let response = await fetch(props.endpoint+'/bamIndex', { method: 'post', body: JSON.stringify({ baiUrl: props.track.baiUrl, refId: refId }), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); let bamIndexResponse = await response.arrayBuffer(); let bamIndexRefData = parseRawIndexRefData(bamIndexResponse); if (bamIndexRefData.linearIndex && bamIndexRefData.linearIndex.length > 0 && bamIndexRefData.binIndex) { setIndexRefData(bamIndexRefData); } } catch (e) { console.log(e); } } fetchBamIndexData() },[refId]) useEffect(() => { const fetchBamHeaderData = async () => { let bamHeaderData = ''; let d = true try { let response = await fetch(props.endpoint+'/bamHeader', { method: 'post', body: JSON.stringify({bamUrl: props.track.bamUrl}), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); const reader = response && response.body && response.body.getReader(); while (d) { const { done, value } = await reader!.read(); const val = new TextDecoder('utf-8').decode(value); bamHeaderData += val; if (done) { console.log('done reading bam header'); d = false; } } const headerData = JSON.parse(bamHeaderData); setRefId(headerData.chromToId[props.track.chr]); } catch (e){ console.log(e) } }; fetchBamHeaderData(); }, [ props.track.bamUrl, props.track.chr ]); let data:BamRect[] | undefined = bamData && bamData.map((feature: BamAlignment)=>{ return { strand: feature.strand, start: feature.start, end: feature.start + feature.cigarOps.map((cg: CigarOp)=> cg.opLen).reduce((a: number, b: number) => a + b, 0), color: props.track.color, seq: feature.seq, cigarOps: feature.cigarOps.map((cg: CigarOp,i: number)=> { let s = i !== 0 && (feature.cigarOps[i - 1].op == 'D' || feature.cigarOps[i - 1].op == 'N') ? feature.cigarOps[i - 1].opLen : 0; return { opStart: (feature.start + +s + cg.seqOffset), opEnd: ( (feature.start + +s + cg.seqOffset)+ cg.opLen), op: cg.op }}) } }) return data && data.length > 0 && data[0].start ? ( { React.Children.map( props.children, (child: React.ReactNode) => ( isReactElement(child) ? ( React.cloneElement( child, { ...child.props, data: data } ) ) : ( child ) ))} ) : ( ); } export default BamTrack;