Highcharts:箭头在错误的图表上呈现

时间:2017-07-21 09:40:22

标签: javascript jquery asp.net highcharts

我在一个带有jQuery-UI标签导航系统的网页上有3个Highcharts图表 - 每个标签一个图表。在其中一个图表中,我在绘制的线条上添加了一个箭头。此箭头在IIFE内生成(请参阅下面的代码示例)。否则 Highcharts功能非常标准。

当我尝试切换标签并显示其他两个图表的数据时会出现问题:箭头正在不应该有任何箭头的图表上绘制。

错误的箭头始终总是在其他图表上绘制 - 从不在第一次渲染时,通常只有在用户切换标签两次或三次后,才会出现箭头所在的位置“T。我还注意到每次渲染图表时都会调用此IIFE(即使是从其他选项卡中调用)。

我不知道Highcharts如何在内部工作,但我的每个图表都附加到一个不同的DOM元素(通过ID),因此Highcharts不应该在渲染箭头时混合图表。

有谁知道为什么会这样?

      (function (H) {

            var arrowCheck = false, //This variable helps the arrow to be responsive
                pathTag;



            H.wrap(H.Series.prototype, 'drawGraph', function (proceed) {

                // Now apply the original function with the original arguments,
                // which are sliced off this function's arguments
                // This section takes care of the arrow of the graph

                proceed.apply(this, Array.prototype.slice.call(arguments, 1));

                var arrowLength = 14,
                    arrowWidth = 7,
                    series = this,
                    data = series.data,
                    segments = data,
                    lastSeg = segments[segments.length - 1],
                    path = [],
                    lastPoint = null,
                    nextLastPoint = null;

                if (typeof (lastSeg) === "undefined") {
                    return;
                }

                if (lastSeg.y === 0) {
                    lastPoint = segments[segments.length - 2];
                    nextLastPoint = segments[segments.length - 1];
                } else {
                    lastPoint = segments[segments.length - 1];
                    nextLastPoint = segments[segments.length - 2];
                }

                var angle = Math.atan((lastPoint.plotX - nextLastPoint.plotX) /
                    (lastPoint.plotY - nextLastPoint.plotY));

                if (angle < 0) angle = Math.PI + angle;


                path.push('M', lastPoint.plotX, lastPoint.plotY);

                if (lastPoint.plotX > nextLastPoint.plotX) {

                    if (arrowCheck === true) {

                        pathTag = doc.getElementById("arrow");
                        if (pathTag != null) {
                            pathTag.remove(pathTag);
                        }
                    }

                    path.push(
                        'L',
                        lastPoint.plotX + arrowWidth * Math.cos(angle),
                        lastPoint.plotY - arrowWidth * Math.sin(angle)
                    );
                    path.push(
                        lastPoint.plotX + arrowLength * Math.sin(angle),
                        lastPoint.plotY + arrowLength * Math.cos(angle)
                    );
                    path.push(
                        lastPoint.plotX - arrowWidth * Math.cos(angle),
                        lastPoint.plotY + arrowWidth * Math.sin(angle),
                        'Z'
                    );

                } else {

                    if (arrowCheck === true) {

                        pathTag = doc.getElementById("arrow");
                        if (pathTag != null) {
                            pathTag.remove(pathTag);
                        }
                    }

                    path.push(
                        lastPoint.plotY + arrowWidth * Math.sin(angle)
                    );
                    path.push(
                        lastPoint.plotX - arrowLength * Math.sin(angle),
                        lastPoint.plotY - arrowLength * Math.cos(angle)
                    );
                    path.push(
                        lastPoint.plotX + arrowWidth * Math.cos(angle),
                        lastPoint.plotY - arrowWidth * Math.sin(angle),
                        'Z'
                    );

                }

                series.chart.renderer.path(path)
                    .attr({
                        fill: series.color,
                        id: 'arrow'
                    })
                    .add(series.group);
                arrowCheck = true;

            });

        }(Highcharts));

这是一个JSFiddle示例(您只需要调整图表所在的部分,以查看箭头如何跳转到错误的图表)

1 个答案:

答案 0 :(得分:1)

简而言之,问题实际上是双重的:

  1. 箭头代码运行并显示在每个图表上
  2. 只有一个html元素ID用于它,因此它将删除上一个图表绘制中的该元素并将其显示在当前。
  3. 所以......当您第一次绘制图表时,箭头会添加到第二个图表中。然后删除。然后添加到第一个图表(因为这是您在代码中拥有它们的顺序)。所以此时你会看到第一张图表上的箭头,而不是第二张图表上的箭头。

    当HighCharts检测到需要调整大小时,它会重绘图表。但是在图表内部,图表的顺序不同,因此绘制第一个图表(这个图表需要箭头),首先删除带id="arrow"的箭头,然后重新添加。现在第二个图表重绘:它删除了id="arrow"的任何箭头(即使它现在碰巧在另一个图表上),然后将其添加到其图表中。现在箭头出现在图表2上。

    这就是为什么它从一个交换到另一个的原因。该怎么办?

    首先,如果您希望在该特定图表中包含箭头,请将参数添加到图表的plotOptions。请注意,您可以在多个图表上执行此操作:

    ...
    plotOptions: {
      showArrow: true  // signals that this chart requires an arrow
    },
    ...
    

    其次,检测此设置并仅在其存在时进行处理:

    (function(H) {
    
        var arrowCheck = false,
          pathTag;
    
        H.wrap(H.Series.prototype, 'drawGraph', function(proceed) {
    
          // Now apply the original function with the original arguments, 
          // which are sliced off this function's arguments
          proceed.apply(this, Array.prototype.slice.call(arguments, 1));
    
          if (this.chart.options.plotOptions.showArrow) {
            // used a bit of regex to clean up the series name enough to be used as an id
            var arrowName = "arrow" + this.name.replace(/\W/g, "_").toLowerCase();
    
            var arrowLength = 15,
              arrowWidth = 9,
              series = this,
              data = series.data,
              len = data.length,
              segments = data,
              lastSeg = segments[segments.length - 1],
              path = [],
              lastPoint = null,
              nextLastPoint = null;
    
            if (lastSeg.y == 0) {
              lastPoint = segments[segments.length - 2];
              nextLastPoint = segments[segments.length - 1];
            } else {
              lastPoint = segments[segments.length - 1];
              nextLastPoint = segments[segments.length - 2];
            }
    
            var angle = Math.atan((lastPoint.plotX - nextLastPoint.plotX) /
              (lastPoint.plotY - nextLastPoint.plotY));
    
            if (angle < 0) angle = Math.PI + angle;
    
            path.push('M', lastPoint.plotX, lastPoint.plotY);
    
            if (lastPoint.plotX > nextLastPoint.plotX) {
    
              if (arrowCheck === true) {
                //replaced 'arrow' with arrowName
                pathTag = document.getElementById(arrowName);
                if (pathTag != null) {
                  pathTag.remove(pathTag);
                }
              }
    
              path.push(
                'L',
                lastPoint.plotX + arrowWidth * Math.cos(angle),
                lastPoint.plotY - arrowWidth * Math.sin(angle)
              );
              path.push(
                lastPoint.plotX + arrowLength * Math.sin(angle),
                lastPoint.plotY + arrowLength * Math.cos(angle)
              );
              path.push(
                lastPoint.plotX - arrowWidth * Math.cos(angle),
                lastPoint.plotY + arrowWidth * Math.sin(angle),
                'Z'
              );
            } else {
    
    
              if (arrowCheck === true) {
                //replaced 'arrow' with arrowName
                pathTag = document.getElementById(arrowName);
                if (pathTag != null) {
                  pathTag.remove(pathTag);
                }
              }
    
              path.push(
                'L',
                lastPoint.plotX - arrowWidth * Math.cos(angle),
                lastPoint.plotY + arrowWidth * Math.sin(angle)
              );
              path.push(
                lastPoint.plotX - arrowLength * Math.sin(angle),
                lastPoint.plotY - arrowLength * Math.cos(angle)
              );
              path.push(
                lastPoint.plotX + arrowWidth * Math.cos(angle),
                lastPoint.plotY - arrowWidth * Math.sin(angle),
                'Z'
              );
            }
    
            series.chart.renderer.path(path)
              .attr({
                fill: series.color,
                id: arrowName //changed from 'arrow' to arrowName to enable more than one series with an arrow
              })
              .add(series.group);
    
            arrowCheck = true;
    
          }
        });
    }(Highcharts));
    

    最后,请注意我已使用https://stackoverflow.com/a/39925450/1544886中的提示确保每个图表都有箭头的唯一元素ID。

    演示:https://jsfiddle.net/4y86mwyk/