You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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>

关键修改说明

  1. 全局变量声明:把dataTable和chart移到全局作用域,确保添加函数能访问到图表实例和数据表格
  2. 图表就绪事件:将隐藏零宽度条的逻辑绑定到ready事件,避免图表未渲染完成时执行导致的元素找不到问题
  3. 日期处理与验证:针对datetime-local类型的输入框做了格式转换,并添加了时间有效性校验
  4. 重新渲染图表:添加新数据后调用chart.draw(),确保时间线实时更新
  5. 数据库操作预留:添加了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:48:57