Skip to content

Commit

Permalink
wip(more charts): added
Browse files Browse the repository at this point in the history
  • Loading branch information
eunchurn committed Sep 1, 2024
1 parent f17c852 commit 059d96a
Show file tree
Hide file tree
Showing 28 changed files with 1,800 additions and 3 deletions.
Binary file modified .DS_Store
Binary file not shown.
4 changes: 3 additions & 1 deletion apps/next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
},
"dependencies": {
"@eunchurn/react-windrose": "workspace:*",
"d3-force": "^3.0.0",
"next": "^14.2.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.2.3",
"@eunchurn/eslint-config": "workspace:*",
"@eunchurn/heatmap": "workspace:*",
"@eunchurn/tailwind-config": "workspace:*",
"@eunchurn/typescript-config": "workspace:*",
"@next/eslint-plugin-next": "^14.2.3",
"@types/node": "^20.11.24",
"@types/react": "^18.2.61",
"@types/react-dom": "^18.2.19",
Expand Down
86 changes: 86 additions & 0 deletions apps/next-app/src/app/heatmap/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use client";

import React, { useState, useEffect } from "react";
import HeatmapChart, { HeatmapData } from "@eunchurn/heatmap";
import { Gradient } from "@/components";

const generateRandomData = (): HeatmapData => {
const now = Date.now();
const hit: [number, number[]][] = [];
const err: [number, number[]][] = [];

for (let i = 0; i < 120; i++) {
const time = now - i * 5000;
hit.push([
time,
Array(120)
.fill(0)
.map(() => Math.floor(Math.random() * 100)),
]);
err.push([
time,
Array(120)
.fill(0)
.map(() => Math.floor(Math.random() * 10)),
]);
}

return { hit, err };
};

const App: React.FC = () => {
const [data, setData] = useState<HeatmapData>(generateRandomData());

useEffect(() => {
const interval = setInterval(() => {
setData(generateRandomData());
}, 5000);

return () => clearInterval(interval);
}, []);

return (
<main className="flex flex-col items-center justify-between min-h-screen p-24">
<div className="z-10 items-center justify-between w-full max-w-5xl font-mono text-sm lg:flex">
<p className="fixed top-0 left-0 flex justify-center w-full px-4 pt-8 pb-6 border-b bg-gradient-to-b backdrop-blur-2xl border-neutral-800 bg-zinc-800/30 from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:bg-zinc-800/30">
@eunchurn/heatmap -&nbsp;
<code className="font-mono font-bold">Interactive Heatmap Chart</code>
</p>
</div>

<div className="relative flex place-items-center ">
<div className="font-sans w-auto pb-16 pt-[48px] md:pb-24 lg:pb-32 md:pt-16 lg:pt-20 flex justify-between gap-8 items-center flex-col relative z-0">
<div className="z-50 flex items-center justify-center w-full">
<div className="absolute min-w-[614px] min-h-[614px]">
<HeatmapChart
width={800}
height={400}
data={data}
config={{
dragCallback: (...args) => {
console.log(args);
},
}}
/>
</div>
<div className="absolute z-50 flex items-center justify-center w-64 h-64">
{/* <Gradient
className="opacity-90 w-[120px] h-[120px]"
conic
small
/> */}
</div>
</div>
<Gradient
className="top-[-500px] opacity-[0.15] w-[1000px] h-[1000px]"
conic
/>
</div>
</div>

<div className="grid mb-32 text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left" />
</main>
);
};

export default App;
36 changes: 36 additions & 0 deletions apps/next-app/src/app/line-chart/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import React, { useState, useEffect } from 'react';
import LineChart from '@/components/line-chart';
import { DataPoint } from '@/components/line-chart/types';

const LineChartExample: React.FC = () => {
const [data, setData] = useState<DataPoint[]>([]);

useEffect(() => {
// Generate some sample data
const now = Date.now();
const newData: DataPoint[] = Array.from({ length: 50 }, (_, i) => [
now - (49 - i) * 60000, // One point per minute
Math.random() * 100
]);
setData(newData);
}, []);

return (
<div>
<h1>Line Chart Example</h1>
<LineChart
data={data}
width={800}
height={400}
id="example-line-chart"
chartId="example-chart"
timeRange={[data[0]?.[0] || Date.now(), data[data.length - 1]?.[0] || Date.now()]}
maxY={100}
/>
</div>
);
};

export default LineChartExample;
40 changes: 40 additions & 0 deletions apps/next-app/src/app/linked-map/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { Gradient, LinkedMapComponent } from "@/components";

const App: React.FC = () => {
return (
<main className="flex flex-col items-center justify-between min-h-screen p-24">
<div className="z-10 items-center justify-between w-full max-w-5xl font-mono text-sm lg:flex">
<p className="fixed top-0 left-0 flex justify-center w-full px-4 pt-8 pb-6 border-b bg-gradient-to-b backdrop-blur-2xl border-neutral-800 bg-zinc-800/30 from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:bg-zinc-800/30">
@eunchurn/heatmap -&nbsp;
<code className="font-mono font-bold">Interactive Heatmap Chart</code>
</p>
</div>

<div className="relative flex place-items-center ">
<div className="font-sans w-auto pb-16 pt-[48px] md:pb-24 lg:pb-32 md:pt-16 lg:pt-20 flex justify-between gap-8 items-center flex-col relative z-0">
<div className="z-50 flex items-center justify-center w-full">
<div className="absolute min-w-[614px] min-h-[614px]">
<LinkedMapComponent />
</div>
<div className="absolute z-50 flex items-center justify-center w-64 h-64">
{/* <Gradient
className="opacity-90 w-[120px] h-[120px]"
conic
small
/> */}
</div>
</div>
<Gradient
className="top-[-500px] opacity-[0.15] w-[1000px] h-[1000px]"
conic
/>
</div>
</div>

<div className="grid mb-32 text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left" />
</main>
);
};

export default App;
27 changes: 27 additions & 0 deletions apps/next-app/src/app/relation-chart/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { RelationChart} from '@/components';
import { ChartData } from '@/components/relation-chart/types';

const sampleData: ChartData = {
nodes: [
{ id: "1", pcode: "001", pname: "Project A", url: "http://example.com/a" },
{ id: "2", pcode: "002", pname: "Project B", url: "http://example.com/b" },
{ id: "3", pcode: "003", pname: "Project C", url: "http://example.com/c" },
],
links: [
{ source: "1", target: "2", count: 10, time_avg: 100 },
{ source: "2", target: "3", count: 5, time_avg: 50 },
{ source: "1", target: "3", count: 8, time_avg: 80 },
],
};

const RelationChartExample: React.FC = () => {
return (
<div>
<h1>Relation Chart Example</h1>
<RelationChart data={sampleData} width={800} height={600} />
</div>
);
};

export default RelationChartExample;
56 changes: 56 additions & 0 deletions apps/next-app/src/app/w3-infinity-chart/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client";

import React, { useState, useEffect } from 'react';
import InfinityChart from '@/components/w3-infinity-chart';
import { ChartDataPoint, ChartConfig } from '@/components/w3-infinity-chart/types';

const InfinityChartExample: React.FC = () => {
const [data, setData] = useState<ChartDataPoint[]>([]);

useEffect(() => {
// Generate some sample data
const newData: ChartDataPoint[] = Array.from({ length: 50 }, (_, i) => ({
date: new Date(2023, 0, i + 1),
total: Math.random() * 100,
value: Math.random() * 50,
x: `Day ${i + 1}`
}));
setData(newData);
}, []);

const config: ChartConfig = {
id: 'example-chart',
SHIFT_SIZE: 10,
ZOOM_SIZE: 50,
ZOOM_DIRECTION: 'LEFT',
STACKED_KEYS: ['value'],
TIME_KEYS: 'date',
X_AXIS_KEY: 'x',
X_AXIS_ID: 'date',
LEFT_AXIS_KEY: 'total',
LEFT_AXIS_TITLE: 'Total',
RIGHT_AXIS_KEY: 'value',
RIGHT_AXIS_TITLE: 'Value',
STACKED_TOTAL_KEY: 'total',
FIXED_HEIGHT: 400
};

const width = 800;
const height = 400;
const margin = { top: 20, right: 20, bottom: 30, left: 40 };

return (
<div>
<h1>Infinity Chart Example</h1>
<InfinityChart
width={width}
height={height}
margin={margin}
data={data}
config={config}
/>
</div>
);
};

export default InfinityChartExample;
17 changes: 17 additions & 0 deletions apps/next-app/src/components/gradient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function Gradient({
conic,
className,
small,
}: {
small?: boolean;
conic?: boolean;
className?: string;
}): JSX.Element {
return (
<span
className={`absolute mix-blend-normal will-change-[filter] rounded-[100%] ${
small ? "blur-[32px]" : "blur-[75px]"
} ${conic ? "bg-glow-conic" : ""} ${className}`}
/>
);
}
3 changes: 3 additions & 0 deletions apps/next-app/src/components/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./gradient";
export * from "./linked-map";
export * from "./relation-chart";
62 changes: 62 additions & 0 deletions apps/next-app/src/components/line-chart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use client";

import React, { useRef, useEffect, useState } from 'react';
import * as d3 from 'd3';
import { LineChartProps, LineChartState, DataPoint } from './types';

const LineChart: React.FC<LineChartProps> = ({ data, width, height, id, chartId, timeRange, maxY }) => {
const svgRef = useRef<SVGSVGElement>(null);
const [state, setState] = useState<LineChartState>({ path: null });

useEffect(() => {
if (!svgRef.current) return;

const svg = d3.select(svgRef.current);

const x = d3.scaleLinear()
.range([0, width])
.domain(timeRange);

const y = d3.scaleLinear()
.range([height, 0])
.domain([0, maxY]);

const line = d3.line<DataPoint>()
.x(d => x(d[0]))
.y(d => y(d[1]));

if (!state.path) {
const newPath = svg
.append('path')
.datum(data)
.attr('class', `superChart ${id}`)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('clip-path', `url(#clipPath-${chartId})`)
.attr('stroke-width', 1.5)
.attr('d', line);

setState({ path: newPath });
} else {
state.path
.datum(data)
.transition()
.duration(1000)
.attr('d', line);
}
}, [data, width, height, id, chartId, timeRange, maxY, state.path]);

return (
<svg ref={svgRef} width={width} height={height}>
<defs>
<clipPath id={`clipPath-${chartId}`}>
<rect width={width} height={height} />
</clipPath>
</defs>
</svg>
);
};

export default LineChart;
18 changes: 18 additions & 0 deletions apps/next-app/src/components/line-chart/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface DataPoint {
[0]: number; // timestamp
[1]: number; // value
}

export interface LineChartProps {
data: DataPoint[];
width: number;
height: number;
id: string;
chartId: string;
timeRange: [number, number];
maxY: number;
}

export interface LineChartState {
path: d3.Selection<SVGPathElement, DataPoint[], null, undefined> | null;
}
Loading

0 comments on commit 059d96a

Please sign in to comment.