Files
Timeline_Generator/test_classic_timeline.html
beabigegg 2d37d23bcf v9.5: 實作標籤完全不重疊算法
- 新增 _calculate_lane_conflicts_v2() 分開返回標籤重疊和線穿框分數
- 修改泳道選擇算法,優先選擇無標籤重疊的泳道
- 兩階段搜尋:優先側別無可用泳道則嘗試另一側
- 增強日誌輸出,顯示標籤範圍和詳細衝突分數

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 11:35:29 +08:00

143 lines
4.5 KiB
HTML

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>經典時間軸測試</title>
<script src="https://cdn.plot.ly/plotly-2.26.0.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: #333;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
}
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
button {
background: #667EEA;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}
button:hover {
background: #5568d3;
}
#timeline {
margin-top: 20px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
</head>
<body>
<h1>經典時間軸渲染器測試</h1>
<div>
<button onclick="loadDemo('project')">載入專案時間軸</button>
<button onclick="loadDemo('life')">載入個人履歷</button>
<button onclick="loadDemo('roadmap')">載入產品路線圖</button>
<button onclick="clearTimeline()">清空</button>
</div>
<div id="status"></div>
<div id="timeline"></div>
<script>
const API_BASE = 'http://localhost:8000/api';
async function showStatus(message, isError = false) {
const statusDiv = document.getElementById('status');
statusDiv.className = 'status ' + (isError ? 'error' : 'success');
statusDiv.textContent = message;
}
async function loadDemo(type) {
try {
showStatus('載入中...');
// 清空現有事件
await fetch(`${API_BASE}/events`, { method: 'DELETE' });
// 選擇檔案
const files = {
'project': 'demo_project_timeline.csv',
'life': 'demo_life_events.csv',
'roadmap': 'demo_product_roadmap.csv'
};
const filename = files[type];
// 讀取檔案
const fileResponse = await fetch(`/examples/${filename}`);
const blob = await fileResponse.blob();
// 上傳檔案
const formData = new FormData();
formData.append('file', blob, filename);
const importResponse = await fetch(`${API_BASE}/import`, {
method: 'POST',
body: formData
});
const importResult = await importResponse.json();
showStatus(`匯入成功:${importResult.data.count} 筆事件`);
// 渲染時間軸
const renderResponse = await fetch(`${API_BASE}/render`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
direction: 'horizontal',
theme: 'modern',
show_grid: true,
enable_zoom: true,
enable_drag: true
})
});
const renderResult = await renderResponse.json();
if (renderResult.success) {
// 顯示 Plotly 圖表
Plotly.newPlot('timeline',
renderResult.data.data,
renderResult.layout,
renderResult.config
);
showStatus(`成功渲染 ${filename}`);
} else {
showStatus(`渲染失敗: ${renderResult.message}`, true);
}
} catch (error) {
showStatus(`錯誤: ${error.message}`, true);
console.error(error);
}
}
async function clearTimeline() {
try {
await fetch(`${API_BASE}/events`, { method: 'DELETE' });
document.getElementById('timeline').innerHTML = '';
showStatus('已清空');
} catch (error) {
showStatus(`錯誤: ${error.message}`, true);
}
}
</script>
</body>
</html>