base_series.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. /**
  2. * DevExtreme (viz/series/base_series.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var seriesNS = {};
  11. var typeUtils = require("../../core/utils/type");
  12. var _extend = require("../../core/utils/extend").extend;
  13. var _each = require("../../core/utils/iterator").each;
  14. var pointModule = require("./points/base_point");
  15. var _isDefined = typeUtils.isDefined;
  16. var vizUtils = require("../core/utils");
  17. var _isEmptyObject = typeUtils.isEmptyObject;
  18. var _normalizeEnum = vizUtils.normalizeEnum;
  19. var _noop = require("../../core/utils/common").noop;
  20. var states = require("../components/consts").states;
  21. var rangeCalculator = require("./helpers/range_data_calculator");
  22. var scatterSeries = require("./scatter_series");
  23. var lineSeries = require("./line_series");
  24. var areaSeries = require("./area_series");
  25. var barSeries = require("./bar_series");
  26. var rangeSeries = require("./range_series");
  27. var bubbleSeries = require("./bubble_series");
  28. var pieSeries = require("./pie_series");
  29. var financialSeries = require("./financial_series");
  30. var stackedSeries = require("./stacked_series");
  31. var DISCRETE = "discrete";
  32. var SELECTED_STATE = states.selectedMark;
  33. var HOVER_STATE = states.hoverMark;
  34. var HOVER = states.hover;
  35. var NORMAL = states.normal;
  36. var SELECTION = states.selection;
  37. var APPLY_SELECTED = states.applySelected;
  38. var APPLY_HOVER = states.applyHover;
  39. var RESET_ITEM = states.resetItem;
  40. var NONE_MODE = "none";
  41. var INCLUDE_POINTS = "includepoints";
  42. var NEAREST_POINT = "nearestpoint";
  43. var SERIES_SELECTION_CHANGED = "seriesSelectionChanged";
  44. var POINT_SELECTION_CHANGED = "pointSelectionChanged";
  45. var SERIES_HOVER_CHANGED = "seriesHoverChanged";
  46. var POINT_HOVER_CHANGED = "pointHoverChanged";
  47. var ALL_SERIES_POINTS = "allseriespoints";
  48. var ALL_ARGUMENT_POINTS = "allargumentpoints";
  49. var POINT_HOVER = "pointHover";
  50. var CLEAR_POINT_HOVER = "clearPointHover";
  51. var SERIES_SELECT = "seriesSelect";
  52. var POINT_SELECT = "pointSelect";
  53. var POINT_DESELECT = "pointDeselect";
  54. var getEmptyBusinessRange = function() {
  55. return {
  56. arg: {},
  57. val: {}
  58. }
  59. };
  60. function triggerEvent(element, event, point) {
  61. element && element.trigger(event, point)
  62. }
  63. seriesNS.mixins = {
  64. chart: {},
  65. pie: {},
  66. polar: {}
  67. };
  68. seriesNS.mixins.chart.scatter = scatterSeries.chart;
  69. seriesNS.mixins.polar.scatter = scatterSeries.polar;
  70. _extend(seriesNS.mixins.pie, pieSeries);
  71. _extend(seriesNS.mixins.chart, lineSeries.chart, areaSeries.chart, barSeries.chart, rangeSeries.chart, bubbleSeries.chart, financialSeries, stackedSeries.chart);
  72. _extend(seriesNS.mixins.polar, lineSeries.polar, areaSeries.polar, barSeries.polar, rangeSeries.polar, bubbleSeries.polar, stackedSeries.polar);
  73. function includePointsMode(mode) {
  74. mode = _normalizeEnum(mode);
  75. return mode === INCLUDE_POINTS || mode === ALL_SERIES_POINTS
  76. }
  77. function getLabelOptions(labelOptions, defaultColor) {
  78. var opt = labelOptions || {};
  79. var labelFont = _extend({}, opt.font) || {};
  80. var labelBorder = opt.border || {};
  81. var labelConnector = opt.connector || {};
  82. var backgroundAttr = {
  83. fill: opt.backgroundColor || defaultColor,
  84. "stroke-width": labelBorder.visible ? labelBorder.width || 0 : 0,
  85. stroke: labelBorder.visible && labelBorder.width ? labelBorder.color : "none",
  86. dashStyle: labelBorder.dashStyle
  87. };
  88. var connectorAttr = {
  89. stroke: labelConnector.visible && labelConnector.width ? labelConnector.color || defaultColor : "none",
  90. "stroke-width": labelConnector.visible ? labelConnector.width || 0 : 0
  91. };
  92. labelFont.color = "none" === opt.backgroundColor && "#ffffff" === _normalizeEnum(labelFont.color) && "inside" !== opt.position ? defaultColor : labelFont.color;
  93. return {
  94. alignment: opt.alignment,
  95. format: opt.format,
  96. argumentFormat: opt.argumentFormat,
  97. customizeText: typeUtils.isFunction(opt.customizeText) ? opt.customizeText : void 0,
  98. attributes: {
  99. font: labelFont
  100. },
  101. visible: 0 !== labelFont.size ? opt.visible : false,
  102. showForZeroValues: opt.showForZeroValues,
  103. horizontalOffset: opt.horizontalOffset,
  104. verticalOffset: opt.verticalOffset,
  105. radialOffset: opt.radialOffset,
  106. background: backgroundAttr,
  107. position: opt.position,
  108. connector: connectorAttr,
  109. rotationAngle: opt.rotationAngle,
  110. wordWrap: opt.wordWrap,
  111. textOverflow: opt.textOverflow,
  112. cssClass: opt.cssClass
  113. }
  114. }
  115. function setPointHoverState(point, legendCallback) {
  116. point.fullState |= HOVER_STATE;
  117. point.applyView(legendCallback)
  118. }
  119. function releasePointHoverState(point, legendCallback) {
  120. point.fullState &= ~HOVER_STATE;
  121. point.applyView(legendCallback);
  122. point.releaseHoverState()
  123. }
  124. function setPointSelectedState(point, legendCallback) {
  125. point.fullState |= SELECTED_STATE;
  126. point.applyView(legendCallback)
  127. }
  128. function releasePointSelectedState(point, legendCallback) {
  129. point.fullState &= ~SELECTED_STATE;
  130. point.applyView(legendCallback)
  131. }
  132. function mergePointOptionsCore(base, extra) {
  133. var options = _extend({}, base, extra);
  134. options.border = _extend({}, base && base.border, extra && extra.border);
  135. return options
  136. }
  137. function mergePointOptions(base, extra) {
  138. var options = mergePointOptionsCore(base, extra);
  139. options.image = _extend(true, {}, base.image, extra.image);
  140. options.selectionStyle = mergePointOptionsCore(base.selectionStyle, extra.selectionStyle);
  141. options.hoverStyle = mergePointOptionsCore(base.hoverStyle, extra.hoverStyle);
  142. return options
  143. }
  144. function Series(settings, options) {
  145. var that = this;
  146. that.fullState = 0;
  147. that._extGroups = settings;
  148. that._renderer = settings.renderer;
  149. that._group = settings.renderer.g().attr({
  150. "class": "dxc-series"
  151. });
  152. that._eventTrigger = settings.eventTrigger;
  153. that._eventPipe = settings.eventPipe;
  154. that._incidentOccurred = settings.incidentOccurred;
  155. that._legendCallback = _noop;
  156. that.updateOptions(options, settings)
  157. }
  158. function getData(pointData) {
  159. return pointData.data
  160. }
  161. exports.Series = Series;
  162. exports.mixins = seriesNS.mixins;
  163. Series.prototype = {
  164. constructor: Series,
  165. _createLegendState: _noop,
  166. getLegendStyles: function() {
  167. return this._styles.legendStyles
  168. },
  169. _createStyles: function(options) {
  170. var that = this;
  171. var mainSeriesColor = options.mainSeriesColor;
  172. that._styles = {
  173. normal: that._parseStyle(options, mainSeriesColor, mainSeriesColor),
  174. hover: that._parseStyle(options.hoverStyle || {}, mainSeriesColor, mainSeriesColor),
  175. selection: that._parseStyle(options.selectionStyle || {}, mainSeriesColor, mainSeriesColor),
  176. legendStyles: {
  177. normal: that._createLegendState(options, mainSeriesColor),
  178. hover: that._createLegendState(options.hoverStyle || {}, mainSeriesColor),
  179. selection: that._createLegendState(options.selectionStyle || {}, mainSeriesColor)
  180. }
  181. }
  182. },
  183. setClippingParams: function(baseId, wideId, forceClipping) {
  184. this._paneClipRectID = baseId;
  185. this._widePaneClipRectID = wideId;
  186. this._forceClipping = forceClipping
  187. },
  188. applyClip: function() {
  189. this._group.attr({
  190. "clip-path": this._paneClipRectID
  191. })
  192. },
  193. resetClip: function() {
  194. this._group.attr({
  195. "clip-path": null
  196. })
  197. },
  198. getTagField: function() {
  199. return this._options.tagField || "tag"
  200. },
  201. getValueFields: _noop,
  202. getSizeField: _noop,
  203. getArgumentField: _noop,
  204. getPoints: function() {
  205. return this._points
  206. },
  207. getPointsInViewPort: function() {
  208. return rangeCalculator.getPointsInViewPort(this)
  209. },
  210. _createPoint: function(data, index, oldPoint) {
  211. data.index = index;
  212. var that = this;
  213. var pointsByArgument = that.pointsByArgument;
  214. var options = that._getCreatingPointOptions(data);
  215. var arg = data.argument.valueOf();
  216. var point = oldPoint;
  217. if (point) {
  218. point.update(data, options)
  219. } else {
  220. point = new pointModule.Point(that, data, options);
  221. if (that.isSelected() && includePointsMode(that.lastSelectionMode)) {
  222. point.setView(SELECTION)
  223. }
  224. }
  225. var pointByArgument = pointsByArgument[arg];
  226. if (pointByArgument) {
  227. pointByArgument.push(point)
  228. } else {
  229. pointsByArgument[arg] = [point]
  230. }
  231. if (point.hasValue()) {
  232. that.customizePoint(point, data)
  233. }
  234. return point
  235. },
  236. getRangeData: function() {
  237. return this._visible ? this._getRangeData() : getEmptyBusinessRange()
  238. },
  239. getArgumentRange: function() {
  240. return this._visible ? rangeCalculator.getArgumentRange(this) : getEmptyBusinessRange()
  241. },
  242. getViewport: function() {
  243. return rangeCalculator.getViewport(this)
  244. },
  245. _deleteGroup: function(groupName) {
  246. var group = this[groupName];
  247. if (group) {
  248. group.dispose();
  249. this[groupName] = null
  250. }
  251. },
  252. updateOptions: function(newOptions, settings) {
  253. var that = this;
  254. var widgetType = newOptions.widgetType;
  255. var oldType = that.type;
  256. var newType = newOptions.type;
  257. that.type = newType && _normalizeEnum(newType.toString());
  258. if (!that._checkType(widgetType) || that._checkPolarBarType(widgetType, newOptions)) {
  259. that.dispose();
  260. that.isUpdated = false;
  261. return
  262. }
  263. if (oldType !== that.type) {
  264. that._firstDrawing = true;
  265. that._resetType(oldType, widgetType);
  266. that._setType(that.type, widgetType)
  267. } else {
  268. that._defineDrawingState()
  269. }
  270. that._options = newOptions;
  271. that._pointOptions = null;
  272. that.name = newOptions.name;
  273. that.pane = newOptions.pane;
  274. that.tag = newOptions.tag;
  275. if (settings) {
  276. that._seriesModes = settings.commonSeriesModes || that._seriesModes;
  277. that._valueAxis = settings.valueAxis || that._valueAxis;
  278. that.axis = that._valueAxis && that._valueAxis.name;
  279. that._argumentAxis = settings.argumentAxis || that._argumentAxis
  280. }
  281. that._createStyles(newOptions);
  282. that._stackName = null;
  283. that._updateOptions(newOptions);
  284. that._visible = newOptions.visible;
  285. that.isUpdated = true;
  286. that.stack = newOptions.stack;
  287. that.barOverlapGroup = newOptions.barOverlapGroup;
  288. that._createGroups();
  289. that._processEmptyValue = newOptions.ignoreEmptyPoints ? function(x) {
  290. return null === x ? void 0 : x
  291. } : function(x) {
  292. return x
  293. }
  294. },
  295. _defineDrawingState: function() {
  296. this._firstDrawing = true
  297. },
  298. _disposePoints: function(points) {
  299. _each(points || [], function(_, p) {
  300. p.dispose()
  301. })
  302. },
  303. updateDataType: function(settings) {
  304. var that = this;
  305. that.argumentType = settings.argumentType;
  306. that.valueType = settings.valueType;
  307. that.argumentAxisType = settings.argumentAxisType;
  308. that.valueAxisType = settings.valueAxisType;
  309. that.showZero = settings.showZero;
  310. return that
  311. },
  312. getOptions: function() {
  313. return this._options
  314. },
  315. _getOldPoint: function(data, oldPointsByArgument, index) {
  316. var arg = data.argument && data.argument.valueOf();
  317. var point = (oldPointsByArgument[arg] || [])[0];
  318. if (point) {
  319. oldPointsByArgument[arg].splice(0, 1)
  320. }
  321. return point
  322. },
  323. updateData: function(data) {
  324. var that = this;
  325. var options = that._options;
  326. var nameField = options.nameField;
  327. data = data || [];
  328. if (data.length) {
  329. that._canRenderCompleteHandle = true
  330. }
  331. var dataSelector = this._getPointDataSelector();
  332. var itemsWithoutArgument = 0;
  333. that._data = data.reduce(function(data, dataItem, index) {
  334. var pointDataItem = dataSelector(dataItem);
  335. if (_isDefined(pointDataItem.argument)) {
  336. if (!nameField || dataItem[nameField] === options.nameFieldValue) {
  337. pointDataItem.index = index;
  338. data.push(pointDataItem)
  339. }
  340. } else {
  341. itemsWithoutArgument++
  342. }
  343. return data
  344. }, []);
  345. if (itemsWithoutArgument && itemsWithoutArgument === data.length) {
  346. that._incidentOccurred("W2002", [that.name, that.getArgumentField()])
  347. }
  348. that._endUpdateData()
  349. },
  350. _getData: function() {
  351. var data = this._data || [];
  352. if (this.useAggregation()) {
  353. data = this._resample(this.getArgumentAxis().getAggregationInfo(this._useAllAggregatedPoints, this.argumentAxisType !== DISCRETE ? this.getArgumentRange() : {}), data)
  354. }
  355. return data
  356. },
  357. useAggregation: function() {
  358. var aggregation = this.getOptions().aggregation;
  359. return aggregation && aggregation.enabled
  360. },
  361. autoHidePointMarkersEnabled: _noop,
  362. usePointsToDefineAutoHiding: _noop,
  363. createPoints: function(useAllAggregatedPoints) {
  364. this._normalizeUsingAllAggregatedPoints(useAllAggregatedPoints);
  365. this._createPoints()
  366. },
  367. _normalizeUsingAllAggregatedPoints: function(useAllAggregatedPoints) {
  368. this._useAllAggregatedPoints = this.useAggregation() && (this.argumentAxisType === DISCRETE || (this._data || []).length > 1 && !!useAllAggregatedPoints)
  369. },
  370. _createPoints: function() {
  371. var that = this;
  372. var oldPointsByArgument = that.pointsByArgument || {};
  373. var data = that._getData();
  374. that.pointsByArgument = {};
  375. that._calculateErrorBars(data);
  376. var skippedFields = {};
  377. var points = data.reduce(function(points, pointDataItem) {
  378. if (that._checkData(pointDataItem, skippedFields)) {
  379. var pointIndex = points.length;
  380. var oldPoint = that._getOldPoint(pointDataItem, oldPointsByArgument, pointIndex);
  381. var point = that._createPoint(pointDataItem, pointIndex, oldPoint);
  382. points.push(point)
  383. }
  384. return points
  385. }, []);
  386. for (var field in skippedFields) {
  387. if (skippedFields[field] === data.length) {
  388. that._incidentOccurred("W2002", [that.name, field])
  389. }
  390. }
  391. Object.keys(oldPointsByArgument).forEach(function(key) {
  392. return that._disposePoints(oldPointsByArgument[key])
  393. });
  394. that._points = points
  395. },
  396. _removeOldSegments: function() {
  397. var that = this;
  398. var startIndex = that._segments.length;
  399. _each(that._graphics.splice(startIndex, that._graphics.length) || [], function(_, elem) {
  400. that._removeElement(elem)
  401. });
  402. if (that._trackers) {
  403. _each(that._trackers.splice(startIndex, that._trackers.length) || [], function(_, elem) {
  404. elem.remove()
  405. })
  406. }
  407. },
  408. _drawElements: function(animationEnabled, firstDrawing, translateAllPoints) {
  409. var that = this;
  410. var points = that._points || [];
  411. var closeSegment = points[0] && points[0].hasValue() && that._options.closed;
  412. var groupForPoint = {
  413. markers: that._markersGroup,
  414. errorBars: that._errorBarGroup
  415. };
  416. that._drawnPoints = [];
  417. that._graphics = that._graphics || [];
  418. that._segments = [];
  419. var segments = points.reduce(function(segments, p) {
  420. var segment = segments[segments.length - 1];
  421. if (!p.translated || translateAllPoints) {
  422. p.translate();
  423. !translateAllPoints && p.setDefaultCoords()
  424. }
  425. if (p.hasValue() && p.hasCoords()) {
  426. translateAllPoints && that._drawPoint({
  427. point: p,
  428. groups: groupForPoint,
  429. hasAnimation: animationEnabled,
  430. firstDrawing: firstDrawing
  431. });
  432. segment.push(p)
  433. } else {
  434. if (!p.hasValue()) {
  435. segment.length && segments.push([])
  436. } else {
  437. p.setInvisibility()
  438. }
  439. }
  440. return segments
  441. }, [
  442. []
  443. ]);
  444. segments.forEach(function(segment, index) {
  445. if (segment.length) {
  446. that._drawSegment(segment, animationEnabled, index, closeSegment && index === this.length - 1)
  447. }
  448. }, segments);
  449. that._firstDrawing = points.length ? false : true;
  450. that._removeOldSegments();
  451. animationEnabled && that._animate(firstDrawing)
  452. },
  453. draw: function(animationEnabled, hideLayoutLabels, legendCallback) {
  454. var that = this;
  455. var firstDrawing = that._firstDrawing;
  456. that._legendCallback = legendCallback || that._legendCallback;
  457. if (!that._visible) {
  458. animationEnabled = false;
  459. that._group.remove();
  460. return
  461. }
  462. that._appendInGroup();
  463. that._applyVisibleArea();
  464. that._setGroupsSettings(animationEnabled, firstDrawing);
  465. !firstDrawing && that._drawElements(false, firstDrawing, false);
  466. that._drawElements(animationEnabled, firstDrawing, true);
  467. hideLayoutLabels && that.hideLabels();
  468. if (that.isSelected()) {
  469. that._changeStyle(that.lastSelectionMode, void 0, true)
  470. } else {
  471. if (that.isHovered()) {
  472. that._changeStyle(that.lastHoverMode, void 0, true)
  473. }
  474. }
  475. },
  476. _setLabelGroupSettings: function(animationEnabled) {
  477. var settings = {
  478. "class": "dxc-labels",
  479. "pointer-events": "none"
  480. };
  481. this._applyElementsClipRect(settings);
  482. this._applyClearingSettings(settings);
  483. animationEnabled && (settings.opacity = .001);
  484. this._labelsGroup.attr(settings).append(this._extGroups.labelsGroup)
  485. },
  486. _checkType: function(widgetType) {
  487. return !!seriesNS.mixins[widgetType][this.type]
  488. },
  489. _checkPolarBarType: function(widgetType, options) {
  490. return "polar" === widgetType && options.spiderWidget && this.type.indexOf("bar") !== -1
  491. },
  492. _resetType: function(seriesType, widgetType) {
  493. var methodName;
  494. var methods;
  495. if (seriesType) {
  496. methods = seriesNS.mixins[widgetType][seriesType];
  497. for (methodName in methods) {
  498. delete this[methodName]
  499. }
  500. }
  501. },
  502. _setType: function(seriesType, widgetType) {
  503. var methodName;
  504. var methods = seriesNS.mixins[widgetType][seriesType];
  505. for (methodName in methods) {
  506. this[methodName] = methods[methodName]
  507. }
  508. },
  509. _setPointsView: function(view, target) {
  510. this.getPoints().forEach(function(point) {
  511. if (target !== point) {
  512. point.setView(view)
  513. }
  514. })
  515. },
  516. _resetPointsView: function(view, target) {
  517. this.getPoints().forEach(function(point) {
  518. if (target !== point) {
  519. point.resetView(view)
  520. }
  521. })
  522. },
  523. _resetNearestPoint: function() {
  524. var that = this;
  525. that._nearestPoint && null !== that._nearestPoint.series && that._nearestPoint.resetView(HOVER);
  526. that._nearestPoint = null
  527. },
  528. _setSelectedState: function(mode) {
  529. var that = this;
  530. that.lastSelectionMode = _normalizeEnum(mode || that._options.selectionMode);
  531. that.fullState = that.fullState | SELECTED_STATE;
  532. that._resetNearestPoint();
  533. that._changeStyle(that.lastSelectionMode);
  534. if (that.lastSelectionMode !== NONE_MODE && that.isHovered() && includePointsMode(that.lastHoverMode)) {
  535. that._resetPointsView(HOVER)
  536. }
  537. },
  538. _releaseSelectedState: function() {
  539. var that = this;
  540. that.fullState = that.fullState & ~SELECTED_STATE;
  541. that._changeStyle(that.lastSelectionMode, SELECTION);
  542. if (that.lastSelectionMode !== NONE_MODE && that.isHovered() && includePointsMode(that.lastHoverMode)) {
  543. that._setPointsView(HOVER)
  544. }
  545. },
  546. isFullStackedSeries: function() {
  547. return 0 === this.type.indexOf("fullstacked")
  548. },
  549. isStackedSeries: function() {
  550. return 0 === this.type.indexOf("stacked")
  551. },
  552. isFinancialSeries: function() {
  553. return "stock" === this.type || "candlestick" === this.type
  554. },
  555. _canChangeView: function() {
  556. return !this.isSelected() && _normalizeEnum(this._options.hoverMode) !== NONE_MODE
  557. },
  558. _changeStyle: function(mode, resetView, skipPoints) {
  559. var that = this;
  560. var state = that.fullState;
  561. var styles = [NORMAL, HOVER, SELECTION, SELECTION];
  562. if ("none" === that.lastHoverMode) {
  563. state &= ~HOVER_STATE
  564. }
  565. if ("none" === that.lastSelectionMode) {
  566. state &= ~SELECTED_STATE
  567. }
  568. if (includePointsMode(mode) && !skipPoints) {
  569. if (!resetView) {
  570. that._setPointsView(styles[state])
  571. } else {
  572. that._resetPointsView(resetView)
  573. }
  574. }
  575. that._legendCallback([RESET_ITEM, APPLY_HOVER, APPLY_SELECTED, APPLY_SELECTED][state]);
  576. that._applyStyle(that._styles[styles[state]])
  577. },
  578. updateHover: function(x, y) {
  579. var that = this;
  580. var currentNearestPoint = that._nearestPoint;
  581. var point = that.isHovered() && that.lastHoverMode === NEAREST_POINT && that.getNeighborPoint(x, y);
  582. if (point !== currentNearestPoint && !(that.isSelected() && that.lastSelectionMode !== NONE_MODE)) {
  583. that._resetNearestPoint();
  584. if (point) {
  585. point.setView(HOVER);
  586. that._nearestPoint = point
  587. }
  588. }
  589. },
  590. _getMainAxisName: function() {
  591. return this._options.rotated ? "X" : "Y"
  592. },
  593. areLabelsVisible: function() {
  594. return !_isDefined(this._options.maxLabelCount) || this._points.length <= this._options.maxLabelCount
  595. },
  596. getLabelVisibility: function() {
  597. return this.areLabelsVisible() && this._options.label && this._options.label.visible
  598. },
  599. customizePoint: function customizePoint(point, pointData) {
  600. var that = this;
  601. var options = that._options;
  602. var customizePoint = options.customizePoint;
  603. var customizeObject;
  604. var pointOptions;
  605. var customLabelOptions;
  606. var customOptions;
  607. var customizeLabel = options.customizeLabel;
  608. var useLabelCustomOptions;
  609. var usePointCustomOptions;
  610. if (customizeLabel && customizeLabel.call) {
  611. customizeObject = _extend({
  612. seriesName: that.name
  613. }, pointData);
  614. customizeObject.series = that;
  615. customLabelOptions = customizeLabel.call(customizeObject, customizeObject);
  616. useLabelCustomOptions = customLabelOptions && !_isEmptyObject(customLabelOptions);
  617. customLabelOptions = useLabelCustomOptions ? _extend(true, {}, options.label, customLabelOptions) : null
  618. }
  619. if (customizePoint && customizePoint.call) {
  620. customizeObject = customizeObject || _extend({
  621. seriesName: that.name
  622. }, pointData);
  623. customizeObject.series = that;
  624. customOptions = customizePoint.call(customizeObject, customizeObject);
  625. usePointCustomOptions = customOptions && !_isEmptyObject(customOptions)
  626. }
  627. if (useLabelCustomOptions || usePointCustomOptions) {
  628. pointOptions = that._parsePointOptions(that._preparePointOptions(customOptions), customLabelOptions || options.label, pointData, point);
  629. pointOptions.styles.useLabelCustomOptions = useLabelCustomOptions;
  630. pointOptions.styles.usePointCustomOptions = usePointCustomOptions;
  631. point.updateOptions(pointOptions)
  632. }
  633. },
  634. show: function() {
  635. if (!this._visible) {
  636. this._changeVisibility(true)
  637. }
  638. },
  639. hide: function() {
  640. if (this._visible) {
  641. this._changeVisibility(false)
  642. }
  643. },
  644. _changeVisibility: function(visibility) {
  645. var that = this;
  646. that._visible = that._options.visible = visibility;
  647. that._updatePointsVisibility();
  648. that.hidePointTooltip();
  649. that._options.visibilityChanged(that)
  650. },
  651. _updatePointsVisibility: _noop,
  652. hideLabels: function() {
  653. _each(this._points, function(_, point) {
  654. point._label.draw(false)
  655. })
  656. },
  657. _parsePointOptions: function(pointOptions, labelOptions, data, point) {
  658. var that = this;
  659. var options = that._options;
  660. var styles = that._createPointStyles(pointOptions, data, point);
  661. var parsedOptions = _extend({}, pointOptions, {
  662. type: options.type,
  663. rotated: options.rotated,
  664. styles: styles,
  665. widgetType: options.widgetType,
  666. visibilityChanged: options.visibilityChanged
  667. });
  668. parsedOptions.label = getLabelOptions(labelOptions, styles.normal.fill);
  669. if (that.areErrorBarsVisible()) {
  670. parsedOptions.errorBars = options.valueErrorBar
  671. }
  672. return parsedOptions
  673. },
  674. _preparePointOptions: function(customOptions) {
  675. var pointOptions = this._getOptionsForPoint();
  676. return customOptions ? mergePointOptions(pointOptions, customOptions) : pointOptions
  677. },
  678. _getMarkerGroupOptions: function() {
  679. return _extend(false, {}, this._getOptionsForPoint(), {
  680. hoverStyle: {},
  681. selectionStyle: {}
  682. })
  683. },
  684. _getAggregationMethod: function(isDiscrete) {
  685. var options = this.getOptions().aggregation;
  686. var method = _normalizeEnum(options.method);
  687. var customAggregator = "custom" === method && options.calculate;
  688. var aggregator;
  689. if (isDiscrete) {
  690. aggregator = function(_ref) {
  691. var data = _ref.data;
  692. return data[0]
  693. }
  694. } else {
  695. aggregator = this._aggregators[method] || this._aggregators[this._defaultAggregator]
  696. }
  697. return customAggregator || aggregator
  698. },
  699. _resample: function(_ref2, data) {
  700. var interval = _ref2.interval,
  701. ticks = _ref2.ticks;
  702. var that = this;
  703. var isDiscrete = that.argumentAxisType === DISCRETE || that.valueAxisType === DISCRETE;
  704. var dataIndex = 0;
  705. var dataSelector = this._getPointDataSelector();
  706. var options = that.getOptions();
  707. var addAggregatedData = function(target, data, aggregationInfo) {
  708. if (!data) {
  709. return
  710. }
  711. var processData = function(d) {
  712. var pointData = d && dataSelector(d, options);
  713. if (pointData && that._checkData(pointData)) {
  714. pointData.aggregationInfo = aggregationInfo;
  715. target.push(pointData)
  716. }
  717. };
  718. if (data.length) {
  719. data.forEach(processData)
  720. } else {
  721. processData(data)
  722. }
  723. };
  724. var aggregationMethod = this._getAggregationMethod(isDiscrete);
  725. if (isDiscrete) {
  726. return data.reduce(function(result, dataItem, index, data) {
  727. result[1].push(dataItem);
  728. if (index === data.length - 1 || (index + 1) % interval === 0) {
  729. var dataInInterval = result[1];
  730. var aggregationInfo = {
  731. aggregationInterval: interval,
  732. data: dataInInterval.map(getData)
  733. };
  734. addAggregatedData(result[0], aggregationMethod(aggregationInfo, that));
  735. result[1] = []
  736. }
  737. return result
  738. }, [
  739. [],
  740. []
  741. ])[0]
  742. }
  743. var aggregatedData = [];
  744. for (var i = 1; i < ticks.length; i++) {
  745. var intervalEnd = ticks[i];
  746. var intervalStart = ticks[i - 1];
  747. var dataInInterval = [];
  748. while (data[dataIndex] && data[dataIndex].argument < intervalEnd) {
  749. if (data[dataIndex].argument >= intervalStart) {
  750. dataInInterval.push(data[dataIndex])
  751. }
  752. dataIndex++
  753. }
  754. var aggregationInfo = {
  755. intervalStart: intervalStart,
  756. intervalEnd: intervalEnd,
  757. aggregationInterval: interval,
  758. data: dataInInterval.map(getData)
  759. };
  760. addAggregatedData(aggregatedData, aggregationMethod(aggregationInfo, that), aggregationInfo)
  761. }
  762. that._endUpdateData();
  763. return aggregatedData
  764. },
  765. canRenderCompleteHandle: function() {
  766. var result = this._canRenderCompleteHandle;
  767. delete this._canRenderCompleteHandle;
  768. return !!result
  769. },
  770. isHovered: function() {
  771. return !!(1 & this.fullState)
  772. },
  773. isSelected: function() {
  774. return !!(2 & this.fullState)
  775. },
  776. isVisible: function() {
  777. return this._visible
  778. },
  779. getAllPoints: function() {
  780. this._createAllAggregatedPoints();
  781. return (this._points || []).slice()
  782. },
  783. getPointByPos: function(pos) {
  784. this._createAllAggregatedPoints();
  785. return (this._points || [])[pos]
  786. },
  787. getVisiblePoints: function() {
  788. return (this._drawnPoints || []).slice()
  789. },
  790. selectPoint: function(point) {
  791. if (!point.isSelected()) {
  792. setPointSelectedState(point, this._legendCallback);
  793. this._eventPipe({
  794. action: POINT_SELECT,
  795. target: point
  796. });
  797. this._eventTrigger(POINT_SELECTION_CHANGED, {
  798. target: point
  799. })
  800. }
  801. },
  802. deselectPoint: function(point) {
  803. if (point.isSelected()) {
  804. releasePointSelectedState(point, this._legendCallback);
  805. this._eventPipe({
  806. action: POINT_DESELECT,
  807. target: point
  808. });
  809. this._eventTrigger(POINT_SELECTION_CHANGED, {
  810. target: point
  811. })
  812. }
  813. },
  814. hover: function(mode) {
  815. var that = this;
  816. var eventTrigger = that._eventTrigger;
  817. if (that.isHovered()) {
  818. return
  819. }
  820. that.lastHoverMode = _normalizeEnum(mode || that._options.hoverMode);
  821. that.fullState = that.fullState | HOVER_STATE;
  822. that._changeStyle(that.lastHoverMode, void 0, that.isSelected() && that.lastSelectionMode !== NONE_MODE);
  823. eventTrigger(SERIES_HOVER_CHANGED, {
  824. target: that
  825. })
  826. },
  827. clearHover: function() {
  828. var that = this;
  829. var eventTrigger = that._eventTrigger;
  830. if (!that.isHovered()) {
  831. return
  832. }
  833. that._resetNearestPoint();
  834. that.fullState = that.fullState & ~HOVER_STATE;
  835. that._changeStyle(that.lastHoverMode, HOVER, that.isSelected() && that.lastSelectionMode !== NONE_MODE);
  836. eventTrigger(SERIES_HOVER_CHANGED, {
  837. target: that
  838. })
  839. },
  840. hoverPoint: function(point) {
  841. var that = this;
  842. if (!point.isHovered()) {
  843. point.clearHover();
  844. setPointHoverState(point, that._legendCallback);
  845. that._canChangeView() && that._applyStyle(that._styles.hover);
  846. that._eventPipe({
  847. action: POINT_HOVER,
  848. target: point
  849. });
  850. that._eventTrigger(POINT_HOVER_CHANGED, {
  851. target: point
  852. })
  853. }
  854. },
  855. clearPointHover: function() {
  856. var that = this;
  857. that.getPoints().some(function(currentPoint) {
  858. if (currentPoint.isHovered()) {
  859. releasePointHoverState(currentPoint, that._legendCallback);
  860. that._canChangeView() && that._applyStyle(that._styles.normal);
  861. that._eventPipe({
  862. action: CLEAR_POINT_HOVER,
  863. target: currentPoint
  864. });
  865. that._eventTrigger(POINT_HOVER_CHANGED, {
  866. target: currentPoint
  867. });
  868. return true
  869. }
  870. return false
  871. })
  872. },
  873. showPointTooltip: function(point) {
  874. triggerEvent(this._extGroups.seriesGroup, "showpointtooltip", point)
  875. },
  876. hidePointTooltip: function(point) {
  877. triggerEvent(this._extGroups.seriesGroup, "hidepointtooltip", point)
  878. },
  879. select: function() {
  880. var that = this;
  881. if (!that.isSelected()) {
  882. that._setSelectedState(that._options.selectionMode);
  883. that._eventPipe({
  884. action: SERIES_SELECT,
  885. target: that
  886. });
  887. that._group.toForeground();
  888. that._eventTrigger(SERIES_SELECTION_CHANGED, {
  889. target: that
  890. })
  891. }
  892. },
  893. clearSelection: function() {
  894. var that = this;
  895. if (that.isSelected()) {
  896. that._releaseSelectedState();
  897. that._eventTrigger(SERIES_SELECTION_CHANGED, {
  898. target: that
  899. })
  900. }
  901. },
  902. getPointsByArg: function(arg, skipPointsCreation) {
  903. var that = this;
  904. var argValue = arg.valueOf();
  905. var points = that.pointsByArgument[argValue];
  906. if (!points && !skipPointsCreation && that._createAllAggregatedPoints()) {
  907. points = that.pointsByArgument[argValue]
  908. }
  909. return points || []
  910. },
  911. _createAllAggregatedPoints: function() {
  912. if (this.useAggregation() && !this._useAllAggregatedPoints) {
  913. this.createPoints(true);
  914. return true
  915. }
  916. return false
  917. },
  918. getPointsByKeys: function(arg) {
  919. return this.getPointsByArg(arg)
  920. },
  921. notify: function(data) {
  922. var that = this;
  923. var action = data.action;
  924. var seriesModes = that._seriesModes;
  925. var target = data.target;
  926. var targetOptions = target.getOptions();
  927. var pointHoverMode = _normalizeEnum(targetOptions.hoverMode);
  928. var selectionModeOfPoint = _normalizeEnum(targetOptions.selectionMode);
  929. if (action === POINT_HOVER) {
  930. that._hoverPointHandler(target, pointHoverMode, data.notifyLegend)
  931. } else {
  932. if (action === CLEAR_POINT_HOVER) {
  933. that._clearPointHoverHandler(target, pointHoverMode, data.notifyLegend)
  934. } else {
  935. if (action === SERIES_SELECT) {
  936. target !== that && "single" === seriesModes.seriesSelectionMode && that.clearSelection()
  937. } else {
  938. if (action === POINT_SELECT) {
  939. if ("single" === seriesModes.pointSelectionMode) {
  940. that.getPoints().some(function(currentPoint) {
  941. if (currentPoint !== target && currentPoint.isSelected()) {
  942. that.deselectPoint(currentPoint);
  943. return true
  944. }
  945. return false
  946. })
  947. }
  948. that._selectPointHandler(target, selectionModeOfPoint)
  949. } else {
  950. if (action === POINT_DESELECT) {
  951. that._deselectPointHandler(target, selectionModeOfPoint)
  952. }
  953. }
  954. }
  955. }
  956. }
  957. },
  958. _selectPointHandler: function(target, mode) {
  959. var that = this;
  960. if (mode === ALL_SERIES_POINTS) {
  961. target.series === that && that._setPointsView(SELECTION, target)
  962. } else {
  963. if (mode === ALL_ARGUMENT_POINTS) {
  964. that.getPointsByKeys(target.argument, target.argumentIndex).forEach(function(currentPoint) {
  965. currentPoint !== target && currentPoint.setView(SELECTION)
  966. })
  967. }
  968. }
  969. },
  970. _deselectPointHandler: function(target, mode) {
  971. if (mode === ALL_SERIES_POINTS) {
  972. target.series === this && this._resetPointsView(SELECTION, target)
  973. } else {
  974. if (mode === ALL_ARGUMENT_POINTS) {
  975. this.getPointsByKeys(target.argument, target.argumentIndex).forEach(function(currentPoint) {
  976. currentPoint !== target && currentPoint.resetView(SELECTION)
  977. })
  978. }
  979. }
  980. },
  981. _hoverPointHandler: function(target, mode, notifyLegend) {
  982. var that = this;
  983. if (target.series !== that && mode === ALL_ARGUMENT_POINTS) {
  984. that.getPointsByKeys(target.argument, target.argumentIndex).forEach(function(currentPoint) {
  985. currentPoint.setView(HOVER)
  986. });
  987. notifyLegend && that._legendCallback(target)
  988. } else {
  989. if (mode === ALL_SERIES_POINTS && target.series === that) {
  990. that._setPointsView(HOVER, target)
  991. }
  992. }
  993. },
  994. _clearPointHoverHandler: function(target, mode, notifyLegend) {
  995. var that = this;
  996. if (mode === ALL_ARGUMENT_POINTS) {
  997. target.series !== that && that.getPointsByKeys(target.argument, target.argumentIndex).forEach(function(currentPoint) {
  998. currentPoint.resetView(HOVER)
  999. });
  1000. notifyLegend && that._legendCallback(target)
  1001. } else {
  1002. if (mode === ALL_SERIES_POINTS && target.series === that) {
  1003. that._resetPointsView(HOVER, target)
  1004. }
  1005. }
  1006. },
  1007. _deletePoints: function() {
  1008. var that = this;
  1009. that._disposePoints(that._points);
  1010. that._points = that._drawnPoints = null
  1011. },
  1012. _deleteTrackers: function() {
  1013. var that = this;
  1014. _each(that._trackers || [], function(_, tracker) {
  1015. tracker.remove()
  1016. });
  1017. that._trackersGroup && that._trackersGroup.dispose();
  1018. that._trackers = that._trackersGroup = null
  1019. },
  1020. dispose: function() {
  1021. var that = this;
  1022. that._deletePoints();
  1023. that._group.dispose();
  1024. that._labelsGroup && that._labelsGroup.dispose();
  1025. that._errorBarGroup && that._errorBarGroup.dispose();
  1026. that._deleteTrackers();
  1027. that._group = that._extGroups = that._markersGroup = that._elementsGroup = that._bordersGroup = that._labelsGroup = that._errorBarGroup = that._graphics = that._rangeData = that._renderer = that._styles = that._options = that._pointOptions = that._drawnPoints = that.pointsByArgument = that._segments = that._prevSeries = null
  1028. },
  1029. correctPosition: _noop,
  1030. drawTrackers: _noop,
  1031. getNeighborPoint: _noop,
  1032. areErrorBarsVisible: _noop,
  1033. getMarginOptions: function() {
  1034. return this._patchMarginOptions({
  1035. percentStick: this.isFullStackedSeries()
  1036. })
  1037. },
  1038. getColor: function() {
  1039. return this.getLegendStyles().normal.fill
  1040. },
  1041. getOpacity: function() {
  1042. return this._options.opacity
  1043. },
  1044. getStackName: function() {
  1045. return this._stackName
  1046. },
  1047. getBarOverlapGroup: function() {
  1048. return this._options.barOverlapGroup
  1049. },
  1050. getPointByCoord: function(x, y) {
  1051. var point = this.getNeighborPoint(x, y);
  1052. return point && point.coordsIn(x, y) ? point : null
  1053. },
  1054. getValueAxis: function() {
  1055. return this._valueAxis
  1056. },
  1057. getArgumentAxis: function() {
  1058. return this._argumentAxis
  1059. },
  1060. getMarkersGroup: function() {
  1061. return this._markersGroup
  1062. },
  1063. getRenderer: function() {
  1064. return this._renderer
  1065. }
  1066. };