Skip to content

Commit

Permalink
add chart sync on hover
Browse files Browse the repository at this point in the history
  • Loading branch information
xvvvyz committed Jun 24, 2024
1 parent 5eacab4 commit a6dbeb2
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 150 deletions.
34 changes: 16 additions & 18 deletions app/_components/insight-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,24 @@ const InsightForm = ({
</div>
<div className="bg-alpha-reverse-1">
<PlotFigure
column={inputOptions.find((o) => o.id === input)?.label as string}
curveFunction={form.watch('curveFunction')}
defaultHeight={250}
options={{
column: inputOptions.find((o) => o.id === input)?.label as string,
curveFunction: form.watch('curveFunction'),
events,
marginBottom: form.watch('marginBottom'),
marginLeft: form.watch('marginLeft'),
marginRight: form.watch('marginRight'),
marginTop: form.watch('marginTop'),
showDots: form.watch('showDots'),
showLine,
showLinearRegression: form.watch('showLinearRegression'),
showXAxisLabel: form.watch('showXAxisLabel'),
showXAxisTicks: form.watch('showXAxisTicks'),
showYAxisLabel: form.watch('showYAxisLabel'),
showYAxisTicks: form.watch('showYAxisTicks'),
title: form.watch('name'),
type: form.watch('type'),
}}
events={events}
marginBottom={form.watch('marginBottom')}
marginLeft={form.watch('marginLeft')}
marginRight={form.watch('marginRight')}
marginTop={form.watch('marginTop')}
showDots={form.watch('showDots')}
showLine={showLine}
showLinearRegression={form.watch('showLinearRegression')}
showXAxisLabel={form.watch('showXAxisLabel')}
showXAxisTicks={form.watch('showXAxisTicks')}
showYAxisLabel={form.watch('showYAxisLabel')}
showYAxisTicks={form.watch('showYAxisTicks')}
subjectId={subjectId}
title={form.watch('name')}
type={form.watch('type')}
/>
</div>
<div className="grid grid-cols-2 gap-4 px-4 py-8 sm:px-8 md:grid-cols-4">
Expand Down
34 changes: 16 additions & 18 deletions app/_components/insight-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,24 @@ const InsightPage = async ({
/>
<div className="rounded-b bg-alpha-reverse-1">
<PlotFigure
column={idLabelMap[config.input]}
curveFunction={config.curveFunction}
events={events}
isPublic={isPublic}
options={{
column: idLabelMap[config.input],
curveFunction: config.curveFunction,
events,
marginBottom: config.marginBottom,
marginLeft: config.marginLeft,
marginRight: config.marginRight,
marginTop: config.marginTop,
showDots: config.showDots,
showLine: config.showLine,
showLinearRegression: config.showLinearRegression,
showXAxisLabel: config.showXAxisLabel,
showXAxisTicks: config.showXAxisTicks,
showYAxisLabel: config.showYAxisLabel,
showYAxisTicks: config.showYAxisTicks,
title: insight.name,
type: config.type,
}}
marginBottom={config.marginBottom}
marginLeft={config.marginLeft}
marginRight={config.marginRight}
marginTop={config.marginTop}
showDots={config.showDots}
showLine={config.showLine}
showLinearRegression={config.showLinearRegression}
showXAxisLabel={config.showXAxisLabel}
showXAxisTicks={config.showXAxisTicks}
showYAxisLabel={config.showYAxisLabel}
showYAxisTicks={config.showYAxisTicks}
subjectId={subjectId}
title={insight.name}
type={config.type}
/>
</div>
</>
Expand Down
99 changes: 99 additions & 0 deletions app/_components/insights.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
'use client';

import Button from '@/_components/button';
import InsightCardMenu from '@/_components/insight-card-menu';
import PlotFigure from '@/_components/plot-figure';
import { ListInsightsData } from '@/_queries/list-insights';
import { InsightConfigJson } from '@/_types/insight-config-json';
import formatInputIdLabelMap from '@/_utilities/format-input-id-label-map';
import formatTabularEvents from '@/_utilities/format-tabular-events';
import ArrowUpRightIcon from '@heroicons/react/24/outline/ArrowUpRightIcon';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';

interface InsightsProps {
events: ReturnType<typeof formatTabularEvents>;
idLabelMap: ReturnType<typeof formatInputIdLabelMap>;
insights: NonNullable<ListInsightsData>;
isPublic?: boolean;
isTeamMember: boolean;
searchString: string;
shareOrSubjects: 'share' | 'subjects';
subjectId: string;
}

const Insights = ({
events,
idLabelMap,
insights,
isPublic,
isTeamMember,
searchString,
shareOrSubjects,
subjectId,
}: InsightsProps) => {
const [activeId, setActiveId] = useState<string | null>(null);
const [syncDate, setSyncDate] = useState<Date | null>(null);

return insights.map((insight) => {
const config = insight.config as InsightConfigJson;

return (
<article
className="rounded border border-alpha-1 bg-bg-2 pt-1"
key={insight.id}
>
<div className="border-b border-alpha-1 pb-1">
<div className="flex items-stretch hover:bg-alpha-1">
<Button
className={twMerge(
'm-0 flex w-full gap-4 px-4 py-3 leading-snug',
isTeamMember && 'pr-0',
)}
href={`/${shareOrSubjects}/${subjectId}/insights/${insight.id}${searchString}`}
scroll={false}
variant="link"
>
{insight.name}
{!isTeamMember && (
<ArrowUpRightIcon className="ml-auto w-5 shrink-0" />
)}
</Button>
{isTeamMember && (
<InsightCardMenu insightId={insight.id} subjectId={subjectId} />
)}
</div>
</div>
<div className="rounded-b bg-alpha-reverse-1">
<PlotFigure
column={idLabelMap[config.input]}
curveFunction={config.curveFunction}
defaultHeight={250}
events={events}
id={insight.id}
isPublic={isPublic}
marginBottom={config.marginBottom}
marginLeft={config.marginLeft}
marginRight={config.marginRight}
marginTop={config.marginTop}
setActiveId={setActiveId}
setSyncDate={setSyncDate}
showDots={config.showDots}
showLine={config.showLine}
showLinearRegression={config.showLinearRegression}
showXAxisLabel={config.showXAxisLabel}
showXAxisTicks={config.showXAxisTicks}
showYAxisLabel={config.showYAxisLabel}
showYAxisTicks={config.showYAxisTicks}
subjectId={subjectId}
syncDate={insight.id === activeId ? null : syncDate}
title={insight.name}
type={config.type}
/>
</div>
</article>
);
});
};

export default Insights;
142 changes: 100 additions & 42 deletions app/_components/plot-figure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,57 @@ import formatPlot from '@/_utilities/format-plot';
import formatTabularEvents from '@/_utilities/format-tabular-events';
import { plot } from '@observablehq/plot';
import { useParentSize } from '@visx/responsive';
import { throttle } from 'lodash';
import { useRouter } from 'next/navigation';
import { useEffect, useRef } from 'react';
import { Dispatch, SetStateAction, useEffect, useRef } from 'react';

const PlotFigure = ({
column,
curveFunction,
defaultHeight,
events,
id,
isPublic,
options,
marginBottom,
marginLeft,
marginRight,
marginTop,
setActiveId,
setSyncDate,
showDots,
showLine,
showLinearRegression,
showXAxisLabel,
showXAxisTicks,
showYAxisLabel,
showYAxisTicks,
subjectId,
syncDate,
type,
}: {
column: string;
curveFunction: string;
defaultHeight?: number;
events: ReturnType<typeof formatTabularEvents>;
id?: string;
isPublic?: boolean;
options: {
column: string;
curveFunction: string;
events: ReturnType<typeof formatTabularEvents>;
marginBottom: string;
marginLeft: string;
marginRight: string;
marginTop: string;
showDots: boolean;
showLine: boolean;
showLinearRegression: boolean;
showXAxisLabel: boolean;
showXAxisTicks: boolean;
showYAxisLabel: boolean;
showYAxisTicks: boolean;
title: string;
type: ChartType;
};
marginBottom: string;
marginLeft: string;
marginRight: string;
marginTop: string;
setActiveId?: Dispatch<SetStateAction<string | null>>;
setSyncDate?: Dispatch<SetStateAction<Date | null>>;
showDots: boolean;
showLine: boolean;
showLinearRegression: boolean;
showXAxisLabel: boolean;
showXAxisTicks: boolean;
showYAxisLabel: boolean;
showYAxisTicks: boolean;
subjectId: string;
syncDate?: Date | null;
title: string;
type: ChartType;
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const router = useRouter();
Expand All @@ -45,39 +66,76 @@ const PlotFigure = ({

const p = plot(
formatPlot({
column: options.column,
curveFunction: options.curveFunction,
column,
curveFunction,
defaultHeight,
events: options.events,
marginBottom: options.marginBottom,
marginLeft: options.marginLeft,
marginRight: options.marginRight,
marginTop: options.marginTop,
showDots: options.showDots,
showLine: options.showLine,
showLinearRegression: options.showLinearRegression,
showXAxisLabel: options.showXAxisLabel,
showXAxisTicks: options.showXAxisTicks,
showYAxisLabel: options.showYAxisLabel,
showYAxisTicks: options.showYAxisTicks,
type: options.type,
events,
marginBottom,
marginLeft,
marginRight,
marginTop,
showDots,
showLine,
showLinearRegression,
showXAxisLabel,
showXAxisTicks,
showYAxisLabel,
showYAxisTicks,
syncDate,
type,
width,
}),
);

p.addEventListener(
'mousemove',
throttle(() => {
const datum = p.querySelector('title')?.innerHTML ?? '';
if (!datum) return;
const { Time } = JSON.parse(datum);
setActiveId?.(id ?? null);
setSyncDate?.(Time ? new Date(Time) : null);
}, 50),
);

p.addEventListener('click', () => {
const eventId = p.querySelector('title')?.innerHTML ?? '';
if (!eventId) return;
const datum = p.querySelector('title')?.innerHTML ?? '';
if (!datum) return;
const { Id } = JSON.parse(datum);
if (!Id) return;
const shareOrSubjects = isPublic ? 'share' : 'subjects';

router.push(`/${shareOrSubjects}/${subjectId}/events/${eventId}`, {
scroll: false,
});
const href = `/${shareOrSubjects}/${subjectId}/events/${Id}`;
router.push(href, { scroll: false });
});

containerRef.current.append(p);
return () => p.remove();
}, [isPublic, options, router, defaultHeight, subjectId, width]);
}, [
column,
curveFunction,
defaultHeight,
events,
id,
isPublic,
marginBottom,
marginLeft,
marginRight,
marginTop,
router,
setActiveId,
setSyncDate,
showDots,
showLine,
showLinearRegression,
showXAxisLabel,
showXAxisTicks,
showYAxisLabel,
showYAxisTicks,
subjectId,
syncDate,
type,
width,
]);

return (
<div className="h-full w-full" ref={parentRef}>
Expand Down
Loading

0 comments on commit a6dbeb2

Please sign in to comment.