add a hook to track window resize so we can dynamically size charts; default highlight Home link in nav; some typescript fixes

This commit is contained in:
gingervitis 2020-11-02 20:49:52 -08:00
parent 9e4e6b2df3
commit 112cc3af14
6 changed files with 96 additions and 51 deletions

View File

@ -1,5 +1,7 @@
import { LineChart, XAxis, YAxis, Line, Tooltip, Legend } from "recharts";
import { timeFormat } from "d3-time-format";
import useWindowSize from '../../utils/hook-windowresize';
import styles from '../../styles/styles.module.css';
interface ToolTipProps {
active?: boolean,
@ -10,20 +12,18 @@ interface ToolTipProps {
const defaultProps = {
active: false,
payload: Object,
unit: "",
unit: '',
};
interface TimedValue {
time: Date;
value: Number;
value: number;
}
interface ChartProps {
// eslint-disable-next-line react/require-default-props
data?: TimedValue[],
color: string,
unit: string,
// eslint-disable-next-line react/require-default-props
dataCollections?: any[],
}
@ -47,61 +47,67 @@ export default function Chart({ data, color, unit, dataCollections }: ChartProps
if (!data && !dataCollections) {
return null;
}
const windowSize = useWindowSize();
const chartWidth = windowSize.width * .68;
const chartHeight = chartWidth * .333;
const timeFormatter = (tick: string) => {
return timeFormat("%I:%M")(new Date(tick));
};
let ticks
let ticks = [];
if (dataCollections.length > 0) {
ticks = dataCollections[0].data?.map(function (collection) {
ticks = dataCollections[0].data?.map((collection) => {
return collection?.time;
})
} else if (data?.length > 0){
ticks = data?.map(function (item) {
ticks = data?.map(item => {
return item?.time;
});
}
return (
<LineChart width={1200} height={400} data={data}>
<XAxis
dataKey="time"
tickFormatter={timeFormatter}
interval="preserveStartEnd"
tickCount={5}
minTickGap={15}
domain={["dataMin", "dataMax"]}
ticks={ticks}
/>
<YAxis
dataKey="value"
interval="preserveStartEnd"
unit={unit}
domain={["dataMin", "dataMax"]}
/>
<Tooltip content={<CustomizedTooltip unit={unit} />} />
<Legend />
<Line
type="monotone"
dataKey="value"
stroke={color}
dot={null}
strokeWidth={3}
/>
{dataCollections?.map((s) => (
<Line
<div className={styles.lineChartContainer}>
<LineChart width={chartWidth} height={chartHeight} data={data}>
<XAxis
dataKey="time"
tickFormatter={timeFormatter}
interval="preserveStartEnd"
tickCount={5}
minTickGap={15}
domain={["dataMin", "dataMax"]}
ticks={ticks}
/>
<YAxis
dataKey="value"
data={s.data}
name={s.name}
key={s.name}
interval="preserveStartEnd"
unit={unit}
domain={["dataMin", "dataMax"]}
/>
<Tooltip content={<CustomizedTooltip unit={unit} />} />
<Legend />
<Line
type="monotone"
stroke={s.color}
dataKey="value"
stroke={color}
dot={null}
strokeWidth={3}
/>
))}
</LineChart>
{dataCollections?.map((s) => (
<Line
dataKey="value"
data={s.data}
name={s.name}
key={s.name}
type="monotone"
stroke={s.color}
dot={null}
strokeWidth={3}
/>
))}
</LineChart>
</div>
);
}

View File

@ -13,7 +13,7 @@ import {
MinusSquareFilled,
} from '@ant-design/icons';
import classNames from 'classnames';
import {parseSecondsToDurationString} from '../../utils/format'
import { parseSecondsToDurationString } from '../../utils/format'
import OwncastLogo from './logo';
import { BroadcastStatusContext } from '../../utils/broadcast-status-context';
@ -24,7 +24,7 @@ export default function MainLayout(props) {
const { children } = props;
const context = useContext(BroadcastStatusContext);
const { broadcastActive } = context || {};
const { broadcastActive, broadcaster } = context || {};
const router = useRouter();
const { route } = router || {};
@ -33,7 +33,7 @@ export default function MainLayout(props) {
const { SubMenu } = Menu;
const streamDurationString = broadcastActive ?
parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(context.broadcaster.time))) : ""
parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) : ""
const statusIcon = broadcastActive ?
<PlayCircleFilled /> : <MinusSquareFilled />;
@ -56,7 +56,7 @@ export default function MainLayout(props) {
>
<Menu
theme="dark"
defaultSelectedKeys={[route.substring(1)]}
defaultSelectedKeys={[route.substring(1) || "home"]}
defaultOpenKeys={["current-stream-menu", "utilities-menu"]}
mode="inline"
>

View File

@ -35,7 +35,6 @@ export default function ViewersOverTime() {
try {
const result = await fetchData(CONNECTED_CLIENTS);
console.log("result", result);
setClients(result);
} catch (error) {
console.log("==== error", error);
@ -71,7 +70,6 @@ export default function ViewersOverTime() {
return "no info";
}
const columns = [
{
title: "User name",
@ -124,11 +122,8 @@ export default function ViewersOverTime() {
</Row>
<div className="chart-container">
<Chart data={viewerInfo} color="#ff84d8" unit="" />
<div>
<Table dataSource={clients} columns={columns} />;
</div>
</div>
<Table dataSource={clients} columns={columns} />;
</div>
);
}

View File

@ -23,3 +23,12 @@ a {
.owncast-layout .ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected {
background-color: $owncast-purple;
}
// misc system overrides
.ant-card {
border-radius: .5em;
}
.recharts-wrapper {
font-size: 12px;
}

View File

@ -67,4 +67,7 @@
color: #52c41a;
}
/* //844-227-3943 */
.lineChartContainer {
margin: 2em auto;
}

View File

@ -0,0 +1,32 @@
import { useState, useEffect } from 'react';
export default function useWindowSize() {
// Initialize state with undefined width/height so server and client renders match
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
// Handler to call on window resize
function handleResize() {
// Set window width/height to state
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
// Add event listener
window.addEventListener("resize", handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
// Remove event listener on cleanup
return () => window.removeEventListener("resize", handleResize);
}, []); // Empty array ensures that effect is only run on mount
return windowSize;
}