如何为Google Timeline图表动态添加数据?餐厅预订系统开发求助
解决Google Timeline Chart添加餐厅预订数据的问题
我来帮你梳理下当前代码的问题,并且给出可行的解决方案,让你能顺利实现点击添加预订到时间线的功能:
现有代码的核心问题
你的代码目前有几个关键问题导致添加功能无法正常工作:
dataTable和chart是drawChart函数的局部变量,addPrenotazione函数无法访问它们,调用时会抛出未定义错误- 直接用表单获取的日期字符串创建
Date对象可能存在兼容性问题,需要统一格式处理 - 添加新数据后没有重新绘制图表,时间线不会自动更新
- 隐藏零宽度条的逻辑没有绑定到图表的就绪事件,可能在图表未渲染完成时执行,导致找不到元素
修正后的完整代码
首先需要补充对应的表单HTML结构,然后修改JavaScript逻辑:
HTML 表单与图表容器
<!-- 预订表单 --> <div class="reservation-form"> <label>选择餐桌:</label> <select id="tavolo"> <option value="1">Tavolo 1</option> <option value="2">Tavolo 2</option> <option value="3">Tavolo 3</option> <option value="4">Tavolo 4</option> <option value="5">Tavolo 5</option> <option value="6">Tavolo 6</option> <option value="7">Tavolo 7</option> <option value="8">Tavolo 8</option> <option value="9">Tavolo 9</option> </select> <label>开始时间:</label> <input type="datetime-local" id="datainizio" required> <label>结束时间:</label> <input type="datetime-local" id="datafine" required> <button onclick="addPrenotazione()">添加预订</button> </div> <!-- 时间线图表容器 --> <div id="timeline" style="height: 400px; margin-top: 20px;"></div>
修正后的JavaScript代码
<script type="text/javascript"> // 把dataTable和chart提升到全局作用域,让添加函数能访问 let dataTable; let chart; google.charts.load("current", { packages: ["timeline"] }); google.charts.setOnLoadCallback(drawChart); function drawChart() { const container = document.getElementById('timeline'); chart = new google.visualization.Timeline(container); dataTable = new google.visualization.DataTable(); dataTable.addColumn({ type: 'string', id: 'Tavolo' }); dataTable.addColumn({ type: 'date', id: 'Start' }); dataTable.addColumn({ type: 'date', id: 'End' }); // 初始预订数据 dataTable.addRows([ ['Tavolo 1', new Date(0, 0, 0, 12, 00, 0), new Date(0, 0, 0, 12, 00, 0)], ['Tavolo 2', new Date(0, 0, 0, 12, 00, 0), new Date(0, 0, 0, 12, 00, 0)], ['Tavolo 3', new Date(0, 0, 0, 12, 30, 0), new Date(0, 0, 0, 14, 0, 0)], ['Tavolo 3', new Date(0, 0, 0, 14, 30, 0), new Date(0, 0, 0, 16, 0, 0)], ['Tavolo 3', new Date(0, 0, 0, 16, 30, 0), new Date(0, 0, 0, 18, 0, 0)], ['Tavolo 4', new Date(0, 0, 0, 14, 30, 0), new Date(0, 0, 0, 16, 0, 0)], ['Tavolo 4', new Date(0, 0, 0, 16, 30, 0), new Date(0, 0, 0, 18, 0, 0)], ['Tavolo 5', new Date(0, 0, 0, 12, 0, 0), new Date(0, 0, 0, 13, 30, 0)], ['Tavolo 6', new Date(0, 0, 0, 14, 0, 0), new Date(0, 0, 0, 15, 30, 0)], ['Tavolo 7', new Date(0, 0, 0, 12, 30, 0), new Date(0, 0, 0, 14, 0, 0)], ['Tavolo 8', new Date(0, 0, 0, 14, 30, 0), new Date(0, 0, 0, 16, 0, 0)], ['Tavolo 8', new Date(0, 0, 0, 16, 30, 0), new Date(0, 0, 0, 18, 0, 0)], ['Tavolo 9', new Date(0, 0, 0, 14, 30, 0), new Date(0, 0, 0, 16, 0, 0)] ]); const options = { timeline: { singleColor: '#ff0000' } }; // 绑定图表就绪事件,确保渲染完成后再处理零宽度条 google.visualization.events.addListener(chart, 'ready', function() { const el = container.getElementsByTagName("rect"); let minWidth = Infinity; const elToRem = []; for (let i = 0; i < el.length; i++) { const cwidth = parseInt(el[i].getAttribute("width")); if (cwidth < minWidth) { elToRem.length = 0; // 清空数组,记录最小宽度的元素 elToRem.push(el[i]); minWidth = cwidth; } else if (cwidth === minWidth) { elToRem.push(el[i]); } } elToRem.forEach(element => { element.setAttribute("fill", "none"); }); }); chart.draw(dataTable, options); } function addPrenotazione() { // 获取表单值 const tavoloNum = $("#tavolo").val(); const startStr = $("#datainizio").val(); const endStr = $("#datafine").val(); // 处理日期格式:把datetime-local的字符串转成Date对象 const startTime = new Date(startStr); const endTime = new Date(endStr); // 验证时间有效性 if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) { alert("请选择有效的开始和结束时间"); return; } // 添加新行到数据表格 dataTable.addRows([ [`Tavolo ${tavoloNum}`, startTime, endTime] ]); // 重新绘制图表 chart.draw(dataTable, { timeline: { singleColor: '#ff0000' } }); // --- 后续数据库操作可以在这里添加 --- // 示例:用AJAX把数据发送到后端保存 /* $.ajax({ url: '/api/save-reservation', method: 'POST', data: { tableNumber: tavoloNum, startTime: startTime.toISOString(), endTime: endTime.toISOString() }, success: function(response) { console.log("预订已成功保存到数据库"); }, error: function(err) { console.error("保存预订失败:", err); } }); */ } </script>
关键修改说明
- 全局变量声明:把
dataTable和chart移到全局作用域,确保添加函数能访问到图表实例和数据表格 - 图表就绪事件:将隐藏零宽度条的逻辑绑定到
ready事件,避免图表未渲染完成时执行导致的元素找不到问题 - 日期处理与验证:针对
datetime-local类型的输入框做了格式转换,并添加了时间有效性校验 - 重新渲染图表:添加新数据后调用
chart.draw(),确保时间线实时更新 - 数据库操作预留:添加了AJAX保存数据的示例代码,你可以根据后端接口调整参数和路径
页面加载时从数据库读取数据的思路
在drawChart函数初始化时,先通过AJAX请求后端接口获取已有的预订数据,再填充到dataTable中:
function drawChart() { const container = document.getElementById('timeline'); chart = new google.visualization.Timeline(container); dataTable = new google.visualization.DataTable(); dataTable.addColumn({ type: 'string', id: 'Tavolo' }); dataTable.addColumn({ type: 'date', id: 'Start' }); dataTable.addColumn({ type: 'date', id: 'End' }); // 先从数据库加载已有预订数据 $.ajax({ url: '/api/get-reservations', method: 'GET', success: function(reservations) { // 转换后端返回的数据格式 const rows = reservations.map(res => [ `Tavolo ${res.tableNumber}`, new Date(res.startTime), new Date(res.endTime) ]); dataTable.addRows(rows); // 绘制图表 const options = { timeline: { singleColor: '#ff0000' } }; google.visualization.events.addListener(chart, 'ready', function() { // 隐藏零宽度条的逻辑... }); chart.draw(dataTable, options); }, error: function(err) { console.error("加载预订数据失败:", err); // 加载失败时用初始数据绘制图表 dataTable.addRows([/* 初始数据 */]); chart.draw(dataTable, options); } }); }
内容的提问来源于stack exchange,提问作者NiceToMytyuk
相关产品推荐
相关产品推荐

