Skip to content

Commit

Permalink
feat(console2): add layercharts
Browse files Browse the repository at this point in the history
  • Loading branch information
xmlking committed Dec 26, 2023
1 parent 403a92c commit f7ab953
Show file tree
Hide file tree
Showing 8 changed files with 770 additions and 16 deletions.
2 changes: 1 addition & 1 deletion apps/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
"tailwindcss-animate": "1.0.7",
"tslib": "2.6.2",
"typescript": "5.3.3",
"vite": "5.0.10",
"vite": "4.5.1",
"vite-plugin-pwa": "0.17.4",
"vite-plugin-tailwind-purgecss": "0.2.0",
"vitest": "1.1.0",
Expand Down
5 changes: 5 additions & 0 deletions apps/console2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,19 @@
"@tailwindcss/container-queries": "0.1.1",
"@tailwindcss/forms": "0.5.7",
"@tailwindcss/typography": "0.5.10",
"@types/d3-scale": "4.0.8",
"@types/node": "20.10.5",
"@typescript-eslint/eslint-plugin": "6.16.0",
"@typescript-eslint/parser": "6.16.0",
"@vitest/coverage-v8": "1.1.0",
"autoprefixer": "10.4.16",
"d3-scale": "4.0.2",
"date-fns": "3.0.6",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-svelte": "2.35.1",
"formsnap": "0.4.2",
"layerchart": "0.27.0",
"postcss": "8.4.32",
"prettier": "3.1.1",
"prettier-plugin-svelte": "3.1.2",
Expand All @@ -57,6 +61,7 @@
"svelte-awesome-icons": "0.6.6",
"svelte-check": "3.6.2",
"svelte-meta-tags": "3.1.0",
"svelte-ux": "0.57.1",
"sveltekit-rate-limiter": "0.4.2",
"sveltekit-superforms": "1.13.1",
"sveltekit-view-transition": "0.5.3",
Expand Down
137 changes: 137 additions & 0 deletions apps/console2/src/lib/utils/genData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { addMinutes, startOfDay, startOfToday, subDays } from 'date-fns';
import { degreesToRadians, radiansToDegrees } from './math';

/**
* Get random number between min (inclusive) and max (exclusive)
* see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#getting_a_random_number_between_0_inclusive_and_1_exclusive
*/
export function getRandomNumber(min: number, max: number) {
return Math.random() * (max - min) + min;
}

/**
* Get random integer between min (inclusive) and max (inclusive by default)
* see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#getting_a_random_integer_between_two_values_inclusive
*/
export function getRandomInteger(min: number, max: number, includeMax = true) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + (includeMax ? 1 : 0)) + min);
}

export function createSeries(options: { count?: number; min: number; max: number; keys?: Array<string>; value?: 'number' | 'integer' }) {
const count = options.count ?? 10;
const min = options.min;
const max = options.max;
const keys = options.keys ?? ['y'];

return Array.from({ length: count }).map((_) => {
return {
x: options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max),
...Object.fromEntries(
keys.map((key) => {
return [key, options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max)];
})
)
};
});
}

export function createDateSeries(options: {
count?: number;
min: number;
max: number;
keys?: Array<string>;
value?: 'number' | 'integer';
}) {
const now = startOfToday();

const count = options.count ?? 10;
const min = options.min;
const max = options.max;
const keys = options.keys ?? ['value'];

return Array.from({ length: count }).map((_, i) => {
return {
date: subDays(now, count - i - 1),
...Object.fromEntries(
keys.map((key) => {
return [key, options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max)];
})
)
};
});
}

export function createTimeSeries(options: { count?: number; min: number; max: number; keys: Array<string>; value: 'number' | 'integer' }) {
const count = options.count ?? 10;
const min = options.min;
const max = options.max;
const keys = options.keys ?? ['value'];

let lastStartDate = startOfDay(new Date());

const timeSeries = Array.from({ length: count }).map((_, i) => {
const startDate = addMinutes(lastStartDate, getRandomInteger(0, 60));
const endDate = addMinutes(startDate, getRandomInteger(5, 60));
lastStartDate = startDate;
return {
name: `item ${i + 1}`,
startDate,
endDate,
...Object.fromEntries(
keys.map((key) => {
return [key, options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max)];
})
)
};
});

return timeSeries;
}

export const wideData = [
{ year: '2019', apples: 3840, bananas: 1920, cherries: 960, dates: 400 },
{ year: '2018', apples: 1600, bananas: 1440, cherries: 960, dates: 400 },
{ year: '2017', apples: 820, bananas: 1000, cherries: 640, dates: 400 },
{ year: '2016', apples: 820, bananas: 560, cherries: 720, dates: 400 }
];

export const longData = [
{ year: '2019', basket: 1, fruit: 'apples', value: 3840 },
{ year: '2019', basket: 1, fruit: 'bananas', value: 1920 },
{ year: '2019', basket: 2, fruit: 'cherries', value: 960 },
{ year: '2019', basket: 2, fruit: 'dates', value: 400 },

{ year: '2018', basket: 1, fruit: 'apples', value: 1600 },
{ year: '2018', basket: 1, fruit: 'bananas', value: 1440 },
{ year: '2018', basket: 2, fruit: 'cherries', value: 960 },
{ year: '2018', basket: 2, fruit: 'dates', value: 400 },

{ year: '2017', basket: 1, fruit: 'apples', value: 820 },
{ year: '2017', basket: 1, fruit: 'bananas', value: 1000 },
{ year: '2017', basket: 2, fruit: 'cherries', value: 640 },
{ year: '2017', basket: 2, fruit: 'dates', value: 400 },

{ year: '2016', basket: 1, fruit: 'apples', value: 820 },
{ year: '2016', basket: 1, fruit: 'bananas', value: 560 },
{ year: '2016', basket: 2, fruit: 'cherries', value: 720 },
{ year: '2016', basket: 2, fruit: 'dates', value: 400 }
];

export function getPhyllotaxis({ radius, count, width, height }) {
// Phyllotaxis: https://www.youtube.com/watch?v=KWoJgHFYWxY
const rads = Math.PI * (3 - Math.sqrt(5)); // ~2.4 rads or ~137.5 degrees
return getSpiral({ angle: radiansToDegrees(rads), radius, count, width, height });
}

export function getSpiral({ angle, radius, count, width, height }) {
return Array.from({ length: count }, (_, i) => {
const r = radius * Math.sqrt(i);
const a = degreesToRadians(angle * i);
return {
x: width / 2 + r * Math.cos(a),
y: height / 2 + r * Math.sin(a)
};
});
}
13 changes: 13 additions & 0 deletions apps/console2/src/lib/utils/math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Convert degrees to radians
*/
export function degreesToRadians(degrees: number) {
return (degrees * Math.PI) / 180;
}

/**
* Convert radians to degrees
*/
export function radiansToDegrees(radians: number) {
return radians * (180 / Math.PI);
}
32 changes: 32 additions & 0 deletions apps/console2/src/routes/(app)/dashboard/reports/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { formatDate, PeriodType } from 'svelte-ux';
import { scaleBand } from 'd3-scale';
import { Chart, Svg, Axis, Bars } from 'layerchart';
import { createDateSeries } from '$lib/utils/genData';
const data = createDateSeries({
count: 30,
min: 20,
max: 100,
value: 'integer',
keys: ['value', 'baseline']
});
</script>

<div class="h-[300px] rounded border p-4">
<Chart
{data}
x="date"
xScale={scaleBand().padding(0.4)}
y="value"
yDomain={[0, null]}
yNice
padding={{ left: 16, bottom: 24 }}
>
<Svg>
<Axis placement="left" grid rule />
<Axis placement="bottom" format={(d) => formatDate(d, PeriodType.Day, 'short')} rule />
<Bars radius={4} strokeWidth={1} class="fill-accent-500" />
</Svg>
</Chart>
</div>
9 changes: 7 additions & 2 deletions apps/console2/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import baseConfig from '@spectacular/skeleton/tailwind.config';
import colors from 'tailwindcss/colors';
import type { Config } from 'tailwindcss';

export default {
presets: [baseConfig],
content: [...baseConfig.content],
content: [...baseConfig.content, './node_modules/layerchart/**/*.{svelte,js}'],
theme: {
extend: {
colors: {
accent: colors.indigo
},
fontFamily: {
heading: "'Sora Variable', sans-serif",
sans: "'Inter Variable', sans-serif",
mono: "'JetBrains Mono', monospace",
serif: "'Roboto Slab Variable', sans-serif"
}
}
}
},
plugins: [...baseConfig.plugins, require('svelte-ux/plugins/tailwind.cjs')]
} satisfies Config;
2 changes: 1 addition & 1 deletion apps/web/src/components/ui/icons/index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default as Tick } from './tick.astro';
export { default as Tick } from './Tick.astro';
Loading

1 comment on commit f7ab953

@vercel
Copy link

@vercel vercel bot commented on f7ab953 Dec 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

spectacular-docs – ./apps/docs

spectacular-docs.vercel.app
spectacular-docs-git-main-xmlking.vercel.app
spectacular-docs-xmlking.vercel.app

Please sign in to comment.