483 lines
17 KiB
TypeScript
483 lines
17 KiB
TypeScript
import { html, css } from '@design.estate/dees-element';
|
|
import type { DeesChartArea } from './dees-chart-area.js';
|
|
import '@design.estate/dees-wcctools/demotools';
|
|
|
|
export const demoFunc = () => {
|
|
// Initial dataset values
|
|
const initialDatasets = {
|
|
system: {
|
|
label: 'System Usage (%)',
|
|
series: [
|
|
{
|
|
name: 'CPU',
|
|
data: [
|
|
{ x: new Date(Date.now() - 300000).toISOString(), y: 25 },
|
|
{ x: new Date(Date.now() - 240000).toISOString(), y: 30 },
|
|
{ x: new Date(Date.now() - 180000).toISOString(), y: 28 },
|
|
{ x: new Date(Date.now() - 120000).toISOString(), y: 35 },
|
|
{ x: new Date(Date.now() - 60000).toISOString(), y: 32 },
|
|
{ x: new Date().toISOString(), y: 38 },
|
|
],
|
|
},
|
|
{
|
|
name: 'Memory',
|
|
data: [
|
|
{ x: new Date(Date.now() - 300000).toISOString(), y: 45 },
|
|
{ x: new Date(Date.now() - 240000).toISOString(), y: 48 },
|
|
{ x: new Date(Date.now() - 180000).toISOString(), y: 46 },
|
|
{ x: new Date(Date.now() - 120000).toISOString(), y: 52 },
|
|
{ x: new Date(Date.now() - 60000).toISOString(), y: 50 },
|
|
{ x: new Date().toISOString(), y: 55 },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
const initialFormatters = {
|
|
system: (val: number) => `${val}%`,
|
|
};
|
|
|
|
return html`
|
|
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
|
// Get the chart elements
|
|
const chartElement = elementArg.querySelector('#main-chart') as DeesChartArea;
|
|
const connectionsChartElement = elementArg.querySelector('#connections-chart') as DeesChartArea;
|
|
let intervalId: number;
|
|
let connectionsIntervalId: number;
|
|
let currentDataset = 'system';
|
|
|
|
// Y-axis formatters for different datasets
|
|
const formatters = {
|
|
system: (val: number) => `${val}%`,
|
|
network: (val: number) => `${val} Mbps`,
|
|
sales: (val: number) => `$${val.toLocaleString()}`,
|
|
};
|
|
|
|
// Time window configuration (in milliseconds)
|
|
const TIME_WINDOW = 2 * 60 * 1000; // 2 minutes
|
|
const UPDATE_INTERVAL = 1000; // 1 second
|
|
const DATA_POINT_INTERVAL = 5000; // Show data points every 5 seconds
|
|
|
|
// Store previous values for smooth transitions
|
|
let previousValues = {
|
|
cpu: 30,
|
|
memory: 50,
|
|
download: 150,
|
|
upload: 30,
|
|
connections: 150
|
|
};
|
|
|
|
// Generate initial data points for time window
|
|
const generateInitialData = (baseValue: number, variance: number, interval: number = DATA_POINT_INTERVAL) => {
|
|
const data = [];
|
|
const now = Date.now();
|
|
const pointCount = Math.floor(TIME_WINDOW / interval);
|
|
|
|
for (let i = pointCount; i >= 0; i--) {
|
|
const timestamp = new Date(now - (i * interval)).toISOString();
|
|
const value = baseValue + (Math.random() - 0.5) * variance;
|
|
data.push({ x: timestamp, y: Math.round(value) });
|
|
}
|
|
return data;
|
|
};
|
|
|
|
// Different datasets to showcase
|
|
const datasets = {
|
|
system: {
|
|
label: 'System Usage (%)',
|
|
series: [
|
|
{
|
|
name: 'CPU',
|
|
data: generateInitialData(previousValues.cpu, 10),
|
|
},
|
|
{
|
|
name: 'Memory',
|
|
data: generateInitialData(previousValues.memory, 8),
|
|
},
|
|
],
|
|
},
|
|
network: {
|
|
label: 'Network Traffic (Mbps)',
|
|
series: [
|
|
{
|
|
name: 'Download',
|
|
data: generateInitialData(previousValues.download, 30),
|
|
},
|
|
{
|
|
name: 'Upload',
|
|
data: generateInitialData(previousValues.upload, 10),
|
|
},
|
|
],
|
|
},
|
|
sales: {
|
|
label: 'Sales Analytics',
|
|
series: [
|
|
{
|
|
name: 'Revenue',
|
|
data: [
|
|
{ x: '2025-01-01', y: 45000 },
|
|
{ x: '2025-01-02', y: 52000 },
|
|
{ x: '2025-01-03', y: 48000 },
|
|
{ x: '2025-01-04', y: 61000 },
|
|
{ x: '2025-01-05', y: 58000 },
|
|
{ x: '2025-01-06', y: 65000 },
|
|
],
|
|
},
|
|
{
|
|
name: 'Profit',
|
|
data: [
|
|
{ x: '2025-01-01', y: 12000 },
|
|
{ x: '2025-01-02', y: 14000 },
|
|
{ x: '2025-01-03', y: 11000 },
|
|
{ x: '2025-01-04', y: 18000 },
|
|
{ x: '2025-01-05', y: 16000 },
|
|
{ x: '2025-01-06', y: 20000 },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
// Generate smooth value transitions
|
|
const getNextValue = (current: number, min: number, max: number, maxChange: number = 5) => {
|
|
// Add some randomness but keep it close to current value
|
|
const change = (Math.random() - 0.5) * maxChange * 2;
|
|
let newValue = current + change;
|
|
|
|
// Apply some "pressure" to move towards center of range
|
|
const center = (min + max) / 2;
|
|
const pressure = (center - newValue) * 0.1;
|
|
newValue += pressure;
|
|
|
|
// Ensure within bounds
|
|
newValue = Math.max(min, Math.min(max, newValue));
|
|
return Math.round(newValue);
|
|
};
|
|
|
|
// Track time of last data point
|
|
let lastDataPointTime = Date.now();
|
|
let connectionsLastUpdate = Date.now();
|
|
|
|
// Add real-time data
|
|
const addRealtimeData = () => {
|
|
if (!chartElement) return;
|
|
|
|
const now = Date.now();
|
|
|
|
// Only add new data point every DATA_POINT_INTERVAL
|
|
const shouldAddPoint = (now - lastDataPointTime) >= DATA_POINT_INTERVAL;
|
|
|
|
if (shouldAddPoint) {
|
|
lastDataPointTime = now;
|
|
const newTimestamp = new Date(now).toISOString();
|
|
|
|
// Generate smooth transitions for new values
|
|
if (currentDataset === 'system') {
|
|
// Generate new values
|
|
previousValues.cpu = getNextValue(previousValues.cpu, 20, 50, 3);
|
|
previousValues.memory = getNextValue(previousValues.memory, 40, 70, 2);
|
|
|
|
// Get current data and add new points
|
|
const currentSeries = chartElement.chartSeries.map((series, index) => ({
|
|
name: series.name,
|
|
data: [
|
|
...(series.data as Array<{x: any; y: any}>),
|
|
index === 0
|
|
? { x: newTimestamp, y: previousValues.cpu }
|
|
: { x: newTimestamp, y: previousValues.memory }
|
|
]
|
|
}));
|
|
|
|
chartElement.updateSeries(currentSeries, false);
|
|
|
|
} else if (currentDataset === 'network') {
|
|
// Generate new values
|
|
previousValues.download = getNextValue(previousValues.download, 100, 200, 10);
|
|
previousValues.upload = getNextValue(previousValues.upload, 20, 50, 5);
|
|
|
|
// Get current data and add new points
|
|
const currentSeries = chartElement.chartSeries.map((series, index) => ({
|
|
name: series.name,
|
|
data: [
|
|
...(series.data as Array<{x: any; y: any}>),
|
|
index === 0
|
|
? { x: newTimestamp, y: previousValues.download }
|
|
: { x: newTimestamp, y: previousValues.upload }
|
|
]
|
|
}));
|
|
|
|
chartElement.updateSeries(currentSeries, false);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Update connections chart data
|
|
const updateConnections = () => {
|
|
if (!connectionsChartElement) return;
|
|
|
|
const now = Date.now();
|
|
const newTimestamp = new Date(now).toISOString();
|
|
|
|
// Generate new connections value with discrete changes
|
|
const change = Math.floor(Math.random() * 21) - 10; // -10 to +10 connections
|
|
previousValues.connections = Math.max(50, Math.min(300, previousValues.connections + change));
|
|
|
|
// Get current data and add new point
|
|
const currentSeries = connectionsChartElement.chartSeries;
|
|
const newData = [{
|
|
name: currentSeries[0]?.name || 'Connections',
|
|
data: [
|
|
...(currentSeries[0]?.data as Array<{x: any; y: any}> || []),
|
|
{ x: newTimestamp, y: previousValues.connections }
|
|
]
|
|
}];
|
|
|
|
connectionsChartElement.updateSeries(newData, false);
|
|
};
|
|
|
|
// Switch dataset
|
|
const switchDataset = (name: string) => {
|
|
currentDataset = name;
|
|
const dataset = datasets[name];
|
|
chartElement.label = dataset.label;
|
|
chartElement.series = dataset.series;
|
|
chartElement.yAxisFormatter = formatters[name];
|
|
|
|
// Set appropriate y-axis scaling
|
|
if (name === 'system') {
|
|
chartElement.yAxisScaling = 'percentage';
|
|
chartElement.yAxisMax = 100;
|
|
} else if (name === 'network') {
|
|
chartElement.yAxisScaling = 'dynamic';
|
|
} else {
|
|
chartElement.yAxisScaling = 'dynamic';
|
|
}
|
|
|
|
// Reset last data point time to get fresh data immediately
|
|
lastDataPointTime = Date.now() - DATA_POINT_INTERVAL;
|
|
};
|
|
|
|
// Start/stop real-time updates
|
|
const startRealtime = () => {
|
|
if (!intervalId && (currentDataset === 'system' || currentDataset === 'network')) {
|
|
chartElement.realtimeMode = true;
|
|
// Only add data every 5 seconds, chart auto-scrolls independently
|
|
intervalId = window.setInterval(() => addRealtimeData(), DATA_POINT_INTERVAL);
|
|
}
|
|
|
|
// Start connections updates
|
|
if (!connectionsIntervalId) {
|
|
connectionsChartElement.realtimeMode = true;
|
|
// Update connections every second
|
|
connectionsIntervalId = window.setInterval(() => updateConnections(), UPDATE_INTERVAL);
|
|
}
|
|
};
|
|
|
|
const stopRealtime = () => {
|
|
if (intervalId) {
|
|
window.clearInterval(intervalId);
|
|
intervalId = null;
|
|
chartElement.realtimeMode = false;
|
|
}
|
|
|
|
// Stop connections updates
|
|
if (connectionsIntervalId) {
|
|
window.clearInterval(connectionsIntervalId);
|
|
connectionsIntervalId = null;
|
|
connectionsChartElement.realtimeMode = false;
|
|
}
|
|
};
|
|
|
|
// Randomize current data (spike/drop simulation)
|
|
const randomizeData = () => {
|
|
if (currentDataset === 'system') {
|
|
// Simulate CPU/Memory spike
|
|
previousValues.cpu = Math.random() > 0.5 ? 85 : 25;
|
|
previousValues.memory = Math.random() > 0.5 ? 80 : 45;
|
|
} else if (currentDataset === 'network') {
|
|
// Simulate network traffic spike
|
|
previousValues.download = Math.random() > 0.5 ? 250 : 100;
|
|
previousValues.upload = Math.random() > 0.5 ? 80 : 20;
|
|
}
|
|
|
|
// Also spike connections
|
|
previousValues.connections = Math.random() > 0.5 ? 280 : 80;
|
|
|
|
// Force immediate update by resetting timers
|
|
lastDataPointTime = 0;
|
|
connectionsLastUpdate = 0;
|
|
};
|
|
|
|
// Wire up button click handlers
|
|
const buttons = elementArg.querySelectorAll('dees-button');
|
|
buttons.forEach(button => {
|
|
const text = button.textContent?.trim();
|
|
if (text === 'System Usage') {
|
|
button.addEventListener('click', () => switchDataset('system'));
|
|
} else if (text === 'Network Traffic') {
|
|
button.addEventListener('click', () => switchDataset('network'));
|
|
} else if (text === 'Sales Data') {
|
|
button.addEventListener('click', () => switchDataset('sales'));
|
|
} else if (text === 'Start Live') {
|
|
button.addEventListener('click', () => startRealtime());
|
|
} else if (text === 'Stop Live') {
|
|
button.addEventListener('click', () => stopRealtime());
|
|
} else if (text === 'Spike Values') {
|
|
button.addEventListener('click', () => randomizeData());
|
|
}
|
|
});
|
|
|
|
// Update button states based on current dataset
|
|
const updateButtonStates = () => {
|
|
const buttons = elementArg.querySelectorAll('dees-button');
|
|
buttons.forEach(button => {
|
|
const text = button.textContent?.trim();
|
|
if (text === 'System Usage') {
|
|
button.type = currentDataset === 'system' ? 'highlighted' : 'normal';
|
|
} else if (text === 'Network Traffic') {
|
|
button.type = currentDataset === 'network' ? 'highlighted' : 'normal';
|
|
} else if (text === 'Sales Data') {
|
|
button.type = currentDataset === 'sales' ? 'highlighted' : 'normal';
|
|
}
|
|
});
|
|
};
|
|
|
|
// Configure main chart with rolling window
|
|
chartElement.rollingWindow = TIME_WINDOW;
|
|
chartElement.realtimeMode = false; // Will be enabled when starting live updates
|
|
chartElement.yAxisScaling = 'percentage'; // Initial system dataset uses percentage
|
|
chartElement.yAxisMax = 100;
|
|
chartElement.autoScrollInterval = 1000; // Auto-scroll every second
|
|
|
|
// Set initial time window
|
|
setTimeout(() => {
|
|
chartElement.updateTimeWindow();
|
|
}, 100);
|
|
|
|
// Update button states when dataset changes
|
|
const originalSwitchDataset = switchDataset;
|
|
const switchDatasetWithButtonUpdate = (name: string) => {
|
|
originalSwitchDataset(name);
|
|
updateButtonStates();
|
|
};
|
|
|
|
// Replace switchDataset with the one that updates buttons
|
|
buttons.forEach(button => {
|
|
const text = button.textContent?.trim();
|
|
if (text === 'System Usage') {
|
|
button.removeEventListener('click', () => switchDataset('system'));
|
|
button.addEventListener('click', () => switchDatasetWithButtonUpdate('system'));
|
|
} else if (text === 'Network Traffic') {
|
|
button.removeEventListener('click', () => switchDataset('network'));
|
|
button.addEventListener('click', () => switchDatasetWithButtonUpdate('network'));
|
|
} else if (text === 'Sales Data') {
|
|
button.removeEventListener('click', () => switchDataset('sales'));
|
|
button.addEventListener('click', () => switchDatasetWithButtonUpdate('sales'));
|
|
}
|
|
});
|
|
|
|
// Initialize connections chart with data
|
|
if (connectionsChartElement) {
|
|
const initialConnectionsData = generateInitialData(previousValues.connections, 30, UPDATE_INTERVAL);
|
|
connectionsChartElement.series = [{
|
|
name: 'Connections',
|
|
data: initialConnectionsData
|
|
}];
|
|
|
|
// Configure connections chart
|
|
connectionsChartElement.rollingWindow = TIME_WINDOW;
|
|
connectionsChartElement.realtimeMode = false; // Will be enabled when starting live updates
|
|
connectionsChartElement.yAxisScaling = 'fixed';
|
|
connectionsChartElement.yAxisMax = 350;
|
|
connectionsChartElement.autoScrollInterval = 1000; // Auto-scroll every second
|
|
|
|
// Set initial time window
|
|
setTimeout(() => {
|
|
connectionsChartElement.updateTimeWindow();
|
|
}, 100);
|
|
}
|
|
}}>
|
|
<style>
|
|
${css`
|
|
.demoBox {
|
|
position: relative;
|
|
background: #000000;
|
|
height: 100%;
|
|
width: 100%;
|
|
padding: 40px;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
}
|
|
|
|
.controls {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.chart-container {
|
|
flex: 1;
|
|
min-height: 400px;
|
|
}
|
|
|
|
.info {
|
|
color: #666;
|
|
font-size: 11px;
|
|
font-family: 'Geist Sans', sans-serif;
|
|
text-align: center;
|
|
margin-top: 8px;
|
|
}
|
|
`}
|
|
</style>
|
|
<div class="demoBox">
|
|
<div class="controls">
|
|
<dees-button-group label="Dataset:">
|
|
<dees-button type="highlighted">System Usage</dees-button>
|
|
<dees-button>Network Traffic</dees-button>
|
|
<dees-button>Sales Data</dees-button>
|
|
</dees-button-group>
|
|
|
|
<dees-button-group label="Real-time:">
|
|
<dees-button>Start Live</dees-button>
|
|
<dees-button>Stop Live</dees-button>
|
|
</dees-button-group>
|
|
|
|
<dees-button-group label="Actions:">
|
|
<dees-button>Spike Values</dees-button>
|
|
</dees-button-group>
|
|
</div>
|
|
|
|
<div class="chart-container">
|
|
<dees-chart-area
|
|
id="main-chart"
|
|
.label=${initialDatasets.system.label}
|
|
.series=${initialDatasets.system.series}
|
|
.yAxisFormatter=${initialFormatters.system}
|
|
></dees-chart-area>
|
|
</div>
|
|
|
|
<div class="chart-container" style="margin-top: 20px;">
|
|
<dees-chart-area
|
|
id="connections-chart"
|
|
.label=${'Active Connections'}
|
|
.series=${[{
|
|
name: 'Connections',
|
|
data: [] as Array<{x: any; y: any}>
|
|
}]}
|
|
.yAxisFormatter=${(val: number) => `${val}`}
|
|
></dees-chart-area>
|
|
</div>
|
|
|
|
<div class="info">
|
|
Real-time monitoring with 2-minute rolling window •
|
|
Updates every second with smooth value transitions •
|
|
Click 'Spike Values' to simulate load spikes
|
|
</div>
|
|
</div>
|
|
</dees-demowrapper>
|
|
`;
|
|
}; |