447c433324a13653e1760bc7e4d1a854e517a1e6 braney Mon Dec 13 09:57:45 2021 -0800 fix mouseovers for logo wiggles diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index 48e28ec..87deb7a 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -833,74 +833,53 @@ return wgo; } struct wigGraphOutput *wigGraphOutputSolid(int xOff, int yOff, struct hvGfx *image) /* Get appropriate wigGraphOutput for non-transparent rendering */ { struct wigGraphOutput *wgo; AllocVar(wgo); wgo->image = image; wgo->vLine = vLineViaHvg; wgo->xOff = xOff; wgo->yOff = yOff; return wgo; } -struct wigMouseOver *graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width, - struct track *tg, void *image, WigVerticalLineVirtual vLine, int xOff, int yOff, double *yOffsets, int numTrack, - double graphUpperLimit, double graphLowerLimit, double graphRange, - double epsilon, Color *colorArray, enum trackVisibility vis, - struct wigCartOptions *wigCart, struct pixelCountBin *pixelBins) -/* graph the preDraw array, returns mouse over data, or NULL */ +struct wigMouseOver *getMouseOverData(struct track *tg, struct preDrawElement *preDraw, int width, int xOff, int preDrawZero) +/* Calculate the mouseOver data. */ { int x1; -int h = tg->lineHeight; /* the height of our drawing window */ -double scaleFactor = h/graphRange; -Color oldDrawColor = colorArray[0] + 1; /* Just to be different from 1st drawColor. */ -Color mediumColor = MG_BLACK; // Will be overriden -Color lightColor = MG_BLACK; // Will be overriden -Color clipColor = MG_MAGENTA; -enum wiggleTransformFuncEnum transformFunc = wigCart->transformFunc; -enum wiggleGraphOptEnum lineBar = wigCart->lineBar; -boolean whiskers = (wigCart->windowingFunction == wiggleWindowingWhiskers - && width < winEnd-winStart); -struct wigMouseOver *mouseOverData = NULL; - /* list of mouse over data, if created here */ - boolean skipMouseOvers = TRUE; /* assuming not using */ +boolean dropMouseOverData = FALSE; // will become TRUE if noAverage int mouseOverX2 = -1; +struct wigMouseOver *mouseOverData = NULL; double previousValue = 0; -if (enableMouseOver) - skipMouseOvers = FALSE; - -boolean noAverage = FALSE; -boolean dropMouseOverData = FALSE; // will become TRUE if noAverage - // condition is encountered char *mouseOverFunction = trackDbSetting(tg->tdb, "mouseOverFunction"); +boolean noAverage = FALSE; if (sameOk(mouseOverFunction, "noAverage")) noAverage = TRUE; -/* right now this is a simple pixel by pixel loop. Future - * enhancements could draw boxes where pixels - * are all the same height in a run. - */ +if (enableMouseOver) + skipMouseOvers = FALSE; + // condition is encountered +/* ===== mouseOver calculations===== */ for (x1 = 0; x1 < width; ++x1) { - int x = x1 + xOff; + //int x = x1 + xOff; int preDrawIndex = x1 + preDrawZero; struct preDrawElement *p = &preDraw[preDrawIndex]; - /* ===== mouseOver calculations===== */ if (enableMouseOver && !dropMouseOverData) { /* checking if mouseOver construction is allowed */ if (!skipMouseOvers && (p->count > 0) && !(noAverage && p->count>1)) { if (p->count > 0) /* allow any number of values to display */ { double thisValue = p->sumData/p->count; /*average if count > 1*/ if (mouseOverX2 < 0) /* first valid data found */ { struct wigMouseOver *dataItem; AllocVar(dataItem); mouseOverX2 = x1+1; dataItem->x1 = x1; dataItem->x2 = mouseOverX2; @@ -939,32 +918,68 @@ if (noAverage && p->count>1) dropMouseOverData = TRUE; else if (mouseOverX2 > 0) /* yes, been in data, end it here */ { mouseOverData->x2 = mouseOverX2; mouseOverX2 = -1; /* start over with new data when found*/ } } /* potentially end the last mouseOver box */ if (mouseOverX2 > 0 && mouseOverX2 > mouseOverData->x2) mouseOverData->x2 = mouseOverX2; } // if (enableMouseOver) else skipMouseOvers = TRUE; + } +if (dropMouseOverData) + slFreeList(&mouseOverData); - /* ===== done with mouseOver calculations===== */ +return mouseOverData; +} + +struct wigMouseOver *graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width, + struct track *tg, void *image, WigVerticalLineVirtual vLine, int xOff, int yOff, double *yOffsets, int numTrack, + double graphUpperLimit, double graphLowerLimit, double graphRange, + double epsilon, Color *colorArray, enum trackVisibility vis, + struct wigCartOptions *wigCart, struct pixelCountBin *pixelBins) +/* graph the preDraw array, returns mouse over data, or NULL */ +{ +int x1; +int h = tg->lineHeight; /* the height of our drawing window */ +double scaleFactor = h/graphRange; +Color oldDrawColor = colorArray[0] + 1; /* Just to be different from 1st drawColor. */ +Color mediumColor = MG_BLACK; // Will be overriden +Color lightColor = MG_BLACK; // Will be overriden +Color clipColor = MG_MAGENTA; +enum wiggleTransformFuncEnum transformFunc = wigCart->transformFunc; +enum wiggleGraphOptEnum lineBar = wigCart->lineBar; +boolean whiskers = (wigCart->windowingFunction == wiggleWindowingWhiskers + && width < winEnd-winStart); + /* list of mouse over data, if created here */ + +struct wigMouseOver *mouseOverData = getMouseOverData(tg, preDraw, width, xOff, preDrawZero); + +/* right now this is a simple pixel by pixel loop. Future + * enhancements could draw boxes where pixels + * are all the same height in a run. + */ +for (x1 = 0; x1 < width; ++x1) + { + int x = x1 + xOff; + int preDrawIndex = x1 + preDrawZero; + struct preDrawElement *p = &preDraw[preDrawIndex]; assert(x1/pixelBins->binSize < pixelBins->binCount); unsigned long *bitCount = &pixelBins->bins[x1/pixelBins->binSize]; Color drawColor = colorArray[x1]; if (drawColor != oldDrawColor) { mediumColor = somewhatLighterColor32(drawColor); lightColor = somewhatLighterColor32(mediumColor); oldDrawColor = drawColor; } /* count is non-zero meaning valid data exists here */ if (p->count) { @@ -1153,218 +1168,67 @@ { double grayValue; int grayIndex; /* honor the viewLimits, data below is white, data above is black */ grayValue = max(dataValue,graphLowerLimit); grayValue = min(grayValue,graphUpperLimit); grayIndex = ((grayValue-graphLowerLimit)/graphRange)*MAX_WIG_VALUE; drawColor = tg->colorShades[grayInRange(grayIndex, 0, MAX_WIG_VALUE)]; doLine(image, x, yOff, tg->lineHeight, drawColor); } /* vis == tvDense || vis == tvSquish */ } /* if (preDraw[].count) */ } /* for (x1 = 0; x1 < width; ++x1) */ -if (dropMouseOverData) - slFreeList(&mouseOverData); return(mouseOverData); } /* graphPreDraw() */ -#ifdef NOTNOW -static void drawLogoChar( struct hvGfx *hvg, int xOff, int yOff, struct dnaMotif *motif, int width, int height, int count, boolean flip) -{ -int orangeColor = hvGfxFindColorIx(hvg, 230, 130, 0); -int blueColor = hvGfxFindColorIx(hvg, 0,114,198); -int greenColor = hvGfxFindColorIx(hvg, 28,206,40); - -int ii; -FILE *f; -struct tempName pngTn; -unsigned char *buf; - -buf = needMem(width + 1); -makeTempName(&pngTn, "logo", ".pgm"); -dnaMotifToLogoPGM(motif, width / count, width , (double)height - 2, NULL, "../trash", pngTn.forCgi); - -f = mustOpen(pngTn.forCgi, "r"); - -/* get rid of header */ -for(ii=0; ii < 4; ii++) - while(fgetc(f) != '\n') - ; - -/* map colors from PGM to browser colors */ -Color *colors = needMem(sizeof(Color) * (1+width)); -for(ii=0; ii < height; ii++) - { - int jj; - mustRead(f, buf, width); - - for(jj=0; jj < width + 2; jj++) - { - if (buf[jj] == 255) colors[jj] = MG_WHITE; - else if (buf[jj] == 0x87) colors[jj] = MG_RED; - else if (buf[jj] == 0x60) colors[jj] = greenColor; - else if (buf[jj] == 0x7f) colors[jj] = blueColor; - else if (buf[jj] == 0x62) colors[jj] = orangeColor; - } - - if (flip) - { - int pos = yOff + height - ii; - hvGfxVerticalSmear(hvg,xOff,pos,width ,1, colors,TRUE); - // hvGfxBox(hvg, xOff, pos, width, 1, MG_BLACK); - } - else - hvGfxVerticalSmear(hvg,xOff,yOff+ii,width ,1, colors,TRUE); - } -hvGfxUnclip(hvg); - -fclose(f); -remove(pngTn.forCgi); -} -#endif - -struct dnaMotif *getMotif(int numBases) -{ -struct dnaMotif *motif; -AllocVar(motif); -motif->name = NULL; -motif->columnCount = numBases; -motif->aProb = needMem(sizeof(float) * motif->columnCount); -motif->cProb = needMem(sizeof(float) * motif->columnCount); -motif->gProb = needMem(sizeof(float) * motif->columnCount); -motif->tProb = needMem(sizeof(float) * motif->columnCount); - -return motif; -} - static struct wigMouseOver *logoPreDrawContainer(struct preDrawContainer *preDrawContainer, int preDrawZero, int width, struct track *tg, struct hvGfx *hvg, int xOff, int yOff, double graphUpperLimit, double graphLowerLimit, double graphRange, enum trackVisibility vis, struct wigCartOptions *wigCart, int seqStart, int seqEnd) { struct preDrawElement *preDraw = preDrawContainer->preDraw; struct wigGraphOutput *wgo = tg->wigGraphOutput; -struct wigMouseOver *mouseOverData = NULL; +//struct wigMouseOver *mouseOverData = NULL; unsigned numBases = seqEnd - seqStart; struct dnaSeq *seq = hChromSeq(database, chromName, seqStart, seqEnd); struct pixelCountBin *pixelBins = wgo->pixelBins; double *yOffsets = wgo->yOffsets; int numTrack = wgo->numTrack; Color clipColor = MG_MAGENTA; WigVerticalLineVirtual vLine = wgo->vLine; void *image = wgo->image; #define doLine(image, x, y, height, color) {vLine(image, x, y, height, color); } int h = tg->lineHeight; /* the height of our drawing window */ double scaleFactor = h/graphRange; - -boolean skipMouseOvers = TRUE; /* assuming not using */ -int mouseOverX2 = -1; -double previousValue = 0; -if (enableMouseOver) - skipMouseOvers = FALSE; - -boolean noAverage = FALSE; -boolean dropMouseOverData = FALSE; // will become TRUE if noAverage - // condition is encountered -char *mouseOverFunction = trackDbSetting(tg->tdb, "mouseOverFunction"); -if (sameOk(mouseOverFunction, "noAverage")) - noAverage = TRUE; - -struct dnaMotif *motifPos = getMotif(numBases); -struct dnaMotif *motifNeg = getMotif(numBases); +struct wigMouseOver *mouseOverData = getMouseOverData(tg, preDraw, width, xOff, preDrawZero); double xIncr = (double)width / numBases; unsigned baseNum; int lastX = xOff; for(baseNum = 0; baseNum < numBases; baseNum++) { int x1 = baseNum * xIncr; int x = x1 + xOff; int width = x - lastX; int base = seq->dna[baseNum]; lastX = x; int preDrawIndex = x1 + preDrawZero; struct preDrawElement *p = &preDraw[preDrawIndex]; - /* ===== mouseOver calculations===== */ - if (enableMouseOver && !dropMouseOverData) - { - /* checking if mouseOver construction is allowed */ - if (!skipMouseOvers && (p->count > 0) && !(noAverage && p->count>1)) - { - if (p->count > 0) /* allow any number of values to display */ - { - double thisValue = p->sumData/p->count; /*average if count > 1*/ - if (mouseOverX2 < 0) /* first valid data found */ - { - struct wigMouseOver *dataItem; - AllocVar(dataItem); - mouseOverX2 = x1+1; - dataItem->x1 = x1; - dataItem->x2 = mouseOverX2; - dataItem->value = thisValue; - dataItem->valueCount = p->count; - slAddHead(&mouseOverData, dataItem); - previousValue = thisValue; - } - else /* see if we need a new item */ - { -#define epsilonLimit 1.0e-6 - if (fabs(thisValue - previousValue) > epsilonLimit) - { - /* finish off the existing run of data (list head)*/ - mouseOverData->x2 = mouseOverX2; - mouseOverX2 = x1+1; - struct wigMouseOver *dataItem; - AllocVar(dataItem); - dataItem->x1 = x1; - dataItem->x2 = mouseOverX2; - dataItem->value = thisValue; - dataItem->valueCount = p->count; - slAddHead(&mouseOverData, dataItem); - previousValue = thisValue; - } - else /* continue run of same data value */ - mouseOverX2 = x1+1; - } - } - else - skipMouseOvers = TRUE; /* has become too dense to make sense */ - } - else /* perhaps entered region without values after some data already */ - { - - if (noAverage && p->count>1) - dropMouseOverData = TRUE; - else if (mouseOverX2 > 0) /* yes, been in data, end it here */ - { - mouseOverData->x2 = mouseOverX2; - mouseOverX2 = -1; /* start over with new data when found*/ - } - } - /* potentially end the last mouseOver box */ - if (mouseOverX2 > 0 && mouseOverX2 > mouseOverData->x2) - mouseOverData->x2 = mouseOverX2; - - } // if (enableMouseOver) - else - skipMouseOvers = TRUE; - - /* ===== done with mouseOver calculations===== */ assert(x1/pixelBins->binSize < pixelBins->binCount); unsigned long *bitCount = &pixelBins->bins[x1/pixelBins->binSize]; /* count is non-zero meaning valid data exists here */ if (p->count) { /* data value has been picked by previous scanning. * Could be smoothed, maybe not. */ double dataValue = p->smooth; /* save a number that represents how many pixels that would be set if we were drawing bars. * This may used for sorting later on */ int iy0 = graphUpperLimit * scaleFactor; @@ -1401,106 +1265,80 @@ if (numTrack > 0) { y0 = (graphUpperLimit - yOffsets[(numTrack-1) * width + x1]) *scaleFactor; y1 = (graphUpperLimit - dataValue - yOffsets[(numTrack-1) * width + x1])*scaleFactor; } } int boxHeight = max(1,abs(y1 - y0)); int boxTop = min(y1,y0); // positive data value exactly equal to Bottom pixel // make sure it draws at least a pixel there if (boxTop == h) boxTop = h - 1; - // negative data value exactly equal to top pixel - // make sure it draws something - double prob = (double)(dataValue) / (graphUpperLimit - graphLowerLimit); - char string[2]; string[0] = toupper(base); string[1] = 0; MgFont *font = tl.font; int height = dataValue * scaleFactor; unsigned color = MG_BLACK; if (base == 'a') color = MG_RED; else if (base == 't') color = MG_GREEN; else if (base == 'c') color = MG_BROWN; else if (base == 'g') color = MG_BLUE; if (abs(dataValue) > 0.1) { if (dataValue < 0) { - //hvGfxBox(image, x, yOff+graphUpperLimit * scaleFactor, width, -height, MG_RED); hvGfxTextInBox(hvg, x, yOff+graphUpperLimit * scaleFactor, width - 1, dataValue * scaleFactor, color, font, string); } else { - // hvGfxBox(image, x, yOff-height+graphUpperLimit * scaleFactor, width, height, MG_RED); - hvGfxTextInBox(hvg, x, yOff-height+graphUpperLimit * scaleFactor, width - 1, dataValue * scaleFactor, color, font, string); } } if (((boxTop+boxHeight) == 0) && !isnan(dataValue)) boxHeight += 1; - struct dnaMotif *motif; - if (dataValue < 0) - { - motif = motifNeg; - prob = -prob; - } - else - motif = motifPos; - if (base == 'a') - motif->aProb[baseNum] = prob; - if (base == 't') - motif->tProb[baseNum] = prob; - if (base == 'c') - motif->cProb[baseNum] = prob; - if (base == 'g') - motif->gProb[baseNum] = prob; } double stackValue = dataValue; if ((yOffsets != NULL) && (numTrack > 0)) stackValue += yOffsets[(numTrack-1) * width + x1]; if (stackValue > graphUpperLimit) { doLine(image, x, yOff, 2, clipColor); } else if (stackValue < graphLowerLimit) { doLine(image, x, yOff + h - 1, 2, clipColor); } #undef scaleHeightToPixels /* No longer use this symbol */ } /* vis == tvFull || vis == tvPack */ } } /* for (x1 = 0; x1 < width; ++x1) */ -if (dropMouseOverData) - slFreeList(&mouseOverData); return(mouseOverData); } - struct wigMouseOver *graphPreDrawContainer(struct preDrawContainer *preDrawContainer, int preDrawZero, int width, struct track *tg, struct hvGfx *hvg, int xOff, int yOff, double graphUpperLimit, double graphLowerLimit, double graphRange, enum trackVisibility vis, struct wigCartOptions *wigCart) /* Draw the graphs for all tracks in container. */ { double epsilon = graphRange / tg->lineHeight; struct preDrawElement *preDraw = preDrawContainer->preDraw; Color *colorArray = makeColorArray(preDraw, width, preDrawZero, wigCart, tg, hvg); struct wigGraphOutput *wgo = tg->wigGraphOutput; struct wigMouseOver *mouseOverData = graphPreDraw(preDraw, preDrawZero, width, tg, wgo->image, wgo->vLine, wgo->xOff, wgo->yOff, wgo->yOffsets, wgo->numTrack, graphUpperLimit, graphLowerLimit, graphRange, epsilon, colorArray, vis, wigCart, wgo->pixelBins); @@ -1745,31 +1583,32 @@ } /* if we're autoscaling and the range is 0 this implies that all values * in the given range are the same. We create a bottom of the scale * by subtracting one from the only value. * This results in drawing a box that fills the range. */ if (graphUpperLimit == graphLowerLimit) { graphLowerLimit = graphUpperLimit - 1; } graphRange = graphUpperLimit - graphLowerLimit; wigTrackSetGraphOutputDefault(tg, xOff, yOff, width, hvg); struct wigMouseOver *mouseOverData = NULL; -if (zoomedToCodonLevel && trackDbSettingOn(tg->tdb, "logo")) +//if (zoomedToCodonLevel && trackDbSettingOn(tg->tdb, "logo")) +if (zoomedToBaseLevel && trackDbSettingOn(tg->tdb, "logo")) mouseOverData = logoPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, graphUpperLimit, graphLowerLimit, graphRange, vis, wigCart, seqStart, seqEnd); else mouseOverData = graphPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, graphUpperLimit, graphLowerLimit, graphRange, vis, wigCart); drawZeroLine(vis, wigCart->horizontalGrid, graphUpperLimit, graphLowerLimit, hvg, xOff, yOff, width, tg->lineHeight); drawArbitraryYLine(vis, (enum wiggleGridOptEnum)wigCart->yLineOnOff, graphUpperLimit, graphLowerLimit, hvg, xOff, yOff, width, tg->lineHeight, wigCart->yLineMark, graphRange,