From 875a9b54911fb259b795eab7afad853d1ef3e3b7 Mon Sep 17 00:00:00 2001 From: Sehi L'Yi Date: Fri, 22 Sep 2023 14:37:45 -0400 Subject: [PATCH] fix(core): preserve zoom status when new track added (#971) * fix: preserve zoom status when new track added * chore: format --- .../responsive-track-wise-comparison.ts | 8 +++++- src/compiler/spec-preprocess.ts | 4 +-- src/core/gosling-component.tsx | 28 +++++++++++++++++++ src/core/utils/overlay.ts | 11 ++++++-- src/gosling-schema/index.ts | 2 +- src/higlass-schema/index.ts | 2 +- src/index.ts | 2 +- 7 files changed, 49 insertions(+), 8 deletions(-) diff --git a/editor/example/json-spec/responsive-track-wise-comparison.ts b/editor/example/json-spec/responsive-track-wise-comparison.ts index a8412b0a..a61952d4 100644 --- a/editor/example/json-spec/responsive-track-wise-comparison.ts +++ b/editor/example/json-spec/responsive-track-wise-comparison.ts @@ -1,4 +1,10 @@ -import type { DomainChrInterval, GoslingSpec, OverlaidTracks, SingleTrack, TemplateTrack } from '@gosling-lang/gosling-schema'; +import type { + DomainChrInterval, + GoslingSpec, + OverlaidTracks, + SingleTrack, + TemplateTrack +} from '@gosling-lang/gosling-schema'; import { GOSLING_PUBLIC_DATA } from './gosling-data'; const trackColor = { diff --git a/src/compiler/spec-preprocess.ts b/src/compiler/spec-preprocess.ts index 74da6e52..e082ae4f 100644 --- a/src/compiler/spec-preprocess.ts +++ b/src/compiler/spec-preprocess.ts @@ -96,7 +96,7 @@ export function traverseViewArrangements(spec: GoslingSpec, callback: (tv: Multi export function convertToFlatTracks(spec: SingleView): Track[] { if (IsFlatTracks(spec)) { // This is already `FlatTracks`, so just override the view definition - const base = {...spec, tracks: undefined, id: undefined }; + const base = { ...spec, tracks: undefined, id: undefined }; return spec.tracks .filter(track => !track._invalidTrack) .map(track => Object.assign(JSON.parse(JSON.stringify(base)), track) as SingleTrack); @@ -117,7 +117,7 @@ export function convertToFlatTracks(spec: SingleView): Track[] { } as Track); } else { // Override track definitions from views - const base = {...spec, tracks: undefined, id: undefined }; + const base = { ...spec, tracks: undefined, id: undefined }; const newSpec = Object.assign(JSON.parse(JSON.stringify(base)), track) as SingleTrack; newTracks.push(newSpec); } diff --git a/src/core/gosling-component.tsx b/src/core/gosling-component.tsx index 39be93c1..d25af913 100644 --- a/src/core/gosling-component.tsx +++ b/src/core/gosling-component.tsx @@ -82,6 +82,28 @@ export const GoslingComponent = forwardRef((props, [viewConfig, theme] ); + /** + * This makes sure that all the current zooming status is preserved when new tracks are added + */ + const preverseZoomStatus = (newSpec: gosling.HiGlassSpec, prevSpec: gosling.HiGlassSpec) => { + newSpec.views.forEach((view) => { + const viewUid = view.uid!; + const newView = !prevSpec.views.find(v => v.uid === viewUid); + if (newView) { + // if this view is linked with another view, we need to preverse the current zooming status of this view from the linked view + // Otherwise, all the views that is linked with this view will be reset to the original zooming position + const { locksByViewUid } = newSpec.zoomLocks; + const lockUid = locksByViewUid[viewUid]; + const linkedViewUid = Object.entries(locksByViewUid).find(([_, uid]) => _ && uid === lockUid)?.[0]; + if (linkedViewUid) { + // We found a linked view, so copy the current zooming status + view.initialXDomain = prevSpec.views.find(v => v.uid === linkedViewUid)?.initialXDomain; + view.initialYDomain = prevSpec.views.find(v => v.uid === linkedViewUid)?.initialYDomain; + } + } + }); + }; + // TODO: add a `force` parameter since changing `linkingId` might not update vis const compile = useCallback(() => { if (props.spec) { @@ -115,6 +137,10 @@ export const GoslingComponent = forwardRef((props, if (props.experimental?.reactive && isMountedOnce) { // Use API to update visualization. setTimeout(() => { + preverseZoomStatus( + newHiGlassSpec, + hgRef.current?.api.getViewConfig() as gosling.HiGlassSpec + ); hgRef.current?.api.setViewConfig(newHiGlassSpec); }, DELAY_FOR_CONTAINER_RESIZE_BEFORE_RERENDER); } else { @@ -138,6 +164,8 @@ export const GoslingComponent = forwardRef((props, // TODO: If not necessary, do not update `wrapperSize` (i.e., when responsiveSize is not set) useEffect(() => { + if (!props.spec?.responsiveSize) return; + const containerElement = document.getElementById(wrapperDivId); if (!containerElement) return; diff --git a/src/core/utils/overlay.ts b/src/core/utils/overlay.ts index 703fb1ee..495a994c 100644 --- a/src/core/utils/overlay.ts +++ b/src/core/utils/overlay.ts @@ -1,4 +1,11 @@ -import type { AxisPosition, SingleTrack, OverlaidTrack, Track, ChannelDeep, DataDeep } from '@gosling-lang/gosling-schema'; +import type { + AxisPosition, + SingleTrack, + OverlaidTrack, + Track, + ChannelDeep, + DataDeep +} from '@gosling-lang/gosling-schema'; import { IsChannelDeep, IsDataTrack, IsOverlaidTrack, IsSingleTrack, IsDummyTrack } from '@gosling-lang/gosling-schema'; /** @@ -77,7 +84,7 @@ export function spreadTracksByData(tracks: Track[]): Track[] { return [t]; } - const base: Partial = {...t, id: undefined, overlay: undefined }; + const base: Partial = { ...t, id: undefined, overlay: undefined }; const spread: Track[] = []; const original: OverlaidTrack = JSON.parse(JSON.stringify(base)); original.overlay = []; diff --git a/src/gosling-schema/index.ts b/src/gosling-schema/index.ts index e1f84590..41c5aaca 100644 --- a/src/gosling-schema/index.ts +++ b/src/gosling-schema/index.ts @@ -2,4 +2,4 @@ export * from './gosling.schema'; export * from './gosling.schema.guards'; export * from './validate'; export { default as ThemeSchema } from './theme.schema.json'; -export { default as GoslingSchema } from './gosling.schema.json'; \ No newline at end of file +export { default as GoslingSchema } from './gosling.schema.json'; diff --git a/src/higlass-schema/index.ts b/src/higlass-schema/index.ts index 137ce241..2b7c74fe 100644 --- a/src/higlass-schema/index.ts +++ b/src/higlass-schema/index.ts @@ -1,2 +1,2 @@ export * from './higlass.schema'; -export { default as HiGlassSchema } from './higlass.schema.json'; \ No newline at end of file +export { default as HiGlassSchema } from './higlass.schema.json'; diff --git a/src/index.ts b/src/index.ts index da3720a8..920cac94 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,4 +12,4 @@ export { compile } from './compiler/compile'; export { validateGoslingSpec } from '@gosling-lang/gosling-schema'; export { GoslingComponent } from './core/gosling-component'; export type { GoslingRef } from './core/gosling-component'; -export { embed } from './core/gosling-embed'; \ No newline at end of file +export { embed } from './core/gosling-embed';