From 0bbe6d9d2d24a9ab468405aa14cc2ed9eaf0b31a Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 15 Aug 2024 12:21:52 -0400 Subject: [PATCH 1/2] Misc --- .../renderers/FeatureRendererType.ts | 13 ++-- .../renderers/ServerSideRenderedContent.tsx | 8 +-- .../components/PileupRendering.tsx | 59 ++++++++----------- plugins/arc/src/ArcRenderer/ArcRendering.tsx | 7 ++- .../src/BaseChordDisplay/models/model.tsx | 1 - .../components/HicRendering.test.tsx | 3 - .../ReactComponent.tsx | 38 +++++------- 7 files changed, 52 insertions(+), 77 deletions(-) diff --git a/packages/core/pluggableElementTypes/renderers/FeatureRendererType.ts b/packages/core/pluggableElementTypes/renderers/FeatureRendererType.ts index 7fb2659204..d1a62aeea9 100644 --- a/packages/core/pluggableElementTypes/renderers/FeatureRendererType.ts +++ b/packages/core/pluggableElementTypes/renderers/FeatureRendererType.ts @@ -63,20 +63,17 @@ export interface ResultsDeserialized extends ServerSideResultsDeserialized { export default class FeatureRendererType extends ServerSideRendererType { /** * replaces the `displayModel` param (which on the client is a MST model) - * with a stub that only contains the `selectedFeature`, since this is the only - * part of the track model that most renderers read. also serializes the config - * and regions to JSON from MST objects. + * with a stub that only contains the `selectedFeature`, since this is the + * only part of the track model that most renderers read. also serializes the + * config and regions to JSON from MST objects. * * @param args - the arguments passed to render */ serializeArgsInClient(args: RenderArgs) { - const { displayModel, regions } = args + const { regions } = args const serializedArgs = { ...args, - displayModel: displayModel && { - id: displayModel.id, - selectedFeatureId: displayModel.selectedFeatureId, - }, + displayModel: undefined, regions: clone(regions), } return super.serializeArgsInClient(serializedArgs) diff --git a/packages/core/pluggableElementTypes/renderers/ServerSideRenderedContent.tsx b/packages/core/pluggableElementTypes/renderers/ServerSideRenderedContent.tsx index fd65cccc26..235696b940 100644 --- a/packages/core/pluggableElementTypes/renderers/ServerSideRenderedContent.tsx +++ b/packages/core/pluggableElementTypes/renderers/ServerSideRenderedContent.tsx @@ -21,15 +21,13 @@ const NewHydrate = observer(function ServerSideRenderedContent({ ...rest }: Props) { const ref = useRef(null) - const rootRef = useRef() - const { hydrateFn } = getRoot(rest.displayModel) useEffect(() => { - // requestIdleCallback here helps to avoid hydration mismatch - // because it provides time for dangerouslySetInnerHTML to set the innerHTML - // contents of the node, otherwise ref.current.innerHTML can be empty + // requestIdleCallback here helps to avoid hydration mismatch because it + // provides time for dangerouslySetInnerHTML to set the innerHTML contents + // of the node, otherwise ref.current.innerHTML can be empty const renderTimeout = rIC(() => { if (!ref.current) { return diff --git a/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx b/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx index 2f7a1cb1c8..5d5aa65d58 100644 --- a/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx +++ b/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx @@ -5,23 +5,25 @@ import { bpSpanPx } from '@jbrowse/core/util' import { observer } from 'mobx-react' import type { BaseLinearDisplayModel } from '@jbrowse/plugin-linear-genome-view' -interface Rect { - left: number - top: number - width: number - height: number -} - const PileupRendering = observer(function (props: { blockKey: string - displayModel: BaseLinearDisplayModel + displayModel?: BaseLinearDisplayModel width: number height: number regions: Region[] bpPerPx: number - sortedBy?: { type: string; pos: number; refName: string } - colorBy?: { type: string; tag?: string } - filterBy?: { tagFilter?: { tag: string } } + sortedBy?: { + type: string + pos: number + refName: string + } + colorBy?: { + type: string + tag?: string + } + filterBy?: { + tagFilter?: { tag: string } + } onMouseMove?: (event: React.MouseEvent, featureId?: string) => void }) { const { @@ -37,51 +39,40 @@ const PileupRendering = observer(function (props: { filterBy, } = props const { selectedFeatureId, featureIdUnderMouse, contextMenuFeature } = - displayModel + displayModel || {} const [firstRender, setFirstRender] = useState(false) useEffect(() => { setFirstRender(true) }, []) const region = regions[0]! - let selected = undefined as Rect | undefined - let highlight = undefined as Rect | undefined const ref = useRef(null) const [mouseIsDown, setMouseIsDown] = useState(false) const [movedDuringLastMouseDown, setMovedDuringLastMouseDown] = useState(false) const selectedRect = selectedFeatureId - ? displayModel.getFeatureByID(blockKey, selectedFeatureId) + ? displayModel?.getFeatureByID?.(blockKey, selectedFeatureId) : undefined - if (selectedRect) { - const [leftBp, topPx, rightBp, bottomPx] = selectedRect - const [leftPx, rightPx] = bpSpanPx(leftBp, rightBp, region, bpPerPx) - const rectTop = Math.round(topPx) - const rectHeight = Math.round(bottomPx - topPx) - selected = { - left: leftPx - 2, - top: rectTop - 2, - width: rightPx - leftPx, - height: rectHeight, - } - } + const highlightedFeature = featureIdUnderMouse || contextMenuFeature?.id() const highlightedRect = highlightedFeature - ? displayModel.getFeatureByID(blockKey, highlightedFeature) + ? displayModel?.getFeatureByID?.(blockKey, highlightedFeature) : undefined - if (highlightedRect) { - const [leftBp, topPx, rightBp, bottomPx] = highlightedRect + function makeRect(r: [number, number, number, number], offset = 2) { + const [leftBp, topPx, rightBp, bottomPx] = r const [leftPx, rightPx] = bpSpanPx(leftBp, rightBp, region, bpPerPx) const rectTop = Math.round(topPx) const rectHeight = Math.round(bottomPx - topPx) - highlight = { - left: leftPx, - top: rectTop, + return { + left: leftPx - offset, + top: rectTop - offset, width: rightPx - leftPx, height: rectHeight, } } + const selected = selectedRect ? makeRect(selectedRect) : undefined + const highlight = highlightedRect ? makeRect(highlightedRect, 0) : undefined function onMouseDown(event: React.MouseEvent) { setMouseIsDown(true) @@ -137,7 +128,7 @@ const PileupRendering = observer(function (props: { onMouseMove?.( event, - displayModel.getFeatureOverlapping(blockKey, clientBp, offsetY), + displayModel?.getFeatureOverlapping(blockKey, clientBp, offsetY), ) } diff --git a/plugins/arc/src/ArcRenderer/ArcRendering.tsx b/plugins/arc/src/ArcRenderer/ArcRendering.tsx index 35a899411e..011c8e4d4f 100644 --- a/plugins/arc/src/ArcRenderer/ArcRendering.tsx +++ b/plugins/arc/src/ArcRenderer/ArcRendering.tsx @@ -136,7 +136,7 @@ function SemiCircles({ onFeatureClick, feature, }: { - selectedFeatureId: string + selectedFeatureId?: string region: Region config: AnyConfigurationModel onFeatureClick: (event: React.MouseEvent, featureId: string) => void @@ -214,21 +214,22 @@ const ArcRendering = observer(function ({ bpPerPx, height, exportSVG, + displayModel, onFeatureClick, - displayModel: { selectedFeatureId }, }: { features: Map config: AnyConfigurationModel regions: Region[] bpPerPx: number height: number - displayModel: { selectedFeatureId: string } + displayModel?: { selectedFeatureId: string } onFeatureClick: (event: React.MouseEvent, featureId: string) => void exportSVG: boolean }) { const region = regions[0]! const width = (region.end - region.start) / bpPerPx const semicircles = readConfObject(config, 'displayMode') === 'semicircles' + const { selectedFeatureId } = displayModel || {} return ( diff --git a/plugins/circular-view/src/BaseChordDisplay/models/model.tsx b/plugins/circular-view/src/BaseChordDisplay/models/model.tsx index 13607b0c85..75d20eb1f5 100644 --- a/plugins/circular-view/src/BaseChordDisplay/models/model.tsx +++ b/plugins/circular-view/src/BaseChordDisplay/models/model.tsx @@ -116,7 +116,6 @@ export const BaseChordDisplayModel = types return { ...getParentRenderProps(self), rpcDriverName: self.rpcDriverName, - displayModel: self, bezierRadius: view.radiusPx * self.bezierRadiusRatio, radius: view.radiusPx, blockDefinitions: this.blockDefinitions, diff --git a/plugins/hic/src/HicRenderer/components/HicRendering.test.tsx b/plugins/hic/src/HicRenderer/components/HicRendering.test.tsx index a9fd4e5980..ca9c4ea5d8 100644 --- a/plugins/hic/src/HicRenderer/components/HicRendering.test.tsx +++ b/plugins/hic/src/HicRenderer/components/HicRendering.test.tsx @@ -11,9 +11,6 @@ test('one', () => { regions={[{ assemblyName: 'volvox', refName: 'zonk', start: 1, end: 3 }]} bpPerPx={3} blockKey="test" - /* - // @ts-expect-error */ - displayModel={{}} />, ) diff --git a/plugins/variants/src/StructuralVariantChordRenderer/ReactComponent.tsx b/plugins/variants/src/StructuralVariantChordRenderer/ReactComponent.tsx index 3c42162a58..d048dc274c 100644 --- a/plugins/variants/src/StructuralVariantChordRenderer/ReactComponent.tsx +++ b/plugins/variants/src/StructuralVariantChordRenderer/ReactComponent.tsx @@ -13,13 +13,12 @@ const StructuralVariantChordsReactComponent = observer(function ({ blockDefinitions, radius, bezierRadius, - displayModel: { selectedFeatureId }, onChordClick, }: { features: Map radius: number config: AnyConfigurationModel - displayModel: { id: string; selectedFeatureId: string } + displayModel?: { id: string; selectedFeatureId: string } blockDefinitions: Block[] bezierRadius: number onChordClick: ( @@ -29,6 +28,7 @@ const StructuralVariantChordsReactComponent = observer(function ({ evt: unknown, ) => void }) { + const { id, selectedFeatureId } = displayModel || {} // make a map of refName -> blockDefinition const blocksForRefsMemo = useMemo(() => { const blocksForRefs = {} as Record @@ -44,27 +44,19 @@ const StructuralVariantChordsReactComponent = observer(function ({ }, [blockDefinitions]) return ( - - {[...features.values()].map(feature => { - const id = feature.id() - const selected = String(selectedFeatureId) === String(id) - - return ( - - ) - })} + + {[...features.values()].map(feature => ( + + ))} ) }) From be8089def2a4782a9fef2b8d28baca10f4166f2d Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 15 Aug 2024 12:44:21 -0400 Subject: [PATCH 2/2] Wow --- .../renderers/ComparativeServerSideRendererType.ts | 14 +++++--------- .../PileupRenderer/components/PileupRendering.tsx | 4 ++-- plugins/arc/src/ArcRenderer/ArcRendering.tsx | 2 +- plugins/wiggle/src/MultiWiggleRendering.tsx | 5 +++-- .../__image_snapshots__/circular_snapshot.svg | 2 +- .../tests/__snapshots__/ExportSvg.test.tsx.snap | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/core/pluggableElementTypes/renderers/ComparativeServerSideRendererType.ts b/packages/core/pluggableElementTypes/renderers/ComparativeServerSideRendererType.ts index f03bfec3ed..2cf115c91e 100644 --- a/packages/core/pluggableElementTypes/renderers/ComparativeServerSideRendererType.ts +++ b/packages/core/pluggableElementTypes/renderers/ComparativeServerSideRendererType.ts @@ -16,18 +16,15 @@ import { firstValueFrom } from 'rxjs' import { AnyConfigurationModel } from '../../configuration' export interface RenderArgs extends ServerSideRenderArgs { - displayModel: Record blockKey: string } export interface RenderArgsSerialized extends ServerSideRenderArgsSerialized { - displayModel: Record blockKey: string } export interface RenderArgsDeserialized extends ServerSideRenderArgsDeserialized { - displayModel: Record blockKey: string } @@ -53,10 +50,6 @@ export default class ComparativeServerSideRenderer extends ServerSideRenderer { * directly modifies the render arguments to prepare them to be serialized * and sent to the worker. * - * the base class replaces the `displayModel` param (which on the client is a - * MST model) with a stub that only contains the `selectedFeature`, since - * this is the only part of the track model that most renderers read. - * * @param args - the arguments passed to render * @returns the same object */ @@ -68,7 +61,7 @@ export default class ComparativeServerSideRenderer extends ServerSideRenderer { serializeArgsInClient(args: RenderArgs) { const deserializedArgs = { ...args, - displayModel: {}, + displayModel: undefined, } return super.serializeArgsInClient(deserializedArgs) @@ -80,7 +73,10 @@ export default class ComparativeServerSideRenderer extends ServerSideRenderer { args: RenderArgs, ): ResultsDeserialized { const deserialized = super.deserializeResultsInClient(result, args) - return { ...deserialized, blockKey: args.blockKey } + return { + ...deserialized, + blockKey: args.blockKey, + } } /** diff --git a/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx b/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx index 5d5aa65d58..76cfa1e5fc 100644 --- a/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx +++ b/plugins/alignments/src/PileupRenderer/components/PileupRendering.tsx @@ -51,12 +51,12 @@ const PileupRendering = observer(function (props: { const [movedDuringLastMouseDown, setMovedDuringLastMouseDown] = useState(false) const selectedRect = selectedFeatureId - ? displayModel?.getFeatureByID?.(blockKey, selectedFeatureId) + ? displayModel?.getFeatureByID(blockKey, selectedFeatureId) : undefined const highlightedFeature = featureIdUnderMouse || contextMenuFeature?.id() const highlightedRect = highlightedFeature - ? displayModel?.getFeatureByID?.(blockKey, highlightedFeature) + ? displayModel?.getFeatureByID(blockKey, highlightedFeature) : undefined function makeRect(r: [number, number, number, number], offset = 2) { diff --git a/plugins/arc/src/ArcRenderer/ArcRendering.tsx b/plugins/arc/src/ArcRenderer/ArcRendering.tsx index 011c8e4d4f..2648f7f0f5 100644 --- a/plugins/arc/src/ArcRenderer/ArcRendering.tsx +++ b/plugins/arc/src/ArcRenderer/ArcRendering.tsx @@ -17,7 +17,7 @@ function Arc({ onFeatureClick, feature, }: { - selectedFeatureId: string + selectedFeatureId?: string region: Region config: AnyConfigurationModel onFeatureClick: (event: React.MouseEvent, featureId: string) => void diff --git a/plugins/wiggle/src/MultiWiggleRendering.tsx b/plugins/wiggle/src/MultiWiggleRendering.tsx index 7baab0c201..d3cd7f21bf 100644 --- a/plugins/wiggle/src/MultiWiggleRendering.tsx +++ b/plugins/wiggle/src/MultiWiggleRendering.tsx @@ -14,7 +14,7 @@ const MultiWiggleRendering = observer(function (props: { height: number blockKey: string sources: Source[] - displayModel: { isMultiRow: boolean } + displayModel?: { isMultiRow: boolean } onMouseLeave?: (event: React.MouseEvent) => void onMouseMove?: (event: React.MouseEvent, arg?: Feature) => void onFeatureClick?: (event: React.MouseEvent, arg?: Feature) => void @@ -33,6 +33,7 @@ const MultiWiggleRendering = observer(function (props: { } = props const region = regions[0]! const ref = useRef(null) + const { isMultiRow } = displayModel || {} function getFeatureUnderMouse(eventClientX: number, eventClientY: number) { if (!ref.current) { @@ -48,7 +49,7 @@ const MultiWiggleRendering = observer(function (props: { const px = region.reversed ? width - offsetX : offsetX const mouseoverBp = region.start + bpPerPx * px let featureUnderMouse: Feature | undefined - if (displayModel.isMultiRow) { + if (isMultiRow) { for (const feature of features.values()) { if (feature.get('source') !== source.name) { continue diff --git a/products/jbrowse-web/src/tests/__image_snapshots__/circular_snapshot.svg b/products/jbrowse-web/src/tests/__image_snapshots__/circular_snapshot.svg index 1ba09c27d1..2cb49db9a8 100644 --- a/products/jbrowse-web/src/tests/__image_snapshots__/circular_snapshot.svg +++ b/products/jbrowse-web/src/tests/__image_snapshots__/circular_snapshot.svg @@ -1 +1 @@ -ctgActgActgBctgB \ No newline at end of file +ctgActgActgBctgB \ No newline at end of file diff --git a/products/jbrowse-web/src/tests/__snapshots__/ExportSvg.test.tsx.snap b/products/jbrowse-web/src/tests/__snapshots__/ExportSvg.test.tsx.snap index 2cbd14b784..63ebcce731 100644 --- a/products/jbrowse-web/src/tests/__snapshots__/ExportSvg.test.tsx.snap +++ b/products/jbrowse-web/src/tests/__snapshots__/ExportSvg.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`export svg of circular 1`] = `"ctgActgActgBctgB"`; +exports[`export svg of circular 1`] = `"ctgActgActgBctgB"`; exports[`export svg of dotplot 1`] = `"ctgA16,00018,00020,00022,00024,000volvoxctgA13,00014,00015,00016,00017,00018,00019,00020,000volvox_random_inv"`;