UNPKG

auspice

Version:

Web app for visualizing pathogen evolution

126 lines (121 loc) 4.07 kB
import { AnyAction } from "@reduxjs/toolkit"; import { countTraitsAcrossTree } from "../../util/treeCountingHelpers"; import { addNodeAttrs, removeNodeAttrs } from "../../util/treeMiscHelpers"; import * as types from "../../actions/types"; import { TreeState, TreeTooState } from "./types"; export const getDefaultTreeState = (): TreeState | TreeTooState => { return { loaded: false, nodes: null, name: undefined, visibility: null, visibilityVersion: 0, nodeColors: null, nodeColorsVersion: 0, tipRadii: null, tipRadiiVersion: 0, hoveredLegendSwatch: false, branchThickness: null, branchThicknessVersion: 0, vaccines: false, version: 0, idxOfInViewRootNode: 0, totalStateCounts: {}, observedMutations: {}, availableBranchLabels: [], streams: {}, }; }; const Tree = ( state: TreeState = getDefaultTreeState(), action: AnyAction, ): TreeState => { switch (action.type) { case types.URL_QUERY_CHANGE_WITH_COMPUTED_STATE: /* fallthrough */ case types.CLEAN_START: return action.tree; case types.DATA_INVALID: return { ...state, loaded: false, }; case types.CHANGE_EXPLODE_ATTR: /* fallthrough */ case types.CHANGE_DATES_VISIBILITY_THICKNESS: /* fallthrough */ case types.UPDATE_VISIBILITY_AND_BRANCH_THICKNESS: { const newStates: Partial<TreeState> = { visibility: action.visibility, visibilityVersion: action.visibilityVersion, branchThickness: action.branchThickness, branchThicknessVersion: action.branchThicknessVersion, idxOfInViewRootNode: action.idxOfInViewRootNode, idxOfFilteredRoot: action.idxOfFilteredRoot, focusNodes: action.focusNodes, }; return { ...state, ...newStates, }; } case types.SET_FOCUS: return { ...state, focusNodes: action.focusNodes || undefined, } case types.UPDATE_TIP_RADII: return { ...state, tipRadii: action.data, tipRadiiVersion: action.version, hoveredLegendSwatch: action.hoveredLegendSwatch, }; case types.NEW_COLORS: return { ...state, nodeColors: action.nodeColors, nodeColorsVersion: action.version, }; case types.CHANGE_STREAM_TREE_BRANCH_LABEL: return {...state, streams: action.streams} case types.TREE_TOO_DATA: return action.tree; case types.ADD_EXTRA_METADATA: { // add data into `nodes` in-place, so no redux update will be triggered if you only listen to `nodes` addNodeAttrs(state.nodes, action.newNodeAttrs); // add the new nodeAttrKeys to ensure tip labels get updated const nodeAttrKeys = new Set(state.nodeAttrKeys); Object.keys(action.newColorings).forEach((attr) => nodeAttrKeys.add(attr)); // add the new non-continuous colorings to totalStateCounts so that they can function as filters const nonContinuousColorings = Object.keys(action.newColorings).filter((coloring: string) => { return action.newColorings[coloring].type !== "continuous" }); return { ...state, totalStateCounts: { ...state.totalStateCounts, ...countTraitsAcrossTree(state.nodes, nonContinuousColorings, false, true) }, nodeAttrKeys }; } case types.REMOVE_METADATA: { // remove data from `nodes` in-place, so no redux update will be triggered if you only listen to `nodes` removeNodeAttrs(state.nodes, action.nodeAttrsToRemove); const nodeAttrKeys = new Set(state.nodeAttrKeys); const totalStateCounts = {...state.totalStateCounts}; action.nodeAttrsToRemove.forEach((attrKey: string): void => { nodeAttrKeys.delete(attrKey); if (attrKey in totalStateCounts) { delete totalStateCounts[attrKey]; } }) return { ...state, totalStateCounts, nodeAttrKeys, } } default: return state; } }; export default Tree;