Как улучшить производительность Highcharts setExtremes с кучей данных? - PullRequest
1 голос
/ 10 июня 2019

У меня есть страница, использующая Highstock.js и boost.js от Highcharts. Существует одна диаграмма (кроме навигатора), однако одна диаграмма состоит из 200 осей. И каждый ось имеет 30000 точек данных. Мы пытаемся продвигать график медленно каждую секунду. Однако мы находим, что вызов setExtremes для диаграммы медленный ... иногда ужасно медленный (особенно в Chrome). Таким образом, график, похоже, не перемещается в режиме реального времени (мы имеем дело с данными даты и времени).

https://jsfiddle.net/Eves/kapnLbwh/288/

HTML:

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/boost.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment.min.js" type="text/javascript"></script>

<body>
  <button id="add">Set Extremes</button>
  <div id="container" style="height: 4000px; min-width: 500px"></div>
  <button id="addTwo">Set Extremes</button>
</body>

Javascript:

var totalCharts = 200.0;

var data = [];
var time = (new Date()).getTime();

for (var i = 0; i < totalCharts; i++) {
  var temp = [];
  for (var j = 0; j < 30000; j++) {
    temp.push({
      x: time + j * 1000,
      y: Math.random()
    });
  }
  data.push(temp);
}

var yAxises = [];
resize: {
  enabled: true
}

$('#container')[0].style.height = ((110 * totalCharts) + 200).toString() + 'px';

for (var i = 0; i < totalCharts; i++) {
  var yAxis = {
    labels: {
      align: 'right',
      x: -3
    },
    title: {
      text: null
    },
    height: '100',
    top: (110 * (i + 1)).toString(),
    lineWidth: 2,
  }
  yAxises.push(yAxis);
}

var serieses = [];
for (var i = 0; i < totalCharts; i++) {
  var series = {
    type: 'line',
    name: 'Value ' + i.toString(),
    data: data[i],
    yAxis: i,
    boostThreshold:1,
    turboThreshold: 30000
  }
  serieses.push(series);
}

// create the chart
var chart = Highcharts.stockChart('container', {
  rangeSelector: {
    selected: 0,
    allButtonsEnabled: false,
    buttonTheme: {
      width: 60
    },
    buttons: [{
      count: 1,
      type: 'second',
      text: '1S'
    }, {
      count: 5,
      type: 'second',
      text: '5S'
    }, {
      type: 'second',
      text: 'All'
    }]
  },
  scrollbar: {
    liveRedraw: false
  },

  _navigator: {
    enabled: true
  },
  navigatorButtons: [{
    onClick: function() {}
  }, {
    onClick: function() {}
  }],
  chart: {
    marginLeft: 40, // Keep all charts left aligned
    spacingTop: 20,
    spacingBottom: 20,
    zoomType: 'x'
  },
  title: {
    text: 'Live random data',
    align: 'left',
    margin: 0,
    x: 30
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: {
      millisecond: '%Y-%m-%d<br/>%l:%M:%S.%L %p',
      second: '%Y-%m-%d<br/>%l:%M:%S %p',
      minute: '%Y-%m-%d<br/>%l:%M %p',
      hour: '%Y-%m-%d<br/>%l %p',
      day: '%Y<br/>%m-%d',
      week: '%Y<br/>%m-%d',
      month: '%Y-%m',
      year: '%Y'
    },
    labels: {
      style: {
        fontSize: "0.8em"
      }
    },
  },
  yAxis: yAxises,
  series: serieses,
  tooltip: {
    pointFormat: "{point.y}",
    headerFormat: "",
  },

  plotOptions: {
    series: {
      turboThreshold: 30000,
      boostThreshold: 1
    }
  }
});


chart.xAxis[0].setExtremes(data[0][1].x, data[0][2000].x, true, false);

var addToExtremes = 1;
var lastPlaybackTime = null;

function UpdateExtremesEverySecond() {
  var now = new Date();
  if (lastPlaybackTime === null) {
    lastPlaybackTime = new Date(now.getTime() - 1000);
  }
  var nextPlaybackTimeTicks = (lastPlaybackTime.getTime() + 1000 - now.getTime()); // + 1000;
  if (nextPlaybackTimeTicks <= 0) {
    nextPlaybackTimeTicks = 1;
  }
  lastPlaybackTime = now;

  console.log('nextPlaybackTimeTicks: ' + nextPlaybackTimeTicks);
  window.setTimeout(UpdateExtremes(), nextPlaybackTimeTicks);
};

function UpdateExtremes() {
  console.time('setExtremes duration');
  chart.xAxis[0].setExtremes(data[0][1 + (1000*addToExtremes)].x, data[0][2000 + (1000*addToExtremes)].x, true, false);
  console.timeEnd('setExtremes duration');
  addToExtremes = addToExtremes + 1;
  if (addToExtremes < 10) {
    UpdateExtremesEverySecond();
  } else {
    addToExtremes = 1; //reset
  }
};

$('#add').click(function() {
  UpdateExtremesEverySecond();
});
$('#addTwo').click(function() {
  UpdateExtremesEverySecond();
});

Этот пример является самым близким, к которому я смог прийти к тому, что у нас действительно происходит (на нашей странице довольно много событий, а также информация о правах собственности). Тем не менее, он демонстрирует, насколько медленным является setExtremes со всеми этими данными. Вопросы:

Что-нибудь можно сделать, чтобы улучшить производительность?

Правильно ли я использую функцию повышения Highcharts?

Мне просто не повезло из-за количества данных, с которыми я имею дело?

1 Ответ

0 голосов
/ 11 июня 2019

Лучший способ повысить производительность в этом случае - отображать только те серии, чьи yAxes видны на экране.Вы можете сравнить axisLine элемент с window.innerHeight или document.documentElement.clientHeight:

function areSeriesInViewport() {
    var series = chart.series,
        bounding;

    series.forEach(function(s) {
        bounding = s.yAxis.axisLine.element.getBoundingClientRect();

        if (
            bounding.bottom >= 0 &&
            bounding.top <=
            (window.innerHeight || document.documentElement.clientHeight)
        ) {
            s.setVisible(true, false);
        } else {
            s.setVisible(false, false);
        }
    });
    chart.redraw(false);
}

areSeriesInViewport();

window.addEventListener('scroll', function(event) {
    areSeriesInViewport();
});

Демонстрационная версия: https://jsfiddle.net/BlackLabel/m7p0a6xc/

Справочник по API: https://api.highcharts.com/class-reference/Highcharts.Series#setVisible

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...