scatter_series.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /**
  2. * DevExtreme (viz/series/scatter_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. function _defineProperty(obj, key, value) {
  11. if (key in obj) {
  12. Object.defineProperty(obj, key, {
  13. value: value,
  14. enumerable: true,
  15. configurable: true,
  16. writable: true
  17. })
  18. } else {
  19. obj[key] = value
  20. }
  21. return obj
  22. }
  23. var _extend = require("../../core/utils/extend").extend;
  24. var inArray = require("../../core/utils/array").inArray;
  25. var _each = require("../../core/utils/iterator").each;
  26. var rangeCalculator = require("./helpers/range_data_calculator");
  27. var typeUtils = require("../../core/utils/type");
  28. var vizUtils = require("../core/utils");
  29. var _noop = require("../../core/utils/common").noop;
  30. var _isDefined = typeUtils.isDefined;
  31. var _isString = typeUtils.isString;
  32. var _map = vizUtils.map;
  33. var _normalizeEnum = vizUtils.normalizeEnum;
  34. var math = Math;
  35. var _abs = math.abs;
  36. var _sqrt = math.sqrt;
  37. var _max = math.max;
  38. var DEFAULT_TRACKER_WIDTH = 12;
  39. var DEFAULT_DURATION = 400;
  40. var HIGH_ERROR = "highError";
  41. var LOW_ERROR = "lowError";
  42. var VARIANCE = "variance";
  43. var STANDARD_DEVIATION = "stddeviation";
  44. var STANDARD_ERROR = "stderror";
  45. var PERCENT = "percent";
  46. var FIXED = "fixed";
  47. var UNDEFINED = "undefined";
  48. var DISCRETE = "discrete";
  49. var LOGARITHMIC = "logarithmic";
  50. var DATETIME = "datetime";
  51. exports.chart = {};
  52. exports.polar = {};
  53. function sum(array) {
  54. var result = 0;
  55. _each(array, function(_, value) {
  56. result += value
  57. });
  58. return result
  59. }
  60. function isErrorBarTypeCorrect(type) {
  61. return inArray(type, [FIXED, PERCENT, VARIANCE, STANDARD_DEVIATION, STANDARD_ERROR]) !== -1
  62. }
  63. function variance(array, expectedValue) {
  64. return sum(_map(array, function(value) {
  65. return (value - expectedValue) * (value - expectedValue)
  66. })) / array.length
  67. }
  68. function calculateAvgErrorBars(result, data, series) {
  69. var errorBarsOptions = series.getOptions().valueErrorBar;
  70. var valueField = series.getValueFields()[0];
  71. var lowValueField = errorBarsOptions.lowValueField || LOW_ERROR;
  72. var highValueField = errorBarsOptions.highValueField || HIGH_ERROR;
  73. if (series.areErrorBarsVisible() && void 0 === errorBarsOptions.type) {
  74. var fusionData = data.reduce(function(result, item) {
  75. if (_isDefined(item[lowValueField])) {
  76. result[0] += item[valueField] - item[lowValueField];
  77. result[1]++
  78. }
  79. if (_isDefined(item[highValueField])) {
  80. result[2] += item[highValueField] - item[valueField];
  81. result[3]++
  82. }
  83. return result
  84. }, [0, 0, 0, 0]);
  85. if (fusionData[1]) {
  86. result[lowValueField] = result[valueField] - fusionData[0] / fusionData[1]
  87. }
  88. if (fusionData[2]) {
  89. result[highValueField] = result[valueField] + fusionData[2] / fusionData[3]
  90. }
  91. }
  92. return result
  93. }
  94. function calculateSumErrorBars(result, data, series) {
  95. var errorBarsOptions = series.getOptions().valueErrorBar;
  96. var lowValueField = errorBarsOptions.lowValueField || LOW_ERROR;
  97. var highValueField = errorBarsOptions.highValueField || HIGH_ERROR;
  98. if (series.areErrorBarsVisible() && void 0 === errorBarsOptions.type) {
  99. result[lowValueField] = 0;
  100. result[highValueField] = 0;
  101. result = data.reduce(function(result, item) {
  102. result[lowValueField] += item[lowValueField];
  103. result[highValueField] += item[highValueField];
  104. return result
  105. }, result)
  106. }
  107. return result
  108. }
  109. function getMinMaxAggregator(compare) {
  110. return function(_ref, series) {
  111. var intervalStart = _ref.intervalStart,
  112. data = _ref.data;
  113. var valueField = series.getValueFields()[0];
  114. var targetData = data[0];
  115. targetData = data.reduce(function(result, item) {
  116. var value = item[valueField];
  117. if (null === result[valueField]) {
  118. result = item
  119. }
  120. if (null !== value && compare(value, result[valueField])) {
  121. return item
  122. }
  123. return result
  124. }, targetData);
  125. return _extend({}, targetData, _defineProperty({}, series.getArgumentField(), intervalStart))
  126. }
  127. }
  128. function checkFields(data, fieldsToCheck, skippedFields) {
  129. var allFieldsIsValid = true;
  130. for (var field in fieldsToCheck) {
  131. var isArgument = "argument" === field;
  132. if (isArgument || "size" === field ? !_isDefined(data[field]) : void 0 === data[field]) {
  133. var selector = fieldsToCheck[field];
  134. if (!isArgument) {
  135. skippedFields[selector] = (skippedFields[selector] || 0) + 1
  136. }
  137. allFieldsIsValid = false
  138. }
  139. }
  140. return allFieldsIsValid
  141. }
  142. var baseScatterMethods = {
  143. _defaultDuration: DEFAULT_DURATION,
  144. _defaultTrackerWidth: DEFAULT_TRACKER_WIDTH,
  145. _applyStyle: _noop,
  146. _updateOptions: _noop,
  147. _parseStyle: _noop,
  148. _prepareSegment: _noop,
  149. _drawSegment: _noop,
  150. _appendInGroup: function() {
  151. this._group.append(this._extGroups.seriesGroup)
  152. },
  153. _createLegendState: function(styleOptions, defaultColor) {
  154. return {
  155. fill: styleOptions.color || defaultColor,
  156. hatching: styleOptions.hatching ? _extend({}, styleOptions.hatching, {
  157. direction: "right"
  158. }) : void 0
  159. }
  160. },
  161. _applyElementsClipRect: function(settings) {
  162. settings["clip-path"] = this._paneClipRectID
  163. },
  164. _applyMarkerClipRect: function(settings) {
  165. settings["clip-path"] = this._forceClipping ? this._paneClipRectID : null
  166. },
  167. _createGroup: function(groupName, parent, target, settings) {
  168. var group = parent[groupName] = parent[groupName] || this._renderer.g();
  169. target && group.append(target);
  170. settings && group.attr(settings)
  171. },
  172. _applyClearingSettings: function(settings) {
  173. settings.opacity = null;
  174. settings.scale = null;
  175. if (this._options.rotated) {
  176. settings.translateX = null
  177. } else {
  178. settings.translateY = null
  179. }
  180. },
  181. _createGroups: function() {
  182. var that = this;
  183. that._createGroup("_markersGroup", that, that._group);
  184. that._createGroup("_labelsGroup", that)
  185. },
  186. _setMarkerGroupSettings: function() {
  187. var that = this;
  188. var settings = that._createPointStyles(that._getMarkerGroupOptions()).normal;
  189. settings.class = "dxc-markers";
  190. settings.opacity = 1;
  191. that._applyMarkerClipRect(settings);
  192. that._markersGroup.attr(settings)
  193. },
  194. getVisibleArea: function() {
  195. return this._visibleArea
  196. },
  197. areErrorBarsVisible: function() {
  198. var errorBarOptions = this._options.valueErrorBar;
  199. return errorBarOptions && this._errorBarsEnabled() && "none" !== errorBarOptions.displayMode && (isErrorBarTypeCorrect(_normalizeEnum(errorBarOptions.type)) || _isDefined(errorBarOptions.lowValueField) || _isDefined(errorBarOptions.highValueField))
  200. },
  201. groupPointsByCoords: function(rotated) {
  202. var cat = [];
  203. _each(this.getVisiblePoints(), function(_, p) {
  204. var pointCoord = parseInt(rotated ? p.vy : p.vx);
  205. if (!cat[pointCoord]) {
  206. cat[pointCoord] = p
  207. } else {
  208. Array.isArray(cat[pointCoord]) ? cat[pointCoord].push(p) : cat[pointCoord] = [cat[pointCoord], p]
  209. }
  210. });
  211. return cat
  212. },
  213. _createErrorBarGroup: function(animationEnabled) {
  214. var that = this;
  215. var errorBarOptions = that._options.valueErrorBar;
  216. var settings;
  217. if (that.areErrorBarsVisible()) {
  218. settings = {
  219. "class": "dxc-error-bars",
  220. stroke: errorBarOptions.color,
  221. "stroke-width": errorBarOptions.lineWidth,
  222. opacity: animationEnabled ? .001 : errorBarOptions.opacity || 1,
  223. "stroke-linecap": "square",
  224. sharp: true,
  225. "clip-path": that._forceClipping ? that._paneClipRectID : that._widePaneClipRectID
  226. };
  227. that._createGroup("_errorBarGroup", that, that._group, settings)
  228. }
  229. },
  230. _setGroupsSettings: function(animationEnabled) {
  231. var that = this;
  232. that._setMarkerGroupSettings();
  233. that._setLabelGroupSettings(animationEnabled);
  234. that._createErrorBarGroup(animationEnabled)
  235. },
  236. _getCreatingPointOptions: function() {
  237. var that = this;
  238. var defaultPointOptions;
  239. var creatingPointOptions = that._predefinedPointOptions;
  240. var normalStyle;
  241. if (!creatingPointOptions) {
  242. defaultPointOptions = that._getPointOptions();
  243. that._predefinedPointOptions = creatingPointOptions = _extend(true, {
  244. styles: {}
  245. }, defaultPointOptions);
  246. normalStyle = defaultPointOptions.styles && defaultPointOptions.styles.normal || {};
  247. creatingPointOptions.styles = creatingPointOptions.styles || {};
  248. creatingPointOptions.styles.normal = {
  249. "stroke-width": normalStyle["stroke-width"],
  250. r: normalStyle.r,
  251. opacity: normalStyle.opacity
  252. }
  253. }
  254. return creatingPointOptions
  255. },
  256. _getPointOptions: function() {
  257. return this._parsePointOptions(this._preparePointOptions(), this._options.label)
  258. },
  259. _getOptionsForPoint: function() {
  260. return this._options.point
  261. },
  262. _parsePointStyle: function(style, defaultColor, defaultBorderColor, defaultSize) {
  263. var border = style.border || {};
  264. var sizeValue = void 0 !== style.size ? style.size : defaultSize;
  265. return {
  266. fill: style.color || defaultColor,
  267. stroke: border.color || defaultBorderColor,
  268. "stroke-width": border.visible ? border.width : 0,
  269. r: sizeValue / 2 + (border.visible && 0 !== sizeValue ? ~~(border.width / 2) || 0 : 0)
  270. }
  271. },
  272. _createPointStyles: function(pointOptions) {
  273. var that = this;
  274. var mainPointColor = pointOptions.color || that._options.mainSeriesColor;
  275. var containerColor = that._options.containerBackgroundColor;
  276. var normalStyle = that._parsePointStyle(pointOptions, mainPointColor, mainPointColor);
  277. normalStyle.visibility = pointOptions.visible ? "visible" : "hidden";
  278. return {
  279. normal: normalStyle,
  280. hover: that._parsePointStyle(pointOptions.hoverStyle, containerColor, mainPointColor, pointOptions.size),
  281. selection: that._parsePointStyle(pointOptions.selectionStyle, containerColor, mainPointColor, pointOptions.size)
  282. }
  283. },
  284. _checkData: function(data, skippedFields, fieldsToCheck) {
  285. fieldsToCheck = fieldsToCheck || {
  286. value: this.getValueFields()[0]
  287. };
  288. fieldsToCheck.argument = this.getArgumentField();
  289. return checkFields(data, fieldsToCheck, skippedFields || {}) && data.value === data.value
  290. },
  291. getValueRangeInitialValue: function() {
  292. return
  293. },
  294. _getRangeData: function() {
  295. return rangeCalculator.getRangeData(this)
  296. },
  297. _getPointDataSelector: function() {
  298. var _this = this;
  299. var valueField = this.getValueFields()[0];
  300. var argumentField = this.getArgumentField();
  301. var tagField = this.getTagField();
  302. var areErrorBarsVisible = this.areErrorBarsVisible();
  303. var lowValueField;
  304. var highValueField;
  305. if (areErrorBarsVisible) {
  306. var errorBarOptions = this._options.valueErrorBar;
  307. lowValueField = errorBarOptions.lowValueField || LOW_ERROR;
  308. highValueField = errorBarOptions.highValueField || HIGH_ERROR
  309. }
  310. return function(data) {
  311. var pointData = {
  312. value: _this._processEmptyValue(data[valueField]),
  313. argument: data[argumentField],
  314. tag: data[tagField],
  315. data: data
  316. };
  317. if (areErrorBarsVisible) {
  318. pointData.lowError = data[lowValueField];
  319. pointData.highError = data[highValueField]
  320. }
  321. return pointData
  322. }
  323. },
  324. _errorBarsEnabled: function() {
  325. return this.valueAxisType !== DISCRETE && this.valueAxisType !== LOGARITHMIC && this.valueType !== DATETIME
  326. },
  327. _drawPoint: function(options) {
  328. var point = options.point;
  329. if (point.isInVisibleArea()) {
  330. point.clearVisibility();
  331. point.draw(this._renderer, options.groups, options.hasAnimation, options.firstDrawing);
  332. this._drawnPoints.push(point)
  333. } else {
  334. point.setInvisibility()
  335. }
  336. },
  337. _animateComplete: function() {
  338. var that = this;
  339. var animationSettings = {
  340. duration: that._defaultDuration
  341. };
  342. that._labelsGroup && that._labelsGroup.animate({
  343. opacity: 1
  344. }, animationSettings);
  345. that._errorBarGroup && that._errorBarGroup.animate({
  346. opacity: that._options.valueErrorBar.opacity || 1
  347. }, animationSettings)
  348. },
  349. _animate: function() {
  350. var that = this;
  351. var lastPointIndex = that._drawnPoints.length - 1;
  352. _each(that._drawnPoints || [], function(i, p) {
  353. p.animate(i === lastPointIndex ? function() {
  354. that._animateComplete()
  355. } : void 0, {
  356. translateX: p.x,
  357. translateY: p.y
  358. })
  359. })
  360. },
  361. _defaultAggregator: "avg",
  362. _aggregators: {
  363. avg: function(_ref2, series) {
  364. var _calculateAvgErrorBar;
  365. var data = _ref2.data,
  366. intervalStart = _ref2.intervalStart;
  367. if (!data.length) {
  368. return
  369. }
  370. var valueField = series.getValueFields()[0];
  371. var aggregationResult = data.reduce(function(result, item) {
  372. var value = item[valueField];
  373. if (_isDefined(value)) {
  374. result[0] += value;
  375. result[1]++
  376. } else {
  377. if (null === value) {
  378. result[2]++
  379. }
  380. }
  381. return result
  382. }, [0, 0, 0]);
  383. return calculateAvgErrorBars((_calculateAvgErrorBar = {}, _defineProperty(_calculateAvgErrorBar, valueField, aggregationResult[2] === data.length ? null : aggregationResult[0] / aggregationResult[1]), _defineProperty(_calculateAvgErrorBar, series.getArgumentField(), intervalStart), _calculateAvgErrorBar), data, series)
  384. },
  385. sum: function(_ref3, series) {
  386. var _calculateSumErrorBar;
  387. var intervalStart = _ref3.intervalStart,
  388. data = _ref3.data;
  389. if (!data.length) {
  390. return
  391. }
  392. var valueField = series.getValueFields()[0];
  393. var aggregationResult = data.reduce(function(result, item) {
  394. var value = item[valueField];
  395. if (void 0 !== value) {
  396. result[0] += value
  397. }
  398. if (null === value) {
  399. result[1]++
  400. } else {
  401. if (void 0 === value) {
  402. result[2]++
  403. }
  404. }
  405. return result
  406. }, [0, 0, 0]);
  407. var value = aggregationResult[0];
  408. if (aggregationResult[1] === data.length) {
  409. value = null
  410. }
  411. if (aggregationResult[2] === data.length) {
  412. return
  413. }
  414. return calculateSumErrorBars((_calculateSumErrorBar = {}, _defineProperty(_calculateSumErrorBar, valueField, value), _defineProperty(_calculateSumErrorBar, series.getArgumentField(), intervalStart), _calculateSumErrorBar), data, series)
  415. },
  416. count: function(_ref4, series) {
  417. var _ref5;
  418. var data = _ref4.data,
  419. intervalStart = _ref4.intervalStart;
  420. var valueField = series.getValueFields()[0];
  421. return _ref5 = {}, _defineProperty(_ref5, series.getArgumentField(), intervalStart), _defineProperty(_ref5, valueField, data.filter(function(i) {
  422. return void 0 !== i[valueField]
  423. }).length), _ref5
  424. },
  425. min: getMinMaxAggregator(function(a, b) {
  426. return a < b
  427. }),
  428. max: getMinMaxAggregator(function(a, b) {
  429. return a > b
  430. })
  431. },
  432. _endUpdateData: function() {
  433. delete this._predefinedPointOptions
  434. },
  435. getArgumentField: function() {
  436. return this._options.argumentField || "arg"
  437. },
  438. getValueFields: function() {
  439. var options = this._options;
  440. var errorBarsOptions = options.valueErrorBar;
  441. var valueFields = [options.valueField || "val"];
  442. var lowValueField;
  443. var highValueField;
  444. if (errorBarsOptions) {
  445. lowValueField = errorBarsOptions.lowValueField;
  446. highValueField = errorBarsOptions.highValueField;
  447. _isString(lowValueField) && valueFields.push(lowValueField);
  448. _isString(highValueField) && valueFields.push(highValueField)
  449. }
  450. return valueFields
  451. },
  452. _calculateErrorBars: function(data) {
  453. if (!this.areErrorBarsVisible()) {
  454. return
  455. }
  456. var that = this;
  457. var options = that._options;
  458. var errorBarsOptions = options.valueErrorBar;
  459. var errorBarType = _normalizeEnum(errorBarsOptions.type);
  460. var floatErrorValue = parseFloat(errorBarsOptions.value);
  461. var valueField = that.getValueFields()[0];
  462. var value;
  463. var lowValueField = errorBarsOptions.lowValueField || LOW_ERROR;
  464. var highValueField = errorBarsOptions.highValueField || HIGH_ERROR;
  465. var valueArray;
  466. var valueArrayLength;
  467. var meanValue;
  468. var processDataItem;
  469. var addSubError = function(_i, item) {
  470. value = item.value;
  471. item.lowError = value - floatErrorValue;
  472. item.highError = value + floatErrorValue
  473. };
  474. switch (errorBarType) {
  475. case FIXED:
  476. processDataItem = addSubError;
  477. break;
  478. case PERCENT:
  479. processDataItem = function(_, item) {
  480. value = item.value;
  481. var error = value * floatErrorValue / 100;
  482. item.lowError = value - error;
  483. item.highError = value + error
  484. };
  485. break;
  486. case UNDEFINED:
  487. processDataItem = function(_, item) {
  488. item.lowError = item.data[lowValueField];
  489. item.highError = item.data[highValueField]
  490. };
  491. break;
  492. default:
  493. valueArray = _map(data, function(item) {
  494. return _isDefined(item.data[valueField]) ? item.data[valueField] : null
  495. });
  496. valueArrayLength = valueArray.length;
  497. floatErrorValue = floatErrorValue || 1;
  498. switch (errorBarType) {
  499. case VARIANCE:
  500. floatErrorValue = variance(valueArray, sum(valueArray) / valueArrayLength) * floatErrorValue;
  501. processDataItem = addSubError;
  502. break;
  503. case STANDARD_DEVIATION:
  504. meanValue = sum(valueArray) / valueArrayLength;
  505. floatErrorValue = _sqrt(variance(valueArray, meanValue)) * floatErrorValue;
  506. processDataItem = function(_, item) {
  507. item.lowError = meanValue - floatErrorValue;
  508. item.highError = meanValue + floatErrorValue
  509. };
  510. break;
  511. case STANDARD_ERROR:
  512. floatErrorValue = _sqrt(variance(valueArray, sum(valueArray) / valueArrayLength) / valueArrayLength) * floatErrorValue;
  513. processDataItem = addSubError
  514. }
  515. }
  516. processDataItem && _each(data, processDataItem)
  517. },
  518. _patchMarginOptions: function(options) {
  519. var pointOptions = this._getCreatingPointOptions();
  520. var styles = pointOptions.styles;
  521. var maxSize = [styles.normal, styles.hover, styles.selection].reduce(function(max, style) {
  522. return _max(max, 2 * style.r + style["stroke-width"])
  523. }, 0);
  524. options.size = pointOptions.visible ? maxSize : 0;
  525. options.sizePointNormalState = pointOptions.visible ? 2 * styles.normal.r + styles.normal["stroke-width"] : 2;
  526. return options
  527. },
  528. usePointsToDefineAutoHiding: function() {
  529. return true
  530. }
  531. };
  532. exports.chart = _extend({}, baseScatterMethods, {
  533. drawTrackers: function() {
  534. var that = this;
  535. var trackers;
  536. var trackersGroup;
  537. var segments = that._segments || [];
  538. var rotated = that._options.rotated;
  539. if (!that.isVisible()) {
  540. return
  541. }
  542. if (segments.length) {
  543. trackers = that._trackers = that._trackers || [];
  544. trackersGroup = that._trackersGroup = (that._trackersGroup || that._renderer.g().attr({
  545. fill: "gray",
  546. opacity: .001,
  547. stroke: "gray",
  548. "class": "dxc-trackers"
  549. })).attr({
  550. "clip-path": this._paneClipRectID || null
  551. }).append(that._group);
  552. _each(segments, function(i, segment) {
  553. if (!trackers[i]) {
  554. trackers[i] = that._drawTrackerElement(segment).data({
  555. "chart-data-series": that
  556. }).append(trackersGroup)
  557. } else {
  558. that._updateTrackerElement(segment, trackers[i])
  559. }
  560. })
  561. }
  562. that._trackersTranslator = that.groupPointsByCoords(rotated)
  563. },
  564. checkAxisVisibleAreaCoord: function(isArgument, coord) {
  565. var axis = isArgument ? this.getArgumentAxis() : this.getValueAxis();
  566. var visibleArea = axis.getVisibleArea();
  567. return _isDefined(coord) && visibleArea[0] <= coord && visibleArea[1] >= coord
  568. },
  569. checkSeriesViewportCoord: function(axis, coord) {
  570. return true
  571. },
  572. getSeriesPairCoord: function(coord, isArgument) {
  573. var oppositeCoord = null;
  574. var isOpposite = !isArgument && !this._options.rotated || isArgument && this._options.rotated;
  575. var coordName = !isOpposite ? "vx" : "vy";
  576. var oppositeCoordName = !isOpposite ? "vy" : "vx";
  577. var points = this.getVisiblePoints();
  578. for (var i = 0; i < points.length; i++) {
  579. var p = points[i];
  580. var tmpCoord = p[coordName] === coord ? p[oppositeCoordName] : void 0;
  581. if (this.checkAxisVisibleAreaCoord(!isArgument, tmpCoord)) {
  582. oppositeCoord = tmpCoord;
  583. break
  584. }
  585. }
  586. return oppositeCoord
  587. },
  588. getNearestPointsByCoord: function(coord, isArgument) {
  589. var that = this;
  590. var rotated = that.getOptions().rotated;
  591. var isOpposite = !isArgument && !rotated || isArgument && rotated;
  592. var coordName = isOpposite ? "vy" : "vx";
  593. var points = that.getVisiblePoints();
  594. var allPoints = that.getPoints();
  595. var nearestPoints = [];
  596. if (that.isVisible() && allPoints.length > 0) {
  597. if (allPoints.length > 1) {
  598. that.findNeighborPointsByCoord(coord, coordName, points.slice(0), allPoints, function(point, nextPoint) {
  599. nearestPoints.push([point, nextPoint])
  600. })
  601. } else {
  602. if (allPoints[0][coordName] === coord) {
  603. nearestPoints.push([allPoints[0], allPoints[0]])
  604. }
  605. }
  606. }
  607. return nearestPoints
  608. },
  609. findNeighborPointsByCoord: function(coord, coordName, points, allPoints, pushNeighborPoints) {
  610. var searchPoints = allPoints;
  611. if (points.length > 0) {
  612. points.splice(0, 0, allPoints[allPoints.indexOf(points[0]) - 1]);
  613. points.splice(points.length, 0, allPoints[allPoints.indexOf(points[points.length - 1]) + 1]);
  614. searchPoints = points
  615. }
  616. searchPoints.forEach(function(p, i) {
  617. var np = searchPoints[i + 1];
  618. if (p && np && (p[coordName] <= coord && np[coordName] >= coord || p[coordName] >= coord && np[coordName] <= coord)) {
  619. pushNeighborPoints(p, np)
  620. }
  621. })
  622. },
  623. getNeighborPoint: function(x, y) {
  624. var pCoord = this._options.rotated ? y : x;
  625. var nCoord = pCoord;
  626. var cat = this._trackersTranslator;
  627. var point = null;
  628. var minDistance;
  629. var oppositeCoord = this._options.rotated ? x : y;
  630. var oppositeCoordName = this._options.rotated ? "vx" : "vy";
  631. if (this.isVisible() && cat) {
  632. point = cat[pCoord];
  633. do {
  634. point = cat[nCoord] || cat[pCoord];
  635. pCoord--;
  636. nCoord++
  637. } while ((pCoord >= 0 || nCoord < cat.length) && !point);
  638. if (Array.isArray(point)) {
  639. minDistance = _abs(point[0][oppositeCoordName] - oppositeCoord);
  640. _each(point, function(i, p) {
  641. var distance = _abs(p[oppositeCoordName] - oppositeCoord);
  642. if (minDistance >= distance) {
  643. minDistance = distance;
  644. point = p
  645. }
  646. })
  647. }
  648. }
  649. return point
  650. },
  651. _applyVisibleArea: function() {
  652. var that = this;
  653. var rotated = that._options.rotated;
  654. var visibleX = (rotated ? that.getValueAxis() : that.getArgumentAxis()).getVisibleArea();
  655. var visibleY = (rotated ? that.getArgumentAxis() : that.getValueAxis()).getVisibleArea();
  656. that._visibleArea = {
  657. minX: visibleX[0],
  658. maxX: visibleX[1],
  659. minY: visibleY[0],
  660. maxY: visibleY[1]
  661. }
  662. },
  663. getPointCenterByArg: function(arg) {
  664. var point = this.getPointsByArg(arg)[0];
  665. return point ? point.getCenterCoord() : void 0
  666. }
  667. });
  668. exports.polar = _extend({}, baseScatterMethods, {
  669. drawTrackers: function() {
  670. exports.chart.drawTrackers.call(this);
  671. var cat = this._trackersTranslator;
  672. var index;
  673. if (!this.isVisible()) {
  674. return
  675. }
  676. _each(cat, function(i, category) {
  677. if (category) {
  678. index = i;
  679. return false
  680. }
  681. });
  682. cat[index + 360] = cat[index]
  683. },
  684. getNeighborPoint: function(x, y) {
  685. var pos = vizUtils.convertXYToPolar(this.getValueAxis().getCenter(), x, y);
  686. return exports.chart.getNeighborPoint.call(this, pos.phi, pos.r)
  687. },
  688. _applyVisibleArea: function() {
  689. var that = this;
  690. var canvas = that.getValueAxis().getCanvas();
  691. that._visibleArea = {
  692. minX: canvas.left,
  693. maxX: canvas.width - canvas.right,
  694. minY: canvas.top,
  695. maxY: canvas.height - canvas.bottom
  696. }
  697. }
  698. });