Commit 2d2bfef4 authored by Matus Talcik's avatar Matus Talcik
Browse files

Bring back selections and tooltips

parent f17a6bd3
Loading
Loading
Loading
Loading
+13 −12
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ import './RightPanel.scss';
import { ChromatinRepresentation, SmoothCamera, SmoothCameraConfiguration } from "../../modules/graphics";
import { Text } from '@fluentui/react/lib/Text';

import { ChromatinViewportAggregationFunction, ChromatinViewportColorMappingMode, ChromatinViewportConfiguration, ConfigurationAction, ConfigurationState, LabelingDebugTexture, TooltipNumericAggregation, TooltipTextAggregation, ViewportConfigurationType } from '../../modules/storage/models/viewports';
import { ChromatinViewportAggregationFunction, ChromatinViewportColorMappingMode, ChromatinViewportConfiguration, ConfigurationAction, ConfigurationState, IChromatinDataConfiguration, LabelingDebugTexture, TooltipNumericAggregation, TooltipTextAggregation, ViewportConfigurationType } from '../../modules/storage/models/viewports';
import { BinPositionsData, DataAction, DataID, DataState, isoDataID } from "../../modules/storage/models/data";
import { SelectionAction, SelectionState } from "../../modules/storage/models/selections";
import { useConfiguration, useSelections, useViewportName } from "../hooks";
@@ -209,7 +209,7 @@ export function ChromatinViewportConfigurationPanel(props: {

    const [isBackgroundColorCalloutVisible, setIsBackgroundColorCalloutVisible] = useState<boolean>(false);

    const selections = useSelections(0, [configuration, updateConfiguration], props.dataReducer, props.selectionsReducer, 0);
    const selections = useSelections([configuration, updateConfiguration], props.dataReducer, props.selectionsReducer, configuration.selectedDatum);

    //#region Viewport Settings
    const setBackgroundColor = (event: React.SyntheticEvent<HTMLElement>, color: IColor): void => {
@@ -243,12 +243,12 @@ export function ChromatinViewportConfigurationPanel(props: {
    const removeData3D = (index: number) => {
        if (!configuration) return;

        const newData = [...configuration.data];
        const newData: IChromatinDataConfiguration[] = [...configuration.data];
        newData.splice(index, 1);

        updateConfiguration({
            ...configuration,
            selectedDatum: configuration.selectedDatum == index ? null : configuration.selectedDatum,
            selectedSelectionID: null,
            data: newData,
        });
    };
@@ -256,7 +256,7 @@ export function ChromatinViewportConfigurationPanel(props: {
    const addData = () => {
        if (!configuration || !selectedPrimaryData) return;

        const data = [...configuration.data];
        const newData = [...configuration.data];

        //#region Calculate radius range
        const positions = (selectedPrimaryData.type == '3d-positions' ? selectedPrimaryData as BinPositionsData : selectedSecondaryData as BinPositionsData).values;
@@ -273,7 +273,7 @@ export function ChromatinViewportConfigurationPanel(props: {
        const radiusRange = { min: 0.0, max: quantiles[0] / 2.0 };
        //#region Calculate radius range

        data.push({
        newData.push({
            id: selectedPrimaryData.id,
            secondaryID: selectedSecondaryDataID,

@@ -286,6 +286,7 @@ export function ChromatinViewportConfigurationPanel(props: {
            radius,
            radiusRange,

            selectedSelectionID: null,
            selections: [],

            mapValues: {
@@ -324,19 +325,19 @@ export function ChromatinViewportConfigurationPanel(props: {

        updateConfiguration({
            ...configuration,
            data,
            data: newData,
        });
    };

    const setDataColor = (ev: React.SyntheticEvent<HTMLElement, Event>, color: IColor): void => {
        if (configuration.selectedDatum == null) return;

        const data = [...configuration.data];
        data[configuration.selectedDatum] = { ...data[configuration.selectedDatum], color };
        const newData = [...configuration.data];
        newData[configuration.selectedDatum] = { ...newData[configuration.selectedDatum], color };

        updateConfiguration({
            ...configuration,
            data
            data: newData
        });
    };

@@ -607,7 +608,7 @@ export function ChromatinViewportConfigurationPanel(props: {
        (<div className={"treeViewListItem " + (configuration.selectedDatum == index ? 'selected' : '')} key={index} onClick={() => setSelectedDatum(index)}>
            <span style={{ display: 'block', width: '4px' }}></span>
            <Text className="text" nowrap>{datum.id}</Text>
            <Delete16Regular primaryFill={'white'} className='icon iconHoverRed' onClick={() => removeData3D(index)}></Delete16Regular>
            <Delete16Regular primaryFill={'white'} className='icon iconHoverRed' onClick={(e) => { e.stopPropagation(); removeData3D(index); } }></Delete16Regular>
        </div>)
        )}

@@ -862,7 +863,7 @@ export function ChromatinViewportConfigurationPanel(props: {
        {/* SELECTIONS */}
        <div style={{ display: 'block', width: '100%', marginTop: '16px' }}></div>
        <Separator></Separator>
        {configuration.selectedDatum && (
        {configuration.selectedDatum != null && (
            <SelectionsPart
                selections={selections}
                configurationReducer={configurationReducer}
+31 −7
Original line number Diff line number Diff line
import { DistanceMapDataConfiguration, ViewportConfiguration, ViewportConfigurationType, ViewportSelectionOptions } from "../../modules/storage/models/viewports";
import { DistanceMapDataConfiguration, ChromatinViewportConfiguration, ViewportConfiguration, ViewportConfigurationType, ViewportSelectionOptions } from "../../modules/storage/models/viewports";
import { DataAction, DataID, DataState } from "../../modules/storage/models/data";
import { isoSelectionID, SelectionAction, SelectionActionKind, SelectionID, Selection, SelectionState } from "../../modules/storage/models/selections";
import { ConfigurationReducer, ConfigurationsWithSelections } from "../hooks";
@@ -49,17 +49,33 @@ export function SelectionsPart<T extends ConfigurationsWithSelections>(props: Pr
            const dataSize = data.data.find(d => d.id == selectedDataPartID)?.values?.length;

            if (dataSize) {
                console.log('adding selection');
                globalSelectionsDispatch({ type: SelectionActionKind.ADD, dataID: selectedDataPartID as DataID, dataSize });
            }
        }
    }

    const selectSelection = (selectionID: SelectionID) => {
        if (configuration.type === ViewportConfigurationType.Chromatin && configuration.selectedDatum != null) {
            const newData = [...configuration.data];
            newData[configuration.selectedDatum] = {
                ...newData[configuration.selectedDatum],
                selectedSelectionID: selectionID,
            };

            updateConfiguration({
                ...configuration,
                data: newData                
            });

            console.log(configuration);
        } else {
            updateConfiguration({
                ...configuration,
                selectedSelectionID: selectionID,
            });
        }
    }

    const handleRenameStart = (selection: Selection) => setRenaming({ id: selection.id, newName: selection.name })
    const handleRenameChange = (newName: string | undefined) => setRenaming({ ...renaming!, newName: newName ?? "" })
@@ -74,7 +90,6 @@ export function SelectionsPart<T extends ConfigurationsWithSelections>(props: Pr
            name: renaming!.newName.length == 0 ? "unnamed" : renaming!.newName
        })
        setRenaming(null);

    }

    const setSelectionVisiblity = (selectionID: SelectionID, visible: boolean, dataIndex = 0) => {
@@ -144,7 +159,16 @@ export function SelectionsPart<T extends ConfigurationsWithSelections>(props: Pr
                a: color.a != undefined ? (color.a / 255) : 1
            },
        });
    }

    const isSelected = (id: SelectionID) => {
        if (configuration.type === ViewportConfigurationType.Chromatin && configuration.selectedDatum && configuration.data[configuration.selectedDatum]) {
            return configuration.data[configuration.selectedDatum].selectedSelectionID == id;
        } else {
            return configuration.selectedSelectionID == id;
        }

        return false;
    }

    return <>
@@ -161,7 +185,7 @@ export function SelectionsPart<T extends ConfigurationsWithSelections>(props: Pr
                                    <div ref={provided.innerRef}
                                        {...provided.draggableProps}
                                        {...provided.dragHandleProps}
                                        className={selection.id == configuration.selectedSelectionID ? "treeViewListItem selected" : "treeViewListItem"}
                                        className={isSelected(selection.id) ? "treeViewListItem selected" : "treeViewListItem"}
                                        onClick={() => selectSelection(selection.id)}>
                                        <DefaultButton id="selectionColorButton"
                                            style={{
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ export function TADMapViewportConfiguration(props: {

    const [viewportName, setViewportName] = useViewportName(props.node, props.configurationsReducer);

    const selections = useSelections(0, [configuration, updateConfiguration], props.dataReducer, props.selectionsReducer, 0);
    const selections = useSelections([configuration, updateConfiguration], props.dataReducer, props.selectionsReducer, 0);

    const dataList = data.data.filter(d => d.type == 'sparse-distance-matrix' || d.type == '3d-positions').map(d => {
        return {
+6 −1
Original line number Diff line number Diff line
@@ -16,7 +16,12 @@ export function ToolOptions(props: {
    const [configuration, updateConfiguration] = configurationReducer;
    const tool = configuration.tool;
    const isMac = new UAParser().getOS().name == 'Mac OS';
    const hasSelectedSelection = configuration.selectedSelectionID != null;
    
    let hasSelectedSelection = configuration.selectedSelectionID != null;

    if (configuration.type == ViewportConfigurationType.Chromatin && configuration.selectedDatum && configuration.data[configuration.selectedDatum]) {
        hasSelectedSelection = configuration.data[configuration.selectedDatum].selectedSelectionID != null;
    }


    const enforceSelectedSelection = (element: JSX.Element): JSX.Element => {
+30 −17
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@ import { Actions, Model, TabNode } from "flexlayout-react";
import { Dispatch, useEffect, useState, useCallback } from "react";
import { useFreshTick } from "rooks";
import { ChromatinViewportConfiguration, ConfigurationAction, ConfigurationActionKind, ConfigurationState, dataIndex, DistanceViewportConfiguration, ForceGraphViewportConfiguration, IViewportConfiguration, ViewportConfiguration, ViewportSelectionOptions } from "../modules/storage/models/viewports";
import { DataAction, DataState } from "../modules/storage/models/data";
import { SelectionAction, Selection, SelectionState } from "../modules/storage/models/selections";
import { DataAction, DataID, DataState } from "../modules/storage/models/data";
import { SelectionAction, Selection, SelectionState, SelectionID } from "../modules/storage/models/selections";

// Only configurations that have selections can use this part
export type ConfigurationsWithSelections = ChromatinViewportConfiguration | DistanceViewportConfiguration | ForceGraphViewportConfiguration;
@@ -67,29 +67,28 @@ export function useConfiguration<T extends ViewportConfiguration>(id: number, co
export const useConfigurationTypeless = (id: number, configurationsReducer: [ConfigurationState, Dispatch<ConfigurationAction>]) => useConfiguration<ViewportConfiguration>(id, configurationsReducer);

export function useSelections<T extends ConfigurationsWithSelections>(
    dataPartIndex: dataIndex | null,
    configurationReducer: ConfigurationReducer<T>,
    dataReducer: [DataState, Dispatch<DataAction>],
    selectionsReducer: [SelectionState, Dispatch<SelectionAction>],
    selectedDataIndex: number): Array<[Selection, ViewportSelectionOptions]> {
    selectedDataIndex: number | null): Array<[Selection, ViewportSelectionOptions]> {
    const [configuration, updateConfiguration] = configurationReducer;
    const [globalSelections, dispatchGlobalSelections] = selectionsReducer;

    const [result, setResult] = useState<Array<[Selection, ViewportSelectionOptions]>>([]);

    useEffect(() => {
        if (!configuration.data || (Array.isArray(configuration.data) && configuration.data.length === 0)) {
        if (!configuration.data || selectedDataIndex == null || (Array.isArray(configuration.data) && configuration.data.length === 0)) {
            setResult(() => []);
            return;
        }

        const dataPartID = Array.isArray(configuration.data) ? configuration.data[selectedDataIndex] : configuration.data.id;
        const dataSelections = Array.isArray(configuration.data) ? configuration.data[selectedDataIndex].selections : configuration.data.selections
        const dataPartID: DataID | SelectionID | null = Array.isArray(configuration.data) ? configuration.data[selectedDataIndex]?.id || null : configuration.data.id;
        const dataSelections = Array.isArray(configuration.data) ? configuration.data[selectedDataIndex]?.selections || null : configuration.data.selections;

        const selections = dataPartID != null ? globalSelections.selections.filter(selection => selection.dataID === dataPartID) : [];
        const selectionsAssociatedData: Array<ViewportSelectionOptions> = (dataPartID != null && dataPartIndex != null) ? dataSelections.map(s => { return { ...s } }) : [];
        const selectionsAssociatedData: Array<ViewportSelectionOptions> = dataPartID ? dataSelections.map(s => { return { ...s } }) : [];

        if (dataPartIndex == null || dataPartID == null) return;
        if (dataPartID == null) return;

        const selectionsIDs = selections.map(s => s.id);
        const selectionsAssociatedDataIds = selectionsAssociatedData.map(s => s.selectionID);
@@ -107,10 +106,22 @@ export function useSelections<T extends ConfigurationsWithSelections>(
        }

        if (toRemoveAssociatedDataIds.length > 0 || toAddAssociatedDataIds.length > 0) {
            if (Array.isArray(configuration.data)) {
                const newData = [...configuration.data];
                newData[selectedDataIndex] = {
                    ...configuration.data[selectedDataIndex],
                    selections: newSelectionsAssociatedData
                };

                updateConfiguration({
                    ...configuration,
                    data: newData
                });
            } else {
                const newData = {
                    ...configuration.data,
                    selections: newSelectionsAssociatedData
            }
                };

                updateConfiguration({
                    ...configuration,
@@ -118,6 +129,8 @@ export function useSelections<T extends ConfigurationsWithSelections>(
                });
            }

        }

        const newResult: Array<[Selection, ViewportSelectionOptions]> = [];
        for (const selection of selections) {
            const associatedSelection: ViewportSelectionOptions | undefined = selectionsAssociatedData.filter(s => s.selectionID == selection.id).at(0);
@@ -127,7 +140,7 @@ export function useSelections<T extends ConfigurationsWithSelections>(
            }
        }
        setResult(() => newResult);
    }, [configuration, configuration.data, globalSelections, dataPartIndex]);
    }, [configuration, configuration.data, globalSelections, selectedDataIndex]);

    return result;
}
Loading