highcharts
Version:
JavaScript charting framework
1,086 lines (1,055 loc) • 35 kB
JavaScript
// SPDX-License-Identifier: LicenseRef-Highcharts
/**
* @license Highstock JS v13.0.1 (2026-08-17)
* @module highcharts/modules/pointandfigure
* @requires highcharts
* @requires highcharts/modules/stock
*
* Point and figure series type for Highcharts Stock
*
* (c) 2010-2026 Highsoft AS
*
* Author: Kamil Musiałowski
*
* A commercial license may be required depending on use,
* see www.highcharts.com/license
*/
import * as __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__ from "../highcharts.src.js";
/******/ // The require scope
/******/ const __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ const getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter/value functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ if(Array.isArray(definition)) {
/******/ var i = 0;
/******/ while(i < definition.length) {
/******/ var key = definition[i++];
/******/ var binding = definition[i++];
/******/ if(!__webpack_require__.o(exports, key)) {
/******/ if(binding === 0) {
/******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
/******/ } else {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
/******/ }
/******/ } else if(binding === 0) { i++; }
/******/ }
/******/ } else {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/************************************************************************/
;// external ["../highcharts.src.js","default"]
const external_highcharts_src_js_default_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"];
var external_highcharts_src_js_default_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_namespaceObject);
;// ./code/es-modules/Data/ColumnUtils.js
/* *
*
* (c) 2020-2026 Highsoft AS
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* Authors:
* - Dawid Draguła
*
* */
/* *
*
* Functions
*
* */
/**
* Sets the length of the column array.
*
* @param {DataTableColumn} column
* Column to be modified.
*
* @param {number} length
* New length of the column.
*
* @param {boolean} asSubarray
* If column is a typed array, return a subarray instead of a new array. It
* is faster `O(1)`, but the entire buffer will be kept in memory until all
* views of it are destroyed. Default is `false`.
*
* @return {DataTableColumn}
* Modified column.
*
* @private
*/
function setLength(column, length, asSubarray) {
if (Array.isArray(column)) {
column.length = length;
return column;
}
return column[asSubarray ? 'subarray' : 'slice'](0, length);
}
/**
* Splices a column array.
*
* @param {DataTableColumn} column
* Column to be modified.
*
* @param {number} start
* Index at which to start changing the array.
*
* @param {number} deleteCount
* An integer indicating the number of old array elements to remove.
*
* @param {boolean} removedAsSubarray
* If column is a typed array, return a subarray instead of a new array. It
* is faster `O(1)`, but the entire buffer will be kept in memory until all
* views to it are destroyed. Default is `true`.
*
* @param {Array<number>|TypedArray} items
* The elements to add to the array, beginning at the start index. If you
* don't specify any elements, `splice()` will only remove elements from the
* array.
*
* @return {SpliceResult}
* Object containing removed elements and the modified column.
*
* @private
*/
function splice(column, start, deleteCount, removedAsSubarray, items = []) {
if (Array.isArray(column)) {
if (!Array.isArray(items)) {
items = Array.from(items);
}
return {
removed: column.splice(start, deleteCount, ...items),
array: column
};
}
const Constructor = Object.getPrototypeOf(column)
.constructor;
const removed = column[removedAsSubarray ? 'subarray' : 'slice'](start, start + deleteCount);
const newLength = column.length - deleteCount + items.length;
const result = new Constructor(newLength);
result.set(column.subarray(0, start), 0);
result.set(items, start);
result.set(column.subarray(start + deleteCount), start + items.length);
return {
removed: removed,
array: result
};
}
/**
* Converts a cell value to a number.
*
* @param {DataTableCellType} value
* Cell value to convert to a number.
*
* @param {boolean} useNaN
* If `true`, returns `NaN` for non-numeric values; if `false`,
* returns `null` instead.
*
* @return {number | null}
* Number or `null` if the value is not a number.
*
* @private
*/
function convertToNumber(value, useNaN) {
switch (typeof value) {
case 'boolean':
return (value ? 1 : 0);
case 'number':
return (isNaN(value) && !useNaN ? null : value);
default:
value = parseFloat(`${value ?? ''}`);
return (isNaN(value) && !useNaN ? null : value);
}
}
/* *
*
* Default Export
*
* */
const ColumnUtils = {
convertToNumber,
setLength,
splice
};
/* harmony default export */ const Data_ColumnUtils = (ColumnUtils);
;// ./code/es-modules/Data/DataTableCore.js
/* *
*
* (c) 2009-2026 Highsoft AS
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* Authors:
* - Sophie Bremer
* - Gøran Slettemark
* - Torstein Hønsi
*
* */
const { setLength: DataTableCore_setLength, splice: DataTableCore_splice } = Data_ColumnUtils;
/* *
*
* Class
*
* */
/**
* Class to manage columns and rows in a table structure. It provides methods
* to add, remove, and manipulate columns and rows, as well as to retrieve data
* from specific cells.
*
* Highcharts allows passing a `DataTable` or a configuration object for a data
* table in the `dataTable` property, either chart-level
* [dataTable](https://api.highcharts.com/highcharts/dataTable) or as
* [series.dataTable](https://api.highcharts.com/highcharts/series.dataTable).
* The `DataTable` is then used as a source for the series data points, mapped
* by the `series.dataMapping` option.
*
* After chart instantiation, the data table can be accessed from the series as
* `series.dataTable`. CRUD operations on the data table will be reflected in
* the chart.
*
* @example
* const dataTable = new Highcharts.DataTable({
* columns: {
* year: [2020, 2021, 2022, 2023],
* cost: [11, 13, 12, 14],
* revenue: [12, 15, 14, 18]
* }
* });
*
* @class
* @name Highcharts.DataTable
*
* @param {Highcharts.DataTableOptionsObject} [options]
* Options to initialize the new DataTable instance.
*/
class DataTableCore {
constructor(options = {}) {
this.isDataTable = true;
this.autoId = !options.id;
this.columns = {};
this.id = (options.id || (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)());
this.rowCount = 0;
this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)();
let rowCount = 0;
(0,external_highcharts_src_js_default_namespaceObject.objectEach)(options.columns || {}, (column, columnId) => {
this.columns[columnId] = column.slice();
rowCount = Math.max(rowCount, column.length);
});
this.applyRowCount(rowCount);
}
/* *
*
* Functions
*
* */
/**
* Applies a row count to the table by setting the `rowCount` property and
* adjusting the length of all columns.
*
* @private
* @param {number} rowCount The new row count.
*/
applyRowCount(rowCount) {
this.rowCount = rowCount;
(0,external_highcharts_src_js_default_namespaceObject.objectEach)(this.columns, (column, columnId) => {
if (column.length !== rowCount) {
this.columns[columnId] = DataTableCore_setLength(column, rowCount);
}
});
}
/**
* Delete rows. Simplified version of the full
* `DataTable.deleteRows` method.
*
* @sample highcharts/datatable/live-chart/
* Add and delete rows in a live chart
* @sample highcharts/datatable/shared-with-grid/
* Chart with data table CRUD operations
*
* @function Highcharts.DataTable#deleteRows
*
* @param {number} rowIndex
* The start row index
*
* @param {number} [rowCount=1]
* The number of rows to delete
*
* @return {void}
*
* @emits #afterDeleteRows
*/
deleteRows(rowIndex, rowCount = 1) {
if (rowCount > 0 && rowIndex < this.rowCount) {
let length = 0;
(0,external_highcharts_src_js_default_namespaceObject.objectEach)(this.columns, (column, columnId) => {
this.columns[columnId] =
DataTableCore_splice(column, rowIndex, rowCount).array;
length = column.length;
});
this.rowCount = length;
}
(0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterDeleteRows', { rowIndex, rowCount });
this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)();
}
/**
* Fetches the given column by the canonical column ID. Simplified version
* of the full `DataTable.getRow` method, always returning by reference.
*
* @function Highcharts.DataTable#getColumn
*
* @param {string} columnId
* ID of the column to get.
*
* @return {Highcharts.DataTableColumn|undefined}
* A copy of the column, or `undefined` if not found.
*/
getColumn(columnId,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
asReference) {
return this.columns[columnId];
}
/**
* Retrieves all or the given columns. Simplified version of the full
* `DataTable.getColumns` method, always returning by reference.
*
* @function Highcharts.DataTable#getColumns
*
* @param {Array<string>} [columnIds]
* Column ids to retrieve.
*
* @return {Highcharts.DataTableColumnCollection}
* Collection of columns. If a requested column was not found, it is
* `undefined`.
*/
getColumns(columnIds,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
asReference) {
return (columnIds || Object.keys(this.columns)).reduce((columns, columnId) => {
columns[columnId] = this.columns[columnId];
return columns;
}, {});
}
/**
* Retrieves the row at a given index.
*
* @function Highcharts.DataTable#getRowObject
*
* @param {number} rowIndex
* Row index to retrieve. First row has index 0.
*
* @param {Array<string>} [columnNames]
* Column names to retrieve.
*
* @return {Record<string, number|string|undefined>|undefined}
* Returns the row values, or `undefined` if not found.
*/
getRowObject(rowIndex, columnNames) {
const row = {}, columns = this.columns;
columnNames ?? (columnNames = Object.keys(this.columns));
for (const columnName of columnNames) {
row[columnName] = columns[columnName]?.[rowIndex];
}
return row;
}
/**
* Sets cell values for a column. Will insert a new column, if not found.
*
* @function Highcharts.DataTable#setColumn
*
* @param {string} columnId
* Column name to set.
*
* @param {Highcharts.DataTableColumn} [column]
* Values to set in the column.
*
* @param {number} [rowIndex]
* Index of the first row to change. (Default: 0)
*
* @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
* Custom information for pending events.
*
* @emits #setColumns
* @emits #afterSetColumns
*/
setColumn(columnId, column = [], rowIndex = 0, eventDetail) {
this.setColumns({ [columnId]: column }, rowIndex, eventDetail);
}
/**
* Sets cell values for multiple columns. Will insert new columns, if not
* found. Simplified version of the full `DataTable.setColumns`, limited
* to full replacement of the columns (undefined `rowIndex`).
*
* @sample highcharts/datatable/shared-with-grid/
* Chart with data table CRUD operations
*
* @function Highcharts.DataTable#setColumns
*
* @param {Highcharts.DataTableColumnCollection} columns
* Columns as a collection, where the keys are the column names.
*
* @param {number} [rowIndex]
* Index of the first row to change. Ignored in the simplified `DataTable`,
* as it always replaces the full column.
*
* @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
* Custom information for pending events.
*
* @emits #setColumns
* @emits #afterSetColumns
*/
setColumns(columns, rowIndex, eventDetail) {
let rowCount = this.rowCount;
(0,external_highcharts_src_js_default_namespaceObject.objectEach)(columns, (column, columnId) => {
this.columns[columnId] = column.slice();
rowCount = column.length;
});
this.applyRowCount(rowCount);
if (!eventDetail?.silent) {
(0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterSetColumns');
this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)();
}
}
/**
* Sets cell values of a row. Will insert a new row if no index was
* provided, or if the index is higher than the total number of table rows.
* A simplified version of the full `DateTable.setRow`, limited to objects.
*
* @sample highcharts/datatable/live-chart/
* Add and delete rows in a live chart
* @sample stock/datatable/live-candlestick/
* Live candlestick
* @sample highcharts/datatable/shared-with-grid/
* Chart with data table CRUD operations
*
* @function Highcharts.DataTable#setRow
*
* @param {Record<string, number|string|undefined>} row
* Cell values to set.
*
* @param {number} [rowIndex]
* Index of the row to set. Leave `undefined` to add as a new row.
*
* @param {boolean} [insert]
* Whether to insert the row at the given index, or to overwrite the row.
*
* @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
* Custom information for pending events.
*
* @emits #afterSetRows
*/
setRow(row, rowIndex = this.rowCount, insert, eventDetail) {
var _a;
const { columns } = this, indexRowCount = insert ? this.rowCount + 1 : rowIndex + 1, rowKeys = Object.keys(row);
if (eventDetail?.addColumns !== false) {
for (let i = 0, iEnd = rowKeys.length; i < iEnd; i++) {
columns[_a = rowKeys[i]] || (columns[_a] = new Array(this.rowCount));
}
}
(0,external_highcharts_src_js_default_namespaceObject.objectEach)(columns, (column, columnId) => {
if (column) {
if (insert) {
column = DataTableCore_splice(column, rowIndex, 0, true, [row[columnId]]).array;
}
else {
column[rowIndex] =
// Preserve explicit null and undefined but fall back
// to existing value if the new row does not have the
// key
columnId in row ?
row[columnId] :
column[rowIndex];
}
columns[columnId] = column;
}
});
this.applyRowCount(Math.max(indexRowCount, this.rowCount));
if (!eventDetail?.silent) {
(0,external_highcharts_src_js_default_namespaceObject.fireEvent)(this, 'afterSetRows', { rowIndex });
this.versionTag = (0,external_highcharts_src_js_default_namespaceObject.uniqueKey)();
}
}
/**
* Returns the modified (clone) or the original data table if the modified
* one does not exist.
*
* @return {Highcharts.DataTable}
* The modified (clone) or the original data table.
*/
getModified() {
return this.modified || this;
}
}
/* *
*
* Default Export
*
* */
/* harmony default export */ const Data_DataTableCore = (DataTableCore);
/* *
*
* API Declarations
*
* */
/**
* A collection of data table columns defined by a object where the key is the
* column ID and the value is an array of the column values. Typed arrays are
* supported.
*
* @type {Highcharts.DataTableColumnCollection|undefined}
* @apioption dataTable.columns
*/
/**
* Custom ID to identify the new DataTable instance.
*
* @type {string|undefined}
* @apioption dataTable.id
*/
/**
* A typed array.
* @typedef {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} Highcharts.TypedArray
*/ /**
* A column of values in a data table.
* @typedef {Array<boolean|null|number|string|undefined>|Highcharts.TypedArray} Highcharts.DataTableColumn
*/ /**
* A collection of data table columns defined by a object where the key is the
* column ID and the value is an array of the column values. Typed arrays are
* supported.
* @typedef {Record<string, Highcharts.DataTableColumn>} Highcharts.DataTableColumnCollection
*/
/**
* Options for the `DataTable` or `DataTableCore` classes.
* @interface Highcharts.DataTableOptionsObject
*/ /**
* The column options for the data table. The columns are defined by an object
* where the key is the column ID and the value is an array of the column
* values.
*
* @name Highcharts.DataTableOptionsObject.columns
* @type {Highcharts.DataTableColumnCollection|undefined}
*/ /**
* Custom ID to identify the new DataTable instance.
*
* @name Highcharts.DataTableOptionsObject.id
* @type {string|undefined}
*/
(''); // Keeps doclets above in JS file
;// external ["../highcharts.src.js","default","SeriesRegistry"]
const external_highcharts_src_js_default_SeriesRegistry_namespaceObject = __WEBPACK_EXTERNAL_MODULE__highcharts_src_js_8202131d__["default"].SeriesRegistry;
var external_highcharts_src_js_default_SeriesRegistry_default = /*#__PURE__*/__webpack_require__.n(external_highcharts_src_js_default_SeriesRegistry_namespaceObject);
;// ./code/es-modules/Series/PointAndFigure/PointAndFigurePoint.js
/* *
*
* (c) 2010-2026 Highsoft AS
* Author: Kamil Musiałowski
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* */
/* *
*
* Imports
*
* */
const { seriesTypes: { scatter: { prototype: { pointClass: ScatterPoint } } } } = (external_highcharts_src_js_default_SeriesRegistry_default());
/* *
*
* Class
*
* */
/**
* @private
* @class
*/
class PointAndFigurePoint extends ScatterPoint {
/* *
*
* Functions
*
* */
resolveMarker() {
const seriesOptions = this.series.options;
this.marker = this.options.marker =
this.upTrend ? seriesOptions.markerUp : seriesOptions.marker;
this.color = this.options.marker.lineColor;
}
resolveColor() {
super.resolveColor();
this.resolveMarker();
}
/**
* Extend the parent method by adding up or down to the class name.
* @private
* @function Highcharts.seriesTypes.pointandfigure#getClassName
*/
getClassName() {
return super.getClassName.call(this) +
(this.upTrend ?
' highcharts-point-up' :
' highcharts-point-down');
}
}
/* *
*
* Export Default
*
* */
/* harmony default export */ const PointAndFigure_PointAndFigurePoint = (PointAndFigurePoint);
;// ./code/es-modules/Series/PointAndFigure/PointAndFigureSeriesDefaults.js
/* *
*
* (c) 2010-2026 Highsoft AS
* Author: Kamil Musiałowski
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* */
/* *
*
* API Options
*
* */
/**
* The Point and Figure series represents changes in stock price movements,
* without focusing on the time and volume. Each data point is created when the
* `boxSize` criteria is met. Opposite column of points gets created only when
* the `reversalAmount` threshold is met.
*
* @sample stock/demo/pointandfigure/
* Point and Figure series
*
* @extends plotOptions.scatter
* @product highstock
* @excluding boostBlending, boostThreshold, compare, compareBase,
* compareStart, cumulative, cumulativeStart, dataGrouping,
* dataGrouping, dragDrop
* @requires modules/pointandfigure
* @optionparent plotOptions.pointandfigure
*/
const PointAndFigureSeriesDefaults = {
boxSize: '1%',
reversalAmount: 3,
tooltip: {
pointFormat: '<span style="color:{point.color}">\u25CF</span> ' +
'<b> {series.name}</b><br/>' +
'Close: {point.y:.2f}<br/>',
headerFormat: ''
},
turboThreshold: 0,
groupPadding: 0.2,
pointPadding: 0.1,
pointRange: null,
dataGrouping: {
enabled: false
},
markerUp: {
symbol: 'cross',
lineColor: '#00FF00',
lineWidth: 2
},
marker: {
symbol: 'circle',
fillColor: 'transparent',
lineColor: '#FF0000',
lineWidth: 2
},
legendSymbol: 'lineMarker'
};
/* *
*
* API Options
*
* */
/**
* A `pointandfigure` series. If the [type](#series.pointandfigure.type)
* option is not specified, it is inherited from [chart.type](
* #chart.type).
*
* @type {*}
* @extends series,plotOptions.pointandfigure
* @product highstock
* @excluding boostBlending, boostThreshold, compare, compareBase,
* compareStart, cumulative, cumulativeStart, dataGrouping,
* dataGrouping, dragDrop
* @requires modules/pointandfigure
* @apioption series.pointandfigure
*/
/**
* An array of data points for the series. For the `pointandfigure` series
* type, points can be given in the following way:
*
* 1. An array of arrays with 2 values. In this case, the values correspond
* to `x, y`. Y values are parsed under the hood to create
* point and figure format data points.
* ```js
* data: [
* [1665408600000, 140.42],
* [1665495000000, 138.98],
* [1665581400000, 138.34]
* ]
* ```
* 2. An array of objects with named values `{x, y}`.
* ```js
* data: [
* {x: 1665408600000, y: 140.42},
* {x: 1665495000000, y: 138.98},
* {x: 1665581400000, y: 138.34}
* ]
* ```
*
* @basic
* @type {Array<Array<number,number>|*>}
* @extends series.scatter.data
* @product highstock
* @apioption series.pointandfigure.data
*/
/**
* Price increment that determines if a new point should be added to the column.
*
*
* @type {string|number}
* @since 12.0.0
* @product highstock
* @apioption plotOptions.pointandfigure.boxSize
*/
/**
* Threshold that should be met to create a new column in opposite direction.
*
*
* @type {number}
* @since 12.0.0
* @product highstock
* @apioption plotOptions.pointandfigure.reversalAmount
*/
/**
* Marker options for the up direction column, inherited from `series.marker`
* options.
*
* @extends plotOptions.series.marker
* @product highstock
* @apioption plotOptions.pointandfigure.markerUp
*/
''; // Keeps doclets above detached
/* *
*
* Default Export
*
* */
/* harmony default export */ const PointAndFigure_PointAndFigureSeriesDefaults = (PointAndFigureSeriesDefaults);
;// ./code/es-modules/Series/CrossSymbol.js
/* *
*
* (c) 2010-2026 Highsoft AS
* Authors: Kamil Musiałowski, Markus Barstad
*
* Shared cross marker symbol registration used by series modules.
* This keeps `cross` out of Core SVG symbols while allowing modules
* like PointAndFigure and Contour to compose it when needed.
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* */
const { composed } = (external_highcharts_src_js_default_default());
/* *
*
* Composition
*
* */
var CrossSymbol;
(function (CrossSymbol) {
/* *
*
* Functions
*
* */
/**
* Register the shared `cross` symbol on a renderer class.
*
* @internal
*/
function compose(SVGRendererClass) {
if ((0,external_highcharts_src_js_default_namespaceObject.pushUnique)(composed, 'Series.CrossSymbol')) {
SVGRendererClass.prototype.symbols.cross = cross;
}
}
CrossSymbol.compose = compose;
/**
* Cross marker path.
* @internal
*/
function cross(x, y, w, h) {
return [
['M', x, y],
['L', x + w, y + h],
['M', x + w, y],
['L', x, y + h],
['Z']
];
}
})(CrossSymbol || (CrossSymbol = {}));
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const Series_CrossSymbol = (CrossSymbol);
;// ./code/es-modules/Series/PointAndFigure/PointAndFigureSeries.js
/* *
*
* (c) 2010-2026 Highsoft AS
* Author: Kamil Musiałowski
*
* Integration of this software requires a license.
* - For commercial use, see www.highcharts.com/license
* - For non-commercial, see www.highcharts.com/license-eula
*
*
* */
/* *
* Imports
*
* */
const { composed: PointAndFigureSeries_composed } = (external_highcharts_src_js_default_default());
const { scatter: ScatterSeries, column: { prototype: columnProto } } = (external_highcharts_src_js_default_SeriesRegistry_default()).seriesTypes;
/* *
*
* Declarations
*
* */
/* *
*
* Functions
*
* */
/* *
*
* Class
*
* */
/**
* The series type
*
* @private
* @class
* @name Highcharts.seriesTypes.pointandfigure
*
* @augments Highcharts.Series
*/
class PointAndFigureSeries extends ScatterSeries {
constructor() {
/* *
*
* Static Properties
*
* */
super(...arguments);
this.allowDG = false;
}
/* *
*
* Static Functions
*
* */
static compose(SVGRendererClass) {
if ((0,external_highcharts_src_js_default_namespaceObject.pushUnique)(PointAndFigureSeries_composed, 'pointandfigure')) {
Series_CrossSymbol.compose(SVGRendererClass);
}
}
/* *
*
* Functions
*
* */
init() {
super.init.apply(this, arguments);
this.pnfDataGroups = [];
}
getProcessedData() {
if (!this.pnfDataGroups) {
return {
modified: this.dataTable.getModified(),
cropped: false,
cropStart: 0,
closestPointRange: 1
};
}
const series = this, options = series.options, xData = series.getColumn('x', true), yData = series.getColumn('y', true), boxSize = options.boxSize, calculatedBoxSize = (0,external_highcharts_src_js_default_namespaceObject.isNumber)(boxSize) ?
boxSize : (0,external_highcharts_src_js_default_namespaceObject.relativeLength)(boxSize, yData[0]), pnfDataGroups = series.pnfDataGroups, reversal = calculatedBoxSize * options.reversalAmount, dataTable = this.dataTable.getModified(), modified = dataTable === this.dataTable ?
dataTable :
new Data_DataTableCore();
series.calculatedBoxSize = calculatedBoxSize;
let upTrend;
/**
* Get the Y value of last data point, from the last PNF group.
* @private
* @function Highcharts.seriesTypes.pointandfigure#getLastPoint
*/
function getLastPoint(pnfDataGroups) {
const y = pnfDataGroups[pnfDataGroups.length - 1].y;
return y[y.length - 1];
}
/**
* Push new data point to the last PNF group.
* @private
* @function Highcharts.seriesTypes.pointandfigure#pushNewPoint
*/
function pushNewPoint(y, upTrend, lastPoint) {
const currPointGroup = pnfDataGroups[pnfDataGroups.length - 1], flipFactor = upTrend ? 1 : -1, times = Math.floor(flipFactor * (y - lastPoint) / calculatedBoxSize);
for (let i = 1; i <= times; i++) {
const newPoint = lastPoint + flipFactor * (calculatedBoxSize * i);
currPointGroup.y.push(newPoint);
}
}
if (this.isDirtyData || pnfDataGroups.length === 0) {
this.pnfDataGroups.length = 0;
// Get first point and determine its symbol and trend
for (let i = 0; i < yData.length; i++) {
const x = xData[i], close = yData[i], firstPoint = yData[0];
if (close - firstPoint >= calculatedBoxSize) {
upTrend = true;
pnfDataGroups.push({ x, y: [close], upTrend });
break;
}
if (firstPoint - close >= calculatedBoxSize) {
upTrend = false;
pnfDataGroups.push({ x, y: [close], upTrend });
break;
}
}
yData.forEach((close, i) => {
const x = xData[i], lastPoint = getLastPoint(pnfDataGroups);
if (upTrend) {
// Add point going UP
if (close - lastPoint >= calculatedBoxSize) {
pushNewPoint(close, upTrend, lastPoint);
}
if (lastPoint - close >= reversal) { // Handle reversal
upTrend = false;
pnfDataGroups.push({ x, y: [], upTrend });
pushNewPoint(close, upTrend, lastPoint);
}
}
if (!upTrend) {
// Add point going DOWN
if (lastPoint - close >= calculatedBoxSize) {
pushNewPoint(close, upTrend, lastPoint);
}
if (close - lastPoint >= reversal) { // Handle reversal
upTrend = true;
pnfDataGroups.push({ x, y: [], upTrend });
pushNewPoint(close, upTrend, lastPoint);
}
}
});
}
// Process the pnfDataGroups to HC series format
const finalData = [];
const processedXData = [];
const processedYData = [];
const processedUpTrendData = [];
pnfDataGroups.forEach((point) => {
const x = point.x, upTrend = point.upTrend;
point.y.forEach((y) => {
processedXData.push(x);
processedYData.push(y);
processedUpTrendData.push(upTrend);
finalData.push({
x,
y,
upTrend
});
});
});
modified.setColumn('x', processedXData);
modified.setColumn('y', processedYData);
modified.setColumn('upTrend', processedUpTrendData);
series.pnfDataGroups = pnfDataGroups;
series.hasProcessedDataTable = true;
return {
modified,
cropped: false,
cropStart: 0,
closestPointRange: 1
};
}
markerAttribs(point) {
const series = this, options = series.options, attribs = {}, pos = point.pos();
attribs.width = series.markerWidth;
attribs.height = series.markerHeight;
if (pos && attribs.width && attribs.height) {
attribs.x = pos[0] - Math.round(attribs.width) / 2;
attribs.y = pos[1] - Math.round(attribs.height) / 2;
}
if (options.crisp && attribs.x) {
// Math.floor for #1843:
attribs.x = Math.floor(attribs.x);
}
return attribs;
}
translate() {
const metrics = this.getColumnMetrics(), calculatedBoxSize = this.calculatedBoxSize;
this.markerWidth = metrics.width + metrics.paddedWidth + metrics.offset;
this.markerHeight =
this.yAxis.toPixels(0) - this.yAxis.toPixels(calculatedBoxSize);
super.translate();
}
}
PointAndFigureSeries.defaultOptions = (0,external_highcharts_src_js_default_namespaceObject.merge)(ScatterSeries.defaultOptions, PointAndFigure_PointAndFigureSeriesDefaults);
(0,external_highcharts_src_js_default_namespaceObject.extend)(PointAndFigureSeries.prototype, {
takeOrdinalPosition: true,
pnfDataGroups: [],
getColumnMetrics: columnProto.getColumnMetrics,
pointClass: PointAndFigure_PointAndFigurePoint,
sorted: true
});
external_highcharts_src_js_default_SeriesRegistry_default().registerSeriesType('pointandfigure', PointAndFigureSeries);
/* *
*
* Default Export
*
* */
/* harmony default export */ const PointAndFigure_PointAndFigureSeries = (PointAndFigureSeries);
;// ./code/es-modules/masters/modules/pointandfigure.src.js
const G = (external_highcharts_src_js_default_default());
PointAndFigure_PointAndFigureSeries.compose(G.Renderer);
/* harmony default export */ const pointandfigure_src = ((external_highcharts_src_js_default_default()));
export { pointandfigure_src as default };