b707eeb51bad2091d226fc58e025fde1c7646c94
hiram
  Fri Oct 16 16:09:40 2020 -0700
initial prototype of wiggle mouse over values, it is really slow refs #21980

diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c
index 27ffea1..508d7a7 100644
--- src/hg/hgTracks/wigTrack.c
+++ src/hg/hgTracks/wigTrack.c
@@ -831,58 +831,135 @@
 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 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 */
 {
 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);
 
+AllocArray(mouseOverData, width);
+
+int mouseOverX2 = -1;
+double previousValue = 0;
+boolean skipMouseOvers = FALSE;
+#define epsilonLimit 1.0e-6
+// if (psOutput)
+//    skipMouseOvers = 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.
  */
 for (x1 = 0; x1 < width; ++x1)
     {
     int x = x1 + xOff;
     int preDrawIndex = x1 + preDrawZero;
     struct preDrawElement *p = &preDraw[preDrawIndex];
+    /* ===== mouseOver calculations===== */
+    if (!skipMouseOvers && (p->count > 0)) /* checking mouseOver construction */
+	{
+	if (p->count < 3)	/* allow 1 or 2 values to display */
+	    {
+	    double thisValue = p->sumData/p->count;	/* average if 2 */
+	    if (mouseOverX2 < 0)    /* first valid data found */
+		{
+		++mouseOverIdx;
+		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;
+		previousValue = thisValue;
+		}
+	    else	/* see if we need a new item */
+		{
+		if (fabs(thisValue - previousValue) > epsilonLimit)
+		    {
+		    /* finish off the existing run of data */
+		    mouseOverData[mouseOverIdx].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff);
+		    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;
+		    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);
+	    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);
+
+    /* ===== 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	*/
     if (p->count)
 	{
 	/*	data value has been picked by previous scanning.
@@ -1069,30 +1146,34 @@
         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);
+
 }	/*	graphPreDraw()	*/
 
 static void 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,
@@ -1350,30 +1431,45 @@
 
 wigTrackSetGraphOutputDefault(tg, xOff, yOff, width, hvg); 
 
 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 (mouseOverData)
+    {
+    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)
+	{
+	char value[64];
+	safef(value, sizeof(value), " %g", mouseOverData[i].value);
+	mapBoxHc(hvg, seqStart, seqEnd, mouseOverData[i].x, mouseOverData[i].y, mouseOverData[i].width, mouseOverData[i].height,
+      tg->track, value, value);
+        }
+    }
+else
     wigMapSelf(tg, hvg, seqStart, seqEnd, xOff, yOff, width);
 
 }
 
 struct preDrawContainer *wigLoadPreDraw(struct track *tg, int seqStart, int seqEnd, int width)
 /* Do bits that load the predraw buffer tg->preDrawContainer. */
 {
 /* Just need to do this once... */
 if (tg->preDrawContainer)
     return tg->preDrawContainer;
 
 struct wigItem *wi;
 double pixelsPerBase = scaleForPixels(width);
 double basesPerPixel = 1.0;
 int itemCount = 0;