DC.js图表过滤时添加加载GIF的实现问题
解决DC.js仪表板的全局过滤监听与加载GIF显示问题
嘿,我来帮你搞定DC.js里这两个头疼的问题——全局监听所有图表的过滤操作,还有加载GIF显示不出来的bug!
一、全局监听所有图表的过滤操作
你说得对,直接用dc.on('filtered')确实行不通,因为DC.js的filtered事件是跟单个图表实例绑定的,不是全局的。不过咱们可以耍点小聪明,遍历所有已经注册的图表,批量绑定事件,省得一个个手动加:
// 获取所有已注册的DC.js图表 const allCharts = dc.chartRegistry.list(); allCharts.forEach(chart => { chart.on('filtered', (chartInstance, filter) => { // 这里写你全局的过滤处理逻辑,比如立刻显示加载GIF $('#please-wait').css("display","block"); console.log(`图表${chartInstance.chartName()}触发了过滤,过滤值:`, filter); }); });
要是你之后还会新增图表,不想每次都重复绑定,可以监听dc.chartRegistry的registered事件,给新注册的图表自动加上监听:
dc.chartRegistry.on('registered', (chart) => { chart.on('filtered', (chartInstance, filter) => { $('#please-wait').css("display","block"); console.log(`新图表${chartInstance.chartName()}触发了过滤`, filter); }); });
二、修复加载GIF无法显示的问题
你碰到的核心问题是:过滤和重绘操作太快了,浏览器还没来得及把GIF渲染出来,隐藏代码就执行了。要解决这个,咱们得等所有图表都完成重绘之后,再隐藏GIF,不能同步执行。
方法1:利用DC.js的Promise返回值(推荐)
从DC.js 2.1.0版本开始,redrawGroup()和redrawAll()都会返回一个Promise,咱们可以用.then()来监听重绘完成的时机:
修改你的点击事件代码:
chart.on("renderlet", function(chart) { chart.selectAll('rect').on('click', function(d) { // 立刻显示加载GIF $('#please-wait').css("display","block"); console.log("click!", d); var filter = chart.keyAccessor()(d); dc.events.trigger(function () { chart.filter(filter); // 重绘组内图表,等完成后再隐藏GIF chart.redrawGroup().then(() => { $('#please-wait').css("display","none"); }); }); }); });
方法2:用setTimeout兜底(兼容旧版本)
如果你的DC.js版本比较老,不支持Promise返回,那可以用setTimeout把隐藏逻辑延迟个几十毫秒,给浏览器足够的渲染时间:
chart.on("renderlet", function(chart) { chart.selectAll('rect').on('click', function(d) { $('#please-wait').css("display","block"); console.log("click!", d); var filter = chart.keyAccessor()(d); dc.events.trigger(function () { chart.filter(filter); chart.redrawGroup(); // 延迟50ms隐藏,确保GIF能显示出来 setTimeout(() => { $('#please-wait').css("display","none"); }, 50); }); }); });
更优雅的全局方案
结合第一个全局监听的方法,咱们可以做一个全局的加载状态管理,不管哪个图表触发过滤,都自动处理GIF的显示隐藏,完全不用在每个图表里写重复代码:
// 记录当前正在重绘的图表数量 let redrawCount = 0; const setupLoadingIndicator = () => { // 给已有的图表绑定事件 const allCharts = dc.chartRegistry.list(); allCharts.forEach(chart => { chart.on('preRedraw', () => { redrawCount++; // 第一个开始重绘的图表,显示GIF if(redrawCount === 1) { $('#please-wait').css("display","block"); } }); chart.on('postRedraw', () => { redrawCount--; // 所有图表都完成重绘,隐藏GIF if(redrawCount === 0) { $('#please-wait').css("display","none"); } }); }); // 给新注册的图表自动绑定事件 dc.chartRegistry.on('registered', (chart) => { chart.on('preRedraw', () => { redrawCount++; if(redrawCount === 1) { $('#please-wait').css("display","block"); } }); chart.on('postRedraw', () => { redrawCount--; if(redrawCount === 0) { $('#please-wait').css("display","none"); } }); }); }; // 初始化的时候调用一次 setupLoadingIndicator();
这个方案更省心,不管是点击图表过滤,还是其他方式触发的重绘,加载GIF都会自动显示和隐藏!
内容的提问来源于stack exchange,提问作者timJIN520
相关产品推荐
相关产品推荐

