a13101d076e8cf07adf14c4196ecade8b076da30 hiram Fri Nov 13 17:03:44 2020 -0800 convert mouseOverData into a slList instead of a static array refs #26505 diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index 2784455..b8f1c35 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -834,139 +834,121 @@ 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; } -/* prototype version of mouseOverData using this static array, - * will alter this to be a private linked list - */ -static struct wigMouseOver *mouseOverData = NULL; -static int mouseOverIdx = -1; - -struct wigMouseOver - { - int x1; /* beginning of a rectangle for this value */ - int x2; /* end of the rectangle */ - double value; /* data value for this region */ - int valueCount; /* number of data values in this rectangle */ - }; - -void graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width, +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 */ +/* 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); +struct wigMouseOver *mouseOverData = NULL; + /* list of mouse over data, if created here */ -boolean skipMouseOvers = FALSE; -/* start new data for a new track, freez old data if exists */ +boolean skipMouseOvers = TRUE; /* assuming not using */ if (enableMouseOver) - { - if (mouseOverData) - { - mouseOverIdx = -1; - freez(&mouseOverData); - } - AllocArray(mouseOverData, width); - } -else - skipMouseOvers = TRUE; + skipMouseOvers = FALSE; /* 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]; /* ===== mouseOver calculations===== */ if (enableMouseOver) { int mouseOverX2 = -1; double previousValue = 0; if (!skipMouseOvers && (p->count > 0)) /* checking mouseOver construction */ { if (p->count > 0) /* allow any number of values to display */ { double thisValue = p->sumData/p->count; /* average if 2 */ if (mouseOverX2 < 0) /* first valid data found */ { - ++mouseOverIdx; + struct wigMouseOver *dataItem; + AllocVar(dataItem); mouseOverX2 = x1+1; - mouseOverData[mouseOverIdx].x1 = x1; - mouseOverData[mouseOverIdx].x2 = mouseOverX2; - mouseOverData[mouseOverIdx].value = thisValue; - mouseOverData[mouseOverIdx].valueCount = p->count; + 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 */ - mouseOverData[mouseOverIdx].x2 = mouseOverX2; + /* finish off the existing run of data (list head)*/ + mouseOverData->x2 = mouseOverX2; mouseOverX2 = x1+1; - ++mouseOverIdx; - mouseOverData[mouseOverIdx].x1 = x1; - mouseOverData[mouseOverIdx].x2 = mouseOverX2; - mouseOverData[mouseOverIdx].value = thisValue; - mouseOverData[mouseOverIdx].valueCount = p->count; + 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 (mouseOverX2 > 0) /* yes, been in data, end it here */ { - mouseOverData[mouseOverIdx].x2 = mouseOverX2; + mouseOverData->x2 = mouseOverX2; mouseOverX2 = -1; /* start over with new data when found*/ } } /* potentially end the last mouseOver box */ - if (mouseOverX2 > 0 && mouseOverX2 > mouseOverData[mouseOverIdx].x2) - mouseOverData[mouseOverIdx].x2 = mouseOverX2; + 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]; Color drawColor = colorArray[x1]; if (drawColor != oldDrawColor) { mediumColor = somewhatLighterColor32(drawColor); lightColor = somewhatLighterColor32(mediumColor); oldDrawColor = drawColor; @@ -1159,57 +1141,50 @@ else if (vis == tvDense || vis == tvSquish) { 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 (enableMouseOver) - { - if (skipMouseOvers || mouseOverIdx < 0) - { - mouseOverIdx = -1; - freez(&mouseOverData); - } - } +return(mouseOverData); } /* graphPreDraw() */ -static void graphPreDrawContainer(struct preDrawContainer *preDrawContainer, +static 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; -graphPreDraw(preDraw, preDrawZero, width, - tg, wgo->image, wgo->vLine, wgo->xOff, wgo->yOff, wgo->yOffsets, wgo->numTrack, - graphUpperLimit, graphLowerLimit, graphRange, +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); freez(&colorArray); +return mouseOverData; } void drawZeroLine(enum trackVisibility vis, enum wiggleGridOptEnum horizontalGrid, double graphUpperLimit, double graphLowerLimit, struct hvGfx *hvg, int xOff, int yOff, int width, int lineHeight) /* draw a line at y=0 on the graph */ { /* Do we need to draw a zero line ? * This is to be generalized in the future to allow horizontal grid * lines, perhaps user specified to indicate thresholds. */ if ((vis == tvFull) && (horizontalGrid == wiggleHorizontalGridOn)) { @@ -1437,70 +1412,68 @@ tg->graphUpperLimit = graphUpperLimit = tg->tdb->parent->tdbExtras->minMax->max; } /* 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); -graphPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, +struct wigMouseOver *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, wigCart->yLineOnOff); if (enableMouseOver && mouseOverData) { static boolean beenHereDoneThat = FALSE; struct tempName jsonData; trashDirFile(&jsonData, "hgt", tg->track, ".json"); FILE *trashJson = mustOpen(jsonData.forCgi, "w"); struct jsonWrite *jw = jsonWriteNew(); jsonWriteObjectStart(jw, NULL); jsonWriteListStart(jw, tg->track); - int i; - /* could put up a 'no data' box when these items are not contiguous - * e.g. when gaps interrupt the track data - */ - for (i = 0; i <= mouseOverIdx; ++i) + slReverse(&mouseOverData); + struct wigMouseOver *dataItem = mouseOverData; + for (; dataItem; dataItem = dataItem->next) { jsonWriteObjectStart(jw, NULL); - jsonWriteNumber(jw, "x1", (long long)mouseOverData[i].x1); - jsonWriteNumber(jw, "x2", (long long)mouseOverData[i].x2); - jsonWriteDouble(jw, "v", mouseOverData[i].value); - jsonWriteNumber(jw, "c", mouseOverData[i].valueCount); + jsonWriteNumber(jw, "x1", (long long)dataItem->x1); + jsonWriteNumber(jw, "x2", (long long)dataItem->x2); + jsonWriteDouble(jw, "v", dataItem->value); + jsonWriteNumber(jw, "c", dataItem->valueCount); jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); fputs(jw->dy->string,trashJson); carefulClose(&trashJson); - mouseOverIdx = -1; - freez(&mouseOverData); + slFreeList(&mouseOverData); if (! beenHereDoneThat ) { hPrintf("<div id='mouseOverVerticalLine' class='mouseOverVerticalLine'></div>\n"); hPrintf("<div id='mouseOverText' class='mouseOverText'></div>\n"); // hPrintf("<div id='mouseDbg'><span id='debugMsg'><p>. . . mouseDbg</p></span></div>\n"); beenHereDoneThat = TRUE; } // hidden element to pass along jsonData file name and also the trigger // that this track has data to display. hPrintf("<div id='mouseOver_%s' name='%s' class='hiddenText mouseOverData' jsonData='%s'></div>\n", tg->track, tg->track, jsonData.forCgi); } // Might need something like this later for other purposes // else if (enableMouseOver) // system enabled, but no data for this track // { /* signal to indicate zoom in required to see data */