UNPKG

@syncfusion/ej2-charts

Version:

Feature-rich chart control with built-in support for over 25 chart types, technical indictors, trendline, zooming, tooltip, selection, crosshair and trackball.

481 lines (480 loc) 22 kB
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 (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { ChartLocation, ControlPoints } from '../../common/utils/helper'; import { extend, isNullOrUndefined } from '@syncfusion/ej2-base'; import { LineBase } from './line-base'; /** * Base class for spline-type series. * * @private */ var SplineBase = /** @class */ (function (_super) { __extends(SplineBase, _super); /** * Initializes the spline rendering module. * * @param {Chart} [chartModule] - Specifies the chart instance. */ function SplineBase(chartModule) { var _this = _super.call(this, chartModule) || this; _this.splinePoints = []; _this.lowSplinePoints = []; return _this; } /** * Finds the spline points for the series. * * @param {Series} series - The series for which spline points need to be found. * @returns {void} * @private */ SplineBase.prototype.findSplinePoint = function (series) { var value; var lowPoints; var realPoints = []; var points = []; var point; var pointIndex = 0; var negativePoint = false; realPoints = this.filterEmptyPoints(series); for (var i = 0; i < realPoints.length; i++) { point = realPoints[i]; if (point.x === null || point.x === '') { continue; } else { point.index = pointIndex; pointIndex++; points.push(point); } } var isLow = false; this.splinePoints = this.findSplineCoefficients(points, series, isLow); if (series.type === 'SplineRangeArea') { isLow = !isLow; this.lowSplinePoints = this.findSplineCoefficients(points, series, isLow); } if (points.length > 1) { series.drawPoints = []; series.lowDrawPoints = []; for (var _i = 0, points_1 = points; _i < points_1.length; _i++) { var point_1 = points_1[_i]; negativePoint = negativePoint ? negativePoint : point_1.yValue < 0; if (point_1.index !== 0) { var previous = this.getPreviousIndex(points, point_1.index - 1, series); if (series.type === 'SplineRangeArea') { points[previous].yValue = points[previous].high > points[previous].low ? points[previous].high : points[previous].low; point_1.yValue = point_1.high > point_1.low ? point_1.high : point_1.low; } value = this.getControlPoints(points[previous], point_1, this.splinePoints[previous], this.splinePoints[point_1.index], series); series.drawPoints.push(value); if (series.type === 'SplineRangeArea') { points[previous].yValue = points[previous].low < points[previous].high ? points[previous].low : points[previous].high; point_1.yValue = point_1.low < point_1.high ? point_1.low : point_1.high; lowPoints = this.getControlPoints(points[previous], point_1, this.lowSplinePoints[previous], this.lowSplinePoints[point_1.index], series); series.lowDrawPoints.push(lowPoints); } // fix for Y-Axis of Spline chart not adjusting scale to suit dataSource issue var delta = series.yMax - series.yMin; if (point_1.yValue && value.controlPoint1.y && value.controlPoint2.y && delta > 1) { series.yMin = Math.min(series.yMin, point_1.yValue, value.controlPoint1.y, value.controlPoint2.y); series.yMax = Math.ceil(Math.max(series.yMax, point_1.yValue, value.controlPoint1.y, value.controlPoint2.y)); series.yMin = series.yAxis.valueType !== 'Logarithmic' ? Math.floor(series.yMin) : series.yMin; } } } if (!negativePoint && series.yMin < 0) { series.yMin = 0; } if (series.chart.chartAreaType === 'PolarRadar' && series.isClosed) { value = this.getControlPoints({ xValue: points[points.length - 1].xValue, yValue: points[points.length - 1].yValue }, { xValue: points[points.length - 1].xValue + 1, yValue: points[0].yValue }, this.splinePoints[0], this.splinePoints[points[points.length - 1].index], series); series.drawPoints.push(value); } } }; SplineBase.prototype.getPreviousIndex = function (points, i, series) { if (series.emptyPointSettings.mode !== 'Drop') { return i; } while (isNullOrUndefined(points[i]) && i > -1) { i = i - 1; } return i; }; SplineBase.prototype.getNextIndex = function (points, i, series) { if (series.emptyPointSettings.mode !== 'Drop') { return i; } while (isNullOrUndefined(points[i]) && i < points.length) { i = i + 1; } return i; }; SplineBase.prototype.filterEmptyPoints = function (series, seriesPoints) { if (series.emptyPointSettings.mode !== 'Drop' && this.isPointInRange(series.points)) { return seriesPoints ? seriesPoints : series.points; } var points = seriesPoints ? seriesPoints : extend([], series.points, null, true); for (var i = 0; i < points.length; i++) { points[i].index = i; if (points[i].isEmpty) { points[i].symbolLocations = []; points[i].regions = []; points.splice(i, 1); i--; } } return points; }; /** * Checks if the data points are within the range. * * @param {Points[]} points - The data points to check. * @returns {boolean} True if the data points are within the range, false otherwise. * @private */ SplineBase.prototype.isPointInRange = function (points) { for (var _i = 0, points_2 = points; _i < points_2.length; _i++) { var point = points_2[_i]; if (!point.isPointInRange) { return false; } } return true; }; /** * Finds the spline coefficients based on the type of spline interpolation. * * @param {Points[]} points - The data points for spline interpolation. * @param {Series} series - The series associated with the data points. * @param {boolean} [isLow] - Indicates whether to calculate the lower bound. Default is false. * @returns {number[]} The calculated coefficients. * @private */ SplineBase.prototype.findSplineCoefficients = function (points, series, isLow) { var ySpline = []; var ySplineDuplicate = []; var cardinalSplineTension = series.cardinalSplineTension ? series.cardinalSplineTension : 0.5; // cardinalSplineTension = cardinalSplineTension < 0 ? 0 : cardinalSplineTension > 1 ? 1 : cardinalSplineTension; if (cardinalSplineTension < 0) { cardinalSplineTension = 0; } else if (cardinalSplineTension > 1) { cardinalSplineTension = 1; } switch (series.splineType) { case 'Monotonic': ySpline = this.monotonicSplineCoefficients(points, series, isLow); break; case 'Cardinal': ySpline = this.cardinalSplineCofficients(points, series); break; default: if (series.splineType === 'Clamped') { ySpline = this.clampedSplineCofficients(points, series, isLow); } else { // assigning the first and last value as zero ySpline[0] = ySplineDuplicate[0] = 0; ySpline[points.length - 1] = 0; } ySpline = this.naturalSplineCoefficients(points, series, isLow); break; } return ySpline; }; /** * Calculates the coefficients for a monotonic spline interpolation. * * @param {Points[]} points - The data points for spline interpolation. * @param {Series} series - The series associated with the data points. * @param {boolean} isLow - Indicates whether to calculate the lower bound. * @returns {number[]} The calculated coefficients. * @private */ SplineBase.prototype.monotonicSplineCoefficients = function (points, series, isLow) { var count = points.length; var ySpline = []; var dx = []; var dy = []; var slope = []; var interPoint; for (var i = 0; i < count - 1; i++) { if (series.type === 'SplineRangeArea') { if (!isLow) { points[i + 1].yValue = points[i + 1].high > points[i + 1].low ? points[i + 1].high : points[i + 1].low; points[i].yValue = points[i].high > points[i].low ? points[i].high : points[i].low; } if (isLow) { points[i + 1].yValue = points[i + 1].low < points[i + 1].high ? points[i + 1].low : points[i + 1].high; points[i].yValue = points[i].low < points[i].high ? points[i].low : points[i].high; } } dx[i] = points[i + 1].xValue - points[i].xValue; dy[i] = points[i + 1].yValue - points[i].yValue; slope[i] = dy[i] / dx[i]; } //interpolant points var slopeLength = slope.length; // to find the first and last co-efficient value ySpline[0] = slope[0]; ySpline[count - 1] = slope[slopeLength - 1]; //to find the other co-efficient values for (var j = 0; j < dx.length; j++) { if (slopeLength > j + 1) { if (slope[j] * slope[j + 1] <= 0) { ySpline[j + 1] = 0; } else { interPoint = dx[j] + dx[j + 1]; ySpline[j + 1] = 3 * interPoint / ((interPoint + dx[j + 1]) / slope[j] + (interPoint + dx[j]) / slope[j + 1]); } } } return ySpline; }; /** * Calculates the coefficients for a cardinal spline interpolation. * * @param {Points[]} points - The data points for spline interpolation. * @param {Series} series - The series associated with the data points. * @returns {number[]} The calculated coefficients. * @private */ SplineBase.prototype.cardinalSplineCofficients = function (points, series) { var count = points.length; var ySpline = []; var cardinalSplineTension = series.cardinalSplineTension ? series.cardinalSplineTension : 0.5; cardinalSplineTension = cardinalSplineTension < 0 ? 0 : cardinalSplineTension > 1 ? 1 : cardinalSplineTension; for (var i = 0; i < count; i++) { if (i === 0) { ySpline[i] = (count > 2) ? (cardinalSplineTension * (points[i + 2].xValue - points[i].xValue)) : 0; } else if (i === (count - 1)) { ySpline[i] = (count > 2) ? (cardinalSplineTension * (points[count - 1].xValue - points[count - 3].xValue)) : 0; } else { ySpline[i] = (cardinalSplineTension * (points[i + 1].xValue - points[i - 1].xValue)); } } return ySpline; }; /** * Calculates the coefficients for a clamped spline interpolation. * * @param {Points[]} points - The data points for spline interpolation. * @param {Series} series - The series associated with the data points. * @param {boolean} isLow - Indicates whether to calculate the lower bound. * @returns {number[]} The calculated coefficients. * @private */ SplineBase.prototype.clampedSplineCofficients = function (points, series, isLow) { var count = points.length; var ySpline = []; var ySplineDuplicate = []; for (var i = 0; i < count - 1; i++) { if (series.type === 'SplineRangeArea') { if (!isLow) { points[1].yValue = points[1].high > points[1].low ? points[1].high : points[1].low; points[0].yValue = points[0].high > points[0].low ? points[0].high : points[0].low; points[points.length - 1].yValue = points[points.length - 1].high > points[points.length - 1].low ? points[points.length - 1].high : points[points.length - 1].low; points[points.length - 2].yValue = points[points.length - 2].high > points[points.length - 2].low ? points[points.length - 2].high : points[points.length - 2].low; } if (isLow) { points[1].yValue = points[1].low < points[1].high ? points[1].low : points[1].high; points[0].yValue = points[0].low < points[0].high ? points[0].low : points[0].high; points[points.length - 1].yValue = points[points.length - 1].low < points[points.length - 1].high ? points[points.length - 1].low : points[points.length - 1].high; points[points.length - 2].yValue = points[points.length - 2].low < points[points.length - 2].high ? points[points.length - 2].low : points[points.length - 2].high; } } ySpline[0] = (3 * (points[1].yValue - points[0].yValue)) / (points[1].xValue - points[0].xValue) - 3; ySplineDuplicate[0] = 0.5; ySpline[points.length - 1] = (3 * (points[points.length - 1].yValue - points[points.length - 2].yValue)) / (points[points.length - 1].xValue - points[points.length - 2].xValue); ySpline[0] = ySplineDuplicate[0] = Math.abs(ySpline[0]) === Infinity ? 0 : ySpline[0]; ySpline[points.length - 1] = ySplineDuplicate[points.length - 1] = Math.abs(ySpline[points.length - 1]) === Infinity ? 0 : ySpline[points.length - 1]; } return ySpline; }; /** * Calculates the coefficients for a natural spline interpolation. * * @param {Points[]} points - The data points for spline interpolation. * @param {Series} series - The series associated with the data points. * @param {boolean} isLow - Indicates whether to calculate the lower bound. * @returns {number[]} The calculated coefficients. * @private */ SplineBase.prototype.naturalSplineCoefficients = function (points, series, isLow) { var count = points.length; var ySpline = []; var ySplineDuplicate = []; var dy1; var dy2; var coefficient1; var coefficient2; var coefficient3; ySpline[0] = ySplineDuplicate[0] = 0; ySpline[points.length - 1] = 0; for (var i = 1; i < count - 1; i++) { if (series.type === 'SplineRangeArea') { if (!isLow) { points[i + 1].yValue = points[i + 1].low > points[i + 1].high ? points[i + 1].low : points[i + 1].high; points[i].yValue = points[i].low > points[i].high ? points[i].low : points[i].high; points[i - 1].yValue = points[i - 1].low > points[i - 1].high ? points[i - 1].low : points[i - 1].high; } if (isLow) { points[i + 1].yValue = points[i + 1].high < points[i + 1].low ? points[i + 1].high : points[i + 1].low; points[i].yValue = points[i].high < points[i].low ? points[i].high : points[i].low; points[i - 1].yValue = points[i - 1].high < points[i - 1].low ? points[i - 1].high : points[i - 1].low; } } coefficient1 = points[i].xValue - points[i - 1].xValue; coefficient2 = points[i + 1].xValue - points[i - 1].xValue; coefficient3 = points[i + 1].xValue - points[i].xValue; dy1 = points[i + 1].yValue - points[i].yValue || null; dy2 = points[i].yValue - points[i - 1].yValue || null; if (coefficient1 === 0 || coefficient2 === 0 || coefficient3 === 0) { ySpline[i] = 0; ySplineDuplicate[i] = 0; } else { var p = 1 / (coefficient1 * ySpline[i - 1] + 2 * coefficient2); ySpline[i] = -p * coefficient3; ySplineDuplicate[i] = p * (6 * (dy1 / coefficient3 - dy2 / coefficient1) - coefficient1 * ySplineDuplicate[i - 1]); } } for (var k = count - 2; k >= 0; k--) { ySpline[k] = ySpline[k] * ySpline[k + 1] + ySplineDuplicate[k]; } return ySpline; }; /** * Calculates the control points for a spline segment. * * @param {Points} point1 - The first data point. * @param {Points} point2 - The second data point. * @param {number} ySpline1 - The Y-value of the first spline point. * @param {number} ySpline2 - The Y-value of the second spline point. * @param {Series} series - The series associated with the data points. * @returns {ControlPoints} The calculated control points. * @private */ SplineBase.prototype.getControlPoints = function (point1, point2, ySpline1, ySpline2, series) { var controlPoint1; var controlPoint2; var point; var ySplineDuplicate1 = ySpline1; var ySplineDuplicate2 = ySpline2; var xValue1 = point1.xValue; var yValue1 = point1.yValue; var xValue2 = point2.xValue; var yValue2 = point2.yValue; switch (series.splineType) { case 'Cardinal': if (series.xAxis.valueType === 'DateTime') { ySplineDuplicate1 = ySpline1 / this.dateTimeInterval(series); ySplineDuplicate2 = ySpline2 / this.dateTimeInterval(series); } controlPoint1 = new ChartLocation(xValue1 + ySpline1 / 3, yValue1 + ySplineDuplicate1 / 3); controlPoint2 = new ChartLocation(xValue2 - ySpline2 / 3, yValue2 - ySplineDuplicate2 / 3); point = new ControlPoints(controlPoint1, controlPoint2); break; case 'Monotonic': { var value = (xValue2 - xValue1) / 3; controlPoint1 = new ChartLocation(xValue1 + value, yValue1 + ySpline1 * value); controlPoint2 = new ChartLocation(xValue2 - value, yValue2 - ySpline2 * value); point = new ControlPoints(controlPoint1, controlPoint2); break; } default: { var one3 = 1 / 3.0; var deltaX2 = (xValue2 - xValue1); deltaX2 = deltaX2 * deltaX2; var y1 = one3 * (((2 * yValue1) + yValue2) - one3 * deltaX2 * (ySpline1 + 0.5 * ySpline2)); var y2 = one3 * ((yValue1 + (2 * yValue2)) - one3 * deltaX2 * (0.5 * ySpline1 + ySpline2)); controlPoint1 = new ChartLocation((2 * (xValue1) + (xValue2)) * one3, y1); controlPoint2 = new ChartLocation(((xValue1) + 2 * (xValue2)) * one3, y2); point = new ControlPoints(controlPoint1, controlPoint2); break; } } return point; }; /** * Calculates the date-time interval. * * @param {Series} series - The series for which the date-time interval needs to be calculated. * @returns {number} The calculated date-time interval. * @protected */ SplineBase.prototype.dateTimeInterval = function (series) { var interval = series.xAxis.actualIntervalType; var intervalInMilliseconds; if (interval === 'Years') { intervalInMilliseconds = 365 * 24 * 60 * 60 * 1000; } else if (interval === 'Months') { intervalInMilliseconds = 30 * 24 * 60 * 60 * 1000; } else if (interval === 'Days') { intervalInMilliseconds = 24 * 60 * 60 * 1000; } else if (interval === 'Hours') { intervalInMilliseconds = 60 * 60 * 1000; } else if (interval === 'Minutes') { intervalInMilliseconds = 60 * 1000; } else if (interval === 'Seconds') { intervalInMilliseconds = 1000; } else { intervalInMilliseconds = 30 * 24 * 60 * 60 * 1000; } return intervalInMilliseconds; }; /** * Animates the series. * * @param {Series} series - Defines the series to animate. * @returns {void} * @private */ SplineBase.prototype.doAnimation = function (series) { var option = series.animation; this.doLinearAnimation(series, option); }; return SplineBase; }(LineBase)); export { SplineBase };