e1ba0aaa1baec345d56cc8a518b8450c3e5d74c3 tdreszer Wed Jan 22 14:31:22 2014 -0800 Checking in new feature 'drag-select highlight', which was originally coded by Larry. Redmine #709 (been on the shelf for awhile). diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c index c57b6b2..560111e 100644 --- src/hg/hgTracks/hgTracks.c +++ src/hg/hgTracks/hgTracks.c @@ -1906,30 +1906,72 @@ hvGfxUnclip(hvg); return y; } static void rAddToTrackHash(struct hash *trackHash, struct track *trackList) /* Add list and any children of list to hash. */ { struct track *track; for (track = trackList; track != NULL; track = track->next) { hashAddUnique(trackHash, track->track, track); rAddToTrackHash(trackHash, track->subtracks); } } +void highlightRegion(struct cart *cart, struct hvGfx *hvg, int insideX, int imagePixelHeight, + int winStart, int winEnd) +// Highlights a region in the image. Only done if theImgBox is not defined. +// Thus it is done for ps/pdf and view image but the hgTracks image is highlighted via js +{ +char *highlightDef = cartOptionalString(cart, "highlight"); +if(highlightDef && theImgBox == NULL) // Only highlight region when imgBox is not used. + { + // expect db.chrom:start-end#hexColor + char *db = cloneNextWordByDelimiter(&highlightDef,'.'); + char *chrom = cloneNextWordByDelimiter(&highlightDef,':'); + int chromStart = atoi(cloneNextWordByDelimiter(&highlightDef,'-')); + int chromEnd = atoi(cloneNextWordByDelimiter(&highlightDef,'#')); + if ((db != NULL && sameString(db, database )) + && (chrom != NULL && sameString(chrom,chromName)) + && (chromEnd != 0) + && (chromStart <= winEnd && chromEnd >= winStart)) + { + chromStart--; // Not zero based + chromStart = max(chromStart, winStart); + chromEnd = min(chromEnd, winEnd); + double pixelsPerBase = scaleForPixels(insideWidth + 1); + int startPixels = pixelsPerBase * (chromStart - winStart); // floor + if (startPixels < 0) + startPixels *= -1; // reverse complement + int width = pixelsPerBase * (double)(chromEnd - chromStart) + 0.5; // round up + if (width < 2) + width = 2; + + // Default color to light blue, but if setting has color, use it. + unsigned int hexColor = MAKECOLOR_32(170, 255, 255); + if (highlightDef != NULL && *highlightDef != '\0') + { + long rgb = strtol(highlightDef,NULL,16); // Big and little Endians + hexColor = MAKECOLOR_32( ((rgb>>16)&0xff), ((rgb>>8)&0xff), (rgb&0xff) ); + } + + hvGfxBox(hvg, insideX + startPixels, 0, width, imagePixelHeight,hexColor); + } + } +} + struct hash *makeGlobalTrackHash(struct track *trackList) /* Create a global track hash and returns a pointer to it. */ { trackHash = newHash(8); rAddToTrackHash(trackHash, trackList); return trackHash; } void makeActiveImage(struct track *trackList, char *psOutput) /* Make image and image map. */ { struct track *track; MgFont *font = tl.font; struct hvGfx *hvg; @@ -2154,30 +2196,33 @@ trashDirFile(&gifTnSide, "hgtSide", "side", ".png"); hvgSide = hvGfxOpenPng(pixWidth, pixHeight, gifTnSide.forCgi, transparentImage); // Also add the side image theSideImg = imgBoxImageAdd(theImgBox,gifTnSide.forHtml,NULL,pixWidth, pixHeight,FALSE); hvgSide->rc = revCmplDisp; initColors(hvgSide); } } hvg->rc = revCmplDisp; initColors(hvg); /* Start up client side map. */ hPrintf("<MAP id='map' Name=%s>\n", mapName); +if (theImgBox == NULL) // imageV2 highlighting is done by javascript. + highlightRegion(cart, hvg, insideX, imagePixelHeight, winStart, winEnd); + /* Find colors to draw in. */ findTrackColors(hvg, trackList); // Good to go ahead and add all imgTracks regardless of buttons, left label, centerLabel, etc. if (theImgBox) { if (rulerMode != tvHide) { curImgTrack = imgBoxTrackFindOrAdd(theImgBox,NULL,RULER_TRACK_NAME,rulerMode,FALSE, IMG_FIXEDPOS); // No tdb, no centerLbl, not reorderable } for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next) { track = flatTrack->track; @@ -4539,40 +4584,30 @@ if (showTrackControls) { /* Break into a second form so that zooming and scrolling * can be done with a 'GET' so that user can back up from details * page without Internet Explorer popping up an annoying dialog. * Do rest of page as a 'POST' so that the ultra-long URL from * all the track controls doesn't break things. IE URL limit * is 2000 bytes, but some firewalls impose a ~1000 byte limit. * As a side effect of breaking up the page into two forms * we need to repeat the position in a hidden variable here * so that zoom/scrolling always has current position to work * from. */ // This 'dirty' field is used to check if js/ajax changes to the page have occurred. // If so and it is reached by the back button, a page reload will occur instead. hPrintf("<INPUT TYPE='text' style='display:none;' name='dirty' id='dirty' VALUE='false'>\n"); - // Define BACK_SUPPORT to support the back-button via jquery.histoty.js -#define BACK_SUPPORT -#ifndef BACK_SUPPORT - // Unfortunately this does not work in IE, so IE will get reloaded only after this full load - // NOTE: Larry and I have seen that the new URL is not even used, but this will abort - // the page load and hasten the isDirty() check in hgTracks.js - hPrintf("<script type='text/javascript'>if (document.getElementById('dirty').value == " - "'true') {document.getElementById('dirty').value = 'false'; " - "window.location = '%s?hgsid=%d';}</script>\n",hgTracksName(),cart->sessionId); -#endif//ndef BACK_SUPPORT hPrintf("<INPUT TYPE=HIDDEN id='positionHidden' NAME=\"position\" " "VALUE=\"%s:%d-%d\">", chromName, winStart+1, winEnd); hPrintf("\n%s", trackGroupsHidden1->string); hPrintf("</CENTER></FORM>\n"); hPrintf("<FORM ACTION=\"%s\" NAME=\"TrackForm\" id=\"TrackForm\" METHOD=\"POST\">\n\n", hgTracksName()); hPrintf("%s", trackGroupsHidden2->string); freeDyString(&trackGroupsHidden1); freeDyString(&trackGroupsHidden2); if (!psOutput) cartSaveSession(cart); /* Put up hgsid= as hidden variable. */ clearButtonJavascript = "document.TrackForm.position.value=''; document.getElementById('suggest').value='';"; hPrintf("<CENTER>"); } @@ -5685,33 +5720,31 @@ } jsonForClient = newJsonObject(newHash(8)); jsonObjectAdd(jsonForClient, "cgiVersion", newJsonString(CGI_VERSION)); boolean searching = differentString(cartUsualString(cart, TRACK_SEARCH,"0"), "0"); if(!trackImgOnly) { // Write out includes for css and js files hWrites(commonCssStyles()); jsIncludeFile("jquery.js", NULL); jsIncludeFile("jquery-ui.js", NULL); jsIncludeFile("utils.js", NULL); jsIncludeFile("ajax.js", NULL); jsIncludeFile("jquery.watermarkinput.js", NULL); -#ifdef BACK_SUPPORT jsIncludeFile("jquery.history.js", NULL); // Experimental -#endif//def BACK_SUPPORT if(!searching) { jsIncludeFile("jquery.imgareaselect.js", NULL); } jsIncludeFile("autocomplete.js", NULL); jsIncludeFile("hgTracks.js", NULL); #ifdef LOWELAB jsIncludeFile("lowetooltip.js", NULL); #endif///def LOWELAB webIncludeResourceFile("jquery-ui.css"); if (!searching) // NOT doing search { webIncludeResourceFile("jquery.contextmenu.css"); @@ -5784,22 +5817,28 @@ { /* currently not used */ cartRemove(cart, configShowEncodeGroups); struct grp *grp = NULL, *grps = hLoadGrps(database); for (grp = grps; grp != NULL; grp = grp->next) if (startsWith("encode", grp->name)) collapseGroup(grp->name, FALSE); configPageSetTrackVis(-2); } else { tracksDisplay(); } jsonObjectAdd(jsonForClient, "measureTiming", newJsonBoolean(measureTiming)); +// js code needs to know if a highlightRegion is defined for this db +char *highlightDef = cartOptionalString(cart, "highlight"); +if (highlightDef && startsWith(database,highlightDef) && highlightDef[strlen(database)] == '.') + jsonObjectAdd(jsonForClient, "highlight", newJsonString(highlightDef)); +jsonObjectAdd(jsonForClient, "enableHighlightingDialog", + newJsonBoolean(cartUsualBoolean(cart, "enableHighlightingDialog", TRUE))); hPrintf("<script type='text/javascript'>\n"); jsonPrint((struct jsonElement *) jsonForClient, "hgTracks", 0); hPrintf("</script>\n"); if (measureTiming) measureTime("Time at end of doMiddle, next up cart write"); }