PiePoint.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /* *
  2. *
  3. * (c) 2010-2021 Torstein Honsi
  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 A from '../../Core/Animation/AnimationUtilities.js';
  25. var setAnimation = A.setAnimation;
  26. import Point from '../../Core/Series/Point.js';
  27. import U from '../../Core/Utilities.js';
  28. var addEvent = U.addEvent, defined = U.defined, extend = U.extend, isNumber = U.isNumber, pick = U.pick, relativeLength = U.relativeLength;
  29. /* *
  30. *
  31. * Class
  32. *
  33. * */
  34. var PiePoint = /** @class */ (function (_super) {
  35. __extends(PiePoint, _super);
  36. function PiePoint() {
  37. /* *
  38. *
  39. * Properties
  40. *
  41. * */
  42. var _this = _super !== null && _super.apply(this, arguments) || this;
  43. _this.labelDistance = void 0;
  44. _this.options = void 0;
  45. _this.series = void 0;
  46. return _this;
  47. }
  48. /* *
  49. *
  50. * Functions
  51. *
  52. * */
  53. /* eslint-disable valid-jsdoc */
  54. /**
  55. * Extendable method for getting the path of the connector between the
  56. * data label and the pie slice.
  57. * @private
  58. */
  59. PiePoint.prototype.getConnectorPath = function () {
  60. var labelPosition = this.labelPosition, options = this.series.options.dataLabels, connectorShape = options.connectorShape, predefinedShapes = this.connectorShapes;
  61. // find out whether to use the predefined shape
  62. if (predefinedShapes[connectorShape]) {
  63. connectorShape = predefinedShapes[connectorShape];
  64. }
  65. return connectorShape.call(this, {
  66. // pass simplified label position object for user's convenience
  67. x: labelPosition.final.x,
  68. y: labelPosition.final.y,
  69. alignment: labelPosition.alignment
  70. }, labelPosition.connectorPosition, options);
  71. };
  72. /**
  73. * @private
  74. */
  75. PiePoint.prototype.getTranslate = function () {
  76. return this.sliced ? this.slicedTranslation : {
  77. translateX: 0,
  78. translateY: 0
  79. };
  80. };
  81. /**
  82. * @private
  83. */
  84. PiePoint.prototype.haloPath = function (size) {
  85. var shapeArgs = this.shapeArgs;
  86. return this.sliced || !this.visible ?
  87. [] :
  88. this.series.chart.renderer.symbols.arc(shapeArgs.x, shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
  89. // Substract 1px to ensure the background is not bleeding
  90. // through between the halo and the slice (#7495).
  91. innerR: shapeArgs.r - 1,
  92. start: shapeArgs.start,
  93. end: shapeArgs.end
  94. });
  95. };
  96. /**
  97. * Initialize the pie slice.
  98. * @private
  99. */
  100. PiePoint.prototype.init = function () {
  101. Point.prototype.init.apply(this, arguments);
  102. var point = this, toggleSlice;
  103. point.name = pick(point.name, 'Slice');
  104. // add event listener for select
  105. toggleSlice = function (e) {
  106. point.slice(e.type === 'select');
  107. };
  108. addEvent(point, 'select', toggleSlice);
  109. addEvent(point, 'unselect', toggleSlice);
  110. return point;
  111. };
  112. /**
  113. * Negative points are not valid (#1530, #3623, #5322)
  114. * @private
  115. */
  116. PiePoint.prototype.isValid = function () {
  117. return isNumber(this.y) && this.y >= 0;
  118. };
  119. /**
  120. * Toggle the visibility of the pie slice.
  121. * @private
  122. *
  123. * @param {boolean} vis
  124. * Whether to show the slice or not. If undefined, the visibility is
  125. * toggled.
  126. */
  127. PiePoint.prototype.setVisible = function (vis, redraw) {
  128. var point = this, series = point.series, chart = series.chart, ignoreHiddenPoint = series.options.ignoreHiddenPoint;
  129. redraw = pick(redraw, ignoreHiddenPoint);
  130. if (vis !== point.visible) {
  131. // If called without an argument, toggle visibility
  132. point.visible = point.options.visible = vis =
  133. typeof vis === 'undefined' ? !point.visible : vis;
  134. // update userOptions.data
  135. series.options.data[series.data.indexOf(point)] =
  136. point.options;
  137. // Show and hide associated elements. This is performed
  138. // regardless of redraw or not, because chart.redraw only
  139. // handles full series.
  140. ['graphic', 'dataLabel', 'connector', 'shadowGroup'].forEach(function (key) {
  141. if (point[key]) {
  142. point[key][vis ? 'show' : 'hide'](vis);
  143. }
  144. });
  145. if (point.legendItem) {
  146. chart.legend.colorizeItem(point, vis);
  147. }
  148. // #4170, hide halo after hiding point
  149. if (!vis && point.state === 'hover') {
  150. point.setState('');
  151. }
  152. // Handle ignore hidden slices
  153. if (ignoreHiddenPoint) {
  154. series.isDirty = true;
  155. }
  156. if (redraw) {
  157. chart.redraw();
  158. }
  159. }
  160. };
  161. /**
  162. * Set or toggle whether the slice is cut out from the pie.
  163. * @private
  164. *
  165. * @param {boolean} sliced
  166. * When undefined, the slice state is toggled.
  167. *
  168. * @param {boolean} redraw
  169. * Whether to redraw the chart. True by default.
  170. *
  171. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>}
  172. * Animation options.
  173. */
  174. PiePoint.prototype.slice = function (sliced, redraw, animation) {
  175. var point = this, series = point.series, chart = series.chart;
  176. setAnimation(animation, chart);
  177. // redraw is true by default
  178. redraw = pick(redraw, true);
  179. /**
  180. * Pie series only. Whether to display a slice offset from the
  181. * center.
  182. * @name Highcharts.Point#sliced
  183. * @type {boolean|undefined}
  184. */
  185. // if called without an argument, toggle
  186. point.sliced = point.options.sliced = sliced =
  187. defined(sliced) ? sliced : !point.sliced;
  188. // update userOptions.data
  189. series.options.data[series.data.indexOf(point)] =
  190. point.options;
  191. if (point.graphic) {
  192. point.graphic.animate(this.getTranslate());
  193. }
  194. if (point.shadowGroup) {
  195. point.shadowGroup.animate(this.getTranslate());
  196. }
  197. };
  198. return PiePoint;
  199. }(Point));
  200. extend(PiePoint.prototype, {
  201. connectorShapes: {
  202. // only one available before v7.0.0
  203. fixedOffset: function (labelPosition, connectorPosition, options) {
  204. var breakAt = connectorPosition.breakAt, touchingSliceAt = connectorPosition.touchingSliceAt, lineSegment = options.softConnector ? [
  205. 'C',
  206. // 1st control point (of the curve)
  207. labelPosition.x +
  208. // 5 gives the connector a little horizontal bend
  209. (labelPosition.alignment === 'left' ? -5 : 5),
  210. labelPosition.y,
  211. 2 * breakAt.x - touchingSliceAt.x,
  212. 2 * breakAt.y - touchingSliceAt.y,
  213. breakAt.x,
  214. breakAt.y //
  215. ] : [
  216. 'L',
  217. breakAt.x,
  218. breakAt.y
  219. ];
  220. // assemble the path
  221. return ([
  222. ['M', labelPosition.x, labelPosition.y],
  223. lineSegment,
  224. ['L', touchingSliceAt.x, touchingSliceAt.y]
  225. ]);
  226. },
  227. straight: function (labelPosition, connectorPosition) {
  228. var touchingSliceAt = connectorPosition.touchingSliceAt;
  229. // direct line to the slice
  230. return [
  231. ['M', labelPosition.x, labelPosition.y],
  232. ['L', touchingSliceAt.x, touchingSliceAt.y]
  233. ];
  234. },
  235. crookedLine: function (labelPosition, connectorPosition, options) {
  236. var touchingSliceAt = connectorPosition.touchingSliceAt, series = this.series, pieCenterX = series.center[0], plotWidth = series.chart.plotWidth, plotLeft = series.chart.plotLeft, alignment = labelPosition.alignment, radius = this.shapeArgs.r, crookDistance = relativeLength(// % to fraction
  237. options.crookDistance, 1), crookX = alignment === 'left' ?
  238. pieCenterX + radius + (plotWidth + plotLeft -
  239. pieCenterX - radius) * (1 - crookDistance) :
  240. plotLeft + (pieCenterX - radius) * crookDistance, segmentWithCrook = [
  241. 'L',
  242. crookX,
  243. labelPosition.y
  244. ], useCrook = true;
  245. // crookedLine formula doesn't make sense if the path overlaps
  246. // the label - use straight line instead in that case
  247. if (alignment === 'left' ?
  248. (crookX > labelPosition.x || crookX < touchingSliceAt.x) :
  249. (crookX < labelPosition.x || crookX > touchingSliceAt.x)) {
  250. useCrook = false;
  251. }
  252. // assemble the path
  253. var path = [
  254. ['M', labelPosition.x, labelPosition.y]
  255. ];
  256. if (useCrook) {
  257. path.push(segmentWithCrook);
  258. }
  259. path.push(['L', touchingSliceAt.x, touchingSliceAt.y]);
  260. return path;
  261. }
  262. }
  263. });
  264. /* *
  265. *
  266. * Default Export
  267. *
  268. * */
  269. export default PiePoint;