From 2ffbef33ae88a87c70300e60f7963c66915a4699 Mon Sep 17 00:00:00 2001 From: Huxulm Date: Tue, 3 Sep 2024 17:42:58 +0800 Subject: [PATCH] update --- app/build/page.tsx | 249 +--------------------------- app/css/page.tsx | 248 +--------------------------- app/js/page.tsx | 248 +--------------------------- app/page.tsx | 68 +++++--- app/viz/page.tsx | 248 +--------------------------- components/build/Build.tsx | 250 +++++++++++++++++++++++++++++ {app => components}/build/pkg.json | 0 components/css/Css.tsx | 250 +++++++++++++++++++++++++++++ {app => components}/css/pkg.json | 0 components/js/Js.tsx | 250 +++++++++++++++++++++++++++++ {app => components}/js/pkg.json | 0 components/viz/Viz.tsx | 250 +++++++++++++++++++++++++++++ {app => components}/viz/pkg.json | 0 scrap/index.js | 8 +- 14 files changed, 1051 insertions(+), 1018 deletions(-) create mode 100644 components/build/Build.tsx rename {app => components}/build/pkg.json (100%) create mode 100644 components/css/Css.tsx rename {app => components}/css/pkg.json (100%) create mode 100644 components/js/Js.tsx rename {app => components}/js/pkg.json (100%) create mode 100644 components/viz/Viz.tsx rename {app => components}/viz/pkg.json (100%) diff --git a/app/build/page.tsx b/app/build/page.tsx index 6dbfae9..42aabde 100644 --- a/app/build/page.tsx +++ b/app/build/page.tsx @@ -1,253 +1,7 @@ "use client"; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { BuildTrend } from "@/components/build/Build"; import { useParentSize } from "@visx/responsive"; -import { scaleLinear, scaleUtc } from "d3-scale"; -import { min, max } from "d3-array"; -import { utcDay, utcMonth } from "d3-time"; -import pkgs from "./pkg.json"; - -const weeklyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( - (res) => res.default - ); -}); - -const monthlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( - (res) => res.default - ); -}); - -const yearlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( - (res) => res.default - ); -}); - -const DownloadCard = ({ - data, - ticks, - width, - height, -}: { - width: number; - height: number; - ticks: any; - data: { - name: string; - start: string; - end: string; - downloads: DataShape[]; - }[]; -}) => { - const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( - null - ); - const filteredData = useMemo(() => { - return data.map((item) => ({ - ...item, - downloads: item.downloads.filter( - (d) => - !brushSelection || - (new Date(d.day) >= brushSelection[0] && - new Date(d.day) <= brushSelection[1]) - ), - })); - }, [brushSelection, data]); - - const brushHeight = useMemo(() => { - return min([height * 0.1, 80]) as number; - }, [height]); - - const brushMargin = 40; - - const onBrush = useCallback((selection: any) => { - setBrushSelection(selection); - }, []); - - const xDomain = useMemo(() => { - return brushSelection - ? brushSelection - : [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [brushSelection]); - - const yDomain = useMemo(() => { - return [ - min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), - max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [filteredData]); - - const xScale = useMemo(() => { - return scaleUtc() - .domain(xDomain as [Date, Date]) - .range([0, width]); - }, [width, height, xDomain]); - - const yScale = useMemo(() => { - return scaleLinear() - .domain(yDomain as [number, number]) - .range([height - brushHeight - brushMargin, 0]); - }, [width, height, yDomain]); - - const xDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [data]); - - const yDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => v.downloads)), - max(data, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [data]); - - const xScaleBrush = useMemo(() => { - return scaleUtc() - .domain(xDomainBrush as [Date, Date]) - .range([0, width]); - }, [width, height, xDomainBrush]); - - const yScaleBrush = useMemo(() => { - return scaleLinear() - .domain(yDomainBrush as [number, number]) - .range([height - brushMargin, height - brushHeight - brushMargin]); - }, [width, height, yDomainBrush]); - - const xValueFn = useCallback(() => { - return (d: DataShape) => new Date(d.day); - }, []); - - const yValueFn = useCallback(() => { - return (d: DataShape) => d.downloads; - }, []); - - const selectionRef = useRef(null); - const ref = useRef(null); - - useEffect(() => { - if (!selectionRef.current) { - selectionRef.current = render({ - ref, - filteredData, - data, - ticks, - width, - height, - brushHeight, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - onBrush, - brushMargin, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } else if (selectionRef && selectionRef.current) { - refresh({ - selectionRef: selectionRef.current, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - data, - ticks, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } - }, [ - width, - height, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - ticks, - ]); - return ( - - - - - - ); -}; - -export const BuildTrend = ({ - width, - height, -}: { - width: number; - height: number; -}) => { - const [type, setType] = useState<"w" | "y" | "m">("y"); - const getStats = useCallback(async () => { - return await Promise.all( - type === "m" - ? monthlyPkgStats - : type === "y" - ? yearlyPkgStats - : weeklyPkgStats - ); - }, [type]); - - const [stats, setStats] = React.useState([]); - useEffect(() => { - getStats().then((res) => setStats(res)); - }, []); - - return ( - <> - {stats.length === pkgs.length && ( - ({ - name: item["package"], - ...item, - }))} - /> - )} - - ); -}; export default function Home() { const { parentRef, width, height } = useParentSize({ debounceTime: 150 }); @@ -260,3 +14,4 @@ export default function Home() { ); } + diff --git a/app/css/page.tsx b/app/css/page.tsx index 91ce18c..93c0c9b 100644 --- a/app/css/page.tsx +++ b/app/css/page.tsx @@ -1,253 +1,7 @@ "use client"; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { CssTrend } from "@/components/css/Css"; import { useParentSize } from "@visx/responsive"; -import { scaleLinear, scaleUtc } from "d3-scale"; -import { min, max } from "d3-array"; -import { utcDay, utcMonth } from "d3-time"; -import pkgs from "./pkg.json"; - -const weeklyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( - (res) => res.default - ); -}); - -const monthlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( - (res) => res.default - ); -}); - -const yearlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( - (res) => res.default - ); -}); - -const DownloadCard = ({ - data, - ticks, - width, - height, -}: { - width: number; - height: number; - ticks: any; - data: { - name: string; - start: string; - end: string; - downloads: DataShape[]; - }[]; -}) => { - const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( - null - ); - const filteredData = useMemo(() => { - return data.map((item) => ({ - ...item, - downloads: item.downloads.filter( - (d) => - !brushSelection || - (new Date(d.day) >= brushSelection[0] && - new Date(d.day) <= brushSelection[1]) - ), - })); - }, [brushSelection, data]); - - const brushHeight = useMemo(() => { - return min([height * 0.1, 80]) as number; - }, [height]); - - const brushMargin = 40; - - const onBrush = useCallback((selection: any) => { - setBrushSelection(selection); - }, []); - - const xDomain = useMemo(() => { - return brushSelection - ? brushSelection - : [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [brushSelection]); - - const yDomain = useMemo(() => { - return [ - min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), - max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [filteredData]); - - const xScale = useMemo(() => { - return scaleUtc() - .domain(xDomain as [Date, Date]) - .range([0, width]); - }, [width, height, xDomain]); - - const yScale = useMemo(() => { - return scaleLinear() - .domain(yDomain as [number, number]) - .range([height - brushHeight - brushMargin, 0]); - }, [width, height, yDomain]); - - const xDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [data]); - - const yDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => v.downloads)), - max(data, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [data]); - - const xScaleBrush = useMemo(() => { - return scaleUtc() - .domain(xDomainBrush as [Date, Date]) - .range([0, width]); - }, [width, height, xDomainBrush]); - - const yScaleBrush = useMemo(() => { - return scaleLinear() - .domain(yDomainBrush as [number, number]) - .range([height - brushMargin, height - brushHeight - brushMargin]); - }, [width, height, yDomainBrush]); - - const xValueFn = useCallback(() => { - return (d: DataShape) => new Date(d.day); - }, []); - - const yValueFn = useCallback(() => { - return (d: DataShape) => d.downloads; - }, []); - - const selectionRef = useRef(null); - const ref = useRef(null); - - useEffect(() => { - if (!selectionRef.current) { - selectionRef.current = render({ - ref, - filteredData, - data, - ticks, - width, - height, - brushHeight, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - onBrush, - brushMargin, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } else if (selectionRef && selectionRef.current) { - refresh({ - selectionRef: selectionRef.current, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - data, - ticks, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } - }, [ - width, - height, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - ticks, - ]); - return ( - - - - - - ); -}; - -export const CssTrend = ({ - width, - height, -}: { - width: number; - height: number; -}) => { - const [type, setType] = useState<"w" | "y" | "m">("y"); - const getStats = useCallback(async () => { - return await Promise.all( - type === "m" - ? monthlyPkgStats - : type === "y" - ? yearlyPkgStats - : weeklyPkgStats - ); - }, [type]); - - const [stats, setStats] = React.useState([]); - useEffect(() => { - getStats().then((res) => setStats(res)); - }, []); - - return ( - <> - {stats.length === pkgs.length && ( - ({ - name: item["package"], - ...item, - }))} - /> - )} - - ); -}; export default function Home() { const { parentRef, width, height } = useParentSize({ debounceTime: 150 }); diff --git a/app/js/page.tsx b/app/js/page.tsx index 1cafd29..c0702a3 100644 --- a/app/js/page.tsx +++ b/app/js/page.tsx @@ -1,253 +1,7 @@ "use client"; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { JsTrend } from "@/components/js/Js"; import { useParentSize } from "@visx/responsive"; -import { scaleLinear, scaleUtc } from "d3-scale"; -import { min, max } from "d3-array"; -import { utcDay, utcMonth } from "d3-time"; -import pkgs from "./pkg.json"; - -const weeklyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( - (res) => res.default - ); -}); - -const monthlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( - (res) => res.default - ); -}); - -const yearlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( - (res) => res.default - ); -}); - -const DownloadCard = ({ - data, - ticks, - width, - height, -}: { - width: number; - height: number; - ticks: any; - data: { - name: string; - start: string; - end: string; - downloads: DataShape[]; - }[]; -}) => { - const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( - null - ); - const filteredData = useMemo(() => { - return data.map((item) => ({ - ...item, - downloads: item.downloads.filter( - (d) => - !brushSelection || - (new Date(d.day) >= brushSelection[0] && - new Date(d.day) <= brushSelection[1]) - ), - })); - }, [brushSelection, data]); - - const brushHeight = useMemo(() => { - return min([height * 0.1, 80]) as number; - }, [height]); - - const brushMargin = 40; - - const onBrush = useCallback((selection: any) => { - setBrushSelection(selection); - }, []); - - const xDomain = useMemo(() => { - return brushSelection - ? brushSelection - : [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [brushSelection]); - - const yDomain = useMemo(() => { - return [ - min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), - max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [filteredData]); - - const xScale = useMemo(() => { - return scaleUtc() - .domain(xDomain as [Date, Date]) - .range([0, width]); - }, [width, height, xDomain]); - - const yScale = useMemo(() => { - return scaleLinear() - .domain(yDomain as [number, number]) - .range([height - brushHeight - brushMargin, 0]); - }, [width, height, yDomain]); - - const xDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [data]); - - const yDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => v.downloads)), - max(data, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [data]); - - const xScaleBrush = useMemo(() => { - return scaleUtc() - .domain(xDomainBrush as [Date, Date]) - .range([0, width]); - }, [width, height, xDomainBrush]); - - const yScaleBrush = useMemo(() => { - return scaleLinear() - .domain(yDomainBrush as [number, number]) - .range([height - brushMargin, height - brushHeight - brushMargin]); - }, [width, height, yDomainBrush]); - - const xValueFn = useCallback(() => { - return (d: DataShape) => new Date(d.day); - }, []); - - const yValueFn = useCallback(() => { - return (d: DataShape) => d.downloads; - }, []); - - const selectionRef = useRef(null); - const ref = useRef(null); - - useEffect(() => { - if (!selectionRef.current) { - selectionRef.current = render({ - ref, - filteredData, - data, - ticks, - width, - height, - brushHeight, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - onBrush, - brushMargin, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } else if (selectionRef && selectionRef.current) { - refresh({ - selectionRef: selectionRef.current, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - data, - ticks, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } - }, [ - width, - height, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - ticks, - ]); - return ( - - - - - - ); -}; - -export const JsTrend = ({ - width, - height, -}: { - width: number; - height: number; -}) => { - const [type, setType] = useState<"w" | "y" | "m">("y"); - const getStats = useCallback(async () => { - return await Promise.all( - type === "m" - ? monthlyPkgStats - : type === "y" - ? yearlyPkgStats - : weeklyPkgStats - ); - }, [type]); - - const [stats, setStats] = React.useState([]); - useEffect(() => { - getStats().then((res) => setStats(res)); - }, []); - - return ( - <> - {stats.length === pkgs.length && ( - ({ - name: item["package"], - ...item, - }))} - /> - )} - - ); -}; export default function Home() { const { parentRef, width, height } = useParentSize({ debounceTime: 150 }); diff --git a/app/page.tsx b/app/page.tsx index 8e411ba..e4b382a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,40 +1,56 @@ "use client"; import React from "react"; -import { CssTrend } from "./css/page"; -import { JsTrend } from "./js/page"; -import { VizTrend } from "./viz/page"; import { useParentSize } from "@visx/responsive"; -import { BuildTrend } from "./build/page"; +import { BuildTrend } from "@/components/build/Build"; +import { CssTrend } from "@/components/css/Css"; +import { JsTrend } from "@/components/js/Js"; +import { VizTrend } from "@/components/viz/Viz"; function Page() { - const { parentRef: p1, width: w1, height: h1 } = useParentSize({ debounceTime: 150 }); - const { parentRef: p2, width: w2, height: h2 } = useParentSize({ debounceTime: 150 }); - const { parentRef: p3, width: w3, height: h3 } = useParentSize({ debounceTime: 150 }); - const { parentRef: p4, width: w4, height: h4 } = useParentSize({ debounceTime: 150 }); - + const { + parentRef: p1, + width: w1, + height: h1, + } = useParentSize({ debounceTime: 150 }); + const { + parentRef: p2, + width: w2, + height: h2, + } = useParentSize({ debounceTime: 150 }); + const { + parentRef: p3, + width: w3, + height: h3, + } = useParentSize({ debounceTime: 150 }); + const { + parentRef: p4, + width: w4, + height: h4, + } = useParentSize({ debounceTime: 150 }); + return ( -
-
-
- -
+
+
+
+
-
-
- -
+
+
+
+
-
-
- -
+
+
+
+
-
-
- -
+
+
+
+
+
); } diff --git a/app/viz/page.tsx b/app/viz/page.tsx index 1b5b1da..cdd3410 100644 --- a/app/viz/page.tsx +++ b/app/viz/page.tsx @@ -1,253 +1,7 @@ "use client"; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { VizTrend } from "@/components/viz/Viz"; import { useParentSize } from "@visx/responsive"; -import { scaleLinear, scaleUtc } from "d3-scale"; -import { min, max } from "d3-array"; -import { utcDay, utcMonth } from "d3-time"; -import pkgs from "./pkg.json"; - -const weeklyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( - (res) => res.default - ); -}); - -const monthlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( - (res) => res.default - ); -}); - -const yearlyPkgStats = pkgs.map(async (item) => { - return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( - (res) => res.default - ); -}); - -const DownloadCard = ({ - data, - ticks, - width, - height, -}: { - width: number; - height: number; - ticks: any; - data: { - name: string; - start: string; - end: string; - downloads: DataShape[]; - }[]; -}) => { - const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( - null - ); - const filteredData = useMemo(() => { - return data.map((item) => ({ - ...item, - downloads: item.downloads.filter( - (d) => - !brushSelection || - (new Date(d.day) >= brushSelection[0] && - new Date(d.day) <= brushSelection[1]) - ), - })); - }, [brushSelection, data]); - - const brushHeight = useMemo(() => { - return min([height * 0.1, 80]) as number; - }, [height]); - - const brushMargin = 40; - - const onBrush = useCallback((selection: any) => { - setBrushSelection(selection); - }, []); - - const xDomain = useMemo(() => { - return brushSelection - ? brushSelection - : [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [brushSelection]); - - const yDomain = useMemo(() => { - return [ - min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), - max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [filteredData]); - - const xScale = useMemo(() => { - return scaleUtc() - .domain(xDomain as [Date, Date]) - .range([0, width]); - }, [width, height, xDomain]); - - const yScale = useMemo(() => { - return scaleLinear() - .domain(yDomain as [number, number]) - .range([height - brushHeight - brushMargin, 0]); - }, [width, height, yDomain]); - - const xDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => new Date(v.day))), - max(data, (d) => max(d.downloads, (v) => new Date(v.day))), - ]; - }, [data]); - - const yDomainBrush = useMemo(() => { - return [ - min(data, (d) => min(d.downloads, (v) => v.downloads)), - max(data, (d) => max(d.downloads, (v) => v.downloads)), - ]; - }, [data]); - - const xScaleBrush = useMemo(() => { - return scaleUtc() - .domain(xDomainBrush as [Date, Date]) - .range([0, width]); - }, [width, height, xDomainBrush]); - - const yScaleBrush = useMemo(() => { - return scaleLinear() - .domain(yDomainBrush as [number, number]) - .range([height - brushMargin, height - brushHeight - brushMargin]); - }, [width, height, yDomainBrush]); - - const xValueFn = useCallback(() => { - return (d: DataShape) => new Date(d.day); - }, []); - - const yValueFn = useCallback(() => { - return (d: DataShape) => d.downloads; - }, []); - - const selectionRef = useRef(null); - const ref = useRef(null); - - useEffect(() => { - if (!selectionRef.current) { - selectionRef.current = render({ - ref, - filteredData, - data, - ticks, - width, - height, - brushHeight, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - onBrush, - brushMargin, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } else if (selectionRef && selectionRef.current) { - refresh({ - selectionRef: selectionRef.current, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - data, - ticks, - xValue: xValueFn(), - yValue: yValueFn(), - }); - } - }, [ - width, - height, - xScale, - yScale, - xScaleBrush, - yScaleBrush, - filteredData, - ticks, - ]); - return ( - - - - - - ); -}; - -export const VizTrend = ({ - width, - height, -}: { - width: number; - height: number; -}) => { - const [type, setType] = useState<"w" | "y" | "m">("y"); - const getStats = useCallback(async () => { - return await Promise.all( - type === "m" - ? monthlyPkgStats - : type === "y" - ? yearlyPkgStats - : weeklyPkgStats - ); - }, [type]); - - const [stats, setStats] = React.useState([]); - useEffect(() => { - getStats().then((res) => setStats(res)); - }, []); - - return ( - <> - {stats.length === pkgs.length && ( - ({ - name: item["package"], - ...item, - }))} - /> - )} - - ); -}; export default function Home() { const { parentRef, width, height } = useParentSize({ debounceTime: 150 }); diff --git a/components/build/Build.tsx b/components/build/Build.tsx new file mode 100644 index 0000000..4814d4b --- /dev/null +++ b/components/build/Build.tsx @@ -0,0 +1,250 @@ +"use client"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { useParentSize } from "@visx/responsive"; +import { scaleLinear, scaleUtc } from "d3-scale"; +import { min, max } from "d3-array"; +import { utcDay, utcMonth } from "d3-time"; +import pkgs from "./pkg.json"; + +const weeklyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( + (res) => res.default + ); +}); + +const monthlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( + (res) => res.default + ); +}); + +const yearlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( + (res) => res.default + ); +}); + +const DownloadCard = ({ + data, + ticks, + width, + height, +}: { + width: number; + height: number; + ticks: any; + data: { + name: string; + start: string; + end: string; + downloads: DataShape[]; + }[]; +}) => { + const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( + null + ); + const filteredData = useMemo(() => { + return data.map((item) => ({ + ...item, + downloads: item.downloads.filter( + (d) => + !brushSelection || + (new Date(d.day) >= brushSelection[0] && + new Date(d.day) <= brushSelection[1]) + ), + })); + }, [brushSelection, data]); + + const brushHeight = useMemo(() => { + return min([height * 0.1, 80]) as number; + }, [height]); + + const brushMargin = 40; + + const onBrush = useCallback((selection: any) => { + setBrushSelection(selection); + }, []); + + const xDomain = useMemo(() => { + return brushSelection + ? brushSelection + : [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [brushSelection]); + + const yDomain = useMemo(() => { + return [ + min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), + max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [filteredData]); + + const xScale = useMemo(() => { + return scaleUtc() + .domain(xDomain as [Date, Date]) + .range([0, width]); + }, [width, height, xDomain]); + + const yScale = useMemo(() => { + return scaleLinear() + .domain(yDomain as [number, number]) + .range([height - brushHeight - brushMargin, 0]); + }, [width, height, yDomain]); + + const xDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [data]); + + const yDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => v.downloads)), + max(data, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [data]); + + const xScaleBrush = useMemo(() => { + return scaleUtc() + .domain(xDomainBrush as [Date, Date]) + .range([0, width]); + }, [width, height, xDomainBrush]); + + const yScaleBrush = useMemo(() => { + return scaleLinear() + .domain(yDomainBrush as [number, number]) + .range([height - brushMargin, height - brushHeight - brushMargin]); + }, [width, height, yDomainBrush]); + + const xValueFn = useCallback(() => { + return (d: DataShape) => new Date(d.day); + }, []); + + const yValueFn = useCallback(() => { + return (d: DataShape) => d.downloads; + }, []); + + const selectionRef = useRef(null); + const ref = useRef(null); + + useEffect(() => { + if (!selectionRef.current) { + selectionRef.current = render({ + ref, + filteredData, + data, + ticks, + width, + height, + brushHeight, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + onBrush, + brushMargin, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } else if (selectionRef && selectionRef.current) { + refresh({ + selectionRef: selectionRef.current, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + data, + ticks, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } + }, [ + width, + height, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + ticks, + ]); + return ( + + + + + + ); +}; + +export const BuildTrend = ({ + width, + height +}: { + width: number; + height: number; +}) => { + const [type, setType] = useState<"w" | "y" | "m">("y"); + const getStats = useCallback(async () => { + return await Promise.all( + type === "m" + ? monthlyPkgStats + : type === "y" + ? yearlyPkgStats + : weeklyPkgStats + ); + }, [type]); + + const [stats, setStats] = React.useState([]); + useEffect(() => { + getStats().then((res) => setStats(res)); + }, []); + + return ( + <> + {stats.length === pkgs.length && ( + ({ + name: item["package"], + ...item, + }))} + /> + )} + + ); +}; diff --git a/app/build/pkg.json b/components/build/pkg.json similarity index 100% rename from app/build/pkg.json rename to components/build/pkg.json diff --git a/components/css/Css.tsx b/components/css/Css.tsx new file mode 100644 index 0000000..db58773 --- /dev/null +++ b/components/css/Css.tsx @@ -0,0 +1,250 @@ +"use client"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { useParentSize } from "@visx/responsive"; +import { scaleLinear, scaleUtc } from "d3-scale"; +import { min, max } from "d3-array"; +import { utcDay, utcMonth } from "d3-time"; +import pkgs from "./pkg.json"; + +const weeklyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( + (res) => res.default + ); +}); + +const monthlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( + (res) => res.default + ); +}); + +const yearlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( + (res) => res.default + ); +}); + +const DownloadCard = ({ + data, + ticks, + width, + height, +}: { + width: number; + height: number; + ticks: any; + data: { + name: string; + start: string; + end: string; + downloads: DataShape[]; + }[]; +}) => { + const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( + null + ); + const filteredData = useMemo(() => { + return data.map((item) => ({ + ...item, + downloads: item.downloads.filter( + (d) => + !brushSelection || + (new Date(d.day) >= brushSelection[0] && + new Date(d.day) <= brushSelection[1]) + ), + })); + }, [brushSelection, data]); + + const brushHeight = useMemo(() => { + return min([height * 0.1, 80]) as number; + }, [height]); + + const brushMargin = 40; + + const onBrush = useCallback((selection: any) => { + setBrushSelection(selection); + }, []); + + const xDomain = useMemo(() => { + return brushSelection + ? brushSelection + : [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [brushSelection]); + + const yDomain = useMemo(() => { + return [ + min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), + max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [filteredData]); + + const xScale = useMemo(() => { + return scaleUtc() + .domain(xDomain as [Date, Date]) + .range([0, width]); + }, [width, height, xDomain]); + + const yScale = useMemo(() => { + return scaleLinear() + .domain(yDomain as [number, number]) + .range([height - brushHeight - brushMargin, 0]); + }, [width, height, yDomain]); + + const xDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [data]); + + const yDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => v.downloads)), + max(data, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [data]); + + const xScaleBrush = useMemo(() => { + return scaleUtc() + .domain(xDomainBrush as [Date, Date]) + .range([0, width]); + }, [width, height, xDomainBrush]); + + const yScaleBrush = useMemo(() => { + return scaleLinear() + .domain(yDomainBrush as [number, number]) + .range([height - brushMargin, height - brushHeight - brushMargin]); + }, [width, height, yDomainBrush]); + + const xValueFn = useCallback(() => { + return (d: DataShape) => new Date(d.day); + }, []); + + const yValueFn = useCallback(() => { + return (d: DataShape) => d.downloads; + }, []); + + const selectionRef = useRef(null); + const ref = useRef(null); + + useEffect(() => { + if (!selectionRef.current) { + selectionRef.current = render({ + ref, + filteredData, + data, + ticks, + width, + height, + brushHeight, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + onBrush, + brushMargin, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } else if (selectionRef && selectionRef.current) { + refresh({ + selectionRef: selectionRef.current, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + data, + ticks, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } + }, [ + width, + height, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + ticks, + ]); + return ( + + + + + + ); +}; + +export const CssTrend = ({ + width, + height +}: { + width: number; + height: number; +}) => { + const [type, setType] = useState<"w" | "y" | "m">("y"); + const getStats = useCallback(async () => { + return await Promise.all( + type === "m" + ? monthlyPkgStats + : type === "y" + ? yearlyPkgStats + : weeklyPkgStats + ); + }, [type]); + + const [stats, setStats] = React.useState([]); + useEffect(() => { + getStats().then((res) => setStats(res)); + }, []); + + return ( + <> + {stats.length === pkgs.length && ( + ({ + name: item["package"], + ...item, + }))} + /> + )} + + ); +}; diff --git a/app/css/pkg.json b/components/css/pkg.json similarity index 100% rename from app/css/pkg.json rename to components/css/pkg.json diff --git a/components/js/Js.tsx b/components/js/Js.tsx new file mode 100644 index 0000000..0eff1a0 --- /dev/null +++ b/components/js/Js.tsx @@ -0,0 +1,250 @@ +"use client"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { useParentSize } from "@visx/responsive"; +import { scaleLinear, scaleUtc } from "d3-scale"; +import { min, max } from "d3-array"; +import { utcDay, utcMonth } from "d3-time"; +import pkgs from "./pkg.json"; + +const weeklyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( + (res) => res.default + ); +}); + +const monthlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( + (res) => res.default + ); +}); + +const yearlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( + (res) => res.default + ); +}); + +const DownloadCard = ({ + data, + ticks, + width, + height, +}: { + width: number; + height: number; + ticks: any; + data: { + name: string; + start: string; + end: string; + downloads: DataShape[]; + }[]; +}) => { + const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( + null + ); + const filteredData = useMemo(() => { + return data.map((item) => ({ + ...item, + downloads: item.downloads.filter( + (d) => + !brushSelection || + (new Date(d.day) >= brushSelection[0] && + new Date(d.day) <= brushSelection[1]) + ), + })); + }, [brushSelection, data]); + + const brushHeight = useMemo(() => { + return min([height * 0.1, 80]) as number; + }, [height]); + + const brushMargin = 40; + + const onBrush = useCallback((selection: any) => { + setBrushSelection(selection); + }, []); + + const xDomain = useMemo(() => { + return brushSelection + ? brushSelection + : [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [brushSelection]); + + const yDomain = useMemo(() => { + return [ + min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), + max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [filteredData]); + + const xScale = useMemo(() => { + return scaleUtc() + .domain(xDomain as [Date, Date]) + .range([0, width]); + }, [width, height, xDomain]); + + const yScale = useMemo(() => { + return scaleLinear() + .domain(yDomain as [number, number]) + .range([height - brushHeight - brushMargin, 0]); + }, [width, height, yDomain]); + + const xDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [data]); + + const yDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => v.downloads)), + max(data, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [data]); + + const xScaleBrush = useMemo(() => { + return scaleUtc() + .domain(xDomainBrush as [Date, Date]) + .range([0, width]); + }, [width, height, xDomainBrush]); + + const yScaleBrush = useMemo(() => { + return scaleLinear() + .domain(yDomainBrush as [number, number]) + .range([height - brushMargin, height - brushHeight - brushMargin]); + }, [width, height, yDomainBrush]); + + const xValueFn = useCallback(() => { + return (d: DataShape) => new Date(d.day); + }, []); + + const yValueFn = useCallback(() => { + return (d: DataShape) => d.downloads; + }, []); + + const selectionRef = useRef(null); + const ref = useRef(null); + + useEffect(() => { + if (!selectionRef.current) { + selectionRef.current = render({ + ref, + filteredData, + data, + ticks, + width, + height, + brushHeight, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + onBrush, + brushMargin, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } else if (selectionRef && selectionRef.current) { + refresh({ + selectionRef: selectionRef.current, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + data, + ticks, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } + }, [ + width, + height, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + ticks, + ]); + return ( + + + + + + ); +}; + +export const JsTrend = ({ + width, + height, +}: { + width: number; + height: number; +}) => { + const [type, setType] = useState<"w" | "y" | "m">("y"); + const getStats = useCallback(async () => { + return await Promise.all( + type === "m" + ? monthlyPkgStats + : type === "y" + ? yearlyPkgStats + : weeklyPkgStats + ); + }, [type]); + + const [stats, setStats] = React.useState([]); + useEffect(() => { + getStats().then((res) => setStats(res)); + }, []); + + return ( + <> + {stats.length === pkgs.length && ( + ({ + name: item["package"], + ...item, + }))} + /> + )} + + ); +}; diff --git a/app/js/pkg.json b/components/js/pkg.json similarity index 100% rename from app/js/pkg.json rename to components/js/pkg.json diff --git a/components/viz/Viz.tsx b/components/viz/Viz.tsx new file mode 100644 index 0000000..bbfbda9 --- /dev/null +++ b/components/viz/Viz.tsx @@ -0,0 +1,250 @@ +"use client"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { DataShape, refresh, render, SelectionRef } from "../../components/viz"; +import { useParentSize } from "@visx/responsive"; +import { scaleLinear, scaleUtc } from "d3-scale"; +import { min, max } from "d3-array"; +import { utcDay, utcMonth } from "d3-time"; +import pkgs from "./pkg.json"; + +const weeklyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/w.json`).then( + (res) => res.default + ); +}); + +const monthlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/m.json`).then( + (res) => res.default + ); +}); + +const yearlyPkgStats = pkgs.map(async (item) => { + return await import(`../../data/${encodeURIComponent(item)}/y.json`).then( + (res) => res.default + ); +}); + +const DownloadCard = ({ + data, + ticks, + width, + height, +}: { + width: number; + height: number; + ticks: any; + data: { + name: string; + start: string; + end: string; + downloads: DataShape[]; + }[]; +}) => { + const [brushSelection, setBrushSelection] = useState<[Date, Date] | null>( + null + ); + const filteredData = useMemo(() => { + return data.map((item) => ({ + ...item, + downloads: item.downloads.filter( + (d) => + !brushSelection || + (new Date(d.day) >= brushSelection[0] && + new Date(d.day) <= brushSelection[1]) + ), + })); + }, [brushSelection, data]); + + const brushHeight = useMemo(() => { + return min([height * 0.1, 80]) as number; + }, [height]); + + const brushMargin = 40; + + const onBrush = useCallback((selection: any) => { + setBrushSelection(selection); + }, []); + + const xDomain = useMemo(() => { + return brushSelection + ? brushSelection + : [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [brushSelection]); + + const yDomain = useMemo(() => { + return [ + min(filteredData, (d) => min(d.downloads, (v) => v.downloads)), + max(filteredData, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [filteredData]); + + const xScale = useMemo(() => { + return scaleUtc() + .domain(xDomain as [Date, Date]) + .range([0, width]); + }, [width, height, xDomain]); + + const yScale = useMemo(() => { + return scaleLinear() + .domain(yDomain as [number, number]) + .range([height - brushHeight - brushMargin, 0]); + }, [width, height, yDomain]); + + const xDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => new Date(v.day))), + max(data, (d) => max(d.downloads, (v) => new Date(v.day))), + ]; + }, [data]); + + const yDomainBrush = useMemo(() => { + return [ + min(data, (d) => min(d.downloads, (v) => v.downloads)), + max(data, (d) => max(d.downloads, (v) => v.downloads)), + ]; + }, [data]); + + const xScaleBrush = useMemo(() => { + return scaleUtc() + .domain(xDomainBrush as [Date, Date]) + .range([0, width]); + }, [width, height, xDomainBrush]); + + const yScaleBrush = useMemo(() => { + return scaleLinear() + .domain(yDomainBrush as [number, number]) + .range([height - brushMargin, height - brushHeight - brushMargin]); + }, [width, height, yDomainBrush]); + + const xValueFn = useCallback(() => { + return (d: DataShape) => new Date(d.day); + }, []); + + const yValueFn = useCallback(() => { + return (d: DataShape) => d.downloads; + }, []); + + const selectionRef = useRef(null); + const ref = useRef(null); + + useEffect(() => { + if (!selectionRef.current) { + selectionRef.current = render({ + ref, + filteredData, + data, + ticks, + width, + height, + brushHeight, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + onBrush, + brushMargin, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } else if (selectionRef && selectionRef.current) { + refresh({ + selectionRef: selectionRef.current, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + data, + ticks, + xValue: xValueFn(), + yValue: yValueFn(), + }); + } + }, [ + width, + height, + xScale, + yScale, + xScaleBrush, + yScaleBrush, + filteredData, + ticks, + ]); + return ( + + + + + + ); +}; + +export const VizTrend = ({ + width, + height, +}: { + width: number; + height: number; +}) => { + const [type, setType] = useState<"w" | "y" | "m">("y"); + const getStats = useCallback(async () => { + return await Promise.all( + type === "m" + ? monthlyPkgStats + : type === "y" + ? yearlyPkgStats + : weeklyPkgStats + ); + }, [type]); + + const [stats, setStats] = React.useState([]); + useEffect(() => { + getStats().then((res) => setStats(res)); + }, []); + + return ( + <> + {stats.length === pkgs.length && ( + ({ + name: item["package"], + ...item, + }))} + /> + )} + + ); +}; diff --git a/app/viz/pkg.json b/components/viz/pkg.json similarity index 100% rename from app/viz/pkg.json rename to components/viz/pkg.json diff --git a/scrap/index.js b/scrap/index.js index e2ad47c..49d42d1 100644 --- a/scrap/index.js +++ b/scrap/index.js @@ -1,7 +1,7 @@ -const pkg4css = require("../app/css/pkg.json"); -const pkg4js = require("../app/js/pkg.json"); -const pkg4viz = require("../app/viz/pkg.json"); -const pkg4build = require("../app/build/pkg.json"); +const pkg4css = require("../components/css/pkg.json"); +const pkg4js = require("../components/js/pkg.json"); +const pkg4viz = require("../components/viz/pkg.json"); +const pkg4build = require("../components/build/pkg.json"); const fs = require("fs"); // const { ProxyAgent } = require("undici"); // nodejs delete directory