diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 6ba44ec..8d22ca3 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/XNSimHtml/components/FloatingChartWindow.js b/XNSimHtml/components/FloatingChartWindow.js index 554e2da..630b869 100644 --- a/XNSimHtml/components/FloatingChartWindow.js +++ b/XNSimHtml/components/FloatingChartWindow.js @@ -198,10 +198,6 @@ class FloatingChartWindow extends HTMLElement { flex-direction: column; } - .window-content.minimized { - display: none; - } - .chart-container { flex: 1; position: relative; @@ -240,7 +236,6 @@ class FloatingChartWindow extends HTMLElement {
${this.getAttribute('title') || '图表窗口'}
-
@@ -364,6 +359,16 @@ class FloatingChartWindow extends HTMLElement { } }; + // 确保数据集配置正确 + if (chartData.datasets && chartData.datasets.length > 0) { + chartData.datasets = chartData.datasets.map(dataset => ({ + ...dataset, + borderWidth: 2, + pointRadius: 0, + tension: 0 + })); + } + this.chartInstance = new Chart(ctx, { type: 'line', data: chartData, @@ -373,12 +378,10 @@ class FloatingChartWindow extends HTMLElement { addEventListeners() { const header = this.shadowRoot.querySelector('.window-header'); - const minimizeButton = this.shadowRoot.querySelector('.minimize-button'); const closeButton = this.shadowRoot.querySelector('.close-button'); const resizeHandle = this.shadowRoot.querySelector('.resize-handle'); header.addEventListener('mousedown', this.handleMouseDown); - minimizeButton.addEventListener('click', this.handleMinimize); closeButton.addEventListener('click', this.handleClose); resizeHandle.addEventListener('mousedown', this.handleResizeStart); @@ -394,7 +397,7 @@ class FloatingChartWindow extends HTMLElement { handleMouseDown(e) { // 检查点击是否在标题栏或其子元素上 const header = this.shadowRoot.querySelector('.window-header'); - if (header && (e.target === header || header.contains(e.target)) && !this.isMinimized) { + if (header && (e.target === header || header.contains(e.target))) { this.isDragging = true; this.dragOffset = { x: e.clientX - this.position.x, @@ -420,7 +423,7 @@ class FloatingChartWindow extends HTMLElement { y: Math.max(minY, e.clientY - this.dragOffset.y) }; this.updatePosition(); - } else if (this.isResizing && !this.isMinimized) { + } else if (this.isResizing) { const deltaX = e.clientX - this.resizeStart.x; const deltaY = e.clientY - this.resizeStart.y; @@ -452,7 +455,7 @@ class FloatingChartWindow extends HTMLElement { } handleResize(e) { - if (this.isResizing && !this.isMinimized) { + if (this.isResizing) { const deltaX = e.clientX - this.resizeStart.x; const deltaY = e.clientY - this.resizeStart.y; @@ -546,6 +549,38 @@ class FloatingChartWindow extends HTMLElement { // 始终使用普通数字格式,保留一位小数 return `${context.dataset.label}: ${value.toFixed(1)}`; }; + + // 计算所有数据点的范围 + let min = Infinity; + let max = -Infinity; + + data.datasets.forEach(dataset => { + if (dataset.data && dataset.data.length > 0) { + const datasetMin = Math.min(...dataset.data); + const datasetMax = Math.max(...dataset.data); + min = Math.min(min, datasetMin); + max = Math.max(max, datasetMax); + } + }); + + if (min !== Infinity && max !== -Infinity) { + const range = max - min; + // 如果所有数据都是0,使用固定范围 + if (min === 0 && max === 0) { + options.scales.y.min = -1; + options.scales.y.max = 1; + } + // 如果范围很小,使用固定比例 + else if (range < 1) { + options.scales.y.min = min - 0.5; + options.scales.y.max = max + 0.5; + } else { + // 如果范围较大,使用百分比 + const margin = range * 0.2; // 使用20%的边距 + options.scales.y.min = min - margin; + options.scales.y.max = max + margin; + } + } // 更新图表 this.chartInstance.update('none'); @@ -565,6 +600,70 @@ class FloatingChartWindow extends HTMLElement { window.style.zIndex = zIndex; } } + + // 添加新方法:处理数据更新 + handleDataUpdate(values, interfaceName) { + if (!this.chartInstance) return; + + const chartData = this.chartInstance.data; + + // 如果是第一次收到数据,创建数据集 + if (chartData.datasets.length === 0) { + if (values.length > 1) { + // 创建多个数据集 + chartData.datasets = values.map((_, index) => ({ + label: `${interfaceName} (${index + 1})`, + data: [], + borderColor: this.getRandomColor(), + fill: false, + borderWidth: 2, + pointRadius: 0, + tension: 0 + })); + } else { + // 创建单个数据集 + chartData.datasets = [{ + label: interfaceName, + data: [], + borderColor: this.getRandomColor(), + fill: false, + borderWidth: 2, + pointRadius: 0, + tension: 0 + }]; + } + } + + // 添加新的数据点 + chartData.labels.push(this.dataPointIndex.toString()); + values.forEach((value, index) => { + if (index < chartData.datasets.length) { + chartData.datasets[index].data.push(value); + } + }); + this.dataPointIndex++; + + // 保持最近100个数据点 + if (chartData.labels.length > 100) { + chartData.labels.shift(); + chartData.datasets.forEach(dataset => { + dataset.data.shift(); + }); + } + + // 更新图表 + this.updateChartData(chartData); + } + + // 添加新方法:获取随机颜色 + getRandomColor() { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + } } customElements.define('floating-chart-window', FloatingChartWindow); \ No newline at end of file diff --git a/XNSimHtml/components/data-monitor.js b/XNSimHtml/components/data-monitor.js index 73b4b4c..5a955c7 100644 --- a/XNSimHtml/components/data-monitor.js +++ b/XNSimHtml/components/data-monitor.js @@ -366,6 +366,7 @@ class DataMonitor extends HTMLElement { } const groupedInterfaces = this.getGroupedInterfaces(); + const allData = {}; // 存储所有结构体的数据 // 对每个结构体启动监控并获取数据 for (const [structName, interfaceNames] of Object.entries(groupedInterfaces)) { @@ -403,13 +404,18 @@ class DataMonitor extends HTMLElement { throw new Error(`获取监控数据失败: 返回数据为空`); } - // 更新表格数据 - this.updateTableData(responseData.data); + // 合并数据 + Object.assign(allData, responseData.data); } catch (structError) { console.error(`处理结构体 ${structName} 时出错:`, structError); continue; } } + + // 一次性更新所有数据 + if (Object.keys(allData).length > 0) { + this.updateTableData(allData); + } } catch (error) { console.error('数据更新失败:', error); this.stopDataUpdateTimer(); @@ -488,7 +494,12 @@ class DataMonitor extends HTMLElement { * @param {string} modelStructName - 结构体名称 */ async handlePlot(interfaceName, modelStructName) { - + // 检查监控状态 + const statusIndicator = this.shadowRoot.getElementById('statusIndicator'); + if (!statusIndicator || !statusIndicator.classList.contains('active')) { + return; // 如果不在监控状态,直接返回 + } + // 检查是否已经存在该接口的图表窗口 const windowId = `${interfaceName}_${modelStructName}`; if (this.chartWindows.has(windowId)) { @@ -506,12 +517,7 @@ class DataMonitor extends HTMLElement { // 创建图表数据 const chartData = { labels: [], - datasets: [{ - label: interfaceName, - data: [], - borderColor: this.getRandomColor(), - fill: false - }] + datasets: [] }; // 创建图表配置 @@ -530,6 +536,7 @@ class DataMonitor extends HTMLElement { scales: { y: { beginAtZero: false, + display: true, ticks: { callback: function(value) { // 如果数值的绝对值大于1000或小于0.1,使用科学计数法 @@ -567,11 +574,7 @@ class DataMonitor extends HTMLElement { callbacks: { label: function(context) { const value = context.raw; - // 如果数值的绝对值大于1000或小于0.1,使用科学计数法 - if (Math.abs(value) > 1000 || (Math.abs(value) < 0.1 && value !== 0)) { - return `${context.dataset.label}: ${value.toExponential(1)}`; - } - // 否则使用普通数字,保留一位小数 + // 始终使用普通数字格式,保留一位小数 return `${context.dataset.label}: ${value.toFixed(1)}`; } } @@ -594,7 +597,7 @@ class DataMonitor extends HTMLElement { // 再设置属性 floatingWindow.setAttribute('title', interfaceName); - floatingWindow.setAttribute('initial-position', JSON.stringify({ x: 400, y: 200 })); // 调整初始位置 + floatingWindow.setAttribute('initial-position', JSON.stringify({ x: 400, y: 200 })); floatingWindow.setAttribute('initial-size', JSON.stringify({ width: 400, height: 300 })); floatingWindow.setAttribute('chart-data', JSON.stringify(chartData)); floatingWindow.setAttribute('chart-options', JSON.stringify(chartOptions)); @@ -608,42 +611,26 @@ class DataMonitor extends HTMLElement { if (row && row.monitorData) { try { - const data = JSON.parse(row.monitorData); - let value; - // 处理数值类型 - if (typeof data === 'number') { - value = data; - } else if (typeof data === 'object') { - value = JSON.stringify(data); + const data = row.monitorData; + let values = []; + + // 尝试解析数据 + if (typeof data === 'string' && data.includes(',')) { + // 如果是逗号分隔的字符串,分割并转换为数字 + values = data.split(',').map(v => parseFloat(v.trim())); + } else if (typeof data === 'number') { + // 如果是单个数字 + values = [data]; } else { // 尝试将字符串转换为数字 const numValue = parseFloat(data); - value = isNaN(numValue) ? data : numValue; - } - - // 使用独立的数据点计数器 - chartData.labels.push(floatingWindow.dataPointIndex.toString()); - chartData.datasets[0].data.push(value); - floatingWindow.dataPointIndex++; // 增加计数器 - - // 保持最近100个数据点 - if (chartData.labels.length > 100) { - chartData.labels.shift(); - chartData.datasets[0].data.shift(); + values = isNaN(numValue) ? [] : [numValue]; } - // 如果是第一个数据点,设置y轴范围 - if (chartData.datasets[0].data.length === 1 && typeof value === 'number') { - // 计算合适的y轴范围 - const range = Math.abs(value) * 0.2; // 使用20%的范围 - chartOptions.scales.y.min = value - range; - chartOptions.scales.y.max = value + range; - // 更新图表配置 - floatingWindow.setAttribute('chart-options', JSON.stringify(chartOptions)); + // 如果数据有效,更新图表 + if (values.length > 0) { + floatingWindow.handleDataUpdate(values, interfaceName); } - - // 更新图表数据 - floatingWindow.setAttribute('chart-data', JSON.stringify(chartData)); } catch (e) { console.error('解析数据失败:', e); } @@ -671,6 +658,10 @@ class DataMonitor extends HTMLElement { } render() { + // 获取当前监控状态 + const statusIndicator = this.shadowRoot.getElementById('statusIndicator'); + const isMonitoring = statusIndicator && statusIndicator.classList.contains('active'); + // 按ModelStructName分组 const groupedInterfaces = this.filteredInterfaces.reduce((groups, item) => { const group = groups[item.ModelStructName] || []; @@ -1043,7 +1034,8 @@ class DataMonitor extends HTMLElement { - ${this.tableData.map(row => ` + ${this.tableData.map(row => ` + ${row.InterfaceName} ${row.ModelStructName} ${this.formatMonitorData(row.monitorData)}