item-series.src.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /**
  2. * @license Highcharts JS v9.0.1 (2021-02-16)
  3. *
  4. * Item series type for Highcharts
  5. *
  6. * (c) 2019 Torstein Honsi
  7. *
  8. * License: www.highcharts.com/license
  9. */
  10. 'use strict';
  11. (function (factory) {
  12. if (typeof module === 'object' && module.exports) {
  13. factory['default'] = factory;
  14. module.exports = factory;
  15. } else if (typeof define === 'function' && define.amd) {
  16. define('highcharts/modules/item-series', ['highcharts'], function (Highcharts) {
  17. factory(Highcharts);
  18. factory.Highcharts = Highcharts;
  19. return factory;
  20. });
  21. } else {
  22. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  23. }
  24. }(function (Highcharts) {
  25. var _modules = Highcharts ? Highcharts._modules : {};
  26. function _registerModule(obj, path, args, fn) {
  27. if (!obj.hasOwnProperty(path)) {
  28. obj[path] = fn.apply(null, args);
  29. }
  30. }
  31. _registerModule(_modules, 'Series/Item/ItemPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  32. /* *
  33. *
  34. * (c) 2019-2021 Torstein Honsi
  35. *
  36. * Item series type for Highcharts
  37. *
  38. * License: www.highcharts.com/license
  39. *
  40. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  41. *
  42. * */
  43. var __extends = (this && this.__extends) || (function () {
  44. var extendStatics = function (d,
  45. b) {
  46. extendStatics = Object.setPrototypeOf ||
  47. ({ __proto__: [] } instanceof Array && function (d,
  48. b) { d.__proto__ = b; }) ||
  49. function (d,
  50. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  51. return extendStatics(d, b);
  52. };
  53. return function (d, b) {
  54. extendStatics(d, b);
  55. function __() { this.constructor = d; }
  56. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  57. };
  58. })();
  59. var Series = SeriesRegistry.series,
  60. PieSeries = SeriesRegistry.seriesTypes.pie;
  61. var extend = U.extend;
  62. /* *
  63. *
  64. * Class
  65. *
  66. * */
  67. var ItemPoint = /** @class */ (function (_super) {
  68. __extends(ItemPoint, _super);
  69. function ItemPoint() {
  70. /* *
  71. *
  72. * Properties
  73. *
  74. * */
  75. var _this = _super !== null && _super.apply(this,
  76. arguments) || this;
  77. _this.graphics = void 0;
  78. _this.options = void 0;
  79. _this.series = void 0;
  80. return _this;
  81. }
  82. return ItemPoint;
  83. }(PieSeries.prototype.pointClass));
  84. extend(ItemPoint.prototype, {
  85. haloPath: Series.prototype.pointClass.prototype.haloPath
  86. });
  87. /* *
  88. *
  89. * Default Export
  90. *
  91. * */
  92. return ItemPoint;
  93. });
  94. _registerModule(_modules, 'Series/Item/ItemSeries.js', [_modules['Core/Globals.js'], _modules['Series/Item/ItemPoint.js'], _modules['Core/Options.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (H, ItemPoint, O, SeriesRegistry, U) {
  95. /* *
  96. *
  97. * (c) 2019-2021 Torstein Honsi
  98. *
  99. * Item series type for Highcharts
  100. *
  101. * License: www.highcharts.com/license
  102. *
  103. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  104. *
  105. * */
  106. var __extends = (this && this.__extends) || (function () {
  107. var extendStatics = function (d,
  108. b) {
  109. extendStatics = Object.setPrototypeOf ||
  110. ({ __proto__: [] } instanceof Array && function (d,
  111. b) { d.__proto__ = b; }) ||
  112. function (d,
  113. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  114. return extendStatics(d, b);
  115. };
  116. return function (d, b) {
  117. extendStatics(d, b);
  118. function __() { this.constructor = d; }
  119. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  120. };
  121. })();
  122. var defaultOptions = O.defaultOptions;
  123. var PieSeries = SeriesRegistry.seriesTypes.pie;
  124. var defined = U.defined,
  125. extend = U.extend,
  126. fireEvent = U.fireEvent,
  127. isNumber = U.isNumber,
  128. merge = U.merge,
  129. objectEach = U.objectEach,
  130. pick = U.pick;
  131. /* *
  132. *
  133. * Class
  134. *
  135. * */
  136. // Inherits pie as the most tested non-cartesian series with individual point
  137. // legend, tooltips etc. Only downside is we need to re-enable marker options.
  138. /**
  139. * The item series type.
  140. *
  141. * @requires module:modules/item-series
  142. *
  143. * @private
  144. * @class
  145. * @name Highcharts.seriesTypes.item
  146. *
  147. * @augments Highcharts.seriesTypes.pie
  148. */
  149. var ItemSeries = /** @class */ (function (_super) {
  150. __extends(ItemSeries, _super);
  151. function ItemSeries() {
  152. /* *
  153. *
  154. * Static Properties
  155. *
  156. * */
  157. var _this = _super !== null && _super.apply(this,
  158. arguments) || this;
  159. _this.data = void 0;
  160. _this.options = void 0;
  161. _this.points = void 0;
  162. return _this;
  163. /* eslint-enable valid-jsdoc */
  164. }
  165. /* *
  166. *
  167. * Functions
  168. *
  169. * */
  170. /* eslint-disable valid-jsdoc */
  171. /**
  172. * Fade in the whole chart.
  173. * @private
  174. */
  175. ItemSeries.prototype.animate = function (init) {
  176. if (init) {
  177. this.group.attr({
  178. opacity: 0
  179. });
  180. }
  181. else {
  182. this.group.animate({
  183. opacity: 1
  184. }, this.options.animation);
  185. }
  186. };
  187. ItemSeries.prototype.drawDataLabels = function () {
  188. if (this.center && this.slots) {
  189. H.seriesTypes.pie.prototype.drawDataLabels.call(this);
  190. // else, it's just a dot chart with no natural place to put the
  191. // data labels
  192. }
  193. else {
  194. this.points.forEach(function (point) {
  195. point.destroyElements({ dataLabel: 1 });
  196. });
  197. }
  198. };
  199. ItemSeries.prototype.drawPoints = function () {
  200. var series = this,
  201. options = this.options,
  202. renderer = series.chart.renderer,
  203. seriesMarkerOptions = options.marker,
  204. borderWidth = this.borderWidth,
  205. crisp = borderWidth % 2 ? 0.5 : 1,
  206. i = 0,
  207. rows = this.getRows(),
  208. cols = Math.ceil(this.total / rows),
  209. cellWidth = this.chart.plotWidth / cols,
  210. cellHeight = this.chart.plotHeight / rows,
  211. itemSize = this.itemSize || Math.min(cellWidth,
  212. cellHeight);
  213. /* @todo: remove if not needed
  214. this.slots.forEach(slot => {
  215. this.chart.renderer.circle(slot.x, slot.y, 6)
  216. .attr({
  217. fill: 'silver'
  218. })
  219. .add(this.group);
  220. });
  221. //*/
  222. this.points.forEach(function (point) {
  223. var attr,
  224. graphics,
  225. pointAttr,
  226. pointMarkerOptions = point.marker || {},
  227. symbol = (pointMarkerOptions.symbol ||
  228. seriesMarkerOptions.symbol),
  229. r = pick(pointMarkerOptions.radius,
  230. seriesMarkerOptions.radius),
  231. size = defined(r) ? 2 * r : itemSize,
  232. padding = size * options.itemPadding,
  233. x,
  234. y,
  235. width,
  236. height;
  237. point.graphics = graphics = point.graphics || {};
  238. if (!series.chart.styledMode) {
  239. pointAttr = series.pointAttribs(point, point.selected && 'select');
  240. }
  241. if (!point.isNull && point.visible) {
  242. if (!point.graphic) {
  243. point.graphic = renderer.g('point')
  244. .add(series.group);
  245. }
  246. for (var val = 0; val < point.y; val++) {
  247. // Semi-circle
  248. if (series.center && series.slots) {
  249. // Fill up the slots from left to right
  250. var slot = series.slots.shift();
  251. x = slot.x - itemSize / 2;
  252. y = slot.y - itemSize / 2;
  253. }
  254. else if (options.layout === 'horizontal') {
  255. x = cellWidth * (i % cols);
  256. y = cellHeight * Math.floor(i / cols);
  257. }
  258. else {
  259. x = cellWidth * Math.floor(i / rows);
  260. y = cellHeight * (i % rows);
  261. }
  262. x += padding;
  263. y += padding;
  264. width = Math.round(size - 2 * padding);
  265. height = width;
  266. if (series.options.crisp) {
  267. x = Math.round(x) - crisp;
  268. y = Math.round(y) + crisp;
  269. }
  270. attr = {
  271. x: x,
  272. y: y,
  273. width: width,
  274. height: height
  275. };
  276. if (typeof r !== 'undefined') {
  277. attr.r = r;
  278. }
  279. if (graphics[val]) {
  280. graphics[val].animate(attr);
  281. }
  282. else {
  283. graphics[val] = renderer
  284. .symbol(symbol, null, null, null, null, {
  285. backgroundSize: 'within'
  286. })
  287. .attr(extend(attr, pointAttr))
  288. .add(point.graphic);
  289. }
  290. graphics[val].isActive = true;
  291. i++;
  292. }
  293. }
  294. objectEach(graphics, function (graphic, key) {
  295. if (!graphic.isActive) {
  296. graphic.destroy();
  297. delete graphics[key];
  298. }
  299. else {
  300. graphic.isActive = false;
  301. }
  302. });
  303. });
  304. };
  305. ItemSeries.prototype.getRows = function () {
  306. var rows = this.options.rows,
  307. cols,
  308. ratio;
  309. // Get the row count that gives the most square cells
  310. if (!rows) {
  311. ratio = this.chart.plotWidth / this.chart.plotHeight;
  312. rows = Math.sqrt(this.total);
  313. if (ratio > 1) {
  314. rows = Math.ceil(rows);
  315. while (rows > 0) {
  316. cols = this.total / rows;
  317. if (cols / rows > ratio) {
  318. break;
  319. }
  320. rows--;
  321. }
  322. }
  323. else {
  324. rows = Math.floor(rows);
  325. while (rows < this.total) {
  326. cols = this.total / rows;
  327. if (cols / rows < ratio) {
  328. break;
  329. }
  330. rows++;
  331. }
  332. }
  333. }
  334. return rows;
  335. };
  336. /**
  337. * Get the semi-circular slots.
  338. * @private
  339. */
  340. ItemSeries.prototype.getSlots = function () {
  341. var center = this.center,
  342. diameter = center[2],
  343. innerSize = center[3],
  344. row,
  345. slots = this.slots,
  346. x,
  347. y,
  348. rowRadius,
  349. rowLength,
  350. colCount,
  351. increment,
  352. angle,
  353. col,
  354. itemSize = 0,
  355. rowCount,
  356. fullAngle = (this.endAngleRad - this.startAngleRad),
  357. itemCount = Number.MAX_VALUE,
  358. finalItemCount,
  359. rows,
  360. testRows,
  361. rowsOption = this.options.rows,
  362. // How many rows (arcs) should be used
  363. rowFraction = (diameter - innerSize) / diameter,
  364. isCircle = fullAngle % (2 * Math.PI) === 0;
  365. // Increase the itemSize until we find the best fit
  366. while (itemCount > this.total + (rows && isCircle ? rows.length : 0)) {
  367. finalItemCount = itemCount;
  368. // Reset
  369. slots.length = 0;
  370. itemCount = 0;
  371. // Now rows is the last successful run
  372. rows = testRows;
  373. testRows = [];
  374. itemSize++;
  375. // Total number of rows (arcs) from the center to the
  376. // perimeter
  377. rowCount = diameter / itemSize / 2;
  378. if (rowsOption) {
  379. innerSize = ((rowCount - rowsOption) / rowCount) * diameter;
  380. if (innerSize >= 0) {
  381. rowCount = rowsOption;
  382. // If innerSize is negative, we are trying to set too
  383. // many rows in the rows option, so fall back to
  384. // treating it as innerSize 0
  385. }
  386. else {
  387. innerSize = 0;
  388. rowFraction = 1;
  389. }
  390. }
  391. else {
  392. rowCount = Math.floor(rowCount * rowFraction);
  393. }
  394. for (row = rowCount; row > 0; row--) {
  395. rowRadius = (innerSize + (row / rowCount) *
  396. (diameter - innerSize - itemSize)) / 2;
  397. rowLength = fullAngle * rowRadius;
  398. colCount = Math.ceil(rowLength / itemSize);
  399. testRows.push({
  400. rowRadius: rowRadius,
  401. rowLength: rowLength,
  402. colCount: colCount
  403. });
  404. itemCount += colCount + 1;
  405. }
  406. }
  407. if (!rows) {
  408. return;
  409. }
  410. // We now have more slots than we have total items. Loop over
  411. // the rows and remove the last slot until the count is correct.
  412. // For each iteration we sort the last slot by the angle, and
  413. // remove those with the highest angles.
  414. var overshoot = finalItemCount - this.total -
  415. (isCircle ? rows.length : 0);
  416. /**
  417. * @private
  418. * @param {Highcharts.ItemRowContainerObject} item
  419. * Wrapped object with angle and row
  420. * @return {void}
  421. */
  422. function cutOffRow(item) {
  423. if (overshoot > 0) {
  424. item.row.colCount--;
  425. overshoot--;
  426. }
  427. }
  428. while (overshoot > 0) {
  429. rows
  430. // Return a simplified representation of the angle of
  431. // the last slot within each row.
  432. .map(function (row) {
  433. return {
  434. angle: row.colCount / row.rowLength,
  435. row: row
  436. };
  437. })
  438. // Sort by the angles...
  439. .sort(function (a, b) {
  440. return b.angle - a.angle;
  441. })
  442. // ...so that we can ignore the items with the lowest
  443. // angles...
  444. .slice(0, Math.min(overshoot, Math.ceil(rows.length / 2)))
  445. // ...and remove the ones with the highest angles
  446. .forEach(cutOffRow);
  447. }
  448. rows.forEach(function (row) {
  449. var rowRadius = row.rowRadius,
  450. colCount = row.colCount;
  451. increment = colCount ? fullAngle / colCount : 0;
  452. for (col = 0; col <= colCount; col += 1) {
  453. angle = this.startAngleRad + col * increment;
  454. x = center[0] + Math.cos(angle) * rowRadius;
  455. y = center[1] + Math.sin(angle) * rowRadius;
  456. slots.push({ x: x, y: y, angle: angle });
  457. }
  458. }, this);
  459. // Sort by angle
  460. slots.sort(function (a, b) {
  461. return a.angle - b.angle;
  462. });
  463. this.itemSize = itemSize;
  464. return slots;
  465. };
  466. ItemSeries.prototype.translate = function (_positions) {
  467. // Initialize chart without setting data, #13379.
  468. if (this.total === 0) {
  469. this.center = this.getCenter();
  470. }
  471. if (!this.slots) {
  472. this.slots = [];
  473. }
  474. if (isNumber(this.options.startAngle) &&
  475. isNumber(this.options.endAngle)) {
  476. H.seriesTypes.pie.prototype.translate.apply(this, arguments);
  477. this.slots = this.getSlots();
  478. }
  479. else {
  480. this.generatePoints();
  481. fireEvent(this, 'afterTranslate');
  482. }
  483. };
  484. /**
  485. * An item chart is an infographic chart where a number of items are laid
  486. * out in either a rectangular or circular pattern. It can be used to
  487. * visualize counts within a group, or for the circular pattern, typically
  488. * a parliament.
  489. *
  490. * The circular layout has much in common with a pie chart. Many of the item
  491. * series options, like `center`, `size` and data label positioning, are
  492. * inherited from the pie series and don't apply for rectangular layouts.
  493. *
  494. * @sample highcharts/demo/parliament-chart
  495. * Parliament chart (circular item chart)
  496. * @sample highcharts/series-item/rectangular
  497. * Rectangular item chart
  498. * @sample highcharts/series-item/symbols
  499. * Infographic with symbols
  500. *
  501. * @extends plotOptions.pie
  502. * @since 7.1.0
  503. * @product highcharts
  504. * @excluding borderColor, borderWidth, depth, linecap, shadow,
  505. * slicedOffset
  506. * @requires modules/item-series
  507. * @optionparent plotOptions.item
  508. */
  509. ItemSeries.defaultOptions = merge(PieSeries.defaultOptions, {
  510. /**
  511. * In circular view, the end angle of the item layout, in degrees where
  512. * 0 is up.
  513. *
  514. * @sample highcharts/demo/parliament-chart
  515. * Parliament chart
  516. * @type {undefined|number}
  517. */
  518. endAngle: void 0,
  519. /**
  520. * In circular view, the size of the inner diameter of the circle. Can
  521. * be a percentage or pixel value. Percentages are relative to the outer
  522. * perimeter. Pixel values are given as integers.
  523. *
  524. * If the `rows` option is set, it overrides the `innerSize` setting.
  525. *
  526. * @sample highcharts/demo/parliament-chart
  527. * Parliament chart
  528. * @type {string|number}
  529. */
  530. innerSize: '40%',
  531. /**
  532. * The padding between the items, given in relative size where the size
  533. * of the item is 1.
  534. * @type {number}
  535. */
  536. itemPadding: 0.1,
  537. /**
  538. * The layout of the items in rectangular view. Can be either
  539. * `horizontal` or `vertical`.
  540. * @sample highcharts/series-item/symbols
  541. * Horizontal layout
  542. * @type {string}
  543. */
  544. layout: 'vertical',
  545. /**
  546. * @extends plotOptions.series.marker
  547. */
  548. marker: merge(defaultOptions.plotOptions.line.marker, {
  549. radius: null
  550. }),
  551. /**
  552. * The number of rows to display in the rectangular or circular view. If
  553. * the `innerSize` is set, it will be overridden by the `rows` setting.
  554. *
  555. * @sample highcharts/series-item/rows-columns
  556. * Fixed row count
  557. * @type {number}
  558. */
  559. rows: void 0,
  560. crisp: false,
  561. showInLegend: true,
  562. /**
  563. * In circular view, the start angle of the item layout, in degrees
  564. * where 0 is up.
  565. *
  566. * @sample highcharts/demo/parliament-chart
  567. * Parliament chart
  568. * @type {undefined|number}
  569. */
  570. startAngle: void 0
  571. });
  572. return ItemSeries;
  573. }(PieSeries));
  574. extend(ItemSeries.prototype, {
  575. markerAttribs: void 0
  576. });
  577. ItemSeries.prototype.pointClass = ItemPoint;
  578. SeriesRegistry.registerSeriesType('item', ItemSeries);
  579. /* *
  580. *
  581. * Default Export
  582. *
  583. * */
  584. /* *
  585. *
  586. * API Options
  587. *
  588. * */
  589. /**
  590. * An `item` series. If the [type](#series.item.type) option is not specified,
  591. * it is inherited from [chart.type](#chart.type).
  592. *
  593. * @extends series,plotOptions.item
  594. * @excluding dataParser, dataURL, stack, xAxis, yAxis, dataSorting,
  595. * boostThreshold, boostBlending
  596. * @product highcharts
  597. * @requires modules/item-series
  598. * @apioption series.item
  599. */
  600. /**
  601. * An array of data points for the series. For the `item` series type,
  602. * points can be given in the following ways:
  603. *
  604. * 1. An array of numerical values. In this case, the numerical values will be
  605. * interpreted as `y` options. Example:
  606. * ```js
  607. * data: [0, 5, 3, 5]
  608. * ```
  609. *
  610. * 2. An array of objects with named values. The following snippet shows only a
  611. * few settings, see the complete options set below. If the total number of
  612. * data points exceeds the series'
  613. * [turboThreshold](#series.item.turboThreshold),
  614. * this option is not available.
  615. * ```js
  616. * data: [{
  617. * y: 1,
  618. * name: "Point2",
  619. * color: "#00FF00"
  620. * }, {
  621. * y: 7,
  622. * name: "Point1",
  623. * color: "#FF00FF"
  624. * }]
  625. * ```
  626. *
  627. * @sample {highcharts} highcharts/chart/reflow-true/
  628. * Numerical values
  629. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  630. * Arrays of numeric x and y
  631. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  632. * Arrays of datetime x and y
  633. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  634. * Arrays of point.name and y
  635. * @sample {highcharts} highcharts/series/data-array-of-objects/
  636. * Config objects
  637. *
  638. * @type {Array<number|Array<string,(number|null)>|null|*>}
  639. * @extends series.pie.data
  640. * @excludes sliced
  641. * @product highcharts
  642. * @apioption series.item.data
  643. */
  644. /**
  645. * The sequential index of the data point in the legend.
  646. *
  647. * @type {number}
  648. * @product highcharts
  649. * @apioption series.pie.data.legendIndex
  650. */
  651. ''; // adds the doclets above to the transpiled file
  652. return ItemSeries;
  653. });
  654. _registerModule(_modules, 'masters/modules/item-series.src.js', [], function () {
  655. });
  656. }));