src/scripts/TranscriptsTrack.js
/** Draw the exons within a gene */
Draw the exons within a gene
Draw the exons within a gene
function drawExons(
    track,
    tile,
    transcriptId,
    graphics,
    chrOffset,
    centerY,
    height,
    strand
  ) {
    const topY = centerY - height / 2;
    const tileId = +tile.tileId.split(".")[1];
    const zoomLevel = +tile.tileId.split(".")[0]; 
    const tileWidth = +track.tilesetInfo.max_width / 2 ** zoomLevel;
    const tileMinX = track.tilesetInfo.min_pos[0] + tileId * tileWidth; 
    const tileMaxX = track.tilesetInfo.min_pos[0] + (tileId + 1) * tileWidth;
    const exonStarts = track.transcriptInfo[transcriptId]["exonStarts"];
    const exonEnds = track.transcriptInfo[transcriptId]["exonEnds"];
    const isProteinCoding =
      track.transcriptInfo[transcriptId]["startCodonPos"] !== "." && track.transcriptInfo[transcriptId]["stopCodonPos"] !== ".";
    const startCodonPos = isProteinCoding
      ? track.transcriptInfo[transcriptId]["startCodonPos"] + chrOffset
      : -1;
    const stopCodonPos = isProteinCoding
      ? track.transcriptInfo[transcriptId]["stopCodonPos"] + chrOffset
      : -1;
    const txStart = track.transcriptInfo[transcriptId]["txStart"] + chrOffset;
    const txEnd = track.transcriptInfo[transcriptId]["txEnd"] + chrOffset;
    let exonOffsetStarts = exonStarts.map((x) => +x + chrOffset);
    let exonOffsetEnds = exonEnds.map((x) => +x + chrOffset);
    if (isProteinCoding) {
      exonOffsetStarts.push(startCodonPos, stopCodonPos);
      exonOffsetEnds.push(startCodonPos, stopCodonPos);
      exonOffsetStarts.sort();
      exonOffsetEnds.sort();
    }
    const xStartPos = track._xScale(txStart + 1);
    const xEndPos = track._xScale(txEnd + 1);
    const width = xEndPos - xStartPos;
    const yMiddle = centerY;
    const polys = [];
    const polysSVG = []; 
    graphics.beginFill(track.colors.intron);
    let poly = [
      xStartPos,
      yMiddle - 1,
      xStartPos + width,
      yMiddle - 1,
      xStartPos + width,
      yMiddle + 1,
      xStartPos,
      yMiddle + 1,
    ];
    graphics.drawPolygon(poly);
    polys.push([xStartPos, xStartPos + width, topY, topY + height]);
    polysSVG.push({
      rect: poly,
      color: track.colors.intronHEX,
      paintOrder: 0
    });
    for (let j = 0; j < exonOffsetStarts.length; j++) {
      const exonStart = exonOffsetStarts[j];
      const exonEnd = exonOffsetEnds[j];
      if (exonEnd < tileMinX || exonStart > tileMaxX) {
        continue;
      }
      const isNonCodingOrUtr =
        !isProteinCoding ||
        (strand === "+" &&
          (exonEnd <= startCodonPos || exonStart >= stopCodonPos)) ||
        (strand === "-" &&
          (exonStart >= startCodonPos || exonEnd <= stopCodonPos));
      const colorUsed = isNonCodingOrUtr ? track.colors.utr : track.colors[strand];
      const colorUsedSVG = isNonCodingOrUtr ? track.options.utrColor : track.colors[strand+"HEX"];
      graphics.beginFill(colorUsed);
      const xStart = track._xScale(exonStart + 1);
      const localWidth = Math.max(
        2,
        track._xScale(exonEnd + 1) - track._xScale(exonStart + 1)
      );
      let minX = xStartPos;
      let maxX = xEndPos;
      let localPoly = null;
      let localRect = null; 
      if (strand === "+") {
        const rectStartX = Math.min(xStart, maxX);
        const rectStartX2 = Math.max(rectStartX - 5, xStartPos);
        const rectEndX = Math.min(xStart + localWidth, maxX);
        const rectEndX2 = Math.max(rectEndX - 5, xStartPos);
        localPoly = [
          rectStartX,
          topY,
          rectEndX2,
          topY,
          rectEndX,
          topY + height / 2,
          rectEndX2,
          topY + height,
          rectStartX2,
          topY + height,
          rectStartX,
          topY + height / 2,
          rectStartX2,
          topY,
        ];
        localRect = [rectStartX, rectEndX, topY, topY + height];
      } else {
        const rectStartX = Math.max(xStart, minX);
        const rectStartX2 = Math.min(rectStartX + 5, xEndPos);
        const rectEndX = Math.min(Math.max(xStart + localWidth, minX),xEndPos);
        const rectEndX2 = Math.min(rectEndX + 5, xEndPos);
        localPoly = [
          rectStartX,
          topY + height / 2,
          rectStartX2,
          topY,
          rectEndX2,
          topY,
          rectEndX,
          topY + height / 2,
          rectEndX2,
          topY + height,
          rectStartX2,
          topY + height,
          rectStartX,
          topY + height / 2,
        ];
        localRect = [rectStartX, rectEndX, topY, topY + height];
      }
      graphics.drawPolygon(localPoly);
      polys.push(localRect);
      polysSVG.push({
        rect: localPoly,
        color: colorUsedSVG,
        paintOrder: 1
      });
    }
    const polysForMouseOver = polys.map((x) => [
      x,
      track.transcriptInfo[transcriptId],
    ]);
    tile.allExonsForMouseOver = tile.allExonsForMouseOver.concat(
      polysForMouseOver
    );
    tile.allExonsForSVG = tile.allExonsForSVG.concat(
      polysSVG
    );
    return;
  }
function drawExons ( track , tile , transcriptId , graphics , chrOffset , centerY , height , strand ) { const topY = centerY - height / 2 ; const tileId = + tile . tileId . split ( "." ) [ 1 ] ; const zoomLevel = + tile . tileId . split ( "." ) [ 0 ] ; const tileWidth = + track . tilesetInfo . max_width / 2 ** zoomLevel ; const tileMinX = track . tilesetInfo . min_pos [ 0 ] + tileId * tileWidth ; const tileMaxX = track . tilesetInfo . min_pos [ 0 ] + ( tileId + 1 ) * tileWidth ; const exonStarts = track . transcriptInfo [ transcriptId ] [ "exonStarts" ] ; const exonEnds = track . transcriptInfo [ transcriptId ] [ "exonEnds" ] ; const isProteinCoding = track . transcriptInfo [ transcriptId ] [ "startCodonPos" ] !== "." && track . transcriptInfo [ transcriptId ] [ "stopCodonPos" ] !== "." ; const startCodonPos = isProteinCoding ? track . transcriptInfo [ transcriptId ] [ "startCodonPos" ] + chrOffset : - 1 ; const stopCodonPos = isProteinCoding ? track . transcriptInfo [ transcriptId ] [ "stopCodonPos" ] + chrOffset : - 1 ; const txStart = track . transcriptInfo [ transcriptId ] [ "txStart" ] + chrOffset ; const txEnd = track . transcriptInfo [ transcriptId ] [ "txEnd" ] + chrOffset ; let exonOffsetStarts = exonStarts . map ( ( x ) => + x + chrOffset ) ; let exonOffsetEnds = exonEnds . map ( ( x ) => + x + chrOffset ) ; if ( isProteinCoding ) { exonOffsetStarts . push ( startCodonPos , stopCodonPos ) ; exonOffsetEnds . push ( startCodonPos , stopCodonPos ) ; exonOffsetStarts . sort ( ) ; exonOffsetEnds . sort ( ) ; } const xStartPos = track . _xScale ( txStart + 1 ) ; const xEndPos = track . _xScale ( txEnd + 1 ) ; const width = xEndPos - xStartPos ; const yMiddle = centerY ; const polys = [ ] ; const polysSVG = [ ] ; graphics . beginFill ( track . colors . intron ) ; let poly = [ xStartPos , yMiddle - 1 , xStartPos + width , yMiddle - 1 , xStartPos + width , yMiddle + 1 , xStartPos , yMiddle + 1 , ] ; graphics . drawPolygon ( poly ) ; polys . push ( [ xStartPos , xStartPos + width , topY , topY + height ] ) ; polysSVG . push ( { rect : poly , color : track . colors . intronHEX , paintOrder : 0 } ) ; for ( let j = 0 ; j < exonOffsetStarts . length ; j ++ ) { const exonStart = exonOffsetStarts [ j ] ; const exonEnd = exonOffsetEnds [ j ] ; if ( exonEnd < tileMinX || exonStart > tileMaxX ) { continue ; } const isNonCodingOrUtr = ! isProteinCoding || ( strand === "+" && ( exonEnd <= startCodonPos || exonStart >= stopCodonPos ) ) || ( strand === "-" && ( exonStart >= startCodonPos || exonEnd <= stopCodonPos ) ) ; const colorUsed = isNonCodingOrUtr ? track . colors . utr : track . colors [ strand ] ; const colorUsedSVG = isNonCodingOrUtr ? track . options . utrColor : track . colors [ strand + "HEX" ] ; graphics . beginFill ( colorUsed ) ; const xStart = track . _xScale ( exonStart + 1 ) ; const localWidth = Math . max ( 2 , track . _xScale ( exonEnd + 1 ) - track . _xScale ( exonStart + 1 ) ) ; let minX = xStartPos ; let maxX = xEndPos ; let localPoly = null ; let localRect = null ; if ( strand === "+" ) { const rectStartX = Math . min ( xStart , maxX ) ; const rectStartX2 = Math . max ( rectStartX - 5 , xStartPos ) ; const rectEndX = Math . min ( xStart + localWidth , maxX ) ; const rectEndX2 = Math . max ( rectEndX - 5 , xStartPos ) ; localPoly = [ rectStartX , topY , rectEndX2 , topY , rectEndX , topY + height / 2 , rectEndX2 , topY + height , rectStartX2 , topY + height , rectStartX , topY + height / 2 , rectStartX2 , topY , ] ; localRect = [ rectStartX , rectEndX , topY , topY + height ] ; } else { const rectStartX = Math . max ( xStart , minX ) ; const rectStartX2 = Math . min ( rectStartX + 5 , xEndPos ) ; const rectEndX = Math . min ( Math . max ( xStart + localWidth , minX ) , xEndPos ) ; const rectEndX2 = Math . min ( rectEndX + 5 , xEndPos ) ; localPoly = [ rectStartX , topY + height / 2 , rectStartX2 , topY , rectEndX2 , topY , rectEndX , topY + height / 2 , rectEndX2 , topY + height , rectStartX2 , topY + height , rectStartX , topY + height / 2 , ] ; localRect = [ rectStartX , rectEndX , topY , topY + height ] ; } graphics . drawPolygon ( localPoly ) ; polys . push ( localRect ) ; polysSVG . push ( { rect : localPoly , color : colorUsedSVG , paintOrder : 1 } ) ; } const polysForMouseOver = polys . map ( ( x ) => [ x , track . transcriptInfo [ transcriptId ] , ] ) ; tile . allExonsForMouseOver = tile . allExonsForMouseOver . concat ( polysForMouseOver ) ; tile . allExonsForSVG = tile . allExonsForSVG . concat ( polysSVG ) ; return ; }
Draw the exons within a gene
Draw the exons within a gene
// get the bounds of the tile //track.zoomLevel does not always seem to be up to date // abs coordinates // Add start and stop codon to the exon list and distingush between UTR and coding region later // holds all polygons that need to be drawn for SVG export // draw the middle line // For mouseOver // For SVG export // draw the actual exons // if the exon has no overlap with the tile, go on // without direction for mouseOver // For SVG export