/* eslint-disable react-refresh/only-export-components */ import React from 'react' import { renderToStaticMarkup } from '@jbrowse/core/util' import { when } from 'mobx' import MinimapSVG from './components/minimap/MinimapSVG.tsx' import { renderBoxFeatureCanvasBlock } from './components/msa/renderBoxFeatureCanvasBlock.ts' import { renderMSABlock } from './components/msa/renderMSABlock.ts' import { renderAllTracks } from './components/tracks/renderTracksSvg.ts' import { renderTreeCanvas } from './components/tree/renderTreeCanvas.ts' import { colorContrast } from './util.ts' import type { MsaViewModel } from './model.ts' import type { Context as ContextType } from '@jbrowse/svgcanvas' import type { Theme } from '@mui/material' export interface ExportSvgOptions { theme: Theme includeMinimap?: boolean includeTracks?: boolean exportType: string } export async function renderToSvg(model: MsaViewModel, opts: ExportSvgOptions) { await when(() => !!model.dataInitialized) const { width, height, scrollX, scrollY, totalTrackAreaHeight } = model const { exportType, theme, includeMinimap, includeTracks } = opts const trackHeight = includeTracks ? totalTrackAreaHeight : 0 if (exportType === 'entire') { return render({ width: model.totalWidth + model.treeAreaWidth, height: model.totalHeight + trackHeight, contentHeight: model.totalHeight, trackHeight, theme, model, offsetY: 0, offsetX: 0, includeMinimap, includeTracks, }) } if (exportType === 'viewport') { return render({ width, height: height + (includeMinimap ? model.minimapHeight : 0) + trackHeight, contentHeight: height, trackHeight, theme, model, offsetY: -scrollY, offsetX: -scrollX, includeMinimap, includeTracks, }) } throw new Error('unknown export type') } async function render({ width, height, contentHeight, trackHeight, offsetX, offsetY, theme, model, includeMinimap, includeTracks, }: { width: number height: number contentHeight: number trackHeight: number offsetX: number offsetY: number theme: Theme model: MsaViewModel includeMinimap?: boolean includeTracks?: boolean }) { const { Context } = await import('@jbrowse/svgcanvas') const Wrapper = includeMinimap ? MinimapWrapper : NullWrapper return renderToStaticMarkup( {includeTracks && trackHeight > 0 ? ( ) : null} 0 ? `translate(0 ${trackHeight})` : undefined } > , ) } function CoreRendering({ model, theme, width, contentHeight, offsetX, offsetY, Context, }: { model: MsaViewModel theme: Theme width: number contentHeight: number offsetX: number offsetY: number Context: typeof ContextType }) { const { treeAreaWidth, colorScheme, id } = model const clipId1 = `tree-${id}` const clipId2 = `msa-${id}` const contrastScheme = colorContrast(colorScheme, theme) const ctx1 = new Context(width, contentHeight) as any const ctx2 = new Context(width, contentHeight) as any renderBoxFeatureCanvasBlock({ ctx: ctx2, offsetX, offsetY, model, blockSizeYOverride: contentHeight, highResScaleFactorOverride: 1, }) const msaAreaWidth = width - treeAreaWidth renderTreeCanvas({ model, offsetY, ctx: ctx1, theme, blockSizeYOverride: contentHeight, highResScaleFactorOverride: 1, }) renderMSABlock({ model, theme, offsetY, offsetX, contrastScheme, ctx: ctx2, blockSizeXOverride: msaAreaWidth, blockSizeYOverride: contentHeight, highResScaleFactorOverride: 1, }) return ( <> ) } function TrackRendering({ model, theme, width, trackHeight, offsetX, Context, }: { model: MsaViewModel theme: Theme width: number trackHeight: number offsetX: number Context: typeof ContextType }) { const { treeAreaWidth, colorScheme, id } = model const clipId = `tracks-${id}` const contrastScheme = colorContrast(colorScheme, theme) const msaAreaWidth = width - treeAreaWidth const ctx = new Context(msaAreaWidth, trackHeight) as any renderAllTracks({ model, ctx, offsetX, contrastScheme, blockSizeXOverride: msaAreaWidth, highResScaleFactorOverride: 1, }) return ( ) } function MinimapWrapper({ model, children, }: { model: MsaViewModel children: React.ReactNode }) { const { minimapHeight, treeAreaWidth } = model return ( <> {children} ) } function SvgWrapper({ width, height, children, }: { width: number height: number children: React.ReactNode }) { return ( {children} ) } function NullWrapper({ children }: { children: React.ReactNode }) { return children }