NGToolsCSharp/NGTools/Scripts/Highcharts-7.1.1/code/es-modules/modules/boost/boost-utils.js

310 lines
6.8 KiB
JavaScript
Raw Normal View History

2024-09-13 08:44:13 +00:00
/* *
*
* Copyright (c) 2019-2019 Highsoft AS
*
* Boost module: stripped-down renderer for higher performance
*
* License: highcharts.com/license
*
* This files contains generic utility functions used by the boost module.
*
* */
'use strict';
import H from '../../parts/Globals.js';
import '../../parts/Series.js';
import boostableMap from './boostable-map.js';
import createAndAttachRenderer from './boost-attach.js';
var win = H.win,
doc = win.document,
pick = H.pick;
// This should be a const.
var CHUNK_SIZE = 3000;
/**
* Tolerant max() function.
*
* @private
* @function patientMax
*
* @return {number}
* max value
*/
function patientMax() {
var args = Array.prototype.slice.call(arguments),
r = -Number.MAX_VALUE;
args.forEach(function (t) {
if (
typeof t !== 'undefined' &&
t !== null &&
typeof t.length !== 'undefined'
) {
// r = r < t.length ? t.length : r;
if (t.length > 0) {
r = t.length;
return true;
}
}
});
return r;
}
/**
* Return true if ths boost.enabled option is true
*
* @private
* @function boostEnabled
*
* @param {Highcharts.Chart} chart
* The chart
*
* @return {boolean}
*/
function boostEnabled(chart) {
return pick(
(
chart &&
chart.options &&
chart.options.boost &&
chart.options.boost.enabled
),
true
);
}
/**
* Returns true if we should force boosting the chart
* @private
* @function shouldForceChartSeriesBoosting
*
* @param {Highcharts.Chart} chart
* The chart to check for forcing on
*
* @return {boolean}
*/
function shouldForceChartSeriesBoosting(chart) {
// If there are more than five series currently boosting,
// we should boost the whole chart to avoid running out of webgl contexts.
var sboostCount = 0,
canBoostCount = 0,
allowBoostForce = pick(
chart.options.boost && chart.options.boost.allowForce,
true
),
series;
if (typeof chart.boostForceChartBoost !== 'undefined') {
return chart.boostForceChartBoost;
}
if (chart.series.length > 1) {
for (var i = 0; i < chart.series.length; i++) {
series = chart.series[i];
// Don't count series with boostThreshold set to 0
// See #8950
// Also don't count if the series is hidden.
// See #9046
if (series.options.boostThreshold === 0 ||
series.visible === false) {
continue;
}
// Don't count heatmap series as they are handled differently.
// In the future we should make the heatmap/treemap path compatible
// with forcing. See #9636.
if (series.type === 'heatmap') {
continue;
}
if (boostableMap[series.type]) {
++canBoostCount;
}
if (patientMax(
series.processedXData,
series.options.data,
// series.xData,
series.points
) >= (series.options.boostThreshold || Number.MAX_VALUE)) {
++sboostCount;
}
}
}
chart.boostForceChartBoost = allowBoostForce && (
(
canBoostCount === chart.series.length &&
sboostCount > 0
) ||
sboostCount > 5
);
return chart.boostForceChartBoost;
}
/*
* Performs the actual render if the renderer is
* attached to the series.
* @param renderer {OGLRenderer} - the renderer
* @param series {Highcharts.Series} - the series
*/
function renderIfNotSeriesBoosting(renderer, series, chart) {
if (renderer &&
series.renderTarget &&
series.canvas &&
!(chart || series.chart).isChartSeriesBoosting()
) {
renderer.render(chart || series.chart);
}
}
function allocateIfNotSeriesBoosting(renderer, series) {
if (renderer &&
series.renderTarget &&
series.canvas &&
!series.chart.isChartSeriesBoosting()
) {
renderer.allocateBufferForSingleSeries(series);
}
}
/**
* An "async" foreach loop. Uses a setTimeout to keep the loop from blocking the
* UI thread.
*
* @private
*
* @param arr {Array} - the array to loop through
* @param fn {Function} - the callback to call for each item
* @param finalFunc {Function} - the callback to call when done
* @param chunkSize {Number} - the number of iterations per timeout
* @param i {Number} - the current index
* @param noTimeout {Boolean} - set to true to skip timeouts
*/
function eachAsync(arr, fn, finalFunc, chunkSize, i, noTimeout) {
i = i || 0;
chunkSize = chunkSize || CHUNK_SIZE;
var threshold = i + chunkSize,
proceed = true;
while (proceed && i < threshold && i < arr.length) {
proceed = fn(arr[i], i);
++i;
}
if (proceed) {
if (i < arr.length) {
if (noTimeout) {
eachAsync(arr, fn, finalFunc, chunkSize, i, noTimeout);
} else if (win.requestAnimationFrame) {
// If available, do requestAnimationFrame - shaves off a few ms
win.requestAnimationFrame(function () {
eachAsync(arr, fn, finalFunc, chunkSize, i);
});
} else {
setTimeout(function () {
eachAsync(arr, fn, finalFunc, chunkSize, i);
});
}
} else if (finalFunc) {
finalFunc();
}
}
}
/**
* Returns true if the current browser supports webgl
*
* @private
* @function hasWebGLSupport
*
* @return {boolean}
*/
function hasWebGLSupport() {
var i = 0,
canvas,
contexts = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'],
context = false;
if (typeof win.WebGLRenderingContext !== 'undefined') {
canvas = doc.createElement('canvas');
for (; i < contexts.length; i++) {
try {
context = canvas.getContext(contexts[i]);
if (typeof context !== 'undefined' && context !== null) {
return true;
}
} catch (e) {
}
}
}
return false;
}
/**
* Used for treemap|heatmap.drawPoints
*
* @private
* @function pointDrawHandler
*
* @param {Function} proceed
*
* @return {*}
*/
function pointDrawHandler(proceed) {
var enabled = true,
renderer;
if (this.chart.options && this.chart.options.boost) {
enabled = typeof this.chart.options.boost.enabled === 'undefined' ?
true :
this.chart.options.boost.enabled;
}
if (!enabled || !this.isSeriesBoosting) {
return proceed.call(this);
}
this.chart.isBoosting = true;
// Make sure we have a valid OGL context
renderer = createAndAttachRenderer(this.chart, this);
if (renderer) {
allocateIfNotSeriesBoosting(renderer, this);
renderer.pushSeries(this);
}
renderIfNotSeriesBoosting(renderer, this);
}
var funs = {
patientMax: patientMax,
boostEnabled: boostEnabled,
shouldForceChartSeriesBoosting: shouldForceChartSeriesBoosting,
renderIfNotSeriesBoosting: renderIfNotSeriesBoosting,
allocateIfNotSeriesBoosting: allocateIfNotSeriesBoosting,
eachAsync: eachAsync,
hasWebGLSupport: hasWebGLSupport,
pointDrawHandler: pointDrawHandler
};
// This needs to be fixed.
H.hasWebGLSupport = hasWebGLSupport;
export default funs;