仅在Highcharts中存在值时如何启用绘图?

时间:2018-08-16 10:02:38

标签: highcharts

我不熟悉海图。我最近被困在绘制图表中。我正在使用绘图带来绘制背景色。如果存在一个值,则必须对其进行着色;如果不存在一个值,则不应对其进行着色。

例如,在此图表中,对于橙色来说,阴影是好的,因为正面和负面都有值。但是对于香蕉,阴影是不正确的。它只有正值,因此只应给正侧加上阴影,而不给负侧加上阴影,即0到-​​2.5不应带有灰色阴影。

感谢您的帮助。

带有图表带的Highchart列:

Highchart column with plotbands

以下代码:

Highcharts.chart('container', {  
  chart: {  
    type: 'column'  
  },  
  title: {  
    text: 'Column chart with negative values'  
  },  
  xAxis: {  
    categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas'],  
    plotBands: [{   
      color: 'gray',  
      from: 0.5,  
      to: 1.5  
    },  
    {   
      color: 'gray',  
      from: 3.5,  
      to: 4.5  
    }],  
  },  
  credits: {  
    enabled: false  
  },  
  series: [{  
    name: 'John',  
    data: [5, 3, 4, 7, 2]  
  }, {  
    name: 'Jane',  
    data: [2, -2, -2, 2, 1]  
  }, {  
    name: 'Joe',  
    data: [3, 4, 4, -2, 5]  
  }]  
});  

2 个答案:

答案 0 :(得分:0)

您不能将绘图带用于所描述的范围,因为它们的范围是-∞到∞。但是,您可以使用自定义形状并使它们看起来像绘图带。

首先,您需要在加载图表时触发函数:

chart: {
  events: {
    load: function() {
      this.customRect = [] //We use this to keep track off all the shapes we create
      addPlotbands(this); //Function to find what area should be colored in what way
    }
  }
}

然后,您需要一个函数来检测所有值是正值,负值还是混合值。这可以通过以下方式完成(请注意,这假设所有系列的点数完全相同)是

function addPlotbands(chart) {
  let series = chart.series
  let yMin = chart.yAxis[0].getExtremes().min;
  let yMax = chart.yAxis[0].getExtremes().max;

  for (let i = 0; i < series[0].data.length; i++) {
    let allAboveZero = true;
    let allBelowZero = true;
    for (let j = 0; j < chart.series.length; j++) {
      if (series[j].data[i].y >= 0) {
        allBelowZero = false;
      } else {
        allAboveZero = false;
      }
    }
    if (allAboveZero) {
      addCustomElement(chart, i, 0, yMax)
    } else if (allBelowZero) {
      addCustomElement(chart, i, yMin, 0)
    } else {
      addCustomElement(chart, i, yMin, yMax)
    }
  }
}

然后,最后,您需要一个函数来创建自定义矩形形状,可以像这样完成:

function addCustomElement(chart, x, yMin, yMax) { //yMin and yMax refers to the window, not the data
  let yAxis = chart.yAxis[0]
  let xAxis = chart.xAxis[0]
  chart.customRect.push(chart.renderer.rect(
    xAxis.toPixels(x - 0.5, false),                                  //Leftmost pixel
    yAxis.toPixels(yMax, false),                                     //Top pixel
    xAxis.toPixels(x + 0.5, false) - xAxis.toPixels(x - 0.5, false), //Width
    yAxis.toPixels(yMin, false) - yAxis.toPixels(yMax, false)        //Height
  )
  .attr({
    'stroke-width': 2,
    fill: 'gray',
    zIndex: -1
  })
  .add());
}

这很好用,但是,当您调整窗口大小时,形状不会被调整大小。可以通过在redraw事件中添加一些额外的代码来解决此问题:

redraw: function() {
  if (this.customRect) {
    for (let i = 0; i < this.customRect.length; i++) {
      this.customRect[i].destroy(); // Remove all the old rectangles before adding any new ones
    }
    this.customRect = [] //Empty the array of shapes
    let chart = this;
    setTimeout(function() { //We use a small timeout here to make sure the user is done resizing
      addPlotbands(chart)
    }, 100);
  }
}

function addPlotbands(chart) {
  let series = chart.series
  let yMin = chart.yAxis[0].getExtremes().min;
  let yMax = chart.yAxis[0].getExtremes().max;

  for (let i = 0; i < series[0].data.length; i++) {
    let allAboveZero = true;
    let allBelowZero = true;
    for (let j = 0; j < chart.series.length; j++) {
      if (series[j].data[i].y >= 0) {
        allBelowZero = false;
      } else {
        allAboveZero = false;
      }
    }
    if (allAboveZero) {
      addCustomElement(chart, i, 0, yMax)
    } else if (allBelowZero) {
      addCustomElement(chart, i, yMin, 0)
    } else {
      addCustomElement(chart, i, yMin, yMax)
    }
  }
}

function addCustomElement(chart, x, yMin, yMax) {
  let yAxis = chart.yAxis[0]
  let xAxis = chart.xAxis[0]
  chart.customRect.push(chart.renderer.rect(
      xAxis.toPixels(x - 0.5, false), //Leftmost pixel
      yAxis.toPixels(yMax, false), //Topmost pixel
      xAxis.toPixels(x + 0.5, false) - xAxis.toPixels(x - 0.5, false), //Width
      yAxis.toPixels(yMin, false) - yAxis.toPixels(yMax, false) //Height
    )
    .attr({
      'stroke-width': 2,
      fill: 'gray',
      zIndex: -1
    })
    .add());
}

Highcharts.chart('container', {
  chart: {
    type: 'column',
    events: {
      load: function() {
        this.customRect = []
        addPlotbands(this);
      },
      redraw: function() {
        if (this.customRect) {
          for (let i = 0; i < this.customRect.length; i++) {
            this.customRect[i].destroy();
          }
          this.customRect = []
          let chart = this;
          setTimeout(function() {
            addPlotbands(chart)
          }, 100);
        }
      }
    }
  },
  title: {
    text: 'Column chart with negative values'
  },
  xAxis: {
    categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas'],

  },
  credits: {
    enabled: false
  },
  series: [{
    name: 'John',
    data: [5, 3, 4, 7, 2, -3],
  }, {
    name: 'Jane',
    data: [2, -2, -2, 2, 1, -1]
  }, {
    name: 'Joe',
    data: [3, 4, 4, -2, 5, -2]
  }]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>

<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>

工作中的JSFiddle示例: https://jsfiddle.net/ewolden/gbrjd2uk/

API引用:Load eventRedraw eventAdding a rectangle

答案 1 :(得分:0)

除了使用plotBands外,您还可以创建(由Highcharts SVGRenderer创建)白色矩形,以覆盖plotBands的多余部分。您可以在下面找到此解决方案的响应示例:

    events: {
        render: function() {
            var chart = this,
                yAxis = chart.yAxis[0],
                xAxis = chart.xAxis[0],
                minPxY = yAxis.toPixels(yAxis.min),
                zeroPxY = yAxis.toPixels(0),
                series = chart.series,
                i,
                j,
                xValue,
                startCategory,
                endCategory,
                hasNegative;

            if (chart.correctedPlotBand) {
                Highcharts.each(chart.correctedPlotBand, function(el) {

                    el.destroy();
                });
                chart.correctedPlotBand = [];
            } else {
                chart.correctedPlotBand = [];
            }

            for (i = 0; i < series[0].points.length; i++) {
                hasNegative = false;

                for (j = 0; j < series.length; j++) {

                    if (series[j].points[i].y < 0) {
                        hasNegative = true;
                    }
                }
                if (!hasNegative) {
                    xValue = series[0].points[i].x;
                    startCategory = xAxis.toPixels(xValue - 0.5) - 1;
                    endCategory = Math.ceil(xAxis.toPixels(xValue + 0.5));

                    chart.correctedPlotBand.push(chart.renderer.rect(startCategory, zeroPxY, endCategory - startCategory, minPxY - zeroPxY)
                        .attr({
                            fill: '#fff',
                            zIndex: 0
                        })
                        .add())
                }
            }

        }
    }

实时演示:https://jsfiddle.net/BlackLabel/sm1kev4t/

API参考:https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#rect