PackedBubbleSeries.js 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. /* *
  2. *
  3. * (c) 2010-2021 Grzegorz Blachlinski, Sebastian Bochan
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8. *
  9. * */
  10. 'use strict';
  11. var __extends = (this && this.__extends) || (function () {
  12. var extendStatics = function (d, b) {
  13. extendStatics = Object.setPrototypeOf ||
  14. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  15. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  16. return extendStatics(d, b);
  17. };
  18. return function (d, b) {
  19. extendStatics(d, b);
  20. function __() { this.constructor = d; }
  21. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  22. };
  23. })();
  24. import Color from '../../Core/Color/Color.js';
  25. var color = Color.parse;
  26. import H from '../../Core/Globals.js';
  27. import PackedBubblePoint from './PackedBubblePoint.js';
  28. import SeriesRegistry from '../../Core/Series/SeriesRegistry.js';
  29. var Series = SeriesRegistry.series, BubbleSeries = SeriesRegistry.seriesTypes.bubble;
  30. import U from '../../Core/Utilities.js';
  31. var addEvent = U.addEvent, clamp = U.clamp, defined = U.defined, extend = U.extend, fireEvent = U.fireEvent, isArray = U.isArray, isNumber = U.isNumber, merge = U.merge, pick = U.pick;
  32. import '../../Series/Networkgraph/DraggableNodes.js';
  33. var dragNodesMixin = H.dragNodesMixin;
  34. import './PackedBubbleComposition.js';
  35. /* *
  36. *
  37. * Class
  38. *
  39. * */
  40. /**
  41. * @private
  42. * @class
  43. * @name Highcharts.seriesTypes.packedbubble
  44. *
  45. * @extends Highcharts.Series
  46. */
  47. var PackedBubbleSeries = /** @class */ (function (_super) {
  48. __extends(PackedBubbleSeries, _super);
  49. function PackedBubbleSeries() {
  50. /* *
  51. *
  52. * Static Properties
  53. *
  54. * */
  55. var _this = _super !== null && _super.apply(this, arguments) || this;
  56. /* *
  57. *
  58. * Properties
  59. *
  60. * */
  61. _this.chart = void 0;
  62. _this.data = void 0;
  63. _this.layout = void 0;
  64. _this.options = void 0;
  65. _this.points = void 0;
  66. _this.xData = void 0;
  67. return _this;
  68. /* eslint-enable valid-jsdoc */
  69. }
  70. /* *
  71. *
  72. * Functions
  73. *
  74. * */
  75. /* eslint-disable valid-jsdoc */
  76. /**
  77. * Create a single array of all points from all series
  78. * @private
  79. */
  80. PackedBubbleSeries.prototype.accumulateAllPoints = function (series) {
  81. var chart = series.chart, allDataPoints = [], i, j;
  82. for (i = 0; i < chart.series.length; i++) {
  83. series = chart.series[i];
  84. if (series.is('packedbubble') && // #13574
  85. series.visible ||
  86. !chart.options.chart.ignoreHiddenSeries) {
  87. // add data to array only if series is visible
  88. for (j = 0; j < series.yData.length; j++) {
  89. allDataPoints.push([
  90. null, null,
  91. series.yData[j],
  92. series.index,
  93. j,
  94. {
  95. id: j,
  96. marker: {
  97. radius: 0
  98. }
  99. }
  100. ]);
  101. }
  102. }
  103. }
  104. return allDataPoints;
  105. };
  106. /**
  107. * Adding the basic layout to series points.
  108. * @private
  109. */
  110. PackedBubbleSeries.prototype.addLayout = function () {
  111. var series = this, layoutOptions = series.options.layoutAlgorithm, graphLayoutsStorage = series.chart.graphLayoutsStorage, graphLayoutsLookup = series.chart.graphLayoutsLookup, chartOptions = series.chart.options.chart, layout;
  112. if (!graphLayoutsStorage) {
  113. series.chart.graphLayoutsStorage = graphLayoutsStorage = {};
  114. series.chart.graphLayoutsLookup = graphLayoutsLookup = [];
  115. }
  116. layout = graphLayoutsStorage[layoutOptions.type];
  117. if (!layout) {
  118. layoutOptions.enableSimulation =
  119. !defined(chartOptions.forExport) ?
  120. layoutOptions.enableSimulation :
  121. !chartOptions.forExport;
  122. graphLayoutsStorage[layoutOptions.type] = layout =
  123. new H.layouts[layoutOptions.type]();
  124. layout.init(layoutOptions);
  125. graphLayoutsLookup.splice(layout.index, 0, layout);
  126. }
  127. series.layout = layout;
  128. series.points.forEach(function (node) {
  129. node.mass = 2;
  130. node.degree = 1;
  131. node.collisionNmb = 1;
  132. });
  133. layout.setArea(0, 0, series.chart.plotWidth, series.chart.plotHeight);
  134. layout.addElementsToCollection([series], layout.series);
  135. layout.addElementsToCollection(series.points, layout.nodes);
  136. };
  137. /**
  138. * Function responsible for adding series layout, used for parent nodes.
  139. * @private
  140. */
  141. PackedBubbleSeries.prototype.addSeriesLayout = function () {
  142. var series = this, layoutOptions = series.options.layoutAlgorithm, graphLayoutsStorage = series.chart.graphLayoutsStorage, graphLayoutsLookup = series.chart.graphLayoutsLookup, parentNodeOptions = merge(layoutOptions, layoutOptions.parentNodeOptions, {
  143. enableSimulation: series.layout.options.enableSimulation
  144. }), parentNodeLayout;
  145. parentNodeLayout = graphLayoutsStorage[layoutOptions.type + '-series'];
  146. if (!parentNodeLayout) {
  147. graphLayoutsStorage[layoutOptions.type + '-series'] =
  148. parentNodeLayout =
  149. new H.layouts[layoutOptions.type]();
  150. parentNodeLayout.init(parentNodeOptions);
  151. graphLayoutsLookup.splice(parentNodeLayout.index, 0, parentNodeLayout);
  152. }
  153. series.parentNodeLayout = parentNodeLayout;
  154. this.createParentNodes();
  155. };
  156. /**
  157. * The function responsible for calculating the parent node radius
  158. * based on the total surface of iniside-bubbles and the group BBox
  159. * @private
  160. */
  161. PackedBubbleSeries.prototype.calculateParentRadius = function () {
  162. var series = this, bBox, parentPadding = 20, minParentRadius = 20;
  163. bBox = series.seriesBox();
  164. series.parentNodeRadius = clamp(Math.sqrt(2 * series.parentNodeMass / Math.PI) + parentPadding, minParentRadius, bBox ?
  165. Math.max(Math.sqrt(Math.pow(bBox.width, 2) +
  166. Math.pow(bBox.height, 2)) / 2 + parentPadding, minParentRadius) :
  167. Math.sqrt(2 * series.parentNodeMass / Math.PI) + parentPadding);
  168. if (series.parentNode) {
  169. series.parentNode.marker.radius =
  170. series.parentNode.radius = series.parentNodeRadius;
  171. }
  172. };
  173. /**
  174. * Calculate min and max bubble value for radius calculation.
  175. * @private
  176. */
  177. PackedBubbleSeries.prototype.calculateZExtremes = function () {
  178. var chart = this.chart, zMin = this.options.zMin, zMax = this.options.zMax, valMin = Infinity, valMax = -Infinity;
  179. if (zMin && zMax) {
  180. return [zMin, zMax];
  181. }
  182. // it is needed to deal with null
  183. // and undefined values
  184. chart.series.forEach(function (s) {
  185. s.yData.forEach(function (p) {
  186. if (defined(p)) {
  187. if (p > valMax) {
  188. valMax = p;
  189. }
  190. if (p < valMin) {
  191. valMin = p;
  192. }
  193. }
  194. });
  195. });
  196. zMin = pick(zMin, valMin);
  197. zMax = pick(zMax, valMax);
  198. return [zMin, zMax];
  199. };
  200. /**
  201. * Check if two bubbles overlaps.
  202. * @private
  203. * @param {Array} first bubble
  204. * @param {Array} second bubble
  205. * @return {Boolean} overlap or not
  206. */
  207. PackedBubbleSeries.prototype.checkOverlap = function (bubble1, bubble2) {
  208. var diffX = bubble1[0] - bubble2[0], // diff of X center values
  209. diffY = bubble1[1] - bubble2[1], // diff of Y center values
  210. sumRad = bubble1[2] + bubble2[2]; // sum of bubble radius
  211. return (Math.sqrt(diffX * diffX + diffY * diffY) -
  212. Math.abs(sumRad)) < -0.001;
  213. };
  214. /**
  215. * Creating parent nodes for split series, in which all the bubbles
  216. * are rendered.
  217. * @private
  218. */
  219. PackedBubbleSeries.prototype.createParentNodes = function () {
  220. var series = this, chart = series.chart, parentNodeLayout = series.parentNodeLayout, nodeAdded, parentNode = series.parentNode, PackedBubblePoint = series.pointClass;
  221. series.parentNodeMass = 0;
  222. series.points.forEach(function (p) {
  223. series.parentNodeMass +=
  224. Math.PI * Math.pow(p.marker.radius, 2);
  225. });
  226. series.calculateParentRadius();
  227. parentNodeLayout.nodes.forEach(function (node) {
  228. if (node.seriesIndex === series.index) {
  229. nodeAdded = true;
  230. }
  231. });
  232. parentNodeLayout.setArea(0, 0, chart.plotWidth, chart.plotHeight);
  233. if (!nodeAdded) {
  234. if (!parentNode) {
  235. parentNode = (new PackedBubblePoint()).init(this, {
  236. mass: series.parentNodeRadius / 2,
  237. marker: {
  238. radius: series.parentNodeRadius
  239. },
  240. dataLabels: {
  241. inside: false
  242. },
  243. dataLabelOnNull: true,
  244. degree: series.parentNodeRadius,
  245. isParentNode: true,
  246. seriesIndex: series.index
  247. });
  248. }
  249. if (series.parentNode) {
  250. parentNode.plotX = series.parentNode.plotX;
  251. parentNode.plotY = series.parentNode.plotY;
  252. }
  253. series.parentNode = parentNode;
  254. parentNodeLayout.addElementsToCollection([series], parentNodeLayout.series);
  255. parentNodeLayout.addElementsToCollection([parentNode], parentNodeLayout.nodes);
  256. }
  257. };
  258. /**
  259. * Function responsible for adding all the layouts to the chart.
  260. * @private
  261. */
  262. PackedBubbleSeries.prototype.deferLayout = function () {
  263. // TODO split layouts to independent methods
  264. var series = this, layoutOptions = series.options.layoutAlgorithm;
  265. if (!series.visible) {
  266. return;
  267. }
  268. // layout is using nodes for position calculation
  269. series.addLayout();
  270. if (layoutOptions.splitSeries) {
  271. series.addSeriesLayout();
  272. }
  273. };
  274. PackedBubbleSeries.prototype.destroy = function () {
  275. // Remove the series from all layouts series collections #11469
  276. if (this.chart.graphLayoutsLookup) {
  277. this.chart.graphLayoutsLookup.forEach(function (layout) {
  278. layout.removeElementFromCollection(this, layout.series);
  279. }, this);
  280. }
  281. if (this.parentNode &&
  282. this.parentNodeLayout) {
  283. this.parentNodeLayout.removeElementFromCollection(this.parentNode, this.parentNodeLayout.nodes);
  284. if (this.parentNode.dataLabel) {
  285. this.parentNode.dataLabel =
  286. this.parentNode.dataLabel.destroy();
  287. }
  288. }
  289. Series.prototype.destroy.apply(this, arguments);
  290. };
  291. /**
  292. * Packedbubble has two separate collecions of nodes if split, render
  293. * dataLabels for both sets:
  294. * @private
  295. */
  296. PackedBubbleSeries.prototype.drawDataLabels = function () {
  297. var textPath = this.options.dataLabels.textPath, points = this.points;
  298. // Render node labels:
  299. Series.prototype.drawDataLabels.apply(this, arguments);
  300. // Render parentNode labels:
  301. if (this.parentNode) {
  302. this.parentNode.formatPrefix = 'parentNode';
  303. this.points = [this.parentNode];
  304. this.options.dataLabels.textPath =
  305. this.options.dataLabels.parentNodeTextPath;
  306. Series.prototype.drawDataLabels.apply(this, arguments);
  307. // Restore nodes
  308. this.points = points;
  309. this.options.dataLabels.textPath = textPath;
  310. }
  311. };
  312. /**
  313. * Create Background/Parent Nodes for split series.
  314. * @private
  315. */
  316. PackedBubbleSeries.prototype.drawGraph = function () {
  317. // if the series is not using layout, don't add parent nodes
  318. if (!this.layout || !this.layout.options.splitSeries) {
  319. return;
  320. }
  321. var series = this, chart = series.chart, parentAttribs = {}, nodeMarker = this.layout.options.parentNodeOptions.marker, parentOptions = {
  322. fill: nodeMarker.fillColor || color(series.color).brighten(0.4).get(),
  323. opacity: nodeMarker.fillOpacity,
  324. stroke: nodeMarker.lineColor || series.color,
  325. 'stroke-width': nodeMarker.lineWidth
  326. }, visibility = series.visible ? 'inherit' : 'hidden';
  327. // create the group for parent Nodes if doesn't exist
  328. if (!this.parentNodesGroup) {
  329. series.parentNodesGroup = series.plotGroup('parentNodesGroup', 'parentNode', visibility, 0.1, chart.seriesGroup);
  330. series.group.attr({
  331. zIndex: 2
  332. });
  333. }
  334. this.calculateParentRadius();
  335. parentAttribs = merge({
  336. x: series.parentNode.plotX -
  337. series.parentNodeRadius,
  338. y: series.parentNode.plotY -
  339. series.parentNodeRadius,
  340. width: series.parentNodeRadius * 2,
  341. height: series.parentNodeRadius * 2
  342. }, parentOptions);
  343. if (!series.parentNode.graphic) {
  344. series.graph = series.parentNode.graphic =
  345. chart.renderer.symbol(parentOptions.symbol)
  346. .add(series.parentNodesGroup);
  347. }
  348. series.parentNode.graphic.attr(parentAttribs);
  349. };
  350. PackedBubbleSeries.prototype.drawTracker = function () {
  351. var series = this,
  352. /* chart = series.chart,
  353. pointer = chart.pointer,
  354. onMouseOver = function (e: PointerEvent): void {
  355. const point = pointer.getPointFromEvent(e);
  356. // undefined on graph in scatterchart
  357. if (typeof point !== 'undefined') {
  358. pointer.isDirectTouch = true;
  359. point.onMouseOver(e);
  360. }
  361. }, */
  362. parentNode = series.parentNode;
  363. var dataLabels;
  364. _super.prototype.drawTracker.call(this);
  365. // Add reference to the point
  366. if (parentNode) {
  367. dataLabels = (isArray(parentNode.dataLabels) ?
  368. parentNode.dataLabels :
  369. (parentNode.dataLabel ? [parentNode.dataLabel] : []));
  370. if (parentNode.graphic) {
  371. parentNode.graphic.element.point = parentNode;
  372. }
  373. dataLabels.forEach(function (dataLabel) {
  374. if (dataLabel.div) {
  375. dataLabel.div.point = parentNode;
  376. }
  377. else {
  378. dataLabel.element.point = parentNode;
  379. }
  380. });
  381. }
  382. };
  383. /**
  384. * Calculate radius of bubbles in series.
  385. * @private
  386. */
  387. PackedBubbleSeries.prototype.getPointRadius = function () {
  388. var series = this, chart = series.chart, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, seriesOptions = series.options, useSimulation = seriesOptions.useSimulation, smallestSize = Math.min(plotWidth, plotHeight), extremes = {}, radii = [], allDataPoints = chart.allDataPoints, minSize, maxSize, value, radius, zExtremes;
  389. ['minSize', 'maxSize'].forEach(function (prop) {
  390. var length = parseInt(seriesOptions[prop], 10), isPercent = /%$/.test(seriesOptions[prop]);
  391. extremes[prop] = isPercent ?
  392. smallestSize * length / 100 :
  393. length * Math.sqrt(allDataPoints.length);
  394. });
  395. chart.minRadius = minSize = extremes.minSize /
  396. Math.sqrt(allDataPoints.length);
  397. chart.maxRadius = maxSize = extremes.maxSize /
  398. Math.sqrt(allDataPoints.length);
  399. zExtremes = useSimulation ?
  400. series.calculateZExtremes() :
  401. [minSize, maxSize];
  402. (allDataPoints || []).forEach(function (point, i) {
  403. value = useSimulation ?
  404. clamp(point[2], zExtremes[0], zExtremes[1]) :
  405. point[2];
  406. radius = series.getRadius(zExtremes[0], zExtremes[1], minSize, maxSize, value);
  407. if (radius === 0) {
  408. radius = null;
  409. }
  410. allDataPoints[i][2] = radius;
  411. radii.push(radius);
  412. });
  413. series.radii = radii;
  414. };
  415. PackedBubbleSeries.prototype.init = function () {
  416. Series.prototype.init.apply(this, arguments);
  417. /* eslint-disable no-invalid-this */
  418. // When one series is modified, the others need to be recomputed
  419. this.eventsToUnbind.push(addEvent(this, 'updatedData', function () {
  420. this.chart.series.forEach(function (s) {
  421. if (s.type === this.type) {
  422. s.isDirty = true;
  423. }
  424. }, this);
  425. }));
  426. /* eslint-enable no-invalid-this */
  427. return this;
  428. };
  429. /**
  430. * Mouse up action, finalizing drag&drop.
  431. * @private
  432. * @param {Highcharts.Point} point The point that event occured.
  433. */
  434. PackedBubbleSeries.prototype.onMouseUp = function (point) {
  435. if (point.fixedPosition && !point.removed) {
  436. var distanceXY, distanceR, layout = this.layout, parentNodeLayout = this.parentNodeLayout;
  437. if (parentNodeLayout && layout.options.dragBetweenSeries) {
  438. parentNodeLayout.nodes.forEach(function (node) {
  439. if (point && point.marker &&
  440. node !== point.series.parentNode) {
  441. distanceXY = layout.getDistXY(point, node);
  442. distanceR = (layout.vectorLength(distanceXY) -
  443. node.marker.radius -
  444. point.marker.radius);
  445. if (distanceR < 0) {
  446. node.series.addPoint(merge(point.options, {
  447. plotX: point.plotX,
  448. plotY: point.plotY
  449. }), false);
  450. layout.removeElementFromCollection(point, layout.nodes);
  451. point.remove();
  452. }
  453. }
  454. });
  455. }
  456. dragNodesMixin.onMouseUp.apply(this, arguments);
  457. }
  458. };
  459. /**
  460. * This is the main function responsible
  461. * for positioning all of the bubbles
  462. * allDataPoints - bubble array, in format [pixel x value,
  463. * pixel y value, radius,
  464. * related series index, related point index]
  465. * @private
  466. * @param {Array<Highcharts.PackedBubbleData>} allDataPoints All points from all series
  467. * @return {Array<Highcharts.PackedBubbleData>} Positions of all bubbles
  468. */
  469. PackedBubbleSeries.prototype.placeBubbles = function (allDataPoints) {
  470. var series = this, checkOverlap = series.checkOverlap, positionBubble = series.positionBubble, bubblePos = [], stage = 1, j = 0, k = 0, calculatedBubble, sortedArr, arr = [], i;
  471. // sort all points
  472. sortedArr = allDataPoints.sort(function (a, b) {
  473. return b[2] - a[2];
  474. });
  475. if (sortedArr.length) {
  476. // create first bubble in the middle of the chart
  477. bubblePos.push([
  478. [
  479. 0,
  480. 0,
  481. sortedArr[0][2],
  482. sortedArr[0][3],
  483. sortedArr[0][4]
  484. ] // point index
  485. ]); // 0 level bubble
  486. if (sortedArr.length > 1) {
  487. bubblePos.push([
  488. [
  489. 0,
  490. (0 - sortedArr[1][2] -
  491. sortedArr[0][2]),
  492. // move bubble above first one
  493. sortedArr[1][2],
  494. sortedArr[1][3],
  495. sortedArr[1][4]
  496. ]
  497. ]); // 1 level 1st bubble
  498. // first two already positioned so starting from 2
  499. for (i = 2; i < sortedArr.length; i++) {
  500. sortedArr[i][2] = sortedArr[i][2] || 1;
  501. // in case if radius is calculated as 0.
  502. calculatedBubble = positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]); // calculate initial bubble position
  503. if (checkOverlap(calculatedBubble, bubblePos[stage][0])) {
  504. /* if new bubble is overlapping with first bubble
  505. * in current level (stage)
  506. */
  507. bubblePos.push([]);
  508. k = 0;
  509. /* reset index of bubble, used for
  510. * positioning the bubbles around it,
  511. * we are starting from first bubble in next
  512. * stage because we are changing level to higher
  513. */
  514. bubblePos[stage + 1].push(positionBubble(bubblePos[stage][j], bubblePos[stage][0], sortedArr[i]));
  515. // (last bubble, 1. from curr stage, new bubble)
  516. stage++; // the new level is created, above current
  517. j = 0; // set the index of bubble in curr level to 0
  518. }
  519. else if (stage > 1 &&
  520. bubblePos[stage - 1][k + 1] &&
  521. checkOverlap(calculatedBubble, bubblePos[stage - 1][k + 1])) {
  522. /* if new bubble is overlapping with one of the prev
  523. * stage bubbles, it means that - bubble, used for
  524. * positioning the bubbles around it has changed
  525. * so we need to recalculate it
  526. */
  527. k++;
  528. bubblePos[stage].push(positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]));
  529. // (last bubble, prev stage bubble, new bubble)
  530. j++;
  531. }
  532. else { // simply add calculated bubble
  533. j++;
  534. bubblePos[stage].push(calculatedBubble);
  535. }
  536. }
  537. }
  538. series.chart.stages = bubblePos;
  539. // it may not be necessary but adding it just in case -
  540. // it is containing all of the bubble levels
  541. series.chart.rawPositions =
  542. []
  543. .concat.apply([], bubblePos);
  544. // bubble positions merged into one array
  545. series.resizeRadius();
  546. arr = series.chart.rawPositions;
  547. }
  548. return arr;
  549. };
  550. /**
  551. * Function that is adding one bubble based on positions and sizes of
  552. * two other bubbles, lastBubble is the last added bubble, newOrigin is
  553. * the bubble for positioning new bubbles. nextBubble is the curently
  554. * added bubble for which we are calculating positions
  555. * @private
  556. * @param {Array<number>} lastBubble The closest last bubble
  557. * @param {Array<number>} newOrigin New bubble
  558. * @param {Array<number>} nextBubble The closest next bubble
  559. * @return {Array<number>} Bubble with correct positions
  560. */
  561. PackedBubbleSeries.prototype.positionBubble = function (lastBubble, newOrigin, nextBubble) {
  562. var sqrt = Math.sqrt, asin = Math.asin, acos = Math.acos, pow = Math.pow, abs = Math.abs, distance = sqrt(// dist between lastBubble and newOrigin
  563. pow((lastBubble[0] - newOrigin[0]), 2) +
  564. pow((lastBubble[1] - newOrigin[1]), 2)), alfa = acos(
  565. // from cosinus theorem: alfa is an angle used for
  566. // calculating correct position
  567. (pow(distance, 2) +
  568. pow(nextBubble[2] + newOrigin[2], 2) -
  569. pow(nextBubble[2] + lastBubble[2], 2)) / (2 * (nextBubble[2] + newOrigin[2]) * distance)), beta = asin(// from sinus theorem.
  570. abs(lastBubble[0] - newOrigin[0]) /
  571. distance),
  572. // providing helping variables, related to angle between
  573. // lastBubble and newOrigin
  574. gamma = (lastBubble[1] - newOrigin[1]) < 0 ? 0 : Math.PI,
  575. // if new origin y is smaller than last bubble y value
  576. // (2 and 3 quarter),
  577. // add Math.PI to final angle
  578. delta = (lastBubble[0] - newOrigin[0]) *
  579. (lastBubble[1] - newOrigin[1]) < 0 ?
  580. 1 : -1, // (1st and 3rd quarter)
  581. finalAngle = gamma + alfa + beta * delta, cosA = Math.cos(finalAngle), sinA = Math.sin(finalAngle), posX = newOrigin[0] + (newOrigin[2] + nextBubble[2]) * sinA,
  582. // center of new origin + (radius1 + radius2) * sinus A
  583. posY = newOrigin[1] - (newOrigin[2] + nextBubble[2]) * cosA;
  584. return [
  585. posX,
  586. posY,
  587. nextBubble[2],
  588. nextBubble[3],
  589. nextBubble[4]
  590. ]; // the same as described before
  591. };
  592. PackedBubbleSeries.prototype.render = function () {
  593. var series = this, dataLabels = [];
  594. Series.prototype.render.apply(this, arguments);
  595. // #10823 - dataLabels should stay visible
  596. // when enabled allowOverlap.
  597. if (!series.options.dataLabels.allowOverlap) {
  598. series.data.forEach(function (point) {
  599. if (isArray(point.dataLabels)) {
  600. point.dataLabels.forEach(function (dataLabel) {
  601. dataLabels.push(dataLabel);
  602. });
  603. }
  604. });
  605. // Only hide overlapping dataLabels for layouts that
  606. // use simulation. Spiral packedbubble don't need
  607. // additional dataLabel hiding on every simulation step
  608. if (series.options.useSimulation) {
  609. series.chart.hideOverlappingLabels(dataLabels);
  610. }
  611. }
  612. };
  613. /**
  614. * The function responsible for resizing the bubble radius.
  615. * In shortcut: it is taking the initially
  616. * calculated positions of bubbles. Then it is calculating the min max
  617. * of both dimensions, creating something in shape of bBox.
  618. * The comparison of bBox and the size of plotArea
  619. * (later it may be also the size set by customer) is giving the
  620. * value how to recalculate the radius so it will match the size
  621. * @private
  622. */
  623. PackedBubbleSeries.prototype.resizeRadius = function () {
  624. var chart = this.chart, positions = chart.rawPositions, min = Math.min, max = Math.max, plotLeft = chart.plotLeft, plotTop = chart.plotTop, chartHeight = chart.plotHeight, chartWidth = chart.plotWidth, minX, maxX, minY, maxY, radius, bBox, spaceRatio, smallerDimension, i;
  625. minX = minY = Number.POSITIVE_INFINITY; // set initial values
  626. maxX = maxY = Number.NEGATIVE_INFINITY;
  627. for (i = 0; i < positions.length; i++) {
  628. radius = positions[i][2];
  629. minX = min(minX, positions[i][0] - radius);
  630. // (x center-radius) is the min x value used by specific bubble
  631. maxX = max(maxX, positions[i][0] + radius);
  632. minY = min(minY, positions[i][1] - radius);
  633. maxY = max(maxY, positions[i][1] + radius);
  634. }
  635. bBox = [maxX - minX, maxY - minY];
  636. spaceRatio = [
  637. (chartWidth - plotLeft) / bBox[0],
  638. (chartHeight - plotTop) / bBox[1]
  639. ];
  640. smallerDimension = min.apply([], spaceRatio);
  641. if (Math.abs(smallerDimension - 1) > 1e-10) {
  642. // if bBox is considered not the same width as possible size
  643. for (i = 0; i < positions.length; i++) {
  644. positions[i][2] *= smallerDimension;
  645. }
  646. this.placeBubbles(positions);
  647. }
  648. else {
  649. /** if no radius recalculation is needed, we need to position
  650. * the whole bubbles in center of chart plotarea
  651. * for this, we are adding two parameters,
  652. * diffY and diffX, that are related to differences
  653. * between the initial center and the bounding box
  654. */
  655. chart.diffY = chartHeight / 2 +
  656. plotTop - minY - (maxY - minY) / 2;
  657. chart.diffX = chartWidth / 2 +
  658. plotLeft - minX - (maxX - minX) / 2;
  659. }
  660. };
  661. /**
  662. * The function responsible for calculating series bubble' s bBox.
  663. * Needed because of exporting failure when useSimulation
  664. * is set to false
  665. * @private
  666. */
  667. PackedBubbleSeries.prototype.seriesBox = function () {
  668. var series = this, chart = series.chart, data = series.data, max = Math.max, min = Math.min, radius,
  669. // bBox = [xMin, xMax, yMin, yMax]
  670. bBox = [
  671. chart.plotLeft,
  672. chart.plotLeft + chart.plotWidth,
  673. chart.plotTop,
  674. chart.plotTop + chart.plotHeight
  675. ];
  676. data.forEach(function (p) {
  677. if (defined(p.plotX) &&
  678. defined(p.plotY) &&
  679. p.marker.radius) {
  680. radius = p.marker.radius;
  681. bBox[0] = min(bBox[0], p.plotX - radius);
  682. bBox[1] = max(bBox[1], p.plotX + radius);
  683. bBox[2] = min(bBox[2], p.plotY - radius);
  684. bBox[3] = max(bBox[3], p.plotY + radius);
  685. }
  686. });
  687. return isNumber(bBox.width / bBox.height) ?
  688. bBox :
  689. null;
  690. };
  691. /**
  692. * Needed because of z-indexing issue if point is added in series.group
  693. * @private
  694. */
  695. PackedBubbleSeries.prototype.setVisible = function () {
  696. var series = this;
  697. Series.prototype.setVisible.apply(series, arguments);
  698. if (series.parentNodeLayout && series.graph) {
  699. if (series.visible) {
  700. series.graph.show();
  701. if (series.parentNode.dataLabel) {
  702. series.parentNode.dataLabel.show();
  703. }
  704. }
  705. else {
  706. series.graph.hide();
  707. series.parentNodeLayout
  708. .removeElementFromCollection(series.parentNode, series.parentNodeLayout.nodes);
  709. if (series.parentNode.dataLabel) {
  710. series.parentNode.dataLabel.hide();
  711. }
  712. }
  713. }
  714. else if (series.layout) {
  715. if (series.visible) {
  716. series.layout.addElementsToCollection(series.points, series.layout.nodes);
  717. }
  718. else {
  719. series.points.forEach(function (node) {
  720. series.layout.removeElementFromCollection(node, series.layout.nodes);
  721. });
  722. }
  723. }
  724. };
  725. /**
  726. * Extend the base translate method to handle bubble size,
  727. * and correct positioning them.
  728. * @private
  729. */
  730. PackedBubbleSeries.prototype.translate = function () {
  731. var series = this, chart = series.chart, data = series.data, index = series.index, point, radius, positions, i, useSimulation = series.options.useSimulation;
  732. series.processedXData = series.xData;
  733. series.generatePoints();
  734. // merged data is an array with all of the data from all series
  735. if (!defined(chart.allDataPoints)) {
  736. chart.allDataPoints = series.accumulateAllPoints(series);
  737. // calculate radius for all added data
  738. series.getPointRadius();
  739. }
  740. // after getting initial radius, calculate bubble positions
  741. if (useSimulation) {
  742. positions = chart.allDataPoints;
  743. }
  744. else {
  745. positions = series.placeBubbles(chart.allDataPoints);
  746. series.options.draggable = false;
  747. }
  748. // Set the shape and arguments to be picked up in drawPoints
  749. for (i = 0; i < positions.length; i++) {
  750. if (positions[i][3] === index) {
  751. // update the series points with the val from positions
  752. // array
  753. point = data[positions[i][4]];
  754. radius = positions[i][2];
  755. if (!useSimulation) {
  756. point.plotX = (positions[i][0] - chart.plotLeft +
  757. chart.diffX);
  758. point.plotY = (positions[i][1] - chart.plotTop +
  759. chart.diffY);
  760. }
  761. point.marker = extend(point.marker, {
  762. radius: radius,
  763. width: 2 * radius,
  764. height: 2 * radius
  765. });
  766. point.radius = radius;
  767. }
  768. }
  769. if (useSimulation) {
  770. series.deferLayout();
  771. }
  772. fireEvent(series, 'afterTranslate');
  773. };
  774. /**
  775. * A packed bubble series is a two dimensional series type, where each point
  776. * renders a value in X, Y position. Each point is drawn as a bubble
  777. * where the bubbles don't overlap with each other and the radius
  778. * of the bubble relates to the value.
  779. *
  780. * @sample highcharts/demo/packed-bubble/
  781. * Packed bubble chart
  782. * @sample highcharts/demo/packed-bubble-split/
  783. * Split packed bubble chart
  784. * @extends plotOptions.bubble
  785. * @excluding connectEnds, connectNulls, cropThreshold, dragDrop, jitter,
  786. * keys, pointPlacement, sizeByAbsoluteValue, step, xAxis,
  787. * yAxis, zMax, zMin, dataSorting, boostThreshold,
  788. * boostBlending
  789. * @product highcharts
  790. * @since 7.0.0
  791. * @requires highcharts-more
  792. * @optionparent plotOptions.packedbubble
  793. */
  794. PackedBubbleSeries.defaultOptions = merge(BubbleSeries.defaultOptions, {
  795. /**
  796. * Minimum bubble size. Bubbles will automatically size between the
  797. * `minSize` and `maxSize` to reflect the value of each bubble.
  798. * Can be either pixels (when no unit is given), or a percentage of
  799. * the smallest one of the plot width and height, divided by the square
  800. * root of total number of points.
  801. *
  802. * @sample highcharts/plotoptions/bubble-size/
  803. * Bubble size
  804. *
  805. * @type {number|string}
  806. *
  807. * @private
  808. */
  809. minSize: '10%',
  810. /**
  811. * Maximum bubble size. Bubbles will automatically size between the
  812. * `minSize` and `maxSize` to reflect the value of each bubble.
  813. * Can be either pixels (when no unit is given), or a percentage of
  814. * the smallest one of the plot width and height, divided by the square
  815. * root of total number of points.
  816. *
  817. * @sample highcharts/plotoptions/bubble-size/
  818. * Bubble size
  819. *
  820. * @type {number|string}
  821. *
  822. * @private
  823. */
  824. maxSize: '50%',
  825. sizeBy: 'area',
  826. zoneAxis: 'y',
  827. crisp: false,
  828. tooltip: {
  829. pointFormat: 'Value: {point.value}'
  830. },
  831. /**
  832. * Flag to determine if nodes are draggable or not. Available for
  833. * graph with useSimulation set to true only.
  834. *
  835. * @since 7.1.0
  836. *
  837. * @private
  838. */
  839. draggable: true,
  840. /**
  841. * An option is giving a possibility to choose between using simulation
  842. * for calculating bubble positions. These reflects in both animation
  843. * and final position of bubbles. Simulation is also adding options to
  844. * the series graph based on used layout. In case of big data sets, with
  845. * any performance issues, it is possible to disable animation and pack
  846. * bubble in a simple circular way.
  847. *
  848. * @sample highcharts/series-packedbubble/spiral/
  849. * useSimulation set to false
  850. *
  851. * @since 7.1.0
  852. *
  853. * @private
  854. */
  855. useSimulation: true,
  856. /**
  857. * Series options for parent nodes.
  858. *
  859. * @since 8.1.1
  860. *
  861. * @private
  862. */
  863. parentNode: {
  864. /**
  865. * Allow this series' parent nodes to be selected
  866. * by clicking on the graph.
  867. *
  868. * @since 8.1.1
  869. */
  870. allowPointSelect: false
  871. },
  872. /**
  873. /**
  874. *
  875. * @declare Highcharts.SeriesPackedBubbleDataLabelsOptionsObject
  876. *
  877. * @private
  878. */
  879. dataLabels: {
  880. /**
  881. * The
  882. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  883. * specifying what to show for _node_ in the networkgraph. In v7.0
  884. * defaults to `{key}`, since v7.1 defaults to `undefined` and
  885. * `formatter` is used instead.
  886. *
  887. * @type {string}
  888. * @since 7.0.0
  889. * @apioption plotOptions.packedbubble.dataLabels.format
  890. */
  891. // eslint-disable-next-line valid-jsdoc
  892. /**
  893. * Callback JavaScript function to format the data label for a node.
  894. * Note that if a `format` is defined, the format takes precedence
  895. * and the formatter is ignored.
  896. *
  897. * @type {Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction}
  898. * @since 7.0.0
  899. */
  900. formatter: function () {
  901. return this.point.value;
  902. },
  903. /**
  904. * @type {string}
  905. * @since 7.1.0
  906. * @apioption plotOptions.packedbubble.dataLabels.parentNodeFormat
  907. */
  908. // eslint-disable-next-line valid-jsdoc
  909. /**
  910. * @type {Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction}
  911. * @since 7.1.0
  912. */
  913. parentNodeFormatter: function () {
  914. return this.name;
  915. },
  916. /**
  917. * @sample {highcharts} highcharts/series-packedbubble/packed-dashboard
  918. * Dashboard with dataLabels on parentNodes
  919. *
  920. * @declare Highcharts.SeriesPackedBubbleDataLabelsTextPathOptionsObject
  921. * @since 7.1.0
  922. */
  923. parentNodeTextPath: {
  924. /**
  925. * Presentation attributes for the text path.
  926. *
  927. * @type {Highcharts.SVGAttributes}
  928. * @since 7.1.0
  929. * @apioption plotOptions.packedbubble.dataLabels.attributes
  930. */
  931. /**
  932. * Enable or disable `textPath` option for link's or marker's
  933. * data labels.
  934. *
  935. * @since 7.1.0
  936. */
  937. enabled: true
  938. },
  939. /**
  940. * Options for a _node_ label text which should follow marker's
  941. * shape.
  942. *
  943. * **Note:** Only SVG-based renderer supports this option.
  944. *
  945. * @extends plotOptions.series.dataLabels.textPath
  946. * @apioption plotOptions.packedbubble.dataLabels.textPath
  947. */
  948. padding: 0,
  949. style: {
  950. transition: 'opacity 2000ms'
  951. }
  952. },
  953. /**
  954. * Options for layout algorithm when simulation is enabled. Inside there
  955. * are options to change the speed, padding, initial bubbles positions
  956. * and more.
  957. *
  958. * @extends plotOptions.networkgraph.layoutAlgorithm
  959. * @excluding approximation, attractiveForce, repulsiveForce, theta
  960. * @since 7.1.0
  961. *
  962. * @private
  963. */
  964. layoutAlgorithm: {
  965. /**
  966. * Initial layout algorithm for positioning nodes. Can be one of
  967. * the built-in options ("circle", "random") or a function where
  968. * positions should be set on each node (`this.nodes`) as
  969. * `node.plotX` and `node.plotY`.
  970. *
  971. * @sample highcharts/series-networkgraph/initial-positions/
  972. * Initial positions with callback
  973. *
  974. * @type {"circle"|"random"|Function}
  975. */
  976. initialPositions: 'circle',
  977. /**
  978. * @sample highcharts/series-packedbubble/initial-radius/
  979. * Initial radius set to 200
  980. *
  981. * @extends plotOptions.networkgraph.layoutAlgorithm.initialPositionRadius
  982. * @excluding states
  983. */
  984. initialPositionRadius: 20,
  985. /**
  986. * The distance between two bubbles, when the algorithm starts to
  987. * treat two bubbles as overlapping. The `bubblePadding` is also the
  988. * expected distance between all the bubbles on simulation end.
  989. */
  990. bubblePadding: 5,
  991. /**
  992. * Whether bubbles should interact with their parentNode to keep
  993. * them inside.
  994. */
  995. parentNodeLimit: false,
  996. /**
  997. * Whether series should interact with each other or not. When
  998. * `parentNodeLimit` is set to true, thi option should be set to
  999. * false to avoid sticking points in wrong series parentNode.
  1000. */
  1001. seriesInteraction: true,
  1002. /**
  1003. * In case of split series, this option allows user to drag and
  1004. * drop points between series, for changing point related series.
  1005. *
  1006. * @sample highcharts/series-packedbubble/packed-dashboard/
  1007. * Example of drag'n drop bubbles for bubble kanban
  1008. */
  1009. dragBetweenSeries: false,
  1010. /**
  1011. * Layout algorithm options for parent nodes.
  1012. *
  1013. * @extends plotOptions.networkgraph.layoutAlgorithm
  1014. * @excluding approximation, attractiveForce, enableSimulation,
  1015. * repulsiveForce, theta
  1016. */
  1017. parentNodeOptions: {
  1018. maxIterations: 400,
  1019. gravitationalConstant: 0.03,
  1020. maxSpeed: 50,
  1021. initialPositionRadius: 100,
  1022. seriesInteraction: true,
  1023. /**
  1024. * Styling options for parentNodes markers. Similar to
  1025. * line.marker options.
  1026. *
  1027. * @sample highcharts/series-packedbubble/parentnode-style/
  1028. * Bubble size
  1029. *
  1030. * @extends plotOptions.series.marker
  1031. * @excluding states
  1032. */
  1033. marker: {
  1034. fillColor: null,
  1035. fillOpacity: 1,
  1036. lineWidth: 1,
  1037. lineColor: null,
  1038. symbol: 'circle'
  1039. }
  1040. },
  1041. enableSimulation: true,
  1042. /**
  1043. * Type of the algorithm used when positioning bubbles.
  1044. * @ignore-option
  1045. */
  1046. type: 'packedbubble',
  1047. /**
  1048. * Integration type. Integration determines how forces are applied
  1049. * on particles. The `packedbubble` integration is based on
  1050. * the networkgraph `verlet` integration, where the new position
  1051. * is based on a previous position without velocity:
  1052. * `newPosition += previousPosition - newPosition`.
  1053. *
  1054. * @sample highcharts/series-networkgraph/forces/
  1055. *
  1056. * @ignore-option
  1057. */
  1058. integration: 'packedbubble',
  1059. maxIterations: 1000,
  1060. /**
  1061. * Whether to split series into individual groups or to mix all
  1062. * series together.
  1063. *
  1064. * @since 7.1.0
  1065. * @default false
  1066. */
  1067. splitSeries: false,
  1068. /**
  1069. * Max speed that node can get in one iteration. In terms of
  1070. * simulation, it's a maximum translation (in pixels) that a node
  1071. * can move (in both, x and y, dimensions). While `friction` is
  1072. * applied on all nodes, max speed is applied only for nodes that
  1073. * move very fast, for example small or disconnected ones.
  1074. *
  1075. * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration)
  1076. *
  1077. * @see [layoutAlgorithm.friction](#series.networkgraph.layoutAlgorithm.friction)
  1078. */
  1079. maxSpeed: 5,
  1080. gravitationalConstant: 0.01,
  1081. friction: -0.981
  1082. }
  1083. });
  1084. return PackedBubbleSeries;
  1085. }(BubbleSeries));
  1086. extend(PackedBubbleSeries.prototype, {
  1087. alignDataLabel: Series.prototype.alignDataLabel,
  1088. axisTypes: [],
  1089. directTouch: true,
  1090. /**
  1091. * Array of internal forces. Each force should be later defined in
  1092. * integrations.js.
  1093. * @private
  1094. */
  1095. forces: ['barycenter', 'repulsive'],
  1096. /**
  1097. * An internal option used for allowing nodes dragging.
  1098. * @private
  1099. */
  1100. hasDraggableNodes: true,
  1101. isCartesian: false,
  1102. noSharedTooltip: true,
  1103. /**
  1104. * Mouse down action, initializing drag&drop mode.
  1105. * @private
  1106. * @param {global.Event} event Browser event, before normalization.
  1107. * @param {Highcharts.Point} point The point that event occured.
  1108. */
  1109. onMouseDown: dragNodesMixin.onMouseDown,
  1110. /**
  1111. * Mouse move action during drag&drop.
  1112. * @private
  1113. * @param {global.Event} event Browser event, before normalization.
  1114. * @param {Highcharts.Point} point The point that event occured.
  1115. */
  1116. onMouseMove: dragNodesMixin.onMouseMove,
  1117. pointArrayMap: ['value'],
  1118. pointClass: PackedBubblePoint,
  1119. pointValKey: 'value',
  1120. /**
  1121. * Redraw halo on mousemove during the drag&drop action.
  1122. * @private
  1123. * @param {Highcharts.Point} point The point that should show halo.
  1124. */
  1125. redrawHalo: dragNodesMixin.redrawHalo,
  1126. requireSorting: false,
  1127. // solving #12287
  1128. searchPoint: H.noop,
  1129. trackerGroups: ['group', 'dataLabelsGroup', 'parentNodesGroup']
  1130. });
  1131. SeriesRegistry.registerSeriesType('packedbubble', PackedBubbleSeries);
  1132. /* *
  1133. *
  1134. * Default Export
  1135. *
  1136. * */
  1137. export default PackedBubbleSeries;
  1138. /* *
  1139. *
  1140. * API Declarations
  1141. *
  1142. * */
  1143. /**
  1144. * Formatter callback function.
  1145. *
  1146. * @callback Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction
  1147. *
  1148. * @param {Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject} this
  1149. * Data label context to format
  1150. *
  1151. * @return {string}
  1152. * Formatted data label text
  1153. */
  1154. /**
  1155. * Context for the formatter function.
  1156. *
  1157. * @interface Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject
  1158. * @extends Highcharts.PointLabelObject
  1159. * @since 7.0.0
  1160. */ /**
  1161. * The color of the node.
  1162. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#color
  1163. * @type {Highcharts.ColorString}
  1164. * @since 7.0.0
  1165. */ /**
  1166. * The point (node) object. The node name, if defined, is available through
  1167. * `this.point.name`. Arrays: `this.point.linksFrom` and `this.point.linksTo`
  1168. * contains all nodes connected to this point.
  1169. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#point
  1170. * @type {Highcharts.Point}
  1171. * @since 7.0.0
  1172. */ /**
  1173. * The ID of the node.
  1174. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#key
  1175. * @type {string}
  1176. * @since 7.0.0
  1177. */
  1178. ''; // detach doclets above
  1179. /* *
  1180. *
  1181. * API Options
  1182. *
  1183. * */
  1184. /**
  1185. * A `packedbubble` series. If the [type](#series.packedbubble.type) option is
  1186. * not specified, it is inherited from [chart.type](#chart.type).
  1187. *
  1188. * @type {Object}
  1189. * @extends series,plotOptions.packedbubble
  1190. * @excluding cropThreshold, dataParser, dataSorting, dataURL, dragDrop, stack,
  1191. * boostThreshold, boostBlending
  1192. * @product highcharts
  1193. * @requires highcharts-more
  1194. * @apioption series.packedbubble
  1195. */
  1196. /**
  1197. * An array of data points for the series. For the `packedbubble` series type,
  1198. * points can be given in the following ways:
  1199. *
  1200. * 1. An array of `values`.
  1201. *
  1202. * ```js
  1203. * data: [5, 1, 20]
  1204. * ```
  1205. *
  1206. * 2. An array of objects with named values. The objects are point
  1207. * configuration objects as seen below. If the total number of data points
  1208. * exceeds the series' [turboThreshold](#series.packedbubble.turboThreshold),
  1209. * this option is not available.
  1210. *
  1211. * ```js
  1212. * data: [{
  1213. * value: 1,
  1214. * name: "Point2",
  1215. * color: "#00FF00"
  1216. * }, {
  1217. * value: 5,
  1218. * name: "Point1",
  1219. * color: "#FF00FF"
  1220. * }]
  1221. * ```
  1222. *
  1223. * @type {Array<Object|Array>}
  1224. * @extends series.line.data
  1225. * @excluding marker, x, y
  1226. * @sample {highcharts} highcharts/series/data-array-of-objects/
  1227. * Config objects
  1228. * @product highcharts
  1229. * @apioption series.packedbubble.data
  1230. */
  1231. /**
  1232. * @type {Highcharts.SeriesPackedBubbleDataLabelsOptionsObject|Array<Highcharts.SeriesPackedBubbleDataLabelsOptionsObject>}
  1233. * @product highcharts
  1234. * @apioption series.packedbubble.data.dataLabels
  1235. */
  1236. /**
  1237. * @excluding enabled,enabledThreshold,height,radius,width
  1238. * @product highcharts
  1239. * @apioption series.packedbubble.marker
  1240. */
  1241. ''; // adds doclets above to transpiled file