为什么jqPlot显示了一个错误的饼图,其中包含通过AJAX检索的数据

Why does jqPlot show an erroroneous pie chart with data retrieved via AJAX?

本文关键字:包含通 数据 检索 AJAX 为什么 显示 错误 一个 jqPlot      更新时间:2023-09-26

我正在开发一个应用程序,在该应用程序中,我使用jqPlot使用通过AJAX检索的一些数据绘制饼图。然而,我注意到,生成的饼图是错误的。当我手动将数据放入数组时,饼图是正确的。

这是我代码的一部分。

  $.ajax({
    url:'http://localhost/mijson.php',
    dataType:'json',
    async:false,
    success:function(data){
        for(a in data){
            var div_pintar = "<div id='divgrafica"+a+"' class='myChart'></div>";
            $("#espacio_graficas").append(div_pintar);
            var datos_tmp = [];
            datos_tmp.push(['Ok',data[a]['ok']]);
            datos_tmp.push(['Fail',data[a]['fail']]);
            $.jqplot('divgrafica'+a, [datos_tmp], {
                title:data[a]['label'] ,
                seriesDefaults:{
                    renderer:$.jqplot.PieRenderer,
                    trendline:{ show: true },
                },
                legend:{ show: true }
            });
            ...

我得到的JSON是:

[{"label":"FECHA","requer":56,"ok":28,"fail":28},
 {"label":"TTM Y FECHA","requer":35,"ok":8,"fail":27}]

总之,它显示了一个饼图,例如,有两个值,但加起来是14%。

如果我使用ajaxDataRenderer:,也会发生同样的情况

...
    plo12 = $.jqplot('pieChart2', jsonurl,{
        title: 'AJAX JSON Data Renderer',
        dataRenderer: ajaxDataRenderer,
        seriesDefaults: {
            renderer: $.jqplot.PieRenderer,
            rendererOptions: {
                showDataLabels: true
            }
        },
        legend: { show: true, location: 'e' }
    });
    ...

如果没有更多信息,很难确定您的问题到底是什么。

然而,最明显的会导致错误图表的是使用:

for(a in data){

解析AJAX success:function:返回的JSON object,实际上是array

$.ajax({
    success:function(data){

引用MDN上的"for…in"页面:

数组迭代和for。。。在
注意:对于。。in不应用于迭代索引顺序很重要的数组

数组索引只是具有整数名称的可枚举属性,在其他方面与常规Object属性相同。不能保证。。。in将以任何特定顺序返回索引,将返回所有可枚举属性,包括具有非整数名称的属性和继承的属性。

因为迭代的顺序取决于实现,所以在数组上迭代可能不会以一致的顺序访问元素。因此,在访问顺序很重要的数组上迭代时,最好使用带有数字索引的for循环(或Array.forEach或for…of循环)。

在这种情况下,顺序很重要,因为无论使用何种浏览器,都应该希望图表的显示顺序相同。因此,您应该以确定性的方式处理数组的成员。

更重要的是:

仅在自己的属性上迭代

如果只想考虑附加到对象本身的属性,而不想考虑其原型,请使用getOwnPropertyNames或执行hasOwnProperty检查(也可以使用propertyIsEnumerable)。或者,如果您知道不会有任何外部代码干扰,您可以使用check方法扩展内置原型。

每个数组都有与其原型相关联的属性,而不仅仅是数组的成员。在没有任何限制的情况下,使用for(a in data){}在处理过程中包括这些内容,几乎可以保证会导致错误显示。

另一种编码方法是使用forEach():

  $.ajax({
    url:'http://localhost/mijson.php',
    dataType:'json',
    async:false,
    success:function(data){
        data.forEach(function(curObject, a) {
            var div_pintar = "<div id='divgrafica"+a+"' class='myChart'></div>";
            $("#espacio_graficas").append(div_pintar);
            var datos_tmp = [];
            datos_tmp.push(['Ok',data[a]['ok']]);
            datos_tmp.push(['Fail',data[a]['fail']]);
            $.jqplot('divgrafica'+a, [datos_tmp], {
                title:data[a]['label'] ,
                seriesDefaults:{
                    renderer:$.jqplot.PieRenderer,
                    trendline:{ show: true },
                },
                legend:{ show: true }
            });
            ...

注意:我通常会将所有的data[a]引用更改为curObject,但不这样做会起作用(数组索引作为a传入),并且对代码的更改量最小。进行额外的更改应该会使代码稍微快一点,因为不必多次进行数组查找。

有了这些更改,并使用更具描述性的index而不是a,代码看起来像:

  $.ajax({
    url:'http://localhost/mijson.php',
    dataType:'json',
    async:false,
    success:function(data){
        data.forEach(function(curObject, index) {
            var div_pintar = "<div id='divgrafica"+index+"' class='myChart'></div>";
            $("#espacio_graficas").append(div_pintar);
            var datos_tmp = [];
            datos_tmp.push(['Ok',curObject['ok']]);
            datos_tmp.push(['Fail',curObject['fail']]);
            $.jqplot('divgrafica'+index, [datos_tmp], {
                title:curObject['label'] ,
                seriesDefaults:{
                    renderer:$.jqplot.PieRenderer,
                    trendline:{ show: true },
                },
                legend:{ show: true }
            });
            ...

感谢Makyen的帮助,尽管他的回答很好,但错误仍然存在。经过16个多小时的尝试,我找到了解决方案,非常非常简单。

 .....
     var div_pintar = "<div id='divgrafica"+index+"' class='myChart'></div>";
                $("#espacio_graficas").append(div_pintar);
                var datos_tmp = [];
                    datos_tmp.push(['Ok',parseInt(datos[a]['ok'])]);
                    datos_tmp.push(['Fail',parseInt(datos[a]['fail'])]);
    ......

仅使用javascriptparseInt中的函数

我希望这能对其他人有所帮助。我损失了很多小时:(