fix(dees-catalog): update @design.estate/dees-wcctools dependency to version 1.0.98 for compatibility and enhance demo functionality with real-time data updates
This commit is contained in:
@ -17,7 +17,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@design.estate/dees-domtools": "^2.1.1",
|
"@design.estate/dees-domtools": "^2.1.1",
|
||||||
"@design.estate/dees-element": "^2.0.42",
|
"@design.estate/dees-element": "^2.0.42",
|
||||||
"@design.estate/dees-wcctools": "^1.0.97",
|
"@design.estate/dees-wcctools": "^1.0.98",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||||
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@ -15,8 +15,8 @@ importers:
|
|||||||
specifier: ^2.0.42
|
specifier: ^2.0.42
|
||||||
version: 2.0.42
|
version: 2.0.42
|
||||||
'@design.estate/dees-wcctools':
|
'@design.estate/dees-wcctools':
|
||||||
specifier: ^1.0.97
|
specifier: ^1.0.98
|
||||||
version: 1.0.97
|
version: 1.0.98
|
||||||
'@fortawesome/fontawesome-svg-core':
|
'@fortawesome/fontawesome-svg-core':
|
||||||
specifier: ^6.7.2
|
specifier: ^6.7.2
|
||||||
version: 6.7.2
|
version: 6.7.2
|
||||||
@ -305,8 +305,8 @@ packages:
|
|||||||
'@design.estate/dees-element@2.0.42':
|
'@design.estate/dees-element@2.0.42':
|
||||||
resolution: {integrity: sha512-1PzHP6q/PtSiu4P0nCxjSeHtRHn62zoSouMy8JFW2h29FT/CSDVaTUAUqYqnvwE/U98aLNivWTmerZitDF7kBQ==}
|
resolution: {integrity: sha512-1PzHP6q/PtSiu4P0nCxjSeHtRHn62zoSouMy8JFW2h29FT/CSDVaTUAUqYqnvwE/U98aLNivWTmerZitDF7kBQ==}
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@1.0.97':
|
'@design.estate/dees-wcctools@1.0.98':
|
||||||
resolution: {integrity: sha512-0jG6+xuh2kGyCww7oqIJ0OwQI7sMNM6g2pjyARQAzGPzB9khN7H+Yr2+uIF2/wcTc42kObRp/O35aI2TY2V1PA==}
|
resolution: {integrity: sha512-6EolTGBiXgF1wgr+KOeSXAIKpXqU95FU4vOJYPPEvb+e3ebFXCuL/B4UTFZYG3e1KuTZgxiaJ04L8ejm5HfTZA==}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.24.2':
|
'@esbuild/aix-ppc64@0.24.2':
|
||||||
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
|
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
|
||||||
@ -5176,7 +5176,7 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@1.0.97':
|
'@design.estate/dees-wcctools@1.0.98':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-domtools': 2.3.2
|
'@design.estate/dees-domtools': 2.3.2
|
||||||
'@design.estate/dees-element': 2.0.42
|
'@design.estate/dees-element': 2.0.42
|
||||||
|
@ -40,9 +40,11 @@ export const demoFunc = () => {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||||
// Get the chart element
|
// Get the chart elements
|
||||||
const chartElement = elementArg.querySelector('dees-chart-area') as DeesChartArea;
|
const chartElement = elementArg.querySelector('#main-chart') as DeesChartArea;
|
||||||
|
const connectionsChartElement = elementArg.querySelector('#connections-chart') as DeesChartArea;
|
||||||
let intervalId: number;
|
let intervalId: number;
|
||||||
|
let connectionsIntervalId: number;
|
||||||
let currentDataset = 'system';
|
let currentDataset = 'system';
|
||||||
|
|
||||||
// Y-axis formatters for different datasets
|
// Y-axis formatters for different datasets
|
||||||
@ -52,6 +54,34 @@ export const demoFunc = () => {
|
|||||||
sales: (val: number) => `$${val.toLocaleString()}`,
|
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
|
// Different datasets to showcase
|
||||||
const datasets = {
|
const datasets = {
|
||||||
system: {
|
system: {
|
||||||
@ -59,25 +89,11 @@ export const demoFunc = () => {
|
|||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'CPU',
|
name: 'CPU',
|
||||||
data: [
|
data: generateInitialData(previousValues.cpu, 10),
|
||||||
{ 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',
|
name: 'Memory',
|
||||||
data: [
|
data: generateInitialData(previousValues.memory, 8),
|
||||||
{ 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 },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -86,25 +102,11 @@ export const demoFunc = () => {
|
|||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Download',
|
name: 'Download',
|
||||||
data: [
|
data: generateInitialData(previousValues.download, 30),
|
||||||
{ x: new Date(Date.now() - 300000).toISOString(), y: 120 },
|
|
||||||
{ x: new Date(Date.now() - 240000).toISOString(), y: 150 },
|
|
||||||
{ x: new Date(Date.now() - 180000).toISOString(), y: 180 },
|
|
||||||
{ x: new Date(Date.now() - 120000).toISOString(), y: 165 },
|
|
||||||
{ x: new Date(Date.now() - 60000).toISOString(), y: 190 },
|
|
||||||
{ x: new Date().toISOString(), y: 175 },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Upload',
|
name: 'Upload',
|
||||||
data: [
|
data: generateInitialData(previousValues.upload, 10),
|
||||||
{ 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: 35 },
|
|
||||||
{ x: new Date(Date.now() - 120000).toISOString(), y: 28 },
|
|
||||||
{ x: new Date(Date.now() - 60000).toISOString(), y: 32 },
|
|
||||||
{ x: new Date().toISOString(), y: 40 },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -137,40 +139,101 @@ export const demoFunc = () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate random value within range
|
// Generate smooth value transitions
|
||||||
const getRandomValue = (min: number, max: number) => {
|
const getNextValue = (current: number, min: number, max: number, maxChange: number = 5) => {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
// 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
|
// Add real-time data
|
||||||
const addRealtimeData = () => {
|
const addRealtimeData = () => {
|
||||||
if (!chartElement) return;
|
if (!chartElement) return;
|
||||||
|
|
||||||
const newTimestamp = new Date().toISOString();
|
const now = Date.now();
|
||||||
|
|
||||||
// Generate new data points based on dataset type
|
// Only add new data point every DATA_POINT_INTERVAL
|
||||||
let newData: any[][] = [];
|
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') {
|
if (currentDataset === 'system') {
|
||||||
newData = [
|
// Generate new values
|
||||||
[{ x: newTimestamp, y: getRandomValue(25, 45) }], // CPU
|
previousValues.cpu = getNextValue(previousValues.cpu, 20, 50, 3);
|
||||||
[{ x: newTimestamp, y: getRandomValue(45, 65) }], // Memory
|
previousValues.memory = getNextValue(previousValues.memory, 40, 70, 2);
|
||||||
];
|
|
||||||
} else if (currentDataset === 'network') {
|
|
||||||
newData = [
|
|
||||||
[{ x: newTimestamp, y: getRandomValue(100, 250) }], // Download
|
|
||||||
[{ x: newTimestamp, y: getRandomValue(20, 50) }], // Upload
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep only last 20 data points and update without animation
|
// Get current data and add new points
|
||||||
const currentSeries = chartElement.series.map((series, index) => ({
|
const currentSeries = chartElement.chartSeries.map((series, index) => ({
|
||||||
...series,
|
name: series.name,
|
||||||
data: [...series.data.slice(-19), ...(newData[index] || [])],
|
data: [
|
||||||
|
...(series.data as Array<{x: any; y: any}>),
|
||||||
|
index === 0
|
||||||
|
? { x: newTimestamp, y: previousValues.cpu }
|
||||||
|
: { x: newTimestamp, y: previousValues.memory }
|
||||||
|
]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Update without animation for smoother real-time updates
|
|
||||||
chartElement.updateSeries(currentSeries, false);
|
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
|
// Switch dataset
|
||||||
@ -180,21 +243,34 @@ export const demoFunc = () => {
|
|||||||
chartElement.label = dataset.label;
|
chartElement.label = dataset.label;
|
||||||
chartElement.series = dataset.series;
|
chartElement.series = dataset.series;
|
||||||
chartElement.yAxisFormatter = formatters[name];
|
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
|
// Start/stop real-time updates
|
||||||
const startRealtime = () => {
|
const startRealtime = () => {
|
||||||
if (!intervalId && (currentDataset === 'system' || currentDataset === 'network')) {
|
if (!intervalId && (currentDataset === 'system' || currentDataset === 'network')) {
|
||||||
// Disable animations for real-time mode
|
chartElement.realtimeMode = true;
|
||||||
chartElement.updateOptions({
|
// Only add data every 5 seconds, chart auto-scrolls independently
|
||||||
chart: {
|
intervalId = window.setInterval(() => addRealtimeData(), DATA_POINT_INTERVAL);
|
||||||
animations: {
|
|
||||||
enabled: false
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}, false, false);
|
|
||||||
|
|
||||||
intervalId = window.setInterval(() => addRealtimeData(), 2000);
|
// Start connections updates
|
||||||
|
if (!connectionsIntervalId) {
|
||||||
|
connectionsChartElement.realtimeMode = true;
|
||||||
|
// Update connections every second
|
||||||
|
connectionsIntervalId = window.setInterval(() => updateConnections(), UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,37 +278,35 @@ export const demoFunc = () => {
|
|||||||
if (intervalId) {
|
if (intervalId) {
|
||||||
window.clearInterval(intervalId);
|
window.clearInterval(intervalId);
|
||||||
intervalId = null;
|
intervalId = null;
|
||||||
|
chartElement.realtimeMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Re-enable animations when stopping real-time
|
// Stop connections updates
|
||||||
chartElement.updateOptions({
|
if (connectionsIntervalId) {
|
||||||
chart: {
|
window.clearInterval(connectionsIntervalId);
|
||||||
animations: {
|
connectionsIntervalId = null;
|
||||||
enabled: true,
|
connectionsChartElement.realtimeMode = false;
|
||||||
speed: 400,
|
|
||||||
animateGradually: {
|
|
||||||
enabled: true,
|
|
||||||
delay: 150
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, false, true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Randomize current data
|
// Randomize current data (spike/drop simulation)
|
||||||
const randomizeData = () => {
|
const randomizeData = () => {
|
||||||
const currentSeries = chartElement.series.map(series => ({
|
if (currentDataset === 'system') {
|
||||||
...series,
|
// Simulate CPU/Memory spike
|
||||||
data: series.data.map((point: any) => ({
|
previousValues.cpu = Math.random() > 0.5 ? 85 : 25;
|
||||||
...point,
|
previousValues.memory = Math.random() > 0.5 ? 80 : 45;
|
||||||
y: typeof point.y === 'number'
|
} else if (currentDataset === 'network') {
|
||||||
? Math.round(point.y * (0.8 + Math.random() * 0.4)) // +/- 20% variation
|
// Simulate network traffic spike
|
||||||
: point.y,
|
previousValues.download = Math.random() > 0.5 ? 250 : 100;
|
||||||
})),
|
previousValues.upload = Math.random() > 0.5 ? 80 : 20;
|
||||||
}));
|
}
|
||||||
|
|
||||||
// Update with animation for single updates
|
// Also spike connections
|
||||||
chartElement.updateSeries(currentSeries, true);
|
previousValues.connections = Math.random() > 0.5 ? 280 : 80;
|
||||||
|
|
||||||
|
// Force immediate update by resetting timers
|
||||||
|
lastDataPointTime = 0;
|
||||||
|
connectionsLastUpdate = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wire up button click handlers
|
// Wire up button click handlers
|
||||||
@ -249,10 +323,8 @@ export const demoFunc = () => {
|
|||||||
button.addEventListener('click', () => startRealtime());
|
button.addEventListener('click', () => startRealtime());
|
||||||
} else if (text === 'Stop Live') {
|
} else if (text === 'Stop Live') {
|
||||||
button.addEventListener('click', () => stopRealtime());
|
button.addEventListener('click', () => stopRealtime());
|
||||||
} else if (text === 'Randomize Values') {
|
} else if (text === 'Spike Values') {
|
||||||
button.addEventListener('click', () => randomizeData());
|
button.addEventListener('click', () => randomizeData());
|
||||||
} else if (text === 'Add Point') {
|
|
||||||
button.addEventListener('click', () => addRealtimeData());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -271,6 +343,18 @@ export const demoFunc = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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
|
// Update button states when dataset changes
|
||||||
const originalSwitchDataset = switchDataset;
|
const originalSwitchDataset = switchDataset;
|
||||||
const switchDatasetWithButtonUpdate = (name: string) => {
|
const switchDatasetWithButtonUpdate = (name: string) => {
|
||||||
@ -292,6 +376,27 @@ export const demoFunc = () => {
|
|||||||
button.addEventListener('click', () => switchDatasetWithButtonUpdate('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>
|
<style>
|
||||||
${css`
|
${css`
|
||||||
@ -342,23 +447,35 @@ export const demoFunc = () => {
|
|||||||
</dees-button-group>
|
</dees-button-group>
|
||||||
|
|
||||||
<dees-button-group label="Actions:">
|
<dees-button-group label="Actions:">
|
||||||
<dees-button>Randomize Values</dees-button>
|
<dees-button>Spike Values</dees-button>
|
||||||
<dees-button>Add Point</dees-button>
|
|
||||||
</dees-button-group>
|
</dees-button-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<dees-chart-area
|
<dees-chart-area
|
||||||
|
id="main-chart"
|
||||||
.label=${initialDatasets.system.label}
|
.label=${initialDatasets.system.label}
|
||||||
.series=${initialDatasets.system.series}
|
.series=${initialDatasets.system.series}
|
||||||
.yAxisFormatter=${initialFormatters.system}
|
.yAxisFormatter=${initialFormatters.system}
|
||||||
></dees-chart-area>
|
></dees-chart-area>
|
||||||
</div>
|
</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">
|
<div class="info">
|
||||||
Real-time updates work with System Usage and Network Traffic datasets •
|
Real-time monitoring with 2-minute rolling window •
|
||||||
Chart updates every 2 seconds when live mode is active •
|
Updates every second with smooth value transitions •
|
||||||
Try switching datasets and randomizing values
|
Click 'Spike Values' to simulate load spikes
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dees-demowrapper>
|
</dees-demowrapper>
|
||||||
|
@ -34,11 +34,33 @@ export class DeesChartArea extends DeesElement {
|
|||||||
@property({ type: Array })
|
@property({ type: Array })
|
||||||
public series: ApexAxisChartSeries = [];
|
public series: ApexAxisChartSeries = [];
|
||||||
|
|
||||||
|
// Override getter to return internal chart data
|
||||||
|
get chartSeries(): ApexAxisChartSeries {
|
||||||
|
return this.internalChartData.length > 0 ? this.internalChartData : this.series;
|
||||||
|
}
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public yAxisFormatter: (value: number) => string = (val) => `${val} Mbps`;
|
public yAxisFormatter: (value: number) => string = (val) => `${val} Mbps`;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public rollingWindow: number = 0; // 0 means no rolling window
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public realtimeMode: boolean = false;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public yAxisScaling: 'fixed' | 'dynamic' | 'percentage' = 'dynamic';
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public yAxisMax: number = 100; // Used when yAxisScaling is 'fixed' or 'percentage'
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public autoScrollInterval: number = 1000; // Auto-scroll interval in milliseconds (0 to disable)
|
||||||
|
|
||||||
private resizeObserver: ResizeObserver;
|
private resizeObserver: ResizeObserver;
|
||||||
private resizeTimeout: number;
|
private resizeTimeout: number;
|
||||||
|
private internalChartData: ApexAxisChartSeries = [];
|
||||||
|
private autoScrollTimer: number | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -73,6 +95,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
clearTimeout(this.resizeTimeout);
|
clearTimeout(this.resizeTimeout);
|
||||||
}
|
}
|
||||||
this.resizeObserver.disconnect();
|
this.resizeObserver.disconnect();
|
||||||
|
this.stopAutoScroll();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +196,9 @@ export class DeesChartArea extends DeesElement {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Store internal data
|
||||||
|
this.internalChartData = chartSeries;
|
||||||
|
|
||||||
var options: ApexCharts.ApexOptions = {
|
var options: ApexCharts.ApexOptions = {
|
||||||
series: chartSeries,
|
series: chartSeries,
|
||||||
chart: {
|
chart: {
|
||||||
@ -183,14 +209,14 @@ export class DeesChartArea extends DeesElement {
|
|||||||
show: false, // This line disables the toolbar
|
show: false, // This line disables the toolbar
|
||||||
},
|
},
|
||||||
animations: {
|
animations: {
|
||||||
enabled: true,
|
enabled: !this.realtimeMode, // Disable animations in realtime mode
|
||||||
speed: 400,
|
speed: 400,
|
||||||
animateGradually: {
|
animateGradually: {
|
||||||
enabled: false, // Disable gradual animation for cleaner updates
|
enabled: false, // Disable gradual animation for cleaner updates
|
||||||
delay: 0
|
delay: 0
|
||||||
},
|
},
|
||||||
dynamicAnimation: {
|
dynamicAnimation: {
|
||||||
enabled: true,
|
enabled: !this.realtimeMode,
|
||||||
speed: 350
|
speed: 350
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -205,10 +231,11 @@ export class DeesChartArea extends DeesElement {
|
|||||||
xaxis: {
|
xaxis: {
|
||||||
type: 'datetime', // Time-series data
|
type: 'datetime', // Time-series data
|
||||||
labels: {
|
labels: {
|
||||||
format: 'hh:mm A', // Time formatting
|
format: 'HH:mm:ss', // Time formatting with seconds
|
||||||
|
datetimeUTC: false,
|
||||||
style: {
|
style: {
|
||||||
colors: '#9e9e9e', // Label color
|
colors: '#9e9e9e', // Label color
|
||||||
fontSize: '12px',
|
fontSize: '11px',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
axisBorder: {
|
axisBorder: {
|
||||||
@ -220,6 +247,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
},
|
},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
min: 0,
|
min: 0,
|
||||||
|
max: this.yAxisScaling === 'dynamic' ? undefined : this.yAxisMax,
|
||||||
labels: {
|
labels: {
|
||||||
formatter: this.yAxisFormatter,
|
formatter: this.yAxisFormatter,
|
||||||
style: {
|
style: {
|
||||||
@ -313,6 +341,51 @@ export class DeesChartArea extends DeesElement {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle realtime mode changes
|
||||||
|
if (changedProperties.has('realtimeMode') && this.chart) {
|
||||||
|
await this.chart.updateOptions({
|
||||||
|
chart: {
|
||||||
|
animations: {
|
||||||
|
enabled: !this.realtimeMode,
|
||||||
|
speed: 400,
|
||||||
|
animateGradually: {
|
||||||
|
enabled: false,
|
||||||
|
delay: 0
|
||||||
|
},
|
||||||
|
dynamicAnimation: {
|
||||||
|
enabled: !this.realtimeMode,
|
||||||
|
speed: 350
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start/stop auto-scroll based on realtime mode
|
||||||
|
if (this.realtimeMode && this.rollingWindow > 0 && this.autoScrollInterval > 0) {
|
||||||
|
this.startAutoScroll();
|
||||||
|
} else {
|
||||||
|
this.stopAutoScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle auto-scroll interval changes
|
||||||
|
if (changedProperties.has('autoScrollInterval') && this.chart) {
|
||||||
|
this.stopAutoScroll();
|
||||||
|
if (this.realtimeMode && this.rollingWindow > 0 && this.autoScrollInterval > 0) {
|
||||||
|
this.startAutoScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle y-axis scaling changes
|
||||||
|
if ((changedProperties.has('yAxisScaling') || changedProperties.has('yAxisMax')) && this.chart) {
|
||||||
|
await this.chart.updateOptions({
|
||||||
|
yaxis: {
|
||||||
|
min: 0,
|
||||||
|
max: this.yAxisScaling === 'dynamic' ? undefined : this.yAxisMax
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateSeries(newSeries: ApexAxisChartSeries, animate: boolean = true) {
|
public async updateSeries(newSeries: ApexAxisChartSeries, animate: boolean = true) {
|
||||||
@ -320,8 +393,74 @@ export class DeesChartArea extends DeesElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the new data first
|
||||||
|
this.internalChartData = newSeries;
|
||||||
|
|
||||||
|
// Handle rolling window if enabled
|
||||||
|
if (this.rollingWindow > 0 && this.realtimeMode) {
|
||||||
|
const now = Date.now();
|
||||||
|
const cutoffTime = now - this.rollingWindow;
|
||||||
|
|
||||||
|
// Filter data to only include points within the rolling window
|
||||||
|
const filteredSeries = newSeries.map(series => ({
|
||||||
|
name: series.name,
|
||||||
|
data: (series.data as any[]).filter(point => {
|
||||||
|
if (typeof point === 'object' && point !== null && 'x' in point) {
|
||||||
|
return new Date(point.x).getTime() > cutoffTime;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Only update if we have data
|
||||||
|
if (filteredSeries.some(s => s.data.length > 0)) {
|
||||||
|
// Handle y-axis scaling first
|
||||||
|
if (this.yAxisScaling === 'dynamic') {
|
||||||
|
const allValues = filteredSeries.flatMap(s => (s.data as any[]).map(d => d.y));
|
||||||
|
if (allValues.length > 0) {
|
||||||
|
const maxValue = Math.max(...allValues);
|
||||||
|
const dynamicMax = Math.ceil(maxValue * 1.1);
|
||||||
|
await this.chart.updateOptions({
|
||||||
|
yaxis: {
|
||||||
|
min: 0,
|
||||||
|
max: dynamicMax
|
||||||
|
}
|
||||||
|
}, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chart.updateSeries(filteredSeries, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this.chart.updateSeries(newSeries, animate);
|
this.chart.updateSeries(newSeries, animate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New method to update just the x-axis for smooth scrolling
|
||||||
|
public async updateTimeWindow() {
|
||||||
|
if (!this.chart || this.rollingWindow <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const cutoffTime = now - this.rollingWindow;
|
||||||
|
|
||||||
|
await this.chart.updateOptions({
|
||||||
|
xaxis: {
|
||||||
|
min: cutoffTime,
|
||||||
|
max: now,
|
||||||
|
labels: {
|
||||||
|
format: 'HH:mm:ss',
|
||||||
|
datetimeUTC: false,
|
||||||
|
style: {
|
||||||
|
colors: '#9e9e9e',
|
||||||
|
fontSize: '11px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tickAmount: 6,
|
||||||
|
}
|
||||||
|
}, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
public async appendData(newData: { data: any[] }[]) {
|
public async appendData(newData: { data: any[] }[]) {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
@ -329,7 +468,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use ApexCharts' appendData method for smoother real-time updates
|
// Use ApexCharts' appendData method for smoother real-time updates
|
||||||
await this.chart.appendData(newData);
|
this.chart.appendData(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateOptions(options: ApexCharts.ApexOptions, redrawPaths?: boolean, animate?: boolean) {
|
public async updateOptions(options: ApexCharts.ApexOptions, redrawPaths?: boolean, animate?: boolean) {
|
||||||
@ -372,4 +511,21 @@ export class DeesChartArea extends DeesElement {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private startAutoScroll() {
|
||||||
|
if (this.autoScrollTimer) {
|
||||||
|
return; // Already running
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autoScrollTimer = window.setInterval(() => {
|
||||||
|
this.updateTimeWindow();
|
||||||
|
}, this.autoScrollInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopAutoScroll() {
|
||||||
|
if (this.autoScrollTimer) {
|
||||||
|
window.clearInterval(this.autoScrollTimer);
|
||||||
|
this.autoScrollTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user