Skip to content

Commit

Permalink
Merge pull request #786 from CodeForAfrica/feature/charttooltip
Browse files Browse the repository at this point in the history
@Hurumap ChartTooltip
  • Loading branch information
koechkevin authored Jul 26, 2024
2 parents efbe2c6 + fdcaf7d commit 1ebd940
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 476 deletions.
168 changes: 42 additions & 126 deletions apps/climatemappedafrica/src/components/HURUmap/Chart/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { ChartTooltip } from "@hurumap/core";
import { Source } from "@hurumap/next";
import { useMediaQuery } from "@mui/material";
import { ThemeProvider, StyledEngineProvider } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import PropTypes from "prop-types";
import React, { useEffect, useState, useRef, useCallback } from "react";
import ReactDOMServer from "react-dom/server";
import React, { useState, useRef, useCallback, useEffect } from "react";
import embed from "vega-embed";

import configureScope from "./configureScope";
import Filters from "./Filters";
import { calculateTooltipPosition, idify } from "./utils";

import ChartTooltip from "@/climatemappedafrica/components/HURUmap/ChartTooltip";
import IndicatorTitle from "@/climatemappedafrica/components/HURUmap/IndicatorTitle";
import theme from "@/climatemappedafrica/theme";

const useStyles = makeStyles(() => ({
root: {
Expand All @@ -28,7 +24,7 @@ const useStyles = makeStyles(() => ({
function Chart({
indicator,
indicatorTitle,
secondaryIndicator: { indicator: secondaryIndicator },
secondaryIndicator: sI,
title,
geoCode,
profileNames,
Expand All @@ -37,10 +33,12 @@ function Chart({
}) {
const classes = useStyles(props);
const chartRef = useRef();
const tooltipRef = useRef();
const [view, setView] = useState(null);
const [cSpec, setCSpec] = useState(null);
// For charts, cnsider anything less than 600px as mobile
const isMobile = !useMediaQuery("(min-width:600px)");
const [tooltipData, setTooltipData] = useState(null);
const secondaryIndicator = sI?.indicator;

const {
id,
Expand All @@ -65,56 +63,9 @@ function Chart({

const handler = useCallback(
(_, event, item, value) => {
const className = `charttooltip-${id}-${geoCode}`;
/* eslint-env browser */
let el = document.getElementsByClassName(className)[0];
if (!el) {
/* eslint-env browser */
el = document.createElement("div");
el.classList.add(className);
/* eslint-env browser */
document.body.appendChild(el);
}

/* eslint-env browser */
const tooltipContainer = document.fullscreenElement || document.body;
tooltipContainer.appendChild(el);
// hide tooltip for null objects, undefined
if (!value) {
el.remove();
return;
}
el.innerHTML = ReactDOMServer.renderToString(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<ChartTooltip
title={value.group}
value={value.count}
formattedValue={
defaultType?.toLowerCase() === "percentage" || !disableToggle
? value.percentage
: undefined
}
item={value?.category}
itemColor={item?.fill}
/>
</ThemeProvider>
</StyledEngineProvider>,
);

el.classList.add("visible");
const { x, y } = calculateTooltipPosition(
event,
el.getBoundingClientRect(),
0,
10,
);
el.setAttribute(
"style",
`top: ${y}px; left: ${x}px; z-index: 1230; position: absolute`,
);
setTooltipData({ item, value, id, geoCode, event });
},
[defaultType, disableToggle, geoCode, id],
[id, geoCode],
);

useEffect(() => {
Expand All @@ -128,16 +79,13 @@ function Chart({
);
setCSpec(spec);
if (chartRef?.current) {
try {
const newView = await embed(chartRef.current, spec, {
renderer: "canvas",
actions: false,
tooltip: handler,
});
setView(newView.view);
} catch (e) {
console.error("Error rendering chart: ", e);
}
const newView = await embed(chartRef.current, spec, {
renderer: "canvas",
actions: false,
tooltip: handler,
});

setView(newView.view);
}
}
renderChart();
Expand Down Expand Up @@ -205,9 +153,19 @@ function Chart({
}),
];

let position = {};
if (tooltipData?.event && tooltipRef?.current) {
position = calculateTooltipPosition(
tooltipData?.event,
tooltipRef?.current?.getBoundingClientRect(),
0,
10,
);
}
if (!indicator?.data) {
return null;
}

return (
<div className={classes.root} id={`chart-${id}-${geoCode}`}>
<IndicatorTitle
Expand All @@ -230,7 +188,6 @@ function Chart({
</IndicatorTitle>
{!isMobile && (
<Filters
// remove primary group, remove stacked field & defined defaults filters
filterGroups={filterGroups}
filterSelectProps={filterSelectProps}
setFilterSelectProps={setFilterSelectProps}
Expand All @@ -247,66 +204,25 @@ function Chart({
>
{source}
</Source>
{tooltipData && tooltipData?.event && (
<ChartTooltip
id={id}
geoCode={geoCode}
value={tooltipData.value}
itemColor={tooltipData.item?.fill}
event={tooltipData?.event}
title={tooltipData.value?.group}
tooltipRef={tooltipRef}
position={position}
formattedValue={
defaultType?.toLowerCase() === "percentage" || !disableToggle
? tooltipData.value?.percentage
: undefined
}
/>
)}
</div>
);
}

Chart.propTypes = {
indicator: PropTypes.shape({
id: PropTypes.number,
chart_configuration: PropTypes.shape({
disableToggle: PropTypes.bool,
defaultType: PropTypes.string,
filter: PropTypes.PropTypes.shape({
defaults: PropTypes.arrayOf(PropTypes.shape({})),
}),
stacked_field: PropTypes.string,
}),
description: PropTypes.string,
metadata: PropTypes.shape({
source: PropTypes.string,
url: PropTypes.string,
groups: PropTypes.arrayOf(PropTypes.shape({})),
primary_group: PropTypes.string,
}),
data: PropTypes.arrayOf(PropTypes.shape({})),
}),
indicatorTitle: PropTypes.string,
secondaryIndicator: PropTypes.shape({
indicator: PropTypes.shape({
id: PropTypes.number,
chart_configuration: PropTypes.shape({
disableToggle: PropTypes.bool,
defaultType: PropTypes.string,
filter: PropTypes.PropTypes.shape({
defaults: PropTypes.arrayOf(PropTypes.shape({})),
}),
stacked_field: PropTypes.string,
}),
description: PropTypes.string,
metadata: PropTypes.shape({
source: PropTypes.string,
url: PropTypes.string,
groups: PropTypes.arrayOf(PropTypes.shape({})),
primary_group: PropTypes.string,
}),
data: PropTypes.arrayOf(PropTypes.shape({})),
}),
}),
title: PropTypes.string,
geoCode: PropTypes.string,
profileNames: PropTypes.shape({}),
isCompare: PropTypes.bool,
};

Chart.defaultProps = {
indicator: undefined,
indicatorTitle: undefined,
secondaryIndicator: {},
title: undefined,
geoCode: undefined,
profileNames: undefined,
isCompare: false,
};

export default Chart;

This file was deleted.

This file was deleted.

Empty file.
Loading

0 comments on commit 1ebd940

Please sign in to comment.