注意:除非另有说明,否则所有行号和来源均参考2013 年 5 月 13 日从http://code.highcharts.com/3/highcharts.src.js获取的文件 highcharts.src.js。
概括:
似乎在使用 IE8、Highcharts 3.0.1 和 jQuery 1.7.1 渲染柱形图的特定情况下,如果将 plotOptions.column.dataLabels.rotation 指定为真值(未定义以外的其他值),则会出现问题或零)。据我所知,这种因素的组合导致某人(Highcharts,jQuery?)尝试为“对齐”属性设置动画,结果令人不快。我试图在小提琴中重新创建它,但我的简单案例有效。这似乎是因为IE9没有行使问题代码路径,而jsFiddle在IE8下不起作用,所以我无法在那里测试。
无论如何,这是小提琴:http: //jsfiddle.net/Wr9wX/6/
作为旁注,这些柱形图与 Highcharts v2.3.3 相同的错误失败。我最初写的 v2.3.3 没有失败,但后来的测试显示 v2.3.3 也失败了。如果我在 highcharts.js 中注释掉第 13950 行,我的生产页面会正确呈现,从而阻止它尝试为“对齐”属性设置动画。
从那以后,我已经能够创建一个独立的测试页面来重现该问题。关键是调用chart.setSize(width, height, animate)。如果 animate = true,则渲染失败。有趣的是,如果内置回流逻辑正在处理调整大小,则渲染不会失败。代码如下:
<!DOCTYPE html">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<script type='text/javascript' src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type='text/javascript' src="http://code.highcharts.com/highcharts.js"></script>
</head>
<body>
<div class="highcharts-container"
id="highcharts-2"
style='z-index: 0; position: relative; text-align: left; line-height: normal; height: 100%;width: 100%; font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif; height: 100%; font-size: 12px; overflow: hidden;'>
</div>
<script type="text/javascript">
var chart;
var render = function(id) {
var foo;
var chartSpec = {
credits: false,
chart: {
animation: false,
renderTo: id,
type: 'column'
},
xAxis: {
categories: ['Jan']
},
plotOptions: {
series: {animation:false},
column: {
pointPadding: 0.2,
borderWidth: 0,
dataLabels: {
rotation: -75,
align: 'left',
enabled: true
}
}
},
series: [{
data: [29.9]
}]
};
foo = new Highcharts.Chart(chartSpec, function (chart) {
chart.setSize(800, 600, true); // <====== fails here
});
};
$(function () {
render('highcharts-2');
});
</script>
</body>
</html>
血腥细节:
我正在通过 jQuery v1.7.1 访问 highcharts,并且我已经从 Highcharts v2.3.3 升级到 v3.0.1。我们的应用程序在 Highcharts v2.3.3 下运行良好,但在 Highcharts v3.0.1 下失败。在 v3.0.1 和 IE8(浏览器模式:“IE8”;文档模式:“IE8 标准”)下,我从 Highcharts 的 extend() 函数中得到一个“无效参数”:
/**
* Extend an object with the members of another
* @param {Object} a The object to be extended
* @param {Object} b The object to add to the first one
*/
function extend(a, b) {
var n;
if (!a) {
a = {};
}
for (n in b) {
a[n] = b[n]; <------ fails here
}
return a;
}
我在两种情况下失败:一种是 n = ('top', 'left') 之一,另一种是 n = 'textAlign'。
在 n 是 ('top', 'left') 之一的失败情况下,则 a[n] = "<number>px"(其中 <number> 表示数字字符的有效序列;例如,“100px”) , 和 b[n] = "NaNpx"。
当 n = "textAlign" 时,a[n] = "" 和 b[n] 是一个字符串,其值是附加了字符串 "NaN" 的函数的源代码。提供此源的函数似乎是从 highcharts.src.js 中的第 2720 行开始的 align() 函数。在这种情况下,错误消息也有所不同:“无法获取 textAlign 属性。无效参数”
当然,我花了一些时间搜索这个问题,但所有教我的是,extend() 可能由于各种原因而失败,具体取决于 a、b 和 n 的值;这并不奇怪。
然后我花了几个小时在调用堆栈上下调查。我发现,在用于 jQuery 的 Highcharts 适配器中的 animate() 函数中,第 1408 行执行为:
$el.animate(params, options);
它消失在 jQuery 中,在同一个适配器的 init() 方法(第 1090 行)中重新出现在 Highcharts 中。在从 1138 开始的代码块中:
return elem.attr ? // is SVG element wrapper
elem.attr(fx.prop, fn === 'cur' ? UNDEFINED : fx.now) : // apply the SVG wrapper's method
base.apply(this, arguments); // use jQuery's built-in method
有趣的是,虽然我渲染了四种不同类型的图表(条形图、柱形图、饼图和散点图),但只有柱形图失败了。我尝试渲染的所有柱形图都失败了,无论我绘制的是哪个数据集。
好的,它在 animate() 中失败;关闭图表的动画。还是坏了。再看调用栈:hmmm; 仍然通过动画进入。为什么?
调查表明,旋转数据标签仍然涉及 animate(),即使图表渲染本身没有动画。注释掉 plotOptions.column.dataLabels 中的旋转属性,现在它可以工作了。
这是破坏性的情节选项:
plotOptions: {
series: {},
column: {
pointPadding: 0.2,
borderWidth: 0,
dataLabels: {
enabled: true,
rotation: -75,
align: 'left'
}
}
}
旋转的价值似乎并不重要。如果它具有“真实”值,则渲染会中断。如果未定义,则没有问题。
所以,创建一个小提琴。小提琴正确渲染;有或没有旋转。意识到我是个白痴,因为我在 IE9 下运行 Fiddle;很快发现jsFiddle在IE8下不行。无论如何都要发布指向 Fiddle 的链接(参见上面的摘要)。
再看栈。我知道它在从第 13952 行开始进入条件时会失败。dataLabel 的值是多少?嗯... dataLabel.textAlign 是一个字符串,其值是函数的来源。那是从哪里来的?
不幸的是,我不知道。当它在第 1408 行的 $el.animate() 调用中消失到 jQuery 中时,一切看起来仍然很好。当它在第 1093 行的 win.HighchartsAdapeter.init 中弹出时,我可以看到,在请求函数的情况下'_default' 有时 fx.now(fx 在第 1128 行绑定)是这个函数字符串而不是数字。由于 fx 是从 jQuery 传入的,我真的不知道它是从哪里来的。
由于字符串表示的函数似乎在 Highcharts 中,但 fx 来自 jQuery 动画逻辑,似乎 Highcharts 的某些组件将函数字符串化并将其返回给 jQuery。假设这会发生在适配器中似乎也是合理的。我没有证据证明这一点,但它似乎是一个开始寻找的好地方。
我已经在使用 'align' 符号周围寻找范围错误,但没有找到任何东西。在第 4024 行有一些看起来很可疑的猴子业务......是的,我可以看到它被 key = 'align' 和 value = <stringified align() source> + 'NaN' 调用。
这里的调用者是适配器的 attr() 实现(第 4539 行)。hash 和 val 参数都包含我们(可能)错误的字符串。这些值是从 init() 的第 1139 行传入的,这使我们再次回到 jQuery。似曾相识。
那么,这是一个 jQuery 错误吗?如果是这样,为什么它适用于 Highcharts v2.3.3?
我可以看到 init() 中的匿名函数实现了 jQuery 动画步骤使用的 _default() 方法,但我仍然不知道为什么步骤的 'now' 成员有这个奇怪的值。很明显,当应用于点标签时,旋转是作为一种特殊情况处理的,并且要特别注意避免覆盖 SVG 的“对齐”属性。jQuery 1.7+ 似乎也是一个独特的案例,并且 _default() 适配器仅针对 jQuery 1.7+ 生成。
在查看了 animate() 函数的 jQuery 文档后,我怀疑整个问题是系统首先尝试为“align”属性设置动画。动画非数字值对我来说毫无意义,并且元素似乎格式错误,因为“end”和“now”属性具有非数字值,而“start”完全缺失。
显然,“align”正在被动画化,因为它与“x”和“y”一起位于某个对象的“animatedProperties”集合中(不确定它是什么)。animate() 的文档似乎清楚地表明动画属性必须是数字的(对我来说似乎完全合理)。如果我在 plotOptions.column.dataLabels 设置中保留“旋转”属性,但删除“对齐”,会发生什么情况?
还是断了。
我将停止在这里挖掘,并请 Highchart 的人看看这个。