06d7be056190c14b85e71bc12523f18ea6815b5e markd Mon Dec 7 00:50:29 2020 -0800 BLAT mmap index support merge with master diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index b78a3e0..a49dea9 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -832,132 +832,125 @@ 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 x; /* x,y coordinates bottom left corner of box */ - int y; - int width; /* width,height of this box */ - int height; - double value; /* data value for this region */ - }; - -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 */ -AllocArray(mouseOverData, width); - +boolean skipMouseOvers = TRUE; /* assuming not using */ int mouseOverX2 = -1; double previousValue = 0; -boolean skipMouseOvers = FALSE; -#define epsilonLimit 1.0e-6 -// if (psOutput) -// skipMouseOvers = TRUE; +if (enableMouseOver) + 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) + { if (!skipMouseOvers && (p->count > 0)) /* checking mouseOver construction */ { - if (p->count < 3) /* allow 1 or 2 values to display */ + if (p->count > 0) /* allow any number of values to display */ { - double thisValue = p->sumData/p->count; /* average if 2 */ + double thisValue = p->sumData/p->count; /*average if count > 1*/ if (mouseOverX2 < 0) /* first valid data found */ { - ++mouseOverIdx; + struct wigMouseOver *dataItem; + AllocVar(dataItem); mouseOverX2 = x1+1; - mouseOverData[mouseOverIdx].x = xOff+x1; - mouseOverData[mouseOverIdx].width = mouseOverX2 - x1; - mouseOverData[mouseOverIdx].y = yOff; - mouseOverData[mouseOverIdx].height = h; - mouseOverData[mouseOverIdx].value = thisValue; + 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].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + /* finish off the existing run of data (list head)*/ + mouseOverData->x2 = mouseOverX2; mouseOverX2 = x1+1; - ++mouseOverIdx; - mouseOverData[mouseOverIdx].x = xOff+x1; - mouseOverData[mouseOverIdx].width = mouseOverX2 - x1; - mouseOverData[mouseOverIdx].y = yOff; - mouseOverData[mouseOverIdx].height = h; - mouseOverData[mouseOverIdx].value = thisValue; + 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].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + mouseOverData->x2 = mouseOverX2; mouseOverX2 = -1; /* start over with new data when found*/ } } /* potentially end the last mouseOver box */ - if (mouseOverX2 > 0 && (mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff)) > mouseOverData[mouseOverIdx].width) - mouseOverData[mouseOverIdx].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + 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; } /* count is non-zero meaning valid data exists here */ @@ -1147,52 +1140,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 (skipMouseOvers || mouseOverIdx < 0) - 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)) { @@ -1420,85 +1411,73 @@ 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); -#ifdef NOT_READY_TO_GO -if (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) - { - jsonWriteObjectStart(jw, NULL); - jsonWriteNumber(jw, "x1", (long long)mouseOverData[i].x); - jsonWriteNumber(jw, "y1", (long long)mouseOverData[i].y); - jsonWriteNumber(jw, "x2", (long long)(mouseOverData[i].x + mouseOverData[i].width)); - jsonWriteNumber(jw, "y2", (long long)(mouseOverData[i].y + mouseOverData[i].height)); - jsonWriteDouble(jw, "v", mouseOverData[i].value); - jsonWriteObjectEnd(jw); - } - jsonWriteListEnd(jw); - jsonWriteObjectEnd(jw); - fputs(jw->dy->string,trashJson); - // This is the hidden signal to the javaScript of where to pick up - // the json file - hPrintf("\n"); - carefulClose(&trashJson); - if (! beenHereDoneThat ) - { - hPrintf("