UNPKG

scichart

Version:

Fast WebGL JavaScript Charting Library and Framework

353 lines (352 loc) 18.5 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 __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LineArrowAnnotation = exports.EArrowHeadPosition = void 0; var classFactory_1 = require("../../../Builder/classFactory"); var Deleter_1 = require("../../../Core/Deleter"); var Guard_1 = require("../../../Core/Guard"); var BaseType_1 = require("../../../types/BaseType"); var geometryHelpers_1 = require("../../../utils/geometryHelpers"); var BrushCache_1 = require("../../Drawing/BrushCache"); var Pen2DCache_1 = require("../../Drawing/Pen2DCache"); var DpiHelper_1 = require("../TextureManager/DpiHelper"); var constants_1 = require("./constants"); var IAnnotation_1 = require("./IAnnotation"); var LineAnnotation_1 = require("./LineAnnotation"); /** * Enumeration of possible positions for the arrow head inside a {@link LineArrowAnnotation} */ var EArrowHeadPosition; (function (EArrowHeadPosition) { /** * The arrowhead will be at `x2y2` * Default value */ EArrowHeadPosition["End"] = "End"; /** * The arrowhead will be at `x1y1` */ EArrowHeadPosition["Start"] = "Start"; /** * One arrowhead will be at `x1y1` and another at `x2y2` */ EArrowHeadPosition["StartEnd"] = "StartEnd"; })(EArrowHeadPosition = exports.EArrowHeadPosition || (exports.EArrowHeadPosition = {})); var TRANSPARENT = "transparent"; /** * @summary The {@link LineArrowAnnotation} provides an {@link LineAnnotation} which draws 1 or 2 arrow heads at * x1y1, x2y2 coordinates over the {@link SciChartSurface} * @description * To add a {@link LineArrowAnnotation} to a {@link SciChartSurface}, use the following code: * ```ts * const sciChartSurface: SciChartSurface; * const lineArrowAnnotation = new LineArrowAnnotation({ * x1: 1, y1: 3, x2: 2, y2: 4, * stroke: "#FFFFFF", * arrowHeadPosition: EArrowHeadPosition.End, * arrowStyle: { * headLength: 10, * headWidth: 8, * headDepth: 0.8, * fill: "#000000", * stroke: "#FFFFFF", * strokeThickness: 2, * }, * arrowHeadPosition: EArrowHeadPosition.End, * isArrowHeadScalable: true * }); * sciChartSurface.annotations.add(lineArrowAnnotation); * ``` * @remarks Uses the fast WebGL/WebAssembly {@link WebGL2RenderingContext} for rendering */ var LineArrowAnnotation = /** @class */ (function (_super) { __extends(LineArrowAnnotation, _super); /** * Creates an instance of a LineArrowAnnotation * @param options Optional parameters of type {@link ILineArrowAnnotationOptions} which configure the annotation upon construction */ function LineArrowAnnotation(options) { var _this = this; var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r; _this = _super.call(this, options) || this; /** @inheritDoc */ _this.type = IAnnotation_1.EAnnotationType.RenderContextLineArrowAnnotation; _this.arrowHeadPositionProperty = EArrowHeadPosition.End; _this.isArrowHeadScalableProperty = false; /** * Creates a proxy for the arrow style object to trigger updates when properties change */ _this.getArrowStyleProxy = function (newStyle) { return new Proxy(newStyle, { set: function (target, key, value) { target[key] = value; _this.notifyPropertyChanged("arrowStyle"); return true; } }); }; _this.arrowHeadPositionProperty = (_a = options === null || options === void 0 ? void 0 : options.arrowHeadPosition) !== null && _a !== void 0 ? _a : EArrowHeadPosition.End; _this.isArrowHeadScalable = (_b = options === null || options === void 0 ? void 0 : options.isArrowHeadScalable) !== null && _b !== void 0 ? _b : false; _this.arrowStyleProperty = _this.getArrowStyleProxy({ headLength: (_d = (_c = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _c === void 0 ? void 0 : _c.headLength) !== null && _d !== void 0 ? _d : 10, headWidth: (_f = (_e = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _e === void 0 ? void 0 : _e.headWidth) !== null && _f !== void 0 ? _f : 8, headDepth: (_h = (_g = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _g === void 0 ? void 0 : _g.headDepth) !== null && _h !== void 0 ? _h : 0, fill: (_k = (_j = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _j === void 0 ? void 0 : _j.fill) !== null && _k !== void 0 ? _k : TRANSPARENT, stroke: (_o = (_m = (_l = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _l === void 0 ? void 0 : _l.stroke) !== null && _m !== void 0 ? _m : _this.stroke) !== null && _o !== void 0 ? _o : "#FFFFFF", strokeThickness: (_r = (_q = (_p = options === null || options === void 0 ? void 0 : options.arrowStyle) === null || _p === void 0 ? void 0 : _p.strokeThickness) !== null && _q !== void 0 ? _q : _this.strokeThickness) !== null && _r !== void 0 ? _r : 1 }); if (options === null || options === void 0 ? void 0 : options.onArrowHeadSizeChanged) { if (typeof options.onArrowHeadSizeChanged === "string") { _this.typeMap.set("onArrowHeadSizeChanged", options.onArrowHeadSizeChanged); _this.onArrowHeadSizeChangedCallback = (0, classFactory_1.getFunction)(BaseType_1.EBaseType.OptionFunction, options.onArrowHeadSizeChanged); } else { _this.onArrowHeadSizeChangedCallback = options.onArrowHeadSizeChanged; } } return _this; } Object.defineProperty(LineArrowAnnotation.prototype, "arrowStyle", { /** * Gets the arrow style configuration */ get: function () { return this.arrowStyleProperty; }, /** * Sets the arrow style configuration */ set: function (value) { var newStyle = __assign(__assign({}, this.arrowStyle), value); this.arrowStyleProperty = this.getArrowStyleProxy(newStyle); this.notifyPropertyChanged("arrowStyle"); }, enumerable: false, configurable: true }); Object.defineProperty(LineArrowAnnotation.prototype, "arrowHeadPosition", { /** * Gets the position of the arrow head */ get: function () { return this.arrowHeadPositionProperty; }, /** * Sets the position of the arrow head */ set: function (value) { this.arrowHeadPositionProperty = value; this.notifyPropertyChanged(constants_1.PROPERTY.ARROW_HEAD_POSITION); }, enumerable: false, configurable: true }); Object.defineProperty(LineArrowAnnotation.prototype, "isArrowHeadScalable", { /** * Gets whether the arrow head's sizes should be calculated relatively to the line length or not */ get: function () { return this.isArrowHeadScalableProperty; }, /** * Sets whether the arrow head's sizes should be calculated relatively to the line length or not */ set: function (value) { this.isArrowHeadScalableProperty = value; this.notifyPropertyChanged(constants_1.PROPERTY.IS_ARROW_HEAD_RELATIVE); }, enumerable: false, configurable: true }); /** @inheritDoc */ LineArrowAnnotation.prototype.onAttach = function (scs) { _super.prototype.onAttach.call(this, scs); this.updateArrowheadBrushes(scs); }; /** * Updates the fill brush and stroke pen for the arrowhead based on the current arrow style */ LineArrowAnnotation.prototype.updateArrowheadBrushes = function (scs) { if (!this.arrowheadStrokePenCache) { this.arrowheadStrokePenCache = new Pen2DCache_1.Pen2DCache(scs.webAssemblyContext2D); } (0, Pen2DCache_1.createPenInCache)(this.arrowheadStrokePenCache, this.arrowStyle.stroke, this.arrowStyle.strokeThickness, this.opacity); if (this.arrowStyle.fill && this.arrowStyle.fill !== TRANSPARENT) { if (!this.arrowheadFillBrushCache) { this.arrowheadFillBrushCache = new BrushCache_1.BrushCache(scs.webAssemblyContext2D); } (0, BrushCache_1.createBrushInCache)(this.arrowheadFillBrushCache, this.arrowStyle.fill, this.opacity); } }; /** @inheritDoc */ LineArrowAnnotation.prototype.delete = function () { _super.prototype.delete.call(this); this.arrowheadFillBrushCache = (0, Deleter_1.deleteSafe)(this.arrowheadFillBrushCache); this.arrowheadStrokePenCache = (0, Deleter_1.deleteSafe)(this.arrowheadStrokePenCache); }; /** @inheritDoc */ LineArrowAnnotation.prototype.drawWithContext = function (renderContext, xCalc, yCalc, seriesViewRect, surfaceViewRect, chartViewRect) { Guard_1.Guard.notNull(renderContext, "renderContext"); Guard_1.Guard.notNull(xCalc, "xCalc"); Guard_1.Guard.notNull(yCalc, "yCalc"); var _a = this.convertPolarToCartesian(this.getX1Coordinate(xCalc, yCalc), this.getY1Coordinate(xCalc, yCalc)), borderX1 = _a.x, borderY1 = _a.y; var _b = this.convertPolarToCartesian(this.getX2Coordinate(xCalc, yCalc), this.getY2Coordinate(xCalc, yCalc)), borderX2 = _b.x, borderY2 = _b.y; this.setAnnotationBorders(borderX1, borderX2, borderY1, borderY2); var clipRect = this.getClippingRect(this.clipping, seriesViewRect, surfaceViewRect, chartViewRect); var _c = this.getAnnotationBorders(), x1 = _c.x1, x2 = _c.x2, y1 = _c.y1, y2 = _c.y2; var dx = x2 - x1; var dy = y2 - y1; if (dx === 0 && dy === 0) { return; } var angle = Math.atan2(dy, dx); var scaledHeadLength; var scaledHeadWidth; if (this.isArrowHeadScalable) { var currentXRange = this.xAxis.visibleRange.max - this.xAxis.visibleRange.min; var currentYRange = this.yAxis.visibleRange.max - this.yAxis.visibleRange.min; if (!this.storedXRange || !this.storedYRange) { this.storedXRange = currentXRange; this.storedYRange = currentYRange; } var zoomFactorX = currentXRange / this.storedXRange; var zoomFactorY = currentYRange / this.storedYRange; var zoomFactor = (zoomFactorX + zoomFactorY) / 2; scaledHeadLength = (this.arrowStyle.headLength / zoomFactor) * DpiHelper_1.DpiHelper.PIXEL_RATIO; scaledHeadWidth = (this.arrowStyle.headWidth / zoomFactor) * DpiHelper_1.DpiHelper.PIXEL_RATIO; } else { scaledHeadLength = this.arrowStyle.headLength * DpiHelper_1.DpiHelper.PIXEL_RATIO; scaledHeadWidth = this.arrowStyle.headWidth * DpiHelper_1.DpiHelper.PIXEL_RATIO; } var scaledHeadDepth = this.arrowStyle.headDepth * scaledHeadLength; if (this.onArrowHeadSizeChangedCallback) { var callbackArgs = { headLength: this.arrowStyle.headLength, headWidth: this.arrowStyle.headWidth, headDepth: this.arrowStyle.headDepth, angle: angle, x1: x1, y1: y1, x2: x2, y2: y2 }; var result = this.onArrowHeadSizeChangedCallback(callbackArgs); if (result) { if (result.headLength !== undefined) { scaledHeadLength = result.headLength * DpiHelper_1.DpiHelper.PIXEL_RATIO; } if (result.headWidth !== undefined) { scaledHeadWidth = result.headWidth * DpiHelper_1.DpiHelper.PIXEL_RATIO; } if (result.headDepth !== undefined) { scaledHeadDepth = result.headDepth * scaledHeadLength; } } } var _d = geometryHelpers_1.geometryHelpers.calcArrowHeadParameters(x1, y1, angle + Math.PI, scaledHeadLength, scaledHeadWidth, scaledHeadDepth), baseMidX = _d.baseMidX, baseMidY = _d.baseMidY, leftX = _d.leftX, leftY = _d.leftY, rightX = _d.rightX, rightY = _d.rightY; var _e = geometryHelpers_1.geometryHelpers.calcArrowHeadParameters(x2, y2, angle, scaledHeadLength, scaledHeadWidth, scaledHeadDepth), baseMidX2 = _e.baseMidX, baseMidY2 = _e.baseMidY, leftX2 = _e.leftX, leftY2 = _e.leftY, rightX2 = _e.rightX, rightY2 = _e.rightY; var lineX1 = x1; var lineY1 = y1; var lineX2 = x2; var lineY2 = y2; if (this.arrowStyle.headWidth > 0 && this.arrowStyle.headLength > 0) { if ([EArrowHeadPosition.Start, EArrowHeadPosition.StartEnd].includes(this.arrowHeadPosition)) { lineX1 = baseMidX; lineY1 = baseMidY; this.drawArrowHead(renderContext, x1, y1, scaledHeadDepth === 0, baseMidX, baseMidY, leftX, leftY, rightX, rightY, seriesViewRect, clipRect); } if ([EArrowHeadPosition.End, EArrowHeadPosition.StartEnd].includes(this.arrowHeadPosition)) { lineX2 = baseMidX2; lineY2 = baseMidY2; this.drawArrowHead(renderContext, x2, y2, scaledHeadDepth === 0, baseMidX2, baseMidY2, leftX2, leftY2, rightX2, rightY2, seriesViewRect, clipRect); } } // only draw main line until the base(s) of the arrowhead(s) this.drawLine(renderContext, lineX1, lineY1, lineX2, lineY2, seriesViewRect, surfaceViewRect, chartViewRect); }; LineArrowAnnotation.prototype.drawLine = function (renderContext, x1Coord, y1Coord, x2Coord, y2Coord, seriesViewRect, surfaceViewRect, chartViewRect) { var strokePen = this.stroke && this.strokeThickness && this.strokePenCache ? (0, Pen2DCache_1.getWebGlPenFromCache)(this.strokePenCache) : undefined; if (strokePen) { var clipRect = this.getClippingRect(this.clipping, seriesViewRect, surfaceViewRect, chartViewRect); renderContext.drawLine(x1Coord, y1Coord, x2Coord, y2Coord, strokePen, seriesViewRect, clipRect); } this.updateAdornerInner(); }; /** * Used internally to draw the arrow head at the specified coordinates */ LineArrowAnnotation.prototype.drawArrowHead = function (renderContext, tipX, tipY, isZeroHeadDepth, baseMidX, baseMidY, leftX, leftY, rightX, rightY, seriesViewRect, clipRect) { var arrowStrokePen = (0, Pen2DCache_1.getWebGlPenFromCache)(this.arrowheadStrokePenCache); if (!arrowStrokePen) { return; } var isFilled = this.arrowStyle.fill && this.arrowStyle.fill !== TRANSPARENT; var fillBrush = isFilled ? (0, BrushCache_1.getWebGlBrushFromCache)(this.arrowheadFillBrushCache) : undefined; if (isZeroHeadDepth) { // only draw left and right arrow hands, no need for fill or base lines renderContext.drawLines([leftX, leftY, tipX, tipY, rightX, rightY], arrowStrokePen, seriesViewRect, clipRect); } else { if (isFilled) { renderContext.drawTriangleStrip([leftX, baseMidX, tipX, rightX], [leftY, baseMidY, tipY, rightY], seriesViewRect, clipRect, fillBrush); } renderContext.drawLines([baseMidX, baseMidY, leftX, leftY, tipX, tipY, rightX, rightY, baseMidX, baseMidY], arrowStrokePen, seriesViewRect, clipRect); } }; /** @inheritDoc */ LineArrowAnnotation.prototype.notifyPropertyChanged = function (propertyName) { _super.prototype.notifyPropertyChanged.call(this, propertyName); if (propertyName === "arrowStyle" || propertyName === constants_1.PROPERTY.OPACITY) { this.updateArrowheadBrushes(this.parentSurface); } }; /** @inheritDoc */ LineArrowAnnotation.prototype.toJSON = function () { var json = _super.prototype.toJSON.call(this); var options = { arrowStyle: { headLength: this.arrowStyle.headLength, headWidth: this.arrowStyle.headWidth, headDepth: this.arrowStyle.headDepth, fill: this.arrowStyle.fill, stroke: this.arrowStyle.stroke, strokeThickness: this.arrowStyle.strokeThickness }, arrowHeadPosition: this.arrowHeadPosition, isArrowHeadScalable: this.isArrowHeadScalable, onArrowHeadSizeChanged: this.typeMap.get("onArrowHeadSizeChanged") }; Object.assign(json.options, options); return json; }; return LineArrowAnnotation; }(LineAnnotation_1.LineAnnotation)); exports.LineArrowAnnotation = LineArrowAnnotation;