UNPKG

auspice

Version:

Web app for visualizing pathogen evolution

348 lines (305 loc) 10.4 kB
import { Selection } from "d3-selection"; import { Layout, PerformanceFlags, ScatterVariables } from "../../../reducers/controls"; import { ReduxNode, Visibility, Streams, TreeState, FocusNodes } from "../../../reducers/tree/types"; import { change, modifySVG, modifySVGInStages } from "./change"; import { TreeComponent } from "../tree"; import * as confidence from "./confidence"; import * as grid from "./grid"; import * as labels from "./labels"; import * as layouts from "./layouts"; import * as regression from "./regression"; import * as renderers from "./renderers"; // ---------- Basics ---------- // export type Distance = "num_date" | "div" export type TreeElement = ".branch.S" | ".branch.T" | ".branch" | ".branchLabel" | ".conf" | ".grid" | ".regression" | ".tip" | ".tipLabel" | ".vaccineCross" | ".vaccineDottedLine" export interface Regression { intercept?: number r2?: number slope?: number } // ---------- Callbacks ---------- // type NodeCallback = (d: PhyloNode) => void // See <https://github.com/nextstrain/auspice/issues/1900> export interface Callbacks { onBranchClick: NodeCallback onBranchHover: NodeCallback onBranchLeave: NodeCallback onTipClick: NodeCallback onTipHover: NodeCallback onTipLeave: NodeCallback onStreamHover: (this: TreeComponent, node: PhyloNode, categoryIndex: number, paths: SVGPathElement[], isBranch: boolean) => void onStreamLeave: (this: TreeComponent, _node: PhyloNode, _categoryIndex: number, paths: SVGPathElement[], isBranch: boolean) => void tipLabel: NodeCallback } // ---------- PhyloNode ---------- // /** * This is a subset of CSSStyleDeclaration. Reasons for not using that directly: * 1. CSSStyleDeclaration has generic string types for all properties. We allow a number type on many. * 2. We do not use most CSSStyleDeclaration properties. * 3. CSSStyleDeclaration uses strokeWidth instead of stroke-width. * <https://github.com/microsoft/TypeScript/issues/17827#issuecomment-861847433> */ // TODO: consider extending existing interfaces such as SVGCircleElement for cx/cy/r interface SVG { cursor?: unknown cx?: number cy?: number d?: unknown fill?: unknown opacity?: unknown r?: number stroke?: unknown "stroke-width"?: number visibility?: Visibility // TODO: This should be `string | number`, conditional on layout x?: any // TODO: This should be `string | number`, conditional on layout y?: any } export type SVGProperty = keyof SVG export interface PhyloNode extends SVG { angle?: number branch?: [string, string] branchStroke?: string conf?: [number, number] /** SVG path */ confLine?: string crossDepth?: number depth?: number displayOrder?: number displayOrderRange?: [number, number] fill?: string inView: boolean n: ReduxNode pDepth?: number // TODO: This should be `string | number`, conditional on layout px?: any // TODO: This should be `string | number`, conditional on layout py?: any rot?: number smallBigArc?: boolean tau?: number that: PhyloTreeType tipStroke?: string update?: boolean /** SVG path */ vaccineCross?: string w?: number xBase?: number xCBarEnd?: number xCBarStart?: number xCross?: number xTip?: number yBase?: number yCBarEnd?: number yCBarStart?: number yCross?: number yTip?: number rippleDisplayOrders?: [number,number][][] streamRipples?: Ripple[] } export type Ripple = ( { /** x value (pixel space) of the current ripple (part of a stream tree) */ x: number /** y0 value (pixel space) of the current ripple (part of a stream tree) */ y0: number /** y1 value (pixel space) of the current ripple (part of a stream tree) */ y1: number }[] & { /** Unique key intended for use in d3 selections to link incoming data to existing selection */ key: string } ) /** * Properties can be any property on PhyloNode but as an array for multiple nodes. * These are the ones that are used in the code. */ export interface PropsForPhyloNodes { branchStroke?: string[] fill?: string[] r?: number[] tipStroke?: (string | undefined)[] visibility?: Visibility[] } // ---------- PhyloTree ---------- // export interface Params { branchLabelFill: string branchLabelFont: string branchLabelFontWeight: number branchLabelKey: string | false branchLabelPadX: number branchLabelPadY: number branchStroke: string branchStrokeWidth: number confidence?: boolean fillSelected: string fontFamily: string grid?: boolean majorGridStroke: string majorGridWidth: number mapToScreenDebounceTime: number minorGridStroke: string minorGridWidth: number minorTicks: number orientation: [number, number] radiusSelected: number regressionStroke: string regressionWidth: number showAllBranchLabels?: boolean showGrid: boolean showTipLabels?: boolean showStreamTrees: boolean tickLabelFill: string tickLabelSize: number tipFill: string tipLabelBreakL1: number tipLabelBreakL2: number tipLabelBreakL3: number tipLabelFill: string tipLabelFont: string tipLabelFontSizeL1: number tipLabelFontSizeL2: number tipLabelFontSizeL3: number tipLabelPadX: number tipLabelPadY: number tipLabels: boolean tipRadius: number tipStroke: string tipStrokeWidth: number } export interface ChangeParams { // booleans for what should be changed // changeColorBy?: boolean changeVisibility?: boolean changeTipRadii?: boolean changeBranchThickness?: boolean showConfidences?: boolean removeConfidences?: boolean zoomIntoClade?: false | PhyloNode svgHasChangedDimensions?: boolean animationInProgress?: boolean changeNodeOrder?: boolean focusChange?: boolean /** * Streams are either toggled on/off or the partitioning (branch label) has changed */ streamDefinitionChange?: true // change these things to provided value (unless undefined) // newDistance?: Distance newLayout?: Layout updateLayout?: boolean // todo - this seems identical to `newLayout` newBranchLabellingKey?: string showAllBranchLabels?: boolean newTipLabelKey?: string | symbol newMeasurementsColorGrouping?: string | undefined hoveredLegendSwatch?: TreeState['hoveredLegendSwatch'] // arrays of data (the same length as nodes) // branchStroke?: string[] tipStroke?: (string | undefined)[] fill?: string[] visibility?: Visibility[] tipRadii?: number[] branchThickness?: number[] // other data // scatterVariables?: ScatterVariables performanceFlags?: PerformanceFlags } export interface PhyloTreeType { addGrid: typeof grid.addGrid attributes: string[] calculateRegression: typeof regression.calculateRegression callbacks: Callbacks change: typeof change clearSVG: typeof renderers.clearSVG confidencesInSVG: boolean dateRange: [number, number] distance: Distance drawBranchLabels: typeof labels.drawBranchLabels drawBranches: typeof renderers.drawBranches drawConfidence: typeof confidence.drawConfidence drawMeasurementsColoringCrosshair: typeof renderers.drawMeasurementsColoringCrosshair drawRegression: typeof renderers.drawRegression drawSingleCI: typeof confidence.drawSingleCI drawTips: typeof renderers.drawTips drawVaccines: typeof renderers.drawVaccines drawStreams: typeof renderers.drawStreams highlightStreamtreeRipples: typeof renderers.highlightStreamtreeRipples grid: boolean groups: { branchGradientDefs?: Selection<SVGDefsElement, unknown, null, unknown> branchStem?: Selection<SVGDefsElement, unknown, null, unknown> branchTee?: Selection<SVGDefsElement, unknown, null, unknown> clipPath?: Selection<SVGDefsElement, unknown, null, unknown> confidenceIntervals?: Selection<SVGDefsElement, unknown, null, unknown> measurementsColoringCrosshair?: Selection<SVGDefsElement, unknown, null, unknown> regression?: Selection<SVGDefsElement, unknown, null, unknown> tips?: Selection<SVGDefsElement, unknown, null, unknown> vaccines?: Selection<SVGDefsElement, unknown, null, unknown> streams?: Selection<SVGDefsElement, unknown, null, unknown> streamsLabels?: Selection<SVGDefsElement, unknown, null, unknown> } hideGrid: typeof grid.hideGrid hideTemporalSlice: typeof grid.hideTemporalSlice id: string layout: Layout mapToScreen: typeof layouts.mapToScreen mapStreamsToScreen: typeof layouts.mapStreamsToScreen margins: { bottom: number left: number right: number top: number } measurementsColorGrouping: string | undefined modifySVG: typeof modifySVG modifySVGInStages: typeof modifySVGInStages nodes: PhyloNode[] params: Params radialLayout: typeof layouts.radialLayout rectangularLayout: typeof layouts.rectangularLayout regression?: Regression removeBranchLabels: typeof labels.removeBranchLabels removeConfidence: typeof confidence.removeConfidence removeMeasurementsColoringCrosshair: typeof renderers.removeMeasurementsColoringCrosshair removeRegression: typeof renderers.removeRegression removeTipLabels: typeof labels.removeTipLabels render: typeof renderers.render scatterVariables?: ScatterVariables scatterplotLayout: typeof layouts.scatterplotLayout setClipMask: typeof renderers.setClipMask setDistance: typeof layouts.setDistance setLayout: typeof layouts.setLayout setScales: typeof layouts.setScales showTemporalSlice: typeof grid.showTemporalSlice strainToNode: Record<string, PhyloNode> svg: Selection<SVGGElement | null, unknown, null, unknown> timeLastRenderRequested?: number unrootedLayout: typeof layouts.unrootedLayout updateBranchLabels: typeof labels.updateBranchLabels updateColorBy: typeof renderers.updateColorBy updateTipLabels: typeof labels.updateTipLabels vaccines?: PhyloNode[] visibility: Visibility[] showStreamTrees: boolean; streams?: Streams // TODO: This should be `d3.ScalePoint<string> | d3.ScaleContinuousNumeric<number, number>`, conditional on layout xScale: any // TODO: This should be `d3.ScalePoint<string> | d3.ScaleContinuousNumeric<number, number>`, conditional on layout yScale: any zoomNode: PhyloNode /* focus should stay in sync with "Focus on selected" toggle state */ focus: null|"selected" /* (indexes of) focus nodes stay in sync with Redux */ focusNodes?: FocusNodes }