UNPKG

scichart

Version:

Fast WebGL JavaScript Charting Library and Framework

345 lines (344 loc) 20.3 kB
"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.ErrorSeriesDrawingProvider = void 0; var __1 = require("../../../.."); var Deleter_1 = require("../../../../Core/Deleter"); var Rect_1 = require("../../../../Core/Rect"); var AxisType_1 = require("../../../../types/AxisType"); var ErrorDirection_1 = require("../../../../types/ErrorDirection"); var ErrorMode_1 = require("../../../../types/ErrorMode"); var Pen2DCache_1 = require("../../../Drawing/Pen2DCache"); var WebGlRenderContext2D_1 = require("../../../Drawing/WebGlRenderContext2D"); var LogarithmicAxis_1 = require("../../Axis/LogarithmicAxis"); var NativeObject_1 = require("../../Helpers/NativeObject"); var constants_1 = require("../constants"); var BaseSeriesDrawingProvider_1 = require("./BaseSeriesDrawingProvider"); /** * Used internally - a drawing provider performs drawing for a {@link BaseBandRenderableSeries} using * our WebAssembly WebGL rendering engine */ var ErrorSeriesDrawingProvider = /** @class */ (function (_super) { __extends(ErrorSeriesDrawingProvider, _super); /** * Creates an instance of the {@link BandSeriesDrawingProvider} * @param webAssemblyContext The {@link TSciChart | SciChart 2D WebAssembly Context} containing native methods and * access to our WebGL2 Engine and WebAssembly numerical methods * @param parentSeries the parent {@link BaseBandRenderableSeries} which this drawing provider is attached to */ function ErrorSeriesDrawingProvider(webAssemblyContext, parentSeries) { var _this = _super.call(this, webAssemblyContext, parentSeries) || this; _this.linesPenCache = new Pen2DCache_1.Pen2DCache(webAssemblyContext); _this.tempXVec = new _this.webAssemblyContext.SCRTDoubleVector(); _this.tempYVec = new _this.webAssemblyContext.SCRTDoubleVector(); return _this; } /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.onAttachSeries = function () { _super.prototype.onAttachSeries.call(this); this.args = new this.webAssemblyContext.SCRTLineDrawingParams(); this.nativeDrawingProvider = new this.webAssemblyContext.SCRTLineSegmentDrawingProvider(); var _a = this.parentSeries, stroke = _a.stroke, strokeThickness = _a.strokeThickness, opacity = _a.opacity, strokeDashArray = _a.strokeDashArray; (0, Pen2DCache_1.createPenInCache)(this.linesPenCache, stroke, strokeThickness, opacity, strokeDashArray); }; /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.onDetachSeries = function () { _super.prototype.onDetachSeries.call(this); }; /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.delete = function () { this.nativeDrawingProvider = (0, Deleter_1.deleteSafe)(this.nativeDrawingProvider); this.linesPenCache = (0, Deleter_1.deleteSafe)(this.linesPenCache); this.args = (0, Deleter_1.deleteSafe)(this.args); this.tempXVec = (0, Deleter_1.deleteSafe)(this.tempXVec); this.tempYVec = (0, Deleter_1.deleteSafe)(this.tempYVec); _super.prototype.delete.call(this); }; /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.draw = function (renderContext, renderPassData) { var linesPen = (0, Pen2DCache_1.getScrtPenFromCache)(this.linesPenCache); if (!linesPen || linesPen.m_fThickness === 0.0) { return; } var pointSeries = renderPassData.pointSeries; var vertices = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext); // this.xLineCoordinates.clear(); // this.yLineCoordinates.clear(); // this.args.Reset(); // this.args.SetLinesPen(linesPen); // this.args.isDigitalLine = this.parentSeries.isDigitalLine; // this.args.forceShaderMethod = true; // this.args.containsNaN = true; // this.args.lineGaps = this.webAssemblyContext.SCRTLineGapMode.DrawGaps; // this.args.verticalChart = renderPassData.isVerticalChart; // // Stroke paletting per point // this.applyStrokePaletting(linesPen); // if (this.palettingState.palettedColors) { // this.args.SetPalettedColors(this.palettingState.palettedColors); // } // const nativeContext = renderContext.getNativeContext(); var isCategoryAxis = renderPassData.xCoordinateCalculator.isCategoryCoordinateCalculator; var xValues = pointSeries.xValues; var xDrawValues = isCategoryAxis ? pointSeries.indexes : xValues; var yDrawValues = pointSeries.yValues; var hDrawValues = pointSeries.highValues; var lDrawValues = pointSeries.lowValues; var isVerticalDirection = this.parentSeries.errorDirection === ErrorDirection_1.EErrorDirection.Vertical; var dataPointWidthCalc = isVerticalDirection ? renderPassData.xCoordinateCalculator : renderPassData.yCoordinateCalculator; var dataPointWidthPx = this.parentSeries.getDataPointWidth(dataPointWidthCalc, this.parentSeries.dataPointWidth, this.parentSeries.dataPointWidthMode); var dataPointWidth = dataPointWidthCalc.getDataWidth(dataPointWidthPx); var halfRange = dataPointWidthPx * 0.5; var hasLogarithmicXAxis = this.parentSeries.xAxis.type === AxisType_1.EAxisType.LogarithmicAxis; var hasLogarithmicYAxis = this.parentSeries.yAxis.type === AxisType_1.EAxisType.LogarithmicAxis; var hasNegativeLogXAxis = this.parentSeries.xAxis.isNegative; var hasNegativeLogYAxis = this.parentSeries.yAxis.isNegative; var hasHighCap = this.parentSeries.errorMode !== ErrorMode_1.EErrorMode.Low; var hasLowCap = this.parentSeries.errorMode !== ErrorMode_1.EErrorMode.High; var dataPointsCount = xDrawValues.size(); var xView = (0, __1.vectorToArrayViewF64)(xDrawValues, this.webAssemblyContext); var yView = (0, __1.vectorToArrayViewF64)(yDrawValues, this.webAssemblyContext); var hView = (0, __1.vectorToArrayViewF64)(hDrawValues, this.webAssemblyContext); var lView = (0, __1.vectorToArrayViewF64)(lDrawValues, this.webAssemblyContext); this.args.Reset(); this.args.SetLinesPen(linesPen); this.args.forceShaderMethod = true; this.args.verticalChart = renderPassData.isVerticalChart; this.args.startIndex = 0; this.args.count = dataPointsCount; if (!hasLogarithmicYAxis) { if (isVerticalDirection) { // main line if (this.parentSeries.drawConnector) { this.args.fourVectorsMode = true; this.args.SetXValues(xDrawValues); this.args.SetYValues(hasHighCap ? hDrawValues : yDrawValues); this.args.SetZValues(xDrawValues); this.args.SetWValues(hasLowCap ? lDrawValues : yDrawValues); this.args.SetNativeContext(renderContext.getNativeContext()); this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator); this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator); this.nativeDrawingProvider.DrawLinesVec(this.args); } var capCount = this.prepareTempCapVectors(0, dataPointsCount, dataPointWidth, xDrawValues, lDrawValues, hDrawValues, true, hasHighCap, hasLowCap); this.drawCaps(renderContext, renderPassData, linesPen, capCount); } else { // main line if (this.parentSeries.drawConnector) { this.args.fourVectorsMode = true; this.args.SetXValues(hasHighCap ? hDrawValues : xDrawValues); this.args.SetYValues(yDrawValues); this.args.SetZValues(hasLowCap ? lDrawValues : xDrawValues); this.args.SetWValues(yDrawValues); this.args.SetNativeContext(renderContext.getNativeContext()); this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator); this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator); this.nativeDrawingProvider.DrawLinesVec(this.args); } var capCount = this.prepareTempCapVectors(0, dataPointsCount, dataPointWidth, yDrawValues, lDrawValues, hDrawValues, false, hasHighCap, hasLowCap); this.drawCaps(renderContext, renderPassData, linesPen, capCount); } } else { if (isVerticalDirection) { for (var i = 0; i < dataPointsCount; ++i) { var xValue = xView[i]; var yValue = yView[i]; var highValue = hasHighCap ? hView[i] : yValue; var lowValue = hasLowCap ? lView[i] : yValue; var shouldDrawLowErrorToLimit = hasLogarithmicYAxis && !hasNegativeLogYAxis && lowValue <= 0; if (shouldDrawLowErrorToLimit) { lowValue = this.parentSeries.yAxis.visibleRange.min; } var shouldDrawHighErrorToLimit = hasLogarithmicYAxis && hasNegativeLogYAxis && highValue >= 0; if (shouldDrawHighErrorToLimit) { highValue = this.parentSeries.yAxis.visibleRange.max; } var xCoord = renderPassData.xCoordinateCalculator.getCoordinate(xValue); var yCoord = renderPassData.yCoordinateCalculator.getCoordinate(yValue); var highCoord = renderPassData.yCoordinateCalculator.getCoordinate(highValue); var lowCoord = renderPassData.yCoordinateCalculator.getCoordinate(lowValue); var capStart = xCoord - halfRange; var capEnd = xCoord + halfRange; // main line if (this.parentSeries.drawConnector) { this.addLineVertices(vertices, xCoord, isNaN(highValue) ? yCoord : highCoord, xCoord, isNaN(lowValue) ? yCoord : lowCoord); } if (hasHighCap && !shouldDrawHighErrorToLimit && this.parentSeries.drawWhiskers) { // top whiskers this.addLineVertices(vertices, capStart, highCoord, capEnd, highCoord); } if (hasLowCap && !shouldDrawLowErrorToLimit && this.parentSeries.drawWhiskers) { // bottom whiskers this.addLineVertices(vertices, capStart, lowCoord, capEnd, lowCoord); } } } else { for (var i = 0; i < dataPointsCount; ++i) { var xValue = xView[i]; var yValue = yView[i]; var highValue = hasHighCap ? hView[i] : xValue; var lowValue = hasLowCap ? lView[i] : xValue; var shouldDrawLowErrorToLimit = hasLogarithmicXAxis && !hasNegativeLogXAxis && lowValue <= 0; if (shouldDrawLowErrorToLimit) { lowValue = LogarithmicAxis_1.MIN_LOG_AXIS_VALUE; } var shouldDrawHighErrorToLimit = hasLogarithmicXAxis && hasNegativeLogXAxis && highValue >= 0; if (shouldDrawHighErrorToLimit) { highValue = -LogarithmicAxis_1.MIN_LOG_AXIS_VALUE; } var xCoord = renderPassData.xCoordinateCalculator.getCoordinate(xValue); var yCoord = renderPassData.yCoordinateCalculator.getCoordinate(yValue); var highCoord = renderPassData.xCoordinateCalculator.getCoordinate(highValue); var lowCoord = renderPassData.xCoordinateCalculator.getCoordinate(lowValue); var capStart = yCoord - halfRange; var capEnd = yCoord + halfRange; // main line if (this.parentSeries.drawConnector) { this.addLineVertices(vertices, isNaN(lowValue) ? xCoord : lowCoord, yCoord, isNaN(highValue) ? xCoord : highCoord, yCoord); } if (hasHighCap && !shouldDrawHighErrorToLimit && this.parentSeries.drawWhiskers) { // top whiskers this.addLineVertices(vertices, highCoord, capStart, highCoord, capEnd); } if (hasLowCap && !shouldDrawLowErrorToLimit && this.parentSeries.drawWhiskers) { // bottom whiskers this.addLineVertices(vertices, lowCoord, capStart, lowCoord, capEnd); } } } var seriesViewRect = this.parentSeries.parentSurface.seriesViewRect; var clipRect = Rect_1.Rect.intersect(this.parentSeries.parentSurface.clipRect, seriesViewRect); renderContext.drawLinesNative(vertices, linesPen, WebGlRenderContext2D_1.ELineDrawMode.DiscontinuousLine, clipRect, seriesViewRect.x, seriesViewRect.y); } }; /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.onDpiChanged = function (args) { _super.prototype.onDpiChanged.call(this, args); this.onSeriesPropertyChange(constants_1.PROPERTY.STROKE); }; /** * @inheritDoc */ ErrorSeriesDrawingProvider.prototype.onSeriesPropertyChange = function (propertyName) { _super.prototype.onSeriesPropertyChange.call(this, propertyName); var _a = this.parentSeries, stroke = _a.stroke, strokeThickness = _a.strokeThickness, opacity = _a.opacity, strokeDashArray = _a.strokeDashArray; if (propertyName === constants_1.PROPERTY.STROKE || propertyName === constants_1.PROPERTY.STROKE_THICKNESS || propertyName === constants_1.PROPERTY.OPACITY || propertyName === constants_1.PROPERTY.STROKE_DASH_ARRAY) { (0, Pen2DCache_1.createPenInCache)(this.linesPenCache, stroke, strokeThickness, opacity, strokeDashArray); } }; /** * To remove this and prepareTempMedianVectors() we need to update native SCRTLineSegmentDrawingProvider to support * input of three vectors xVals, yVals, x1Vals where x1Vals are treated as length of the line segment in X direction centered in x,y */ ErrorSeriesDrawingProvider.prototype.prepareTempCapVectors = function (startIndex, count, dataPointWidth, xValues, lowValues, highValues, isVerticalErrorDirection, hasHighCap, hasLowCap) { var s = (hasHighCap ? 2 : 0) + (hasLowCap ? 2 : 0); this.tempXVec.resizeFast(count * s); this.tempYVec.resizeFast(count * s); var halfRange = dataPointWidth / 2; var xView = (0, __1.vectorToArrayViewF64)(xValues, this.webAssemblyContext); var tempXView = (0, __1.vectorToArrayViewF64)(isVerticalErrorDirection ? this.tempXVec : this.tempYVec, this.webAssemblyContext); var tempYView = (0, __1.vectorToArrayViewF64)(isVerticalErrorDirection ? this.tempYVec : this.tempXVec, this.webAssemblyContext); if (hasHighCap && hasLowCap) { var minView = (0, __1.vectorToArrayViewF64)(lowValues, this.webAssemblyContext); var maxView = (0, __1.vectorToArrayViewF64)(highValues, this.webAssemblyContext); for (var i = startIndex; i < startIndex + count; i++) { var x = xView[i]; var min = minView[i]; var max = maxView[i]; var outI = i * 4; tempXView[outI] = x - halfRange; tempYView[outI] = max; tempXView[outI + 1] = x + halfRange; tempYView[outI + 1] = max; tempXView[outI + 2] = x - halfRange; tempYView[outI + 2] = min; tempXView[outI + 3] = x + halfRange; tempYView[outI + 3] = min; } } else { var maxView = (0, __1.vectorToArrayViewF64)(hasHighCap ? highValues : lowValues, this.webAssemblyContext); for (var i = startIndex; i < startIndex + count; i++) { var x = xView[i]; var max = maxView[i]; var outI = i * 2; tempXView[outI] = x - halfRange; tempYView[outI] = max; tempXView[outI + 1] = x + halfRange; tempYView[outI + 1] = max; } } return count * s; }; ErrorSeriesDrawingProvider.prototype.drawCaps = function (renderContext, renderPassData, linesPen, count) { if (!linesPen) return; this.args.Reset(); this.args.SetLinesPen(linesPen); this.args.forceShaderMethod = true; this.args.forceClamp = true; // WARNING! Here we always set verticalChart = false because caps are drawn after the connector // and vertical chart has already been applied. Setting it here to True will do another 90 deg rotation // Another option would be to call // renderContext.setTranslationRotationAndClip(clipRect, seriesViewRect.x, seriesViewRect.y); this.args.verticalChart = false; this.args.SetXValues(this.tempXVec); this.args.SetYValues(this.tempYVec); this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator); this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator); this.args.SetNativeContext(renderContext.getNativeContext()); this.args.count = count; this.args.startIndex = 0; this.args.SetNativeContext(renderContext.getNativeContext()); this.args.SetXValues(this.tempXVec); this.args.SetYValues(this.tempYVec); this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator); this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator); // TODO: Do we need to provide paletting support for caps and whiskers? If yes, how it should work? this.nativeDrawingProvider.DrawLinesVec(this.args); }; ErrorSeriesDrawingProvider.prototype.addLineVertices = function (vertices, x1, y1, x2, y2) { var isVerticalChart = this.parentSeries.xAxis.isVerticalChart; if (isVerticalChart) { vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, y1, x1)); vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, y2, x2)); } else { vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, x1, y1)); vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, x2, y2)); } }; return ErrorSeriesDrawingProvider; }(BaseSeriesDrawingProvider_1.BaseSeriesDrawingProvider)); exports.ErrorSeriesDrawingProvider = ErrorSeriesDrawingProvider;