highcharts
Version:
JavaScript charting framework
309 lines (278 loc) • 9.76 kB
JavaScript
/**
* @license Highcharts JS v6.2.0 (2018-10-17)
*
* Indicator series type for Highstock
*
* (c) 2010-2017 Pawel Fus, Sebastian Bochan
*
* License: www.highcharts.com/license
*/
;
(function (factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else if (typeof define === 'function' && define.amd) {
define(function () {
return factory;
});
} else {
factory(Highcharts);
}
}(function (Highcharts) {
(function (H) {
var pick = H.pick,
each = H.each,
error = H.error,
Series = H.Series,
isArray = H.isArray,
addEvent = H.addEvent,
seriesType = H.seriesType;
/**
* The SMA series type.
*
* @constructor seriesTypes.sma
* @augments seriesTypes.line
*/
seriesType('sma', 'line',
/**
* Simple moving average indicator (SMA). This series requires `linkedTo`
* option to be set.
*
* @extends plotOptions.line
* @product highstock
* @sample {highstock} stock/indicators/sma Simple moving average indicator
* @since 6.0.0
* @excluding
* allAreas,colorAxis,compare,compareBase,joinBy,keys,stacking,
* showInNavigator,navigatorOptions,pointInterval,
* pointIntervalUnit,pointPlacement,pointRange,pointStart,joinBy
* @optionparent plotOptions.sma
*/
{
/**
* The name of the series as shown in the legend, tooltip etc. If not
* set, it will be based on a technical indicator type and default
* params.
*
* @type {String}
* @since 6.0.0
* @product highstock
*/
name: undefined,
tooltip: {
/**
* Number of decimals in indicator series.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
valueDecimals: 4
},
/**
* The main series ID that indicator will be based on. Required for this
* indicator.
*
* @type {String}
* @since 6.0.0
* @product highstock
*/
linkedTo: undefined,
params: {
/**
* The point index which indicator calculations will base. For
* example using OHLC data, index=2 means the indicator will be
* calculated using Low values.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
index: 0,
/**
* The base period for indicator calculations. This is the number of
* data points which are taken into account for the indicator
* calculations.
*
* @type {Number}
* @since 6.0.0
* @product highstock
*/
period: 14
}
}, /** @lends Highcharts.Series.prototype */ {
bindTo: {
series: true,
eventName: 'updatedData'
},
useCommonDataGrouping: true,
nameComponents: ['period'],
nameSuffixes: [], // e.g. Zig Zag uses extra '%'' in the legend name
calculateOn: 'init',
init: function (chart, options) {
var indicator = this;
Series.prototype.init.call(
indicator,
chart,
options
);
// Make sure we find series which is a base for an indicator
chart.linkSeries();
indicator.dataEventsToUnbind = [];
function recalculateValues() {
var oldDataLength = (indicator.xData || []).length,
processedData = indicator.getValues(
indicator.linkedParent,
indicator.options.params
) || {
values: [],
xData: [],
yData: []
};
// If number of points is the same, we need to update points to
// reflect changes in all, x and y's, values. However, do it
// only for non-grouped data - grouping does it for us (#8572)
if (
oldDataLength &&
oldDataLength === processedData.xData.length &&
!indicator.cropped && // #8968
!indicator.hasGroupedData &&
indicator.visible &&
indicator.points
) {
indicator.updateData(processedData.values);
} else {
indicator.xData = processedData.xData;
indicator.yData = processedData.yData;
indicator.options.data = processedData.values;
}
// Removal of processedXData property is required because on
// first translate processedXData array is empty
if (indicator.bindTo.series === false) {
delete indicator.processedXData;
indicator.isDirty = true;
indicator.redraw();
}
indicator.isDirtyData = false;
}
if (!indicator.linkedParent) {
return error(
'Series ' +
indicator.options.linkedTo +
' not found! Check `linkedTo`.'
);
}
indicator.dataEventsToUnbind.push(
addEvent(
indicator.bindTo.series ?
indicator.linkedParent : indicator.linkedParent.xAxis,
indicator.bindTo.eventName,
recalculateValues
)
);
if (indicator.calculateOn === 'init') {
recalculateValues();
} else {
var unbinder = addEvent(
indicator.chart,
indicator.calculateOn,
function () {
recalculateValues();
// Call this just once, on init
unbinder();
}
);
}
return indicator;
},
getName: function () {
var name = this.name,
params = [];
if (!name) {
each(
this.nameComponents,
function (component, index) {
params.push(
this.options.params[component] +
pick(this.nameSuffixes[index], '')
);
},
this
);
name = (this.nameBase || this.type.toUpperCase()) +
(this.nameComponents ? ' (' + params.join(', ') + ')' : '');
}
return name;
},
getValues: function (series, params) {
var period = params.period,
xVal = series.xData,
yVal = series.yData,
yValLen = yVal.length,
range = 0,
sum = 0,
SMA = [],
xData = [],
yData = [],
index = -1,
i,
SMAPoint;
if (xVal.length < period) {
return false;
}
// Switch index for OHLC / Candlestick / Arearange
if (isArray(yVal[0])) {
index = params.index ? params.index : 0;
}
// Accumulate first N-points
while (range < period - 1) {
sum += index < 0 ? yVal[range] : yVal[range][index];
range++;
}
// Calculate value one-by-one for each period in visible data
for (i = range; i < yValLen; i++) {
sum += index < 0 ? yVal[i] : yVal[i][index];
SMAPoint = [xVal[i], sum / period];
SMA.push(SMAPoint);
xData.push(SMAPoint[0]);
yData.push(SMAPoint[1]);
sum -= index < 0 ? yVal[i - range] : yVal[i - range][index];
}
return {
values: SMA,
xData: xData,
yData: yData
};
},
destroy: function () {
each(this.dataEventsToUnbind, function (unbinder) {
unbinder();
});
Series.prototype.destroy.call(this);
}
});
/**
* A `SMA` series. If the [type](#series.sma.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* @type {Object}
* @since 6.0.0
* @extends series,plotOptions.sma
* @excluding data,dataParser,dataURL
* @product highstock
* @apioption series.sma
*/
/**
* An array of data points for the series. For the `SMA` series type,
* points are calculated dynamically.
*
* @type {Array<Object|Array>}
* @since 6.0.0
* @extends series.line.data
* @product highstock
* @apioption series.sma.data
*/
}(Highcharts));
return (function () {
}());
}));