Skip to content

Commit

Permalink
[tiles] add source for top event tiles (#2350)
Browse files Browse the repository at this point in the history
  • Loading branch information
chejennifer authored Mar 1, 2023
1 parent a657f66 commit dc28ed6
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 116 deletions.
6 changes: 6 additions & 0 deletions static/css/shared/_tiles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ $box-shadow-8dp: 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0,

.ranking-unit-container {
padding: 0 0.5rem;
display: flex;
flex-direction: column;

.ranking-list {
flex-grow: 1;
}
}

/**
Expand Down
86 changes: 86 additions & 0 deletions static/js/components/tiles/chart_footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Footer for charts in tiles.
*/

import _ from "lodash";
import React from "react";

import { NL_SOURCE_REPLACEMENTS } from "../../constants/app/nl_interface_constants";
import { urlToDomain } from "../../shared/util";
import { isNlInterface } from "../../utils/nl_interface_utils";

interface ChartFooterPropType {
// set of full urls of sources of the data in the chart
sources: Set<string>;
handleEmbed?: () => void;
}

/**
* Gets the JSX element for displaying a list of sources.
*/
function getSourcesJsx(sources: Set<string>): JSX.Element[] {
if (!sources) {
return null;
}

const sourceList: string[] = Array.from(sources);
const seenSourceDomains = new Set();
const sourcesJsx = sourceList.map((source, index) => {
// HACK for updating source for NL interface
let processedSource = source;
if (isNlInterface()) {
processedSource = NL_SOURCE_REPLACEMENTS[source] || source;
}
const domain = urlToDomain(processedSource);
if (seenSourceDomains.has(domain)) {
return null;
}
seenSourceDomains.add(domain);
return (
<span key={processedSource}>
{index > 0 ? ", " : ""}
<a href={processedSource}>{domain}</a>
</span>
);
});
return sourcesJsx;
}

export function ChartFooter(props: ChartFooterPropType): JSX.Element {
return (
<footer id="chart-container-footer">
{!_.isEmpty(props.sources) && (
<div className="sources">Data from {getSourcesJsx(props.sources)}</div>
)}
<div className="outlinks">
{props.handleEmbed && (
<a
href="#"
onClick={(event) => {
event.preventDefault();
props.handleEmbed();
}}
>
Export
</a>
)}
</div>
</footer>
);
}
33 changes: 7 additions & 26 deletions static/js/components/tiles/chart_tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ import _ from "lodash";
import React, { useRef } from "react";

import { ChartEmbed } from "../../place/chart_embed";
import {
formatString,
getSourcesJsx,
ReplacementStrings,
} from "../../utils/tile_utils";
import { formatString, ReplacementStrings } from "../../utils/tile_utils";
import { ChartFooter } from "./chart_footer";

interface ChartTileContainerProp {
title: string;
Expand Down Expand Up @@ -55,26 +52,10 @@ export function ChartTileContainer(props: ChartTileContainerProp): JSX.Element {
>
{title && <h4>{title}</h4>}
{props.children}
<footer id="chart-container-footer">
{!_.isEmpty(props.sources) && (
<div className="sources">
Data from {getSourcesJsx(props.sources)}
</div>
)}
<div className="outlinks">
{props.allowEmbed && (
<a
href="#"
onClick={(event) => {
event.preventDefault();
handleEmbed();
}}
>
Export
</a>
)}
</div>
</footer>
<ChartFooter
sources={props.sources}
handleEmbed={props.allowEmbed ? handleEmbed : null}
/>
{props.allowEmbed && <ChartEmbed ref={embedModalElement} />}
</div>
);
Expand All @@ -98,7 +79,7 @@ export function ChartTileContainer(props: ChartTileContainerProp): JSX.Element {
embedModalElement.current.show(
svgXml,
props.getDataCsv ? props.getDataCsv() : "",
svgWidth,
svgWidth || containerRef.current.offsetWidth,
svgHeight,
chartTitle,
"",
Expand Down
1 change: 0 additions & 1 deletion static/js/components/tiles/disaster_event_map_tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/

import * as d3 from "d3";
import { geoJson } from "leaflet";
import _ from "lodash";
import React, { useContext, useEffect, useRef, useState } from "react";

Expand Down
47 changes: 10 additions & 37 deletions static/js/components/tiles/ranking_tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ import { getPlaceDisplayNames, getPlaceNames } from "../../utils/place_utils";
import { formatNumber } from "../../utils/string_utils";
import {
formatString,
getSourcesJsx,
getStatVarName,
getUnitString,
} from "../../utils/tile_utils";
import { RankingUnit } from "../ranking_unit";
import { ChartFooter } from "./chart_footer";

const RANKING_COUNT = 5;

Expand Down Expand Up @@ -81,7 +81,6 @@ export function RankingTile(props: RankingTilePropType): JSX.Element {
const rankingCount = props.rankingMetadata.rankingCount || RANKING_COUNT;
const isMultiColumn = props.rankingMetadata.showMultiColumn;
const svNames = props.statVarSpec.map((sv) => sv.name);
// TODO: Make use of ChartTileContainer for the footer section.
return (
<div
className={`chart-container ranking-tile ${props.className}`}
Expand Down Expand Up @@ -125,21 +124,10 @@ export function RankingTile(props: RankingTilePropType): JSX.Element {
svNames={isMultiColumn ? svNames : undefined}
formatNumberFn={formatNumber}
/>
<footer>
{!_.isEmpty(sources) && (
<div className="sources">
Data from {getSourcesJsx(sources)}
</div>
)}
<a
href="#"
onClick={(event) => {
handleEmbed(event, points);
}}
>
Export
</a>
</footer>
<ChartFooter
sources={sources}
handleEmbed={() => handleEmbed(points.reverse())}
/>
</div>
)}
{props.rankingMetadata.showLowest && (
Expand Down Expand Up @@ -167,21 +155,10 @@ export function RankingTile(props: RankingTilePropType): JSX.Element {
svNames={isMultiColumn ? svNames : undefined}
formatNumberFn={formatNumber}
/>
<footer>
{!_.isEmpty(sources) && (
<div className="sources">
Data from {getSourcesJsx(sources)}
</div>
)}
<a
href="#"
onClick={(event) => {
handleEmbed(event, points);
}}
>
Export
</a>
</footer>
<ChartFooter
sources={sources}
handleEmbed={() => handleEmbed(points)}
/>
</div>
)}
</React.Fragment>
Expand All @@ -191,11 +168,7 @@ export function RankingTile(props: RankingTilePropType): JSX.Element {
</div>
);

function handleEmbed(
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
rankingPoints: RankingPoint[]
): void {
e.preventDefault();
function handleEmbed(rankingPoints: RankingPoint[]): void {
embedModalElement.current.show(
"",
rankingPointsToCsv(rankingPoints),
Expand Down
25 changes: 10 additions & 15 deletions static/js/components/tiles/top_event_tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { stringifyFn } from "../../utils/axios";
import { rankingPointsToCsv } from "../../utils/chart_csv_utils";
import { getPlaceNames } from "../../utils/place_utils";
import { formatNumber } from "../../utils/string_utils";
import { ChartFooter } from "./chart_footer";

const RANKING_COUNT = 10;
const MIN_PERCENT_PLACE_NAMES = 0.4;
Expand Down Expand Up @@ -92,6 +93,10 @@ export function TopEventTile(props: TopEventTilePropType): JSX.Element {
MIN_PERCENT_PLACE_NAMES;
const showNameColumn =
topEvents.filter((event) => !isUnnamedEvent(event.placeName)).length > 0;
const sources = new Set<string>();
Object.values(props.disasterEventData.provenanceInfo).forEach((provInfo) => {
sources.add(provInfo.provenanceUrl);
});

return (
<div
Expand Down Expand Up @@ -175,16 +180,10 @@ export function TopEventTile(props: TopEventTilePropType): JSX.Element {
})}
</tbody>
</table>
<footer>
<a
href="#"
onClick={(event) => {
handleEmbed(event, topEvents);
}}
>
Export
</a>
</footer>
<ChartFooter
sources={sources}
handleEmbed={() => handleEmbed(topEvents)}
/>
</div>
</div>
)}
Expand Down Expand Up @@ -331,11 +330,7 @@ export function TopEventTile(props: TopEventTilePropType): JSX.Element {
return filteredPoints.slice(0, RANKING_COUNT);
}

function handleEmbed(
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
topEvents: DisasterEventPoint[]
): void {
e.preventDefault();
function handleEmbed(topEvents: DisasterEventPoint[]): void {
const rankingPoints = topEvents.map((point) => {
return {
placeDcid: point.placeDcid,
Expand Down
37 changes: 0 additions & 37 deletions static/js/utils/tile_utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,8 @@
* Util functions used by tile components.
*/

import React from "react";

import { NL_SOURCE_REPLACEMENTS } from "../constants/app/nl_interface_constants";
import { getStatsVarLabel } from "../shared/stats_var_labels";
import { StatVarSpec } from "../shared/types";
import { urlToDomain } from "../shared/util";
import { isNlInterface } from "./nl_interface_utils";

export interface ReplacementStrings {
place: string;
Expand Down Expand Up @@ -72,38 +67,6 @@ export function getStatVarName(
return label;
}

/**
* Gets the JSX element for displaying a list of sources.
* @param sources sources to include in the element
*/
export function getSourcesJsx(sources: Set<string>): JSX.Element[] {
if (!sources) {
return null;
}

const sourceList: string[] = Array.from(sources);
const seenSourceDomains = new Set();
const sourcesJsx = sourceList.map((source, index) => {
// HACK for updating source for NL interface
let processedSource = source;
if (isNlInterface()) {
processedSource = NL_SOURCE_REPLACEMENTS[source] || source;
}
const domain = urlToDomain(processedSource);
if (seenSourceDomains.has(domain)) {
return null;
}
seenSourceDomains.add(domain);
return (
<span key={processedSource}>
{index > 0 ? ", " : ""}
<a href={processedSource}>{domain}</a>
</span>
);
});
return sourcesJsx;
}

/**
* Gets the unit given the unit for the stat var and the dcid of the denominator
* TODO(chejennifer): clean up all the getUnit functions in this repo
Expand Down

0 comments on commit dc28ed6

Please sign in to comment.