import type { IVChartOption } from '@visactor/vchart';
import type { TikTokVideoData } from '../index';
import { TIKTOK_COLORS } from '../index';
/**
* Create a combined dashboard spec with multiple charts
*/
export function createDashboardSpec(data: TikTokVideoData[]): IVChartOption {
// Prepare data for line chart (views over time)
const sortedData = [...data].sort((a, b) =>
new Date(a.datePublished).getTime() - new Date(b.datePublished).getTime()
);
const lineData = sortedData.map(item => ({
date: new Date(item.datePublished).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric'
}),
views: item.views,
type: 'Views'
}));
// Prepare data for bar chart (top 5 videos)
const top5 = [...data]
.sort((a, b) => b.views - a.views)
.slice(0, 5)
.reverse();
const barData = top5.map(item => ({
title: item.title.length > 25 ? item.title.substring(0, 25) + '...' : item.title,
views: item.views
}));
// Prepare data for pie chart (engagement)
const totalLikes = data.reduce((sum, item) => sum + item.likes, 0);
const totalComments = data.reduce((sum, item) => sum + item.comments, 0);
const totalShares = data.reduce((sum, item) => sum + item.shares, 0);
const pieData = [
{ type: 'Likes', value: totalLikes },
{ type: 'Comments', value: totalComments },
{ type: 'Shares', value: totalShares }
];
// Create a composite chart
return {
type: 'common',
layout: {
type: 'grid',
col: 2,
row: 2,
elements: [
{
modelId: 'line',
col: 0,
row: 0,
colSpan: 2
},
{
modelId: 'bar',
col: 0,
row: 1
},
{
modelId: 'pie',
col: 1,
row: 1
}
]
},
region: [
{
id: 'lineRegion'
},
{
id: 'barRegion'
},
{
id: 'pieRegion'
}
],
series: [
{
id: 'line',
regionId: 'lineRegion',
type: 'line',
data: {
id: 'lineData',
values: lineData
},
xField: 'date',
yField: 'views',
point: {
style: {
fill: TIKTOK_COLORS.primary,
size: 5
}
},
line: {
style: {
stroke: TIKTOK_COLORS.primary,
lineWidth: 2
}
}
},
{
id: 'bar',
regionId: 'barRegion',
type: 'bar',
data: {
id: 'barData',
values: barData
},
xField: 'views',
yField: 'title',
direction: 'horizontal',
bar: {
style: {
fill: TIKTOK_COLORS.info
}
}
},
{
id: 'pie',
regionId: 'pieRegion',
type: 'pie',
data: {
id: 'pieData',
values: pieData
},
categoryField: 'type',
valueField: 'value',
radius: 0.7,
innerRadius: 0.4,
color: {
type: 'ordinal',
range: [TIKTOK_COLORS.secondary, TIKTOK_COLORS.warning, TIKTOK_COLORS.success]
}
}
],
axes: [
{
id: 'lineAxisLeft',
regionId: 'lineRegion',
orient: 'left',
title: {
visible: true,
text: 'Views'
},
label: {
formatMethod: (val: number) => {
if (val >= 1000000) return (val / 1000000).toFixed(1) + 'M';
if (val >= 1000) return (val / 1000).toFixed(1) + 'K';
return val.toString();
}
}
},
{
id: 'lineAxisBottom',
regionId: 'lineRegion',
orient: 'bottom',
title: {
visible: true,
text: 'Date'
}
},
{
id: 'barAxisBottom',
regionId: 'barRegion',
orient: 'bottom',
title: {
visible: true,
text: 'Views'
},
label: {
formatMethod: (val: number) => {
if (val >= 1000000) return (val / 1000000).toFixed(1) + 'M';
if (val >= 1000) return (val / 1000).toFixed(1) + 'K';
return val.toString();
}
}
},
{
id: 'barAxisLeft',
regionId: 'barRegion',
orient: 'left'
}
],
title: {
visible: true,
text: 'TikTok Analytics Dashboard',
textStyle: {
fontSize: 24,
fontWeight: 'bold'
}
},
legends: [
{
visible: true,
orient: 'bottom',
regionId: 'pieRegion',
position: 'middle'
}
],
tooltip: {
visible: true
},
animation: {
appear: {
duration: 1000
}
}
};
}