1028183b63771ec4f9f23fdc4edeabf649ff14c4 kate Wed Oct 10 14:01:31 2018 -0700 Finish implementation of split labels in pack mode. refs #21917 diff --git src/hg/hgTracks/interactTrack.c src/hg/hgTracks/interactTrack.c index beed63d..ecf21f5 100644 --- src/hg/hgTracks/interactTrack.c +++ src/hg/hgTracks/interactTrack.c @@ -100,49 +100,79 @@ { if (!(sOnScreen || tOnScreen)) continue; } } slAddHead(&filteredItems, inter); } slReverse(&filteredItems); // consider sorting by score/value so highest scored items draw last (on top) if (slCount(filteredItems) != count) labelTrackAsFiltered(tg); tg->items = filteredItems; } -void interactDrawLeftLabels(struct track *tg, int seqStart, int seqEnd, +void interactNoLeftLabels(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, int height, boolean withCenterLabels, MgFont *font, Color color, enum trackVisibility vis) /* Override default */ { } +/* Interaction displayed as a linked feature */ + +struct interactLfEndNames +/* Stash source and target names when converted to linked feature */ + { + char *source; + char *target; + }; + +static void setInteractLfEndNames(struct linkedFeatures *lf, char *sourceName, char *targetName) +/* Stash endpoint names in linked feature */ +{ +struct interactLfEndNames *ends = NULL; +AllocVar(ends); +ends->source = sourceName; +ends->target = targetName; +lf->original = ends; // coopt this void * field (would have preferred to use extra) +} + +static struct interactLfEndNames *getInteractLfEndNames(struct linkedFeatures *lf) +/* Retrieve endpoint names from linked feature */ +{ +return (struct interactLfEndNames *)lf->original; +} + void interactFreeItems(struct track *tg) /* Free up interact items track */ { interactFreeList((struct interact **)(&tg->items)); } static struct linkedFeatures *interactToLf(struct interact *inter, boolean doColor) /* Convert interact BED to linkedFeatures */ { struct bed *bed = interactToBed(inter); struct linkedFeatures *lf = lfFromBed(bed); + +// save source and target names to extra field of linked feature, so we can display them in pack mode +// TODO: code to free +setInteractLfEndNames(lf, cloneString(inter->sourceName), cloneString(inter->targetName)); + // not sure why this is needed -- lfFromBed seems to reorder blocks, sometimes ? linkedFeaturesSortAndBound(lf); if (doColor) { lf->extra = (void *)USE_ITEM_RGB; /* signal for coloring */ lf->filterColor = bed->itemRgb; } bedFree(&bed); // TODO: use lfFromBedExtra with scoreMin, scoreMax ? return lf; } static boolean isLinkedFeaturesMode(struct track *tg) /* Determine if linked feature display will be used */ { @@ -235,67 +265,98 @@ if (labelStart <= prevLabelEnd && !(labelStart == prevLabelStart && labelEnd == prevLabelEnd && sameString(otherChrom, prevLabel))) tInfo->doOtherLabels = FALSE; prevLabelStart = labelStart; prevLabelEnd = labelEnd; prevLabel = otherChrom; } } tInfo->fontHeight = vgGetFontPixelHeight(hvg->vg, font); tInfo->otherHeight = (tInfo->otherCount) ? 3 * tInfo->fontHeight : 0; tInfo->sameHeight = (tInfo->sameCount) ? tg->height - tInfo->otherHeight : 0; } static int interactRightPixels(struct track *tg, void *item) -/* Return number of pixels we need to the right. */ +/* Return number of pixels we need to the right, in linked features mode. */ { -struct interact *inter = item; struct interactTrackInfo *tInfo = tg->customPt; -if ((tg->visibility == tvPack || tg->visibility == tvFull) && !tInfo->clusterMode) - { - char *rightLabel = ""; - if (tInfo->isDirectional) +if (tInfo->clusterMode || !(tg->visibility == tvPack || tg->visibility == tvFull)) + return 0; +struct linkedFeatures *lf = (struct linkedFeatures *)item; +struct interactLfEndNames *ends = getInteractLfEndNames(lf); +char *rightLabel = ends->target; +if (lf->orientation != 0) + rightLabel = (lf->orientation < 0 ? ends->source : ends->target); +return mgFontStringWidth(tl.font, rightLabel); +} + +static char *interactLfLeftEndName(struct track *tg, void *item) +/* Return name of left end in single interaction linked feature, for left label */ { - if (inter->targetStart == inter->chromStart) - rightLabel = inter->sourceName; - if (inter->targetEnd == inter->chromEnd) - rightLabel = inter->targetName; +struct linkedFeatures *lf = (struct linkedFeatures *)item; +struct interactLfEndNames *ends = getInteractLfEndNames(lf); +return (lf->orientation < 0 ? ends->target : ends->source); } - else - rightLabel = inter->targetName; - return mgFontStringWidth(tl.font, rightLabel); + +#ifdef FOO +static char *interactLfItemName(struct track *tg, void *item) +/* Return item name of interaction linked feature, for map */ +{ +struct linkedFeatures *lf = (struct linkedFeatures *)item; +return lf->name; } -return 0; +#endif + +static void interactLfMapItem(struct track *tg, struct hvGfx *hvg, void *item, + char *itemName, char *mapItemName, int start, int end, + int x, int y, int width, int height) +/* Draw mapbox on interact item when displayed as linked feature */ +{ +struct linkedFeatures *lf = (struct linkedFeatures *)item; +// restore full item name (using end name for label) +itemName = mapItemName = lf->name; +linkedFeaturesMapItem(tg, hvg, item, itemName, mapItemName, start, end, x, y, width, height); } void interactLoadItems(struct track *tg) /* Load interact items in interact format */ { loadAndFilterItems(tg); struct interactTrackInfo *tInfo = NULL; AllocVar(tInfo); tg->customPt = tInfo; tInfo->isDirectional = interactUiDirectional(tg->tdb); tInfo->offset = interactUiOffset(tg->tdb); tInfo->drawUp = trackDbSettingClosestToHomeOn(tg->tdb, INTERACT_UP); tInfo->clusterMode = interactUiClusterMode(cart, tg->track, tg->tdb); -if (tInfo->clusterMode || isLinkedFeaturesMode(tg)) +if (!tInfo->clusterMode && !isLinkedFeaturesMode(tg)) { + // draw curve display + tg->mapsSelf = TRUE; + tg->totalHeight = interactTotalHeight; + tg->drawLeftLabels = interactNoLeftLabels; + tg->freeItems = interactFreeItems; + return; + } + // convert to BEDs for linked feature display +tg->itemName = interactLfLeftEndName; +tg->mapItem = interactLfMapItem; +//tg->mapItemName = interactLfItemName; struct interact *inters = tg->items, *inter; struct linkedFeatures *lfs = NULL, *lf; struct hash *intersCluster = hashNew(0); boolean doColor = !tg->colorShades; for (inter = inters; inter; inter = inter->next) { if (tInfo->clusterMode) { boolean byTarget = sameString(tInfo->clusterMode, INTERACT_CLUSTER_TARGET); // hash by source or target name char *name = (byTarget ? inter->targetName : inter->sourceName); lf = (struct linkedFeatures *) hashFindVal(intersCluster, name); if (lf) { // add a simple feature for the other end (source or target) to the linked feature @@ -351,38 +412,30 @@ for (el = els; el; el = el->next) { lf = (struct linkedFeatures *)el->val; linkedFeaturesSortAndBound(lf); slAddHead(&lfs, lf); } slSort(&lfs, linkedFeaturesCmp); } else { slReverse(&lfs); } tg->items = lfs; // TODO: consider freeing interact items } -else - { - tg->mapsSelf = TRUE; - tg->totalHeight = interactTotalHeight; - tg->drawLeftLabels = interactDrawLeftLabels; - tg->freeItems = interactFreeItems; - } -} char *interactMouseover(struct interact *inter, char *otherChrom) /* Make mouseover text for an interaction */ { struct dyString *ds = dyStringNew(0); if (isEmptyTextField(inter->name)) { if (!isEmptyTextField(inter->exp)) dyStringPrintf(ds, "%s ", inter->exp); if (otherChrom) dyStringPrintf(ds, "%s", otherChrom); else { char buf[4096]; sprintLongWithCommas(buf, inter->chromEnd - inter->chromStart); @@ -730,67 +783,72 @@ // draw grab box and map box on peak int maxY = peakHeight + yOff; int peakX = ((upperX - lowerX + 1) / 2) + lowerX; drawPeakMapbox(tg, hvg, inter->chromStart, inter->chromEnd, inter->name, statusBuf, peakX, maxY, peakColor, highlightColor, drawUp); } } } void interactLinkedFeaturesDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a item with target in contrasting color */ { struct linkedFeatures *lf = item; -if (tg->visibility == tvDense) +if (vis == tvDense) { lf->filterColor = slightlyDarkerColor(hvg, MG_GRAY); // can't distinguish overlapping colors, so force to gray } +struct interactTrackInfo *tInfo = tg->customPt; + linkedFeaturesDrawAt(tg, item, hvg, xOff, y, scale, font, color, vis); // draw overlapping items in white and add right label -struct interactTrackInfo *tInfo = tg->customPt; if (tInfo->clusterMode) { struct simpleFeature *sf; int shortHeight = tg->heightPer/2; for (sf = lf->components; sf; sf = sf->next) { if (sf->start > lf->tallStart && sf->end < lf->tallEnd) { drawScaledBox(hvg, sf->start, sf->end, scale, xOff, y + shortHeight/2, shortHeight, MG_WHITE); } } } else { struct simpleFeature *sf1 = lf->components, *sf2 = sf1->next; if (sf2 && sf2->start < sf1->end) { drawScaledBox(hvg, sf2->start, sf2->end, scale, xOff, y, tg->heightPer, MG_WHITE); } else { + if (vis == tvPack || vis == tvFull) + { // right label int x2 = round((double)((int)lf->end - winStart) * scale) + xOff; int x = x2 + tl.mWidth/2; - char *label = "foo"; - int w = mgFontStringWidth(font, label); - hvGfxTextCentered(hvg, x, y, w, tg->heightPer, lf->filterColor, font, label); + struct interactLfEndNames *ends = getInteractLfEndNames(lf); + char *rightLabel = (lf->orientation < 0 ? ends->source : ends->target); + int w = mgFontStringWidth(font, rightLabel); + hvGfxTextCentered(hvg, x, y, w, tg->heightPer, color, font, rightLabel); + } } } } void interactDrawItems(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw a list of interact structures. */ { struct interactTrackInfo *tInfo = (struct interactTrackInfo *)tg->customPt; if (tInfo->clusterMode || isLinkedFeaturesMode(tg)) { tg->drawItemAt = interactLinkedFeaturesDrawAt; linkedFeaturesDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); }