Skip to content

Commit

Permalink
fix: 1053 Truncate histogram and dataset info panel (#1054)
Browse files Browse the repository at this point in the history
  • Loading branch information
tihuan authored Jul 25, 2024
1 parent 0ae463c commit 88bf816
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .infra/rdev/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ stack:
services:
explorer:
image:
tag: sha-e0592b8d
tag: sha-c6520687
replicaCount: 1
env:
# env vars common to all deployment stages
Expand Down
1 change: 1 addition & 0 deletions client/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const EMPTY_ARRAY = [];
20 changes: 19 additions & 1 deletion client/src/components/brushableHistogram/histogram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import * as d3 from "d3";
import { AxisDomain } from "d3";
import maybeScientific from "../../util/maybeScientific";
import clamp from "../../util/clamp";
import { truncateText } from "./utils";

const TRUNCATION_MAX_WIDTH_PX = 45;

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
const Histogram = ({
Expand Down Expand Up @@ -130,7 +133,22 @@ const Histogram = ({
i: number
) => string
)
);
)
.selectAll("text")
.each((_, i, nodes) => {
const d3Node = d3.select(nodes[i]);
const text = d3Node.text();
const node = d3Node.node() as SVGTextElement;

const truncatedText = truncateText(
text,
node,
TRUNCATION_MAX_WIDTH_PX
);

d3Node.text(truncatedText);
d3Node.append("title").text(text);
});

/* Y AXIS */
container
Expand Down
41 changes: 41 additions & 0 deletions client/src/components/brushableHistogram/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export function truncateText(
text: string,
node: SVGTextElement,
maxWidth: number
) {
let textLength = node.getComputedTextLength();

if (textLength <= maxWidth) return text; // No truncation needed

// Calculate average character width and estimate visible characters
const avgCharWidth = textLength / text.length;
const visibleChars = Math.floor(maxWidth / avgCharWidth);

// Initial truncation guess
let truncatedText = `${text.slice(0, visibleChars - 1)}...`;
node.textContent = truncatedText;
textLength = node.getComputedTextLength();

// Fine-tune adjustment if the text is too long
if (textLength > maxWidth) {
while (textLength > maxWidth && truncatedText.length > 3) {
truncatedText = `${truncatedText.slice(0, -4)}...`;
node.textContent = truncatedText;
textLength = node.getComputedTextLength();
}
} else {
// Fine-tune adjustment if the text is too short
while (textLength < maxWidth && truncatedText.length < text.length) {
const newTruncatedText = `${text.slice(
0,
truncatedText.length - 3 + 1
)}...`;
node.textContent = newTruncatedText;
textLength = node.getComputedTextLength();
if (textLength > maxWidth) break;
truncatedText = newTruncatedText;
}
}

return truncatedText;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { Category } from "../../../../common/types/schema";
import * as globals from "../../../../globals";
import { RootState } from "../../../../reducers";
import Truncate from "../../../util/truncate";

const COLLECTION_LINK_ORDER_BY = [
"DOI",
Expand Down Expand Up @@ -241,6 +242,12 @@ const renderCollectionLinks = (datasetMetadata: Props["datasetMetadata"]) => {
);
};

/**
* (thuang): This ensures the <Truncate /> component truncates the text in the
* table cells properly.
*/
const DATASET_METADATA_TABLE_ROW_MAX_WIDTH_PX = 160;

/**
* Render dataset metadata. That is, attributes found in categorical fields.
* @param renderSingleValues - Attributes from categorical fields
Expand All @@ -254,15 +261,36 @@ const renderDatasetMetadata = (
}
const metadataViews = buildDatasetMetadataViews(renderSingleValues);
metadataViews.sort(sortDatasetMetadata);

return (
<>
{renderSectionTitle("Dataset")}
<HTMLTable style={getTableStyles()}>
<tbody>
{metadataViews.map(({ key, value }) => (
<tr {...{ key }}>
<td>{key}</td>
<td>{value}</td>
<td>
<Truncate>
<span
style={{
maxWidth: DATASET_METADATA_TABLE_ROW_MAX_WIDTH_PX,
}}
>
{key}
</span>
</Truncate>
</td>
<td>
<Truncate>
<span
style={{
maxWidth: DATASET_METADATA_TABLE_ROW_MAX_WIDTH_PX,
}}
>
{value}
</span>
</Truncate>
</td>
</tr>
))}
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { connect } from "react-redux";
import { Props, mapStateToProps } from "./types";
import ContainerInfo from "../common/infoPanelContainer";
import { EMPTY_ARRAY } from "../../../../common/constants";

function GeneInfo(props: Props) {
const { geneInfo } = props;
Expand All @@ -24,7 +25,7 @@ function GeneInfo(props: Props) {
symbol={gene ?? undefined}
description={geneSummary}
synonyms={geneSynonyms}
references={[]}
references={EMPTY_ARRAY}
error={infoError}
loading={loading}
infoType="Gene"
Expand Down
8 changes: 8 additions & 0 deletions client/src/components/util/truncate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ const SECOND_HALF_INNER_STYLE = {

const isTest = getFeatureFlag(FEATURES.TEST);

/**
* (thuang): Make sure to add `max-width` to the first child element of this component
* for truncation to work properly.
* E.g.,
* <Truncate>
* <span style={{ maxWidth: "100px" }}>This is a long string</span>
* </Truncate>
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export default (props: any) => {
const { children, isGenesetDescription, tooltipAddendum = "" } = props;
Expand Down

0 comments on commit 88bf816

Please sign in to comment.