tupali/librerias/gantt/code/es-modules/modules/boost/boost-init.js

293 lines
12 KiB
JavaScript

/* *
*
* Copyright (c) 2019-2020 Highsoft AS
*
* Boost module: stripped-down renderer for higher performance
*
* License: highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../parts/Globals.js';
import U from '../../parts/Utilities.js';
var addEvent = U.addEvent, extend = U.extend, fireEvent = U.fireEvent, wrap = U.wrap;
import '../../parts/Series.js';
import butils from './boost-utils.js';
import createAndAttachRenderer from './boost-attach.js';
var Series = H.Series, seriesTypes = H.seriesTypes, noop = function () { }, eachAsync = butils.eachAsync, pointDrawHandler = butils.pointDrawHandler, allocateIfNotSeriesBoosting = butils.allocateIfNotSeriesBoosting, renderIfNotSeriesBoosting = butils.renderIfNotSeriesBoosting, shouldForceChartSeriesBoosting = butils.shouldForceChartSeriesBoosting, index;
/* eslint-disable valid-jsdoc */
/**
* Initialize the boot module.
*
* @private
* @return {void}
*/
function init() {
extend(Series.prototype, {
/**
* @private
* @function Highcharts.Series#renderCanvas
*/
renderCanvas: function () {
var series = this, options = series.options || {}, renderer = false, chart = series.chart, xAxis = this.xAxis, yAxis = this.yAxis, xData = options.xData || series.processedXData, yData = options.yData || series.processedYData, rawData = options.data, xExtremes = xAxis.getExtremes(), xMin = xExtremes.min, xMax = xExtremes.max, yExtremes = yAxis.getExtremes(), yMin = yExtremes.min, yMax = yExtremes.max, pointTaken = {}, lastClientX, sampling = !!series.sampling, points, enableMouseTracking = options.enableMouseTracking !== false, threshold = options.threshold, yBottom = yAxis.getThreshold(threshold), isRange = series.pointArrayMap &&
series.pointArrayMap.join(',') === 'low,high', isStacked = !!options.stacking, cropStart = series.cropStart || 0, requireSorting = series.requireSorting, useRaw = !xData, minVal, maxVal, minI, maxI, boostOptions, compareX = options.findNearestPointBy === 'x', xDataFull = (this.xData ||
this.options.xData ||
this.processedXData ||
false), addKDPoint = function (clientX, plotY, i) {
// We need to do ceil on the clientX to make things
// snap to pixel values. The renderer will frequently
// draw stuff on "sub-pixels".
clientX = Math.ceil(clientX);
// Shaves off about 60ms compared to repeated concatenation
index = compareX ? clientX : clientX + ',' + plotY;
// The k-d tree requires series points.
// Reduce the amount of points, since the time to build the
// tree increases exponentially.
if (enableMouseTracking && !pointTaken[index]) {
pointTaken[index] = true;
if (chart.inverted) {
clientX = xAxis.len - clientX;
plotY = yAxis.len - plotY;
}
points.push({
x: xDataFull ? xDataFull[cropStart + i] : false,
clientX: clientX,
plotX: clientX,
plotY: plotY,
i: cropStart + i
});
}
};
// Get or create the renderer
renderer = createAndAttachRenderer(chart, series);
chart.isBoosting = true;
boostOptions = renderer.settings;
if (!this.visible) {
return;
}
// If we are zooming out from SVG mode, destroy the graphics
if (this.points || this.graph) {
this.destroyGraphics();
}
// If we're rendering per. series we should create the marker groups
// as usual.
if (!chart.isChartSeriesBoosting()) {
// If all series were boosting, but are not anymore
// restore private markerGroup
if (this.markerGroup === chart.markerGroup) {
this.markerGroup = void 0;
}
this.markerGroup = series.plotGroup('markerGroup', 'markers', true, 1, chart.seriesGroup);
}
else {
// If series has a private markeGroup, remove that
// and use common markerGroup
if (this.markerGroup &&
this.markerGroup !== chart.markerGroup) {
this.markerGroup.destroy();
}
// Use a single group for the markers
this.markerGroup = chart.markerGroup;
// When switching from chart boosting mode, destroy redundant
// series boosting targets
if (this.renderTarget) {
this.renderTarget = this.renderTarget.destroy();
}
}
points = this.points = [];
// Do not start building while drawing
series.buildKDTree = noop;
if (renderer) {
allocateIfNotSeriesBoosting(renderer, this);
renderer.pushSeries(series);
// Perform the actual renderer if we're on series level
renderIfNotSeriesBoosting(renderer, this, chart);
}
/**
* This builds the KD-tree
* @private
*/
function processPoint(d, i) {
var x, y, clientX, plotY, isNull, low = false, chartDestroyed = typeof chart.index === 'undefined', isYInside = true;
if (!chartDestroyed) {
if (useRaw) {
x = d[0];
y = d[1];
}
else {
x = d;
y = yData[i];
}
// Resolve low and high for range series
if (isRange) {
if (useRaw) {
y = d.slice(1, 3);
}
low = y[0];
y = y[1];
}
else if (isStacked) {
x = d.x;
y = d.stackY;
low = y - d.y;
}
isNull = y === null;
// Optimize for scatter zooming
if (!requireSorting) {
isYInside = y >= yMin && y <= yMax;
}
if (!isNull && x >= xMin && x <= xMax && isYInside) {
clientX = xAxis.toPixels(x, true);
if (sampling) {
if (typeof minI === 'undefined' ||
clientX === lastClientX) {
if (!isRange) {
low = y;
}
if (typeof maxI === 'undefined' ||
y > maxVal) {
maxVal = y;
maxI = i;
}
if (typeof minI === 'undefined' ||
low < minVal) {
minVal = low;
minI = i;
}
}
// Add points and reset
if (clientX !== lastClientX) {
// maxI is number too:
if (typeof minI !== 'undefined') {
plotY =
yAxis.toPixels(maxVal, true);
yBottom =
yAxis.toPixels(minVal, true);
addKDPoint(clientX, plotY, maxI);
if (yBottom !== plotY) {
addKDPoint(clientX, yBottom, minI);
}
}
minI = maxI = void 0;
lastClientX = clientX;
}
}
else {
plotY = Math.ceil(yAxis.toPixels(y, true));
addKDPoint(clientX, plotY, i);
}
}
}
return !chartDestroyed;
}
/**
* @private
*/
function doneProcessing() {
fireEvent(series, 'renderedCanvas');
// Go back to prototype, ready to build
delete series.buildKDTree;
series.buildKDTree();
if (boostOptions.debug.timeKDTree) {
console.timeEnd('kd tree building'); // eslint-disable-line no-console
}
}
// Loop over the points to build the k-d tree - skip this if
// exporting
if (!chart.renderer.forExport) {
if (boostOptions.debug.timeKDTree) {
console.time('kd tree building'); // eslint-disable-line no-console
}
eachAsync(isStacked ? series.data : (xData || rawData), processPoint, doneProcessing);
}
}
});
/*
* We need to handle heatmaps separatly, since we can't perform the
* size/color calculations in the shader easily.
*
* This likely needs future optimization.
*/
['heatmap', 'treemap'].forEach(function (t) {
if (seriesTypes[t]) {
wrap(seriesTypes[t].prototype, 'drawPoints', pointDrawHandler);
}
});
/* eslint-disable no-invalid-this */
if (seriesTypes.bubble) {
// By default, the bubble series does not use the KD-tree, so force it
// to.
delete seriesTypes.bubble.prototype.buildKDTree;
// seriesTypes.bubble.prototype.directTouch = false;
// Needed for markers to work correctly
wrap(seriesTypes.bubble.prototype, 'markerAttribs', function (proceed) {
if (this.isSeriesBoosting) {
return false;
}
return proceed.apply(this, [].slice.call(arguments, 1));
});
}
seriesTypes.scatter.prototype.fill = true;
extend(seriesTypes.area.prototype, {
fill: true,
fillOpacity: true,
sampling: true
});
extend(seriesTypes.column.prototype, {
fill: true,
sampling: true
});
// Take care of the canvas blitting
H.Chart.prototype.callbacks.push(function (chart) {
/**
* Convert chart-level canvas to image.
* @private
*/
function canvasToSVG() {
if (chart.ogl && chart.isChartSeriesBoosting()) {
chart.ogl.render(chart);
}
}
/**
* Clear chart-level canvas.
* @private
*/
function preRender() {
// Reset force state
chart.boostForceChartBoost = void 0;
chart.boostForceChartBoost = shouldForceChartSeriesBoosting(chart);
chart.isBoosting = false;
if (!chart.isChartSeriesBoosting() && chart.didBoost) {
chart.didBoost = false;
}
// Clear the canvas
if (chart.boostClear) {
chart.boostClear();
}
if (chart.canvas && chart.ogl && chart.isChartSeriesBoosting()) {
chart.didBoost = true;
// Allocate
chart.ogl.allocateBuffer(chart);
}
// see #6518 + #6739
if (chart.markerGroup &&
chart.xAxis &&
chart.xAxis.length > 0 &&
chart.yAxis &&
chart.yAxis.length > 0) {
chart.markerGroup.translate(chart.xAxis[0].pos, chart.yAxis[0].pos);
}
}
addEvent(chart, 'predraw', preRender);
addEvent(chart, 'render', canvasToSVG);
// addEvent(chart, 'zoom', function () {
// chart.boostForceChartBoost =
// shouldForceChartSeriesBoosting(chart);
// });
});
/* eslint-enable no-invalid-this */
}
export default init;