auspice
Version:
Web app for visualizing pathogen evolution
348 lines (305 loc) • 10.4 kB
text/typescript
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
}