Highcharts中的宽度自适应问题详解--源码分析
阅读前须知
在本文你将得到以下信息:
- 导致Highcharts图表宽度无法自适应的根本原因
- 解决chart宽度自适应的两种方法
- 如何主动触发DOM事件
如有任何疑问或问题,欢迎探讨~
问题
今天在实现div
元素的sizable的功能是,发现一个问题:
作为container
的div
元素宽度发生变化时,内部的Highcharts图表并没有自适应的变化。然而当浏览器窗口宽度发生变化导致container
宽度变化时,Highcharts图表总是可以自适应调整。
分析
官网调研
由于chart的配置完全相同,问题很可能是Highcharts内部的实现导致的。基于这一点,查看Highcharts官方文档,在Highcharts 响应式一节,可以看到:
Highcharts官方文档提到,默认情况下Highcharts图表都是支持整个图表跟随图表容器响应式的,无需额外配置。这一点应当对应着浏览器窗口变化导致container
宽度发生变化时,图表自适应的情况。同时,官方文档也提到可以调用reflow()
方法来实现chart的自适应。
尽管官网给出了解决方案,当container
宽度发生变化时调用reflow()
可以解决这个问题,但并没有给出一个合理的解释:为什么直接修改container
的宽度无法实现图表的自适应。
源码分析
从官网给出的文档,可以获得一个信息:Highcharts本身对chart自适应提供了接口reflow()
,且默认调用了reflow()
方法来支持chart的宽度自适应。换句话说,Highcharts源码中调用reflow()
方法的地方,很可能可以得到导致问题的原因。
基于此,在Highcharts的源码中,发现了调用reflow()
的关键方法setReflow()
:
在红框中,可以看到addEvent()
的写法很像addEventListener()
的用法,可以合理推测:Highcharts在setReflow()
中,调用了addEventListener()
方法,为浏览器的window
对象添加了一个resize
的监听事件,当window
发生resize
时,会调用reflow()
函数。
这个推测可以合理解释当前的问题:浏览器的window变化会触发reflow()
方法,而div
的resize
无法触发reflow()
。
为了验证这个推测,必须验证以下两点:
-
addEvent(win, 'resize', function (e) {})
方法是对addEventListener()
方法的包装,且第三个函数参数是对事件触发时的回调函数 -
第一个参数
win
是事件的监听者,且win
在浏览器中就是window
对象。
验证一
根据对源码的分析,在源代码/code/es-modules/parts/Utilities.js
中找到了addEvent()
的定义:
结论:推测一正确。
验证二
基于源码找到win
的定义:
在浏览器中,通常window
对象都不是undefined
,基于立即执行函数表达式,可以得到结论:验证二正确,第一个参数win
是window
对象。
解决方案
基于上述分析,可以得到两种解决方案:
官网提供的reflow()
当container
宽度发生变化时调用官网提供的reflow()
,这种方法直接参考官网文档,此处不做详细介绍。
主动触发window
的resize
事件
根据对源码的分析可以知道,Highcharts在window
上监听了resize
事件,那通过主动触发resize
事件,应当同样可以保证chart的宽度自适应。
基于这一出发点,这里介绍如何 主动创建和触发 window
的resize
事件来解决这个问题。
事实上,MDN已给出了文档,提供了解决方案(以下标题可点击):
这里直接给出答案,在container
的宽度发生变化时调用以下代码即可:
const resizeEvent = new Event("resize");
window.dispatchEvent(resizeEvent);
事实证明,这种方法确实可行,问题得到解决!
结论
找到问题的根本原因是很重要的,至少在下一次,你不会跌倒在同一个坑里。
谢谢阅读~
上一篇: 2.图形精确点击
下一篇: UGUI学习:拖拽控制面板大小