00006 graph 창 변수 dbc 선택 유지

graph 페이지에서 변수를 선택하고 start 누를 시 그래프 표출을 또다른 창 이동해서 표현하는 것이 나을 것 같아 그리고 선택한 변수들은 다른 페이지 이동해도 선택이 리셋되지 않게 선택한변수들을 유지하게 해줘
This commit is contained in:
2025-10-06 17:08:25 +00:00
parent 3af955852a
commit 1bf6186305
4 changed files with 586 additions and 55 deletions

148
graph.h
View File

@@ -206,8 +206,12 @@ const char graph_html[] PROGMEM = R"rawliteral(
<div id="signal-list" class="signal-grid"></div>
</div>
<h2>Real-time Graphs</h2>
<div id="graphs"></div>
<div style="background: #e3f2fd; padding: 15px; border-radius: 8px; margin-top: 15px; border-left: 4px solid #185a9d;">
<p style="color: #333; font-size: 0.9em; margin: 0;">
<strong> Info:</strong> Click "Start" to open a new window with real-time graphs.
Your selected signals will be saved automatically.
</p>
</div>
</div>
</div>
</div>
@@ -518,6 +522,9 @@ const char graph_html[] PROGMEM = R"rawliteral(
}
document.getElementById('signal-section').style.display = 'block';
// 저장된 선택 복원
setTimeout(() => loadSelectedSignals(), 100);
}
function toggleSignal(signal, element) {
@@ -535,6 +542,9 @@ const char graph_html[] PROGMEM = R"rawliteral(
selectedSignals.push(signal);
element.classList.add('selected');
}
// 선택한 신호 저장
saveSelectedSignals();
}
function clearSelection() {
@@ -542,6 +552,69 @@ const char graph_html[] PROGMEM = R"rawliteral(
document.querySelectorAll('.signal-item').forEach(item => {
item.classList.remove('selected');
});
// 저장된 선택 삭제
saveSelectedSignals();
}
// 선택한 신호를 localStorage에 저장
function saveSelectedSignals() {
try {
localStorage.setItem('selected_signals', JSON.stringify(selectedSignals));
console.log('Saved', selectedSignals.length, 'signals');
} catch(e) {
console.error('Failed to save selected signals:', e);
}
}
// localStorage에서 선택한 신호 복원
function loadSelectedSignals() {
try {
const saved = localStorage.getItem('selected_signals');
if (saved) {
const signals = JSON.parse(saved);
// 신호 목록이 표시된 후에 선택 상태 복원
signals.forEach(savedSignal => {
// DBC에 해당 신호가 있는지 확인
let found = false;
for (let msgId in dbcData.messages) {
const msg = dbcData.messages[msgId];
const signal = msg.signals.find(s =>
s.messageId === savedSignal.messageId && s.name === savedSignal.name);
if (signal) {
selectedSignals.push(signal);
found = true;
break;
}
}
});
// UI 업데이트
document.querySelectorAll('.signal-item').forEach(item => {
const signalName = item.querySelector('.signal-name').textContent;
const signalInfo = item.querySelector('.signal-info').textContent;
const idMatch = signalInfo.match(/ID: 0x([0-9A-F]+)/);
if (idMatch) {
const msgId = parseInt(idMatch[1], 16);
const isSelected = selectedSignals.some(s =>
s.messageId === msgId && s.name === signalName);
if (isSelected) {
item.classList.add('selected');
}
}
});
if (selectedSignals.length > 0) {
showStatus('Restored ' + selectedSignals.length + ' selected signals', 'success');
}
}
} catch(e) {
console.error('Failed to load selected signals:', e);
}
}
function startGraphing() {
@@ -550,67 +623,34 @@ const char graph_html[] PROGMEM = R"rawliteral(
return;
}
graphing = true;
startTime = Date.now(); // 시작 시간 기록
createGraphs();
showStatus('Graphing ' + selectedSignals.length + ' signals', 'success');
// 선택한 신호 저장 (새 창에서 사용)
saveSelectedSignals();
// 새 창 열기
const width = 1200;
const height = 800;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
window.open(
'/graph-view',
'CAN_Graph_Viewer',
'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',resizable=yes,scrollbars=yes'
);
showStatus('Graph viewer opened in new window', 'success');
}
function stopGraphing() {
graphing = false;
showStatus('Stopped', 'success');
showStatus('Use the stop button in the graph viewer window', 'error');
}
function createGraphs() {
const graphsDiv = document.getElementById('graphs');
graphsDiv.innerHTML = '';
charts = {};
selectedSignals.forEach((signal, index) => {
const container = document.createElement('div');
container.className = 'graph-container';
const canvas = document.createElement('canvas');
canvas.id = 'chart-' + index;
container.innerHTML =
'<div class="graph-header">' +
'<div class="graph-title">' + signal.name + ' (0x' + signal.messageId.toString(16).toUpperCase() + ')' +
(signal.unit ? ' [' + signal.unit + ']' : '') + '</div>' +
'<div class="graph-value" id="value-' + index + '">-</div>' +
'</div>';
container.appendChild(canvas);
graphsDiv.appendChild(container);
charts[index] = new SimpleChart(canvas, signal, index);
});
// 이 함수는 새 창에서 사용됨
}
function processCANData(messages) {
// 경과 시간 계산 (초 단위, 소수점 1자리)
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(1);
messages.forEach(canMsg => {
const idStr = canMsg.id.replace(/\s/g, '').toUpperCase();
const msgId = parseInt(idStr, 16);
selectedSignals.forEach((signal, index) => {
if (signal.messageId === msgId && charts[index]) {
try {
const value = decodeSignal(signal, canMsg.data);
charts[index].addData(value, elapsedTime);
const valueDiv = document.getElementById('value-' + index);
if (valueDiv) {
valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : '');
}
} catch(e) {
console.error('Error decoding signal', signal.name, ':', e);
}
}
});
});
// 이 함수는 새 창에서 사용됨
}
function decodeSignal(signal, hexData) {