diff --git a/frontend/src/views/WheresMyGeneV2/common/constants.ts b/frontend/src/views/WheresMyGeneV2/common/constants.ts
index 7a7d6246da084..32cc7709081d0 100644
--- a/frontend/src/views/WheresMyGeneV2/common/constants.ts
+++ b/frontend/src/views/WheresMyGeneV2/common/constants.ts
@@ -2,6 +2,12 @@ export const GENE_SEARCH_BAR_HEIGHT_PX = 32;
export const HEATMAP_CONTAINER_ID = "heatmap-container-id";
export const FMG_GENE_STRENGTH_THRESHOLD = 0.5;
export const FMG_SPECIFICITY_THRESHOLD = 0.0;
+export const GENE_LABEL_WIDTH_PX = 20;
+export const GENE_SEARCH_LEFT_OFFSET_PX = 24;
+export const LOADER_WITH_LABEL_THRESHOLD = 13;
+export const LOADER_WITH_LABEL_OFFSET_PX = 80;
+export const LOADER_NO_LABEL_OFFSET_PX = 85;
+export const LOADER_LABEL_TEXT = "Loading Data...";
/**
* (thuang): The `id` options here must match what the BE expects
diff --git a/frontend/src/views/WheresMyGeneV2/components/GeneSearchBar/style.ts b/frontend/src/views/WheresMyGeneV2/components/GeneSearchBar/style.ts
index 8f9104b17ee13..f52bdc9f3b87c 100644
--- a/frontend/src/views/WheresMyGeneV2/components/GeneSearchBar/style.ts
+++ b/frontend/src/views/WheresMyGeneV2/components/GeneSearchBar/style.ts
@@ -8,15 +8,16 @@ import {
} from "src/components/Layout/style";
import { LEGEND_HEIGHT_PX } from "src/views/WheresMyGeneV2/components/InfoPanel/components/Legend/style";
import { Y_AXIS_CHART_WIDTH_PX } from "src/views/WheresMyGeneV2/components/HeatMap/utils";
-import { GENE_SEARCH_BAR_HEIGHT_PX } from "src/views/WheresMyGeneV2/common/constants";
+import {
+ GENE_SEARCH_BAR_HEIGHT_PX,
+ GENE_SEARCH_LEFT_OFFSET_PX,
+} from "src/views/WheresMyGeneV2/common/constants";
import { HEADER_HEIGHT_PX } from "src/components/Header/style";
interface ContainerProps {
sidebarWidth: number;
}
-const GENE_SEARCH_LEFT_OFFSET_PX = 24;
-
export const Container = styled.div`
height: ${GENE_SEARCH_BAR_HEIGHT_PX}px;
width: fit-content;
diff --git a/frontend/src/views/WheresMyGeneV2/components/HeatMap/connect.ts b/frontend/src/views/WheresMyGeneV2/components/HeatMap/connect.ts
index 4d931c584829f..5fe1cb6143666 100644
--- a/frontend/src/views/WheresMyGeneV2/components/HeatMap/connect.ts
+++ b/frontend/src/views/WheresMyGeneV2/components/HeatMap/connect.ts
@@ -332,11 +332,14 @@ export function useConnect({
dispatch,
});
+ const geneCount = sortedGeneNames.length;
+
return {
allTissueCellTypes,
chartWrapperRef,
expandedTissueIds,
filteredCellTypes,
+ geneCount,
generateMarkerGenes,
handleCellTypeDelete,
handleExpandCollapse,
diff --git a/frontend/src/views/WheresMyGeneV2/components/HeatMap/index.tsx b/frontend/src/views/WheresMyGeneV2/components/HeatMap/index.tsx
index 70a0bf48fea6a..8e2cc16c2f303 100644
--- a/frontend/src/views/WheresMyGeneV2/components/HeatMap/index.tsx
+++ b/frontend/src/views/WheresMyGeneV2/components/HeatMap/index.tsx
@@ -2,24 +2,13 @@ import { memo } from "react";
import { Tissue } from "src/views/WheresMyGeneV2/common/types";
import YAxisChart from "./components/YAxisChart";
-
-import {
- CellTypeTagContainer,
- ChartWrapper,
- Container,
- ContainerWrapper,
- SkeletonContainer,
- SkeletonWrapper,
- StyledTag,
- XAxisMask,
- YAxisWrapper,
-} from "src/views/WheresMyGeneV2/components/HeatMap/style";
import { CellCountLabel } from "src/views/WheresMyGeneV2/components/HeatMap/components/XAxisChart/style";
import {
HEATMAP_CONTAINER_ID,
+ LOADER_WITH_LABEL_THRESHOLD,
+ LOADER_LABEL_TEXT,
MARGIN_BETWEEN_HEATMAPS,
} from "src/views/WheresMyGeneV2/common/constants";
-import Loader from "src/views/WheresMyGeneV2/components/Loader";
import XAxisChart from "src/views/WheresMyGeneV2/components/HeatMap/components/XAxisChart";
import Chart from "src/views/WheresMyGeneV2/components/HeatMap/components/Chart";
import { hyphenize } from "src/views/WheresMyGeneV2/components/HeatMap/utils";
@@ -27,10 +16,20 @@ import { EXCLUDE_IN_SCREENSHOT_CLASS_NAME } from "../GeneSearchBar/components/Sa
import { Autocomplete } from "@czi-sds/components";
import {
CellTypeFilterContainer,
+ CellTypeTagContainer,
+ ChartWrapper,
+ Container,
+ ContainerWrapper,
Divider,
+ LoadingContainer,
+ LoadingLabel,
+ LoadingSpinner,
+ LoadingWrapper,
+ StyledTag,
TopLeftCornerMask,
+ XAxisMask,
XAxisWrapper,
- StyledSkeleton,
+ YAxisWrapper,
} from "./style";
import { useConnect } from "src/views/WheresMyGeneV2/components/HeatMap/connect";
@@ -55,6 +54,7 @@ export default memo(function HeatMap(props: Props): JSX.Element {
chartWrapperRef,
expandedTissueIds,
filteredCellTypes,
+ geneCount,
generateMarkerGenes,
handleCellTypeDelete,
handleExpandCollapse,
@@ -101,7 +101,6 @@ export default memo(function HeatMap(props: Props): JSX.Element {
Cell Count
- {isLoadingAPI || (isAnyTissueLoading(isLoading) && )}
- {isLoadingAPI ||
- (isAnyTissueLoading(isLoading) && (
-
-
- {[...Array(totalElementsCount)].map((_, index) => (
-
- {[...Array(sortedGeneNames.length)].map((_, index) => (
-
- ))}
-
- ))}
-
-
- ))}
+ {(isLoadingAPI || isAnyTissueLoading(isLoading)) && (
+ 0
+ }
+ >
+
+
+
+ LOADER_WITH_LABEL_THRESHOLD}
+ >
+ {LOADER_LABEL_TEXT}
+
+
+
+
+ )}
{allTissueCellTypes.map(({ tissueName, tissueCellTypes }) => {
const selectedGeneData =
diff --git a/frontend/src/views/WheresMyGeneV2/components/HeatMap/style.ts b/frontend/src/views/WheresMyGeneV2/components/HeatMap/style.ts
index 95b93d9887519..efad72b6f2750 100644
--- a/frontend/src/views/WheresMyGeneV2/components/HeatMap/style.ts
+++ b/frontend/src/views/WheresMyGeneV2/components/HeatMap/style.ts
@@ -1,13 +1,20 @@
import styled from "@emotion/styled";
-import { CommonThemeProps, TagFilter } from "@czi-sds/components";
+import { CommonThemeProps, TagFilter, fontHeaderXl } from "@czi-sds/components";
-import { gray300, spacesM, spacesS } from "src/common/theme";
+import { gray100, gray400, gray300, spacesM, spacesS } from "src/common/theme";
import { HEADER_HEIGHT_PX } from "src/components/Header/style";
import {
CONTENT_WRAPPER_LEFT_RIGHT_PADDING_PX,
CONTENT_WRAPPER_TOP_BOTTOM_PADDING_PX,
} from "src/components/Layout/style";
-import { X_AXIS_CHART_HEIGHT_PX } from "src/views/WheresMyGeneV2/common/constants";
+import {
+ LOADER_WITH_LABEL_THRESHOLD,
+ GENE_LABEL_WIDTH_PX,
+ X_AXIS_CHART_HEIGHT_PX,
+ LOADER_WITH_LABEL_OFFSET_PX,
+ LOADER_NO_LABEL_OFFSET_PX,
+ GENE_SEARCH_LEFT_OFFSET_PX,
+} from "src/views/WheresMyGeneV2/common/constants";
import {
CELL_TYPE_FILTER_WIDTH_PX,
DIVIDER_LEFT_POSITION_PX,
@@ -17,7 +24,6 @@ import {
import { LEGEND_HEIGHT_PX } from "../InfoPanel/components/Legend/style";
import { LEGEND_MARGIN_BOTTOM_PX } from "../../style";
import { LIGHT_GRAY } from "src/components/common/theme";
-import { Skeleton } from "@mui/material";
export function xAxisOffset(props: CommonThemeProps) {
/**
@@ -120,7 +126,7 @@ export const TopLeftCornerMask = styled.div`
interface ChartWrapperProps extends CommonThemeProps {
top: number;
- hidden: boolean;
+ visible: boolean;
}
export const ChartWrapper = styled.div`
@@ -130,7 +136,8 @@ export const ChartWrapper = styled.div`
padding-top: ${(props) => xAxisOffset(props) + PADDING_UNDER_HEADERS_PX}px;
left: ${Y_AXIS_CHART_WIDTH_PX}px;
top: ${(props) => props.top}px;
- visibility: ${(props) => (props.hidden ? "hidden" : "visible")};
+ visibility: ${(props) => (props.visible ? "visible" : "hidden")};
+ width: 100%;
`;
export const StyledTag = styled(TagFilter)`
@@ -161,16 +168,74 @@ export const YAxisWrapper = styled.div`
overflow: hidden;
`;
-export const StyledSkeleton = styled(Skeleton)`
- margin: 0px 0px 4px 1px;
+interface LoadingContainerProps extends CommonThemeProps {
+ height: number;
+ width: number;
+}
+
+export const LoadingContainer = styled.div`
+ position: absolute;
+ display: flex;
+ width: ${(props) => props.width * 20}px;
+ height: ${(props) => props.height * 20}px;
+ background-color: ${gray100};
`;
-export const SkeletonContainer = styled.div`
+interface LoadingProps extends CommonThemeProps {
+ geneCount: number;
+ sidebarWidth: number;
+}
+
+export const LoadingWrapper = styled.div`
display: flex;
flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ position: fixed;
+ top: 600px;
+ /**
+ * This is to keep the loader centered under any number of genes selected
+ */
+ left: ${({ geneCount, sidebarWidth }) =>
+ (geneCount * GENE_LABEL_WIDTH_PX) / 2 +
+ (sidebarWidth +
+ CONTENT_WRAPPER_LEFT_RIGHT_PADDING_PX +
+ Y_AXIS_CHART_WIDTH_PX +
+ GENE_SEARCH_LEFT_OFFSET_PX -
+ (geneCount > LOADER_WITH_LABEL_THRESHOLD
+ ? LOADER_WITH_LABEL_OFFSET_PX
+ : LOADER_NO_LABEL_OFFSET_PX))}px;
`;
-export const SkeletonWrapper = styled.div`
- display: flex;
- flex-direction: row;
+interface LoadingLabelProps extends CommonThemeProps {
+ visible: boolean;
+}
+
+export const LoadingLabel = styled.div`
+ color: black;
+ ${fontHeaderXl}
+ padding-top: 20px;
+ visibility: ${(props) => (props.visible ? "visible" : "hidden")};
+`;
+
+export const LoadingSpinner = styled.div`
+ --d: 10.6px;
+ width: 1.9px;
+ height: 1.9px;
+ border-radius: 50%;
+ color: ${gray400};
+ box-shadow:
+ calc(1 * var(--d)) calc(0 * var(--d)) 0 0,
+ calc(0.707 * var(--d)) calc(0.707 * var(--d)) 0 0.5px,
+ calc(0 * var(--d)) calc(1 * var(--d)) 0 1px,
+ calc(-0.707 * var(--d)) calc(0.707 * var(--d)) 0 1.4px,
+ calc(-1 * var(--d)) calc(0 * var(--d)) 0 1.9px,
+ calc(-0.707 * var(--d)) calc(-0.707 * var(--d)) 0 2.4px;
+ animation: spinner 1s infinite steps(8);
+
+ @keyframes spinner {
+ 100% {
+ transform: rotate(1turn);
+ }
+ }
`;