scichart
Version:
Fast WebGL JavaScript Charting Library and Framework
310 lines (309 loc) • 16.7 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.StackedXyCollection = void 0;
var NumberRange_1 = require("../../../Core/NumberRange");
var SearchMode_1 = require("../../../types/SearchMode");
var copyVector_1 = require("../../../utils/copyVector");
var performance_1 = require("../../../utils/performance");
var vectorToArray_1 = require("../../../utils/vectorToArray");
var BaseDataSeries_1 = require("../../Model/BaseDataSeries");
var XyyPointSeriesWrapped_1 = require("../../Model/PointSeries/XyyPointSeriesWrapped");
var RenderPassData_1 = require("../../Services/RenderPassData");
var BaseStackedCollection_1 = require("./BaseStackedCollection");
var constants_1 = require("./constants");
var StackedXyCollection = /** @class */ (function (_super) {
__extends(StackedXyCollection, _super);
/**
* Creates an instance of the {@link StackedMountainCollection}
* @param webAssemblyContext The {@link TSciChart | SciChart WebAssembly Context} containing
* native methods and access to our WebGL2 WebAssembly Drawing Engine
* @param options Optional parameters of type {@link IStackedXyCollectionOptions} to configure the series
*/
function StackedXyCollection(webAssemblyContext, options) {
var _this = this;
var _a;
_this = _super.call(this, webAssemblyContext, options) || this;
_this.separatePositiveNegativeStacksProperty = true;
_this.separatePositiveNegativeStacksProperty = (_a = options === null || options === void 0 ? void 0 : options.separatePositiveNegativeStacks) !== null && _a !== void 0 ? _a : _this.separatePositiveNegativeStacksProperty;
_this.detachChildSeries = _this.detachChildSeries.bind(_this);
_this.attachChildSeries = _this.attachChildSeries.bind(_this);
_this.collectionChanged.subscribe(function (arg) {
var _a, _b;
(_a = arg.getOldItems()) === null || _a === void 0 ? void 0 : _a.forEach(_this.detachChildSeries);
(_b = arg.getNewItems()) === null || _b === void 0 ? void 0 : _b.forEach(_this.attachChildSeries);
});
return _this;
}
/** @inheritDoc */
StackedXyCollection.prototype.updateAccumulatedVectors = function () {
var _this = this;
var dataValuesCount = this.getDataSeriesValuesCount();
if (!this.isAccumulatedVectorDirty || !dataValuesCount) {
return;
}
this.checkXValuesCorrect();
this.isAccumulatedVectorDirty = false;
this.clearAccumulatedVectors(dataValuesCount);
var yValueArrayViews = this.getVisibleSeries().map(function (cur) {
return (0, vectorToArray_1.vectorToArrayViewF64)(cur.dataSeries.getNativeYValues(), _this.webAssemblyContext);
});
var _loop_1 = function (i) {
this_1.accumulatedValues0.push_back(0);
if (this_1.separatePositiveNegativeStacksProperty) {
// Compute separate positive/negative totals for 100% normalization.
var positiveTotal_1 = 0;
var negativeTotal_1 = 0;
if (this_1.isOneHundredPercent) {
this_1.getVisibleSeries().forEach(function (rs, index) {
var y = yValueArrayViews[index][i];
if (y >= 0)
positiveTotal_1 += y;
else
negativeTotal_1 += y;
});
}
// Positive values stack upward from zero; negative values stack downward independently.
var positiveAccum_1 = 0;
var negativeAccum_1 = 0;
this_1.getVisibleSeries().forEach(function (rs, index) {
var currentY = yValueArrayViews[index][i];
if (_this.isOneHundredPercent) {
currentY = currentY >= 0
? (positiveTotal_1 !== 0 ? (currentY / positiveTotal_1) * 100 : 0)
: (negativeTotal_1 !== 0 ? (currentY / Math.abs(negativeTotal_1)) * 100 : 0);
}
if (currentY >= 0) {
rs.bottomAccumulatedValues.push_back(positiveAccum_1);
var top_1 = positiveAccum_1 + currentY;
rs.accumulatedValues.push_back(top_1);
positiveAccum_1 = top_1;
}
else {
var bottom = negativeAccum_1 + currentY;
rs.bottomAccumulatedValues.push_back(bottom);
rs.accumulatedValues.push_back(negativeAccum_1);
negativeAccum_1 = bottom;
}
if (rs.renderDataTransform) {
rs.renderDataTransform.requiresTransform = true;
}
});
}
else {
var totalSum_1;
if (this_1.isOneHundredPercent) {
totalSum_1 = this_1.getVisibleSeries().reduce(function (prev, cur, index) { return prev + yValueArrayViews[index][i]; }, 0);
}
var previous_1 = 0;
this_1.getVisibleSeries().forEach(function (rs, index) {
var currentY = yValueArrayViews[index][i];
if (_this.isOneHundredPercent) {
currentY = (currentY * 100) / totalSum_1;
}
var current = previous_1 + currentY;
rs.accumulatedValues.push_back(current);
previous_1 = current;
if (rs.renderDataTransform) {
rs.renderDataTransform.requiresTransform = true;
}
});
}
};
var this_1 = this;
for (var i = 0; i < dataValuesCount; i++) {
_loop_1(i);
}
};
/** @inheritDoc */
StackedXyCollection.prototype.draw = function (renderContext, renderPassData) {
var _this = this;
var _a, _b, _c, _d;
if (this.canDraw) {
this.updateHitTestProviders(renderPassData);
if (!this.isEnoughDataToDraw()) {
return;
}
if ((_a = this.getFirstSeries().dataSeries) === null || _a === void 0 ? void 0 : _a.fifoCapacity) {
throw new Error("Sorry, fifo is not currently supported for stacked series");
}
var mark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DrawCollectionSeriesStart, {
contextId: this.id,
parentContextId: (_b = this.parentSurface) === null || _b === void 0 ? void 0 : _b.id,
level: performance_1.EPerformanceDebugLevel.Verbose
});
this.updateAccumulatedVectors();
var xAxis_1 = this.xAxis;
var visibleSeries_1 = this.getVisibleSeries();
// draw Stacked Series in reverse order to prevent overlapping with Point Markers
visibleSeries_1.reduceRight(function (nextSeries, series, index, collection) {
var accumulatedValues1 = series.accumulatedValues;
var accumulatedValues = _this.separatePositiveNegativeStacksProperty
? series.bottomAccumulatedValues
: index === 0 ? _this.accumulatedValues0 : collection[index - 1].accumulatedValues;
// wrap XyDataSeries as XyyDataSeries
var xyyPointSeries = new XyyPointSeriesWrapped_1.XyyPointSeriesWrapped(series.dataSeries, accumulatedValues, accumulatedValues1);
var renderData = new RenderPassData_1.RenderPassData(series.getIndicesRange(xAxis_1.visibleRange), renderPassData.getxCoordinateCalculator, renderPassData.getyCoordinateCalculator, xAxis_1.isVerticalChart, xyyPointSeries);
if (series.renderDataTransform) {
var transRenderData = new RenderPassData_1.RenderPassData(series.getIndicesRange(xAxis_1.visibleRange), renderPassData.getxCoordinateCalculator, renderPassData.getyCoordinateCalculator, xAxis_1.isVerticalChart, xyyPointSeries);
transRenderData = series.renderDataTransform.runTransform(transRenderData);
if (index < visibleSeries_1.length - 1) {
(0, copyVector_1.copyDoubleVector)(collection[index + 1].renderDataTransform.pointSeries.yValues, transRenderData.pointSeries.y1Values, _this.webAssemblyContext);
}
if ("strokeY1" in series) {
// @ts-ignore
series.strokeY1 = index === 0 ? "transparent" : collection[index - 1].stroke;
// @ts-ignore
series.strokeY1DashArray = index === 0 ? [] : collection[index - 1].strokeDashArray;
}
series.drawingProviders[0].draw(renderContext, transRenderData);
return series;
}
if ("strokeY1" in series) {
// @ts-ignore
series.strokeY1 = index === 0 ? "transparent" : collection[index - 1].stroke;
// @ts-ignore
series.strokeY1DashArray = index === 0 ? [] : collection[index - 1].strokeDashArray;
}
series.draw(renderContext, renderData);
return series;
}, undefined);
performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DrawCollectionSeriesEnd, {
contextId: this.id,
parentContextId: (_c = this.parentSurface) === null || _c === void 0 ? void 0 : _c.id,
relatedId: (_d = mark === null || mark === void 0 ? void 0 : mark.detail) === null || _d === void 0 ? void 0 : _d.relatedId,
level: performance_1.EPerformanceDebugLevel.Verbose
});
}
};
/** @inheritDoc */
StackedXyCollection.prototype.getXRange = function () {
if (!this.isEnoughDataToDraw()) {
return new NumberRange_1.NumberRange();
}
return this.getFirstSeries().dataSeries.xRange;
};
/** @inheritDoc */
StackedXyCollection.prototype.getYRange = function (xVisibleRange, isXCategoryAxis) {
var _this = this;
var yRange = _super.prototype.getYRange.call(this, xVisibleRange, isXCategoryAxis);
if (this.separatePositiveNegativeStacksProperty) {
// accumulatedValues only contains the tops; also union with bottomAccumulatedValues
// so that negatively-stacked bands are included in the visible range.
this.getVisibleSeries().forEach(function (rs) {
var _a;
var bottomSize = rs.bottomAccumulatedValues.size();
if (bottomSize > 0 && bottomSize === ((_a = _this.getNativeXValues()) === null || _a === void 0 ? void 0 : _a.size())) {
var bottomRange = (0, BaseDataSeries_1.getWindowedYRange)(_this.webAssemblyContext, _this.getNativeXValues(), rs.bottomAccumulatedValues, xVisibleRange, true, isXCategoryAxis, rs.dataSeries.dataDistributionCalculator.isSortedAscending, true, SearchMode_1.ESearchMode.RoundUp, SearchMode_1.ESearchMode.RoundDown);
if (bottomRange) {
yRange = yRange.union(bottomRange);
}
}
});
}
return yRange;
};
/** @inheritDoc */
StackedXyCollection.prototype.onAttach = function (scs) {
_super.prototype.onAttach.call(this, scs);
this.getVisibleSeries().forEach(function (series) {
series.onAttach(scs);
});
};
/** @inheritDoc */
StackedXyCollection.prototype.onDetach = function () {
this.getVisibleSeries().forEach(function (series) {
series.onDetach();
});
_super.prototype.onDetach.call(this);
};
/** @inheritDoc */
StackedXyCollection.prototype.notifyPropertyChanged = function (propertyName) {
_super.prototype.notifyPropertyChanged.call(this, propertyName);
if (propertyName === constants_1.PROPERTY.DATA_SERIES ||
propertyName === constants_1.PROPERTY.IS_VISIBLE ||
propertyName === constants_1.PROPERTY.IS_ONE_HUNDRED_PERCENT ||
propertyName === constants_1.PROPERTY.SEPARATE_POSITIVE_NEGATIVE_STACKS) {
this.isAccumulatedVectorDirty = true;
}
};
Object.defineProperty(StackedXyCollection.prototype, "separatePositiveNegativeStacks", {
/**
* When true (default), positive values stack upward from the zero line and negative values stack downward independently.
* When false, all values accumulate continuously from the previous series top, preserving legacy behaviour.
*/
get: function () {
return this.separatePositiveNegativeStacksProperty;
},
/**
* When true (default), positive values stack upward from the zero line and negative values stack downward independently.
* When false, all values accumulate continuously from the previous series top, preserving legacy behaviour.
*/
set: function (value) {
this.separatePositiveNegativeStacksProperty = value;
this.notifyPropertyChanged(constants_1.PROPERTY.SEPARATE_POSITIVE_NEGATIVE_STACKS);
},
enumerable: false,
configurable: true
});
/** @inheritDoc */
StackedXyCollection.prototype.hasDataSeriesValues = function () {
return this.isEnoughDataToDraw();
};
// PROTECTED
// PRIVATE
StackedXyCollection.prototype.detachChildSeries = function (series) {
series.onDetachFromParentCollection();
this.isAccumulatedVectorDirty = true;
this.invalidateParent();
};
StackedXyCollection.prototype.attachChildSeries = function (series) {
series.onAttachToParentCollection(this, this.getParentSurface, this.notifyPropertyChanged);
if (this.parentSurface) {
series.onAttach(this.parentSurface);
}
this.isAccumulatedVectorDirty = true;
this.invalidateParent();
};
StackedXyCollection.prototype.checkXValuesCorrect = function () {
var length = this.getDataSeriesValuesCount();
this.getVisibleSeries().forEach(function (el) {
if (!(el.dataSeries.count() === length)) {
throw Error("All stacked series in on collection should have the same amount of X Values");
}
});
};
/**
* @param numberOfElements - number of element expected is used for performance to reserve memory
*/
StackedXyCollection.prototype.clearAccumulatedVectors = function (numberOfElements) {
this.accumulatedValues0.clear();
this.accumulatedValues0.reserve(numberOfElements);
this.asArray().forEach(function (el) {
el.accumulatedValues.clear();
el.accumulatedValues.reserve(numberOfElements);
el.bottomAccumulatedValues.clear();
el.bottomAccumulatedValues.reserve(numberOfElements);
});
};
StackedXyCollection.prototype.getLastVisibleSeries = function () {
var lastItem = this.getVisibleSeries().slice(-1)[0];
return lastItem;
};
return StackedXyCollection;
}(BaseStackedCollection_1.BaseStackedCollection));
exports.StackedXyCollection = StackedXyCollection;