如何为Google Charts表格图表设置计算得出的日期范围初始状态
Google Visualization DateRangeFilter 初始状态设置与持久化方案
问题核心
当前代码无法正确设置DateRangeFilter的初始状态,原因是直接将拼接的字符串赋值给state属性——字符串无法被解析为包含实际Date对象的有效状态对象,且存储格式不符合JSON规范(使用单引号而非双引号)。
修复存储与读取逻辑
1. 正确存储状态
避免手动拼接字符串,将日期转换为时间戳后序列化为标准JSON格式存入存储:
// 计算目标日期 const iLowD = new Date(2000, 1, 11); const iHiD = new Date(2022, 1, 1); // 封装为可序列化的状态对象 const filterState = { lowValue: iLowD.getTime(), highValue: iHiD.getTime() }; // 存入sessionStorage(或替换为localStorage实现持久化) sessionStorage.setItem('catPicker', JSON.stringify(filterState));
2. 正确读取并转换状态
读取存储的JSON字符串后,将时间戳转回Date对象,再传入控件的state属性:
// 读取存储的状态 const storedState = sessionStorage.getItem('catPicker'); let initialState = null; if (storedState) { const parsed = JSON.parse(storedState); initialState = { lowValue: new Date(parsed.lowValue), highValue: new Date(parsed.highValue) }; }
setState方法的正确调用时机
若需动态设置初始状态,优先在ControlWrapper初始化时传入解析后的state对象,这样仪表盘第一次绘制就会应用初始状态,用户后续仍可正常调整控件:
const slider = new google.visualization.ControlWrapper({ controlType: 'DateRangeFilter', containerId: 'control', options: { filterColumnLabel: 'Year', ui: { format: { pattern: 'yyyy' } } }, state: initialState // 直接传入有效状态对象 });
如果需要在仪表盘绘制后动态调整状态,可在绘制完成后调用setState并重新绘制:
dashboard.draw(data); if (initialState) { slider.setState(initialState); dashboard.draw(data); // 重新绘制应用新状态 }
切换到localStorage实现持久化
只需将sessionStorage替换为localStorage,用户设置的状态会被永久保存(除非手动清除浏览器存储):
// 存储状态 localStorage.setItem('catPicker', JSON.stringify(filterState)); // 读取状态 const storedState = localStorage.getItem('catPicker');
完整示例代码
JavaScript部分
google.charts.load('current', {packages:['table', 'controls']}); google.charts.setOnLoadCallback(drawVisualization); function drawVisualization() { // 准备图表数据 const data = google.visualization.arrayToDataTable([ ['Extrasolar planet', 'Comment', 'Year'], ['Gamma Cephei Ab', 'Deduced from radial velocity variations of the star Gamma Cephei', new Date(1988, 6, 13)], ['HD 114762 b', 'At least 11 times the mass of Jupiter', new Date(1989, 4, 4)], ['PSR B1257+12', 'First confirmed discovery of an extrasolar planet', new Date(1992, 0, 22)], ['51 Pegasi b', 'Hot Jupiter with a 4.2 day orbit', new Date(1995, 9, 6)], ['47 Ursae Majoris b', 'First long-period planet discovered', new Date(1996, 0, 17)], ['Upsilon Andromedae', 'First multiple planetary system around a main sequence star', new Date(1996, 7, 12)], ['Gliese 876 b', 'First planet found orbiting a red dwarf', new Date(1998, 5, 23)], ['HD 209458 b', 'First exoplanet seen transiting its parent star', new Date(1999, 10, 5)], ['Iota Draconis b', 'Provided evidence that planets can exist around giant stars', new Date(2002, 0, 8)], ['PSR B1620-26 b', '12.7 billion year old planet orbiting a binary star system', new Date(2003, 6, 10)], ['2M1207 b', 'First planet found orbiting a brown dwarf', new Date(2004, 6, 22)], ['Mu Arae c', 'Hot Neptune', new Date(2004, 7, 25)], ['TrES-1 and HD 209458 b', 'First detection of light from exoplanets', new Date(2005, 2, 22)], ['OGLE-2005-BLG-390Lb', 'Detected used gravitational microlensing', new Date(2006, 1, 25)], ['Gliese 581 c', 'Inhospitable due to runaway greenhouse effect', new Date(2007, 3, 4)], ['Fomalhaut b', 'First exoplanet directly imaged by optical telescope', new Date(2008, 10, 13)], ['GJ 1214 b', 'Might be 75% water and 25% rock', new Date(2009, 11, 16)], ['HD 10180', 'Seven planets orbiting a sun-like star', new Date(2010, 7, 24)], ['55 Cancri e', 'Orbital period of just 0.73 days', new Date(2011, 3, 27)], ['Alpha Centauri Bb', 'Earth-mass planet in the star system closest to ours', new Date(2012, 9, 16)], ['PH2 b', 'Potentially habitable Jupiter-sized planet', new Date(2013, 0, 13)], ['Kepler-69c', 'First potentially habitable Earth-sized planet orbiting a sun-sized star', new Date(2013, 3, 18)] ]); // 读取并解析存储的状态 const storedState = sessionStorage.getItem('catPicker'); let initialState = null; if (storedState) { const parsed = JSON.parse(storedState); initialState = { lowValue: new Date(parsed.lowValue), highValue: new Date(parsed.highValue) }; } // 创建日期范围筛选控件 const slider = new google.visualization.ControlWrapper({ controlType: 'DateRangeFilter', containerId: 'control', options: { filterColumnLabel: 'Year', ui: { format: { pattern: 'yyyy' } } }, state: initialState }); // 创建表格图表 const tableChart = new google.visualization.ChartWrapper({ chartType: 'Table', containerId: 'chart', options: { width: '100%', height: '100%', chartArea: {top: 0, right: 0, bottom: 0} } }); // 创建并绘制仪表盘 const dashboard = new google.visualization.Dashboard(document.getElementById('daterange_div')); dashboard.bind(slider, tableChart); dashboard.draw(data); // 可选:实时保存用户调整后的状态到localStorage google.visualization.events.addListener(slider, 'statechange', () => { const currentState = slider.getState(); const saveState = { lowValue: currentState.lowValue.getTime(), highValue: currentState.highValue.getTime() }; localStorage.setItem('catPicker', JSON.stringify(saveState)); }); }
HTML部分
<div id="daterange_div" style="border: 0px solid #ccc"> <div id="control" style="padding-left: 2em"></div> <div id="chart"></div> </div>
额外说明
- 使用时间戳存储日期是因为JSON无法序列化原生Date对象,时间戳是跨会话存储日期最可靠的方式。
- 监听
statechange事件可实时保存用户调整后的状态,下次打开页面时自动恢复设置。
内容的提问来源于stack exchange,提问作者Brian Sherwood
相关产品推荐
相关产品推荐

