scichart
Version:
Fast WebGL JavaScript Charting Library and Framework
353 lines (352 loc) • 18.5 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 __());
};
})();
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;