Highcharts具有缺失数据点的同步图表

时间:2017-07-28 20:07:10

标签: javascript highcharts

我有两个图表显示时间序列数据,我正在尝试同步十字准线和工具提示。但是,图表并不总是具有相同数量的数据点。这会导致十字准线和工具提示在两个图形之间变得不同步。

我在两者上都启用了connectNulls: true,虽然这会使线条平滑,但它不会为它们不存在的时间段添加数据点。

有没有办法配置connectNulls以便插入填充点?

enter image description here

已更新

这是一个简单的jsFiddle示例,其中一天中缺少值,导致十字线在两个图形之间变得不同步。

2 个答案:

答案 0 :(得分:0)

要设置点之间的实际x距离,可以将xAxis.ordinal设置为false。另一种解决方案是将空值放在空位。您还可以设置pointStartpointInterval属性。

API参考:
http://api.highcharts.com/highstock/xAxis.ordinal
http://api.highcharts.com/highstock/plotOptions.series.pointStart
http://api.highcharts.com/highstock/plotOptions.series.pointInterval

示例:
http://jsfiddle.net/csgbxdaj/ - 将序数设为假 http://jsfiddle.net/gjxhbf7w/ - 将空值放在series.data数组

答案 1 :(得分:0)

@d_paul这是一个更新的小提示显示接近预期的行为,但是当顶部图中的十字准线在底部的同一点没有数据时,我还在努力防止点悬停/晕圈曲线图。

https://jsfiddle.net/jknipp/g3vr5v44/13/



// Global state variable
window.isOutOfSync = false;

/**
 * Override the reset function, we don't need to hide the tooltips and crosshairs.
 */
Highcharts.Pointer.prototype.reset = function() {
  return undefined;
};

/**
 * Synchronize zooming through the setExtremes event handler.
 */
function syncExtremes(e) {
  var thisChart = this.chart;

  if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
    Highcharts.each(Highcharts.charts, function(chart) {
      if (chart !== thisChart) {
        if (chart.xAxis[0].setExtremes) { // It is null while updating
          chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
            trigger: 'syncExtremes'
          });
        }
      }
    });
  }
}

/**
 * In order to synchronize tooltips and crosshairs, override the
 * built-in events with handlers defined on the parent element.
 */
$('#success-graphs-container').bind('mousemove touchmove touchstart', function(e) {
  var charts = Highcharts.charts.filter(function(chart) {
    return (chart.title.textStr.match(/success/i)) ? chart : null;
  });

  for (i = 0; i < charts.length; i++) {
    chart = charts[i];
    e = chart.pointer.normalize(e); // Find coordinates within the chart
    points = [chart.series[0].searchPoint(e, true), chart.series[1].searchPoint(e, true)]; // Get the hovered point

    var show = function() {
      if (points[0] && points[1]) {
        chart.tooltip.refresh(points); // Show the tooltip
        points[0].onMouseOver(); // Show the hover marker
        points[1].onMouseOver(); // Show the hover marker

        chart.xAxis[0].drawCrosshair(e, points[0]); // Show the crosshair
      }
    }

    if (i == 0) {
      chart2 = charts[i + 1];
      e2 = chart2.pointer.normalize(e); // Find coordinates within the chart
      points2 = [chart2.series[0].searchPoint(e2, true), chart2.series[1].searchPoint(e2, true)];

      if (((points[0] && points[1]) && points[0].x != points2[0].x && points[1].x != points2[1].x)) {
        console.log("val set " + window.isOutOfSync);
        //console.log("The points are different AF!");
				//if(!window.isOutOfSync) {
        points[0].onMouseOut();
        points[1].onMouseOut();
        points[0].select(false);
        points[1].select(false);
        chart.tooltip.refresh(points); // Show the tooltip
        
        //chart.tooltip.hide(points); // Hide the tooltip
        //points[0].(); // Show the hover marker
        //points[1].onMouseOut(); // Show the hover marker

        chart.xAxis[0].drawCrosshair(e, points[0]); // Show the crosshair
				window.isOutOfSync = true;
        //}
      } else {
        window.isOutOfSync = false
        show();
      }

    } else {
      show();
    }

  }
});

// Remove tool tips when the user leaves the container
// We do this for all charts because we had to override the reset function
$('#success-graphs-container').bind('mouseleave', function(e) {
  Highcharts.each(Highcharts.charts, function(chart) {
    var event = chart.pointer.normalize(e.originalEvent);
    var point = chart.series[0].searchPoint(event, true);


    if (point) {
      point.onMouseOut();
      chart.tooltip.hide(point);
      chart.xAxis[0].hideCrosshair();
    }
  });
});



function formatSuccessRateToolTip(pointValue, isSuccessful) {
  var text = (isSuccessful) ? "Success" : "Failure";
  var style = (isSuccessful) ? "color:#1EC06A; font-family: BentonSans Medium, sans-serif;" : "color:#E23C3F; font-family: BentonSans Medium, sans-serif;";
  // Use whole numbers if no decimal places to report
  var decimalPlaces = (Number(pointValue) === pointValue && pointValue % 1 === 0) ? 0 : 1;
  return "<span style=\"" + style + "\">" + Highcharts.numberFormat(pointValue, decimalPlaces, ".", ",") + "% " + text + "</span>";
}

var App = {
  renderSubsetSuccessRateChart: function renderSubsetSuccessRateChart(container) {
    Highcharts.chart(container, {
      chart: {
        renderTo: container,
        type: 'areaspline',
        height: '220',
        spacingBottom: 20,
        spacingTop: 20,
        spacingLeft: 20,
        spacingRight: 20
      },
      title: {
        align: 'center',
        text: 'Your Success Rate',
        margin: 10,
        style: {
          fontFamily: '\'BentonSans Medium\', sans-serif',
          fontSize: '14px'
        }
      },
      xAxis: {
        type: 'datetime',
        crosshair: {
          zIndex: 4,
          snap: false
        },
        events: {
          setExtremes: syncExtremes
        },
      },
      yAxis: {
        title: {
          text: ''
        },
        min: 0,
        max: 100
      },
      legend: {
        enabled: true,
        align: 'left'
      },
      plotOptions: {
        series: {
          connectNulls: true,
          fillOpacity: 1,
          stacking: 'normal',
          //stickyTracking: true,
          point: {
            events: {
              mouseOver: function(e) {
                /*
                var chart = this.series.chart;
                e = chart.pointer.normalize(e); // Find coordinates within the chart
                console.log("here");
                points = [chart.series[0].searchPoint(e, true), chart.series[1].searchPoint(e, true)]; // Get the hovered point
					
                  var chart2 = $("#total_success_rates").highcharts();
                  var e2 = chart2.pointer.normalize(e); // Find coordinates within the chart
                  var points2 = [chart2.series[0].searchPoint(e2, true), chart2.series[1].searchPoint(e2, true)];
									
                  console.log(points);
									console.log(points2);
                  if (points[0].x != points2[0].x && points[1].x != points2[1].x) {
                    console.log("The points are different AF!");
                    chart.tooltip.hide(points); // Show the tooltip
                    points[0].onMouseOut(); // Don't hover marker
                  	points[1].onMouseOut(); // Don't hover marker
                  }
                  */
              }
            }
          },
          events: {
            mouseOut: function() {
              //console.log("mouse out");
            }
          }
        }
      },
      series: [{
        name: "Failure",
        data: [
          [Date.UTC(2017, 7, 1), 20],
          [Date.UTC(2017, 7, 2), 25],
          [Date.UTC(2017, 7, 3), 24],
          [Date.UTC(2017, 7, 4), 7],
          [Date.UTC(2017, 7, 6), 0],
          [Date.UTC(2017, 7, 7), 35],
          [Date.UTC(2017, 7, 9), 12],
          [Date.UTC(2017, 7, 10), 10]
        ],
        color: '#1C81C6',
        lineColor: 'none',
        legendIndex: 1
      }, {
        name: 'Success',
        data: [
          [Date.UTC(2017, 7, 1), 80],
          [Date.UTC(2017, 7, 2), 75],
          [Date.UTC(2017, 7, 3), 76],
          [Date.UTC(2017, 7, 4), 93],
          [Date.UTC(2017, 7, 6), 100],
          [Date.UTC(2017, 7, 7), 65],
          [Date.UTC(2017, 7, 9), 88],
          [Date.UTC(2017, 7, 10), 90]
        ],
        color: '#E2EFF8',
        lineColor: 'none',
        legendIndex: 0
      }],
      tooltip: {
        padding: 12,
        shared: true,
        borderWidth: 2,
        borderRadius: 3,
        //snap: 0,
        style: {
          fontSize: '12px',
          fontFamily: '\'BentonSans\', sans-serif'
        },
        formatter: function(tooltip) {
          var header,
            s = [];

          console.log(window.isOutOfSync);
          if (window.isOutOfSync) {
            console.log("don't show tooltip");
            //return false;
            return "No data";
          }

          $.each(this.points, function(i, point) {

            // check to see if the point is in the overall graph
            //var overallChart = $("#total_success_rates").highcharts();
            //console.log(overallChart);

            var isSuccessRate = (point.series.name == 'Success');

            if (header == null) {
              var config = point.point.getLabelConfig();
              header = tooltip.tooltipFooterHeaderFormatter(config);
            }
            s.push(formatSuccessRateToolTip(point.y, isSuccessRate));
            // $("#" + point.series.name.toLowerCase() + "-rate").html(point.y + "%");
          });

          return header + s.reverse().join('<br>');
        },
        shared: true
      },
    });
  },
  renderTotalSuccessRateChart: function renderTotalSuccessRateChart(container) {
    Highcharts.chart(container, {
      chart: {
        renderTo: container,
        type: 'areaspline',
        height: '220',
        spacingBottom: 20,
        spacingTop: 20,
        spacingLeft: 20,
        spacingRight: 20,
      },
      title: {
        align: 'center',
        text: "Overall Success Rate",
        margin: 10,
        style: {
          fontFamily: '\'BentonSans Medium\', sans-serif',
          fontSize: '14px'
        }
      },
      xAxis: {
        type: 'datetime',
        crosshair: {
          zIndex: 4,
          snap: false
        },
        events: {
          setExtremes: syncExtremes
        },
      },
      yAxis: {
        title: {
          text: ''
        },
        min: 0,
        max: 100
      },
      legend: {
        enabled: true,
        align: 'left'
      },
      plotOptions: {
        series: {
          connectNulls: true,
          fillOpacity: 1,
          stacking: 'normal',
          stickyTracking: true,
        }
      },
      series: [{
        name: "Failure",
        data: [
          [Date.UTC(2017, 7, 1), 20],
          [Date.UTC(2017, 7, 2), 25],
          [Date.UTC(2017, 7, 3), 24],
          [Date.UTC(2017, 7, 4), 7],
          [Date.UTC(2017, 7, 5), 15],
          [Date.UTC(2017, 7, 6), 0],
          [Date.UTC(2017, 7, 7), 35],
          [Date.UTC(2017, 7, 8), 18],
          [Date.UTC(2017, 7, 9), 12],
          [Date.UTC(2017, 7, 10), 10]
        ],
        color: '#1C81C6',
        lineColor: 'none',
        legendIndex: 1
      }, {
        name: 'Success',
        data: [
          [Date.UTC(2017, 7, 1), 80],
          [Date.UTC(2017, 7, 2), 75],
          [Date.UTC(2017, 7, 3), 76],
          [Date.UTC(2017, 7, 4), 93],
          [Date.UTC(2017, 7, 5), 85],
          [Date.UTC(2017, 7, 6), 100],
          [Date.UTC(2017, 7, 7), 65],
          [Date.UTC(2017, 7, 8), 82],
          [Date.UTC(2017, 7, 9), 88],
          [Date.UTC(2017, 7, 10), 90]
        ],
        color: '#E2EFF8',
        lineColor: 'none',
        legendIndex: 0
      }],
      tooltip: {
        padding: 12,
        crosshair: true,
        shared: true,
        borderWidth: 2,
        borderRadius: 3,
        snap: 0,
        style: {
          fontSize: '12px',
          fontFamily: '\'BentonSans\', sans-serif'
        },
        formatter: function(tooltip) {
          var header,
            s = [];

          $.each(this.points, function(i, point) {
            var isSuccessRate = (point.series.name == 'Success');

            if (header == null) {
              var config = point.point.getLabelConfig();
              header = tooltip.tooltipFooterHeaderFormatter(config);
            }
            s.push(formatSuccessRateToolTip(point.y, isSuccessRate));
            // $("#overall-" + point.series.name.toLowerCase() + "-rate").html(point.y + "%");
          });

          return header + s.reverse().join('<br>');
        },
        shared: true
      },
    });
  }
}
window.App = App;

App.renderSubsetSuccessRateChart('subset_success_rates');
App.renderTotalSuccessRateChart('total_success_rates');
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/5.0.6/highcharts.js"></script>

<div id="success-graphs-container" class="success-graphs">
  <div id="subset_success_rates" style="width:100%; border-bottom: 1px solid #F8F8F8"></div>
  <div id="total_success_rates" style="width:100%;"></div>
</div>
&#13;
&#13;
&#13;