funnel.src.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /**
  2. * @license Highcharts JS v6.1.0 (2018-04-13)
  3. * Highcharts funnel module
  4. *
  5. * (c) 2010-2017 Torstein Honsi
  6. *
  7. * License: www.highcharts.com/license
  8. */
  9. 'use strict';
  10. (function (factory) {
  11. if (typeof module === 'object' && module.exports) {
  12. module.exports = factory;
  13. } else {
  14. factory(Highcharts);
  15. }
  16. }(function (Highcharts) {
  17. (function (Highcharts) {
  18. /**
  19. * Highcharts funnel module
  20. *
  21. * (c) 2010-2017 Torstein Honsi
  22. *
  23. * License: www.highcharts.com/license
  24. */
  25. /* eslint indent: 0 */
  26. // create shortcuts
  27. var seriesType = Highcharts.seriesType,
  28. seriesTypes = Highcharts.seriesTypes,
  29. noop = Highcharts.noop,
  30. pick = Highcharts.pick,
  31. each = Highcharts.each;
  32. seriesType('funnel', 'pie',
  33. /**
  34. * Funnel charts are a type of chart often used to visualize stages in a sales
  35. * project, where the top are the initial stages with the most clients.
  36. * It requires that the modules/funnel.js file is loaded.
  37. *
  38. * @sample highcharts/demo/funnel/ Funnel demo
  39. * @extends {plotOptions.pie}
  40. * @excluding size
  41. * @product highcharts
  42. * @optionparent plotOptions.funnel
  43. */
  44. {
  45. /**
  46. * Initial animation is by default disabled for the funnel chart.
  47. */
  48. animation: false,
  49. /**
  50. * The center of the series. By default, it is centered in the middle
  51. * of the plot area, so it fills the plot area height.
  52. *
  53. * @type {Array<String|Number>}
  54. * @default ["50%", "50%"]
  55. * @since 3.0
  56. * @product highcharts
  57. */
  58. center: ['50%', '50%'],
  59. /**
  60. * The width of the funnel compared to the width of the plot area,
  61. * or the pixel width if it is a number.
  62. *
  63. * @type {Number|String}
  64. * @since 3.0
  65. * @product highcharts
  66. */
  67. width: '90%',
  68. /**
  69. * The width of the neck, the lower part of the funnel. A number defines
  70. * pixel width, a percentage string defines a percentage of the plot
  71. * area width.
  72. *
  73. * @type {Number|String}
  74. * @sample {highcharts} highcharts/demo/funnel/ Funnel demo
  75. * @since 3.0
  76. * @product highcharts
  77. */
  78. neckWidth: '30%',
  79. /**
  80. * The height of the funnel or pyramid. If it is a number it defines
  81. * the pixel height, if it is a percentage string it is the percentage
  82. * of the plot area height.
  83. *
  84. * @type {Number|String}
  85. * @sample {highcharts} highcharts/demo/funnel/ Funnel demo
  86. * @since 3.0
  87. * @product highcharts
  88. */
  89. height: '100%',
  90. /**
  91. * The height of the neck, the lower part of the funnel. A number defines
  92. * pixel width, a percentage string defines a percentage of the plot
  93. * area height.
  94. *
  95. * @type {Number|String}
  96. * @product highcharts
  97. */
  98. neckHeight: '25%',
  99. /**
  100. * A reversed funnel has the widest area down. A reversed funnel with
  101. * no neck width and neck height is a pyramid.
  102. *
  103. * @since 3.0.10
  104. * @product highcharts
  105. */
  106. reversed: false,
  107. /**
  108. * @ignore
  109. */
  110. size: true, // to avoid adapting to data label size in Pie.drawDataLabels
  111. // Presentational
  112. dataLabels: {
  113. connectorWidth: 1
  114. },
  115. /**
  116. * Options for the series states.
  117. *
  118. * @product highcharts
  119. */
  120. states: {
  121. /**
  122. * @excluding halo,marker,lineWidth,lineWidthPlus
  123. * @apioption plotOptions.funnel.states.hover
  124. */
  125. /**
  126. * Options for a selected funnel item.
  127. *
  128. * @excluding halo,marker,lineWidth,lineWidthPlus
  129. * @product highcharts
  130. */
  131. select: {
  132. /**
  133. * A specific color for the selected point.
  134. *
  135. * @type {Color}
  136. * @default #cccccc
  137. * @product highcharts highstock
  138. */
  139. color: '#cccccc',
  140. /**
  141. * A specific border color for the selected point.
  142. *
  143. * @type {Color}
  144. * @default #000000
  145. * @product highcharts highstock
  146. */
  147. borderColor: '#000000'
  148. }
  149. }
  150. },
  151. // Properties
  152. {
  153. animate: noop,
  154. /**
  155. * Overrides the pie translate method
  156. */
  157. translate: function () {
  158. var
  159. // Get positions - either an integer or a percentage string
  160. // must be given
  161. getLength = function (length, relativeTo) {
  162. return (/%$/).test(length) ?
  163. relativeTo * parseInt(length, 10) / 100 :
  164. parseInt(length, 10);
  165. },
  166. sum = 0,
  167. series = this,
  168. chart = series.chart,
  169. options = series.options,
  170. reversed = options.reversed,
  171. ignoreHiddenPoint = options.ignoreHiddenPoint,
  172. plotWidth = chart.plotWidth,
  173. plotHeight = chart.plotHeight,
  174. cumulative = 0, // start at top
  175. center = options.center,
  176. centerX = getLength(center[0], plotWidth),
  177. centerY = getLength(center[1], plotHeight),
  178. width = getLength(options.width, plotWidth),
  179. tempWidth,
  180. getWidthAt,
  181. height = getLength(options.height, plotHeight),
  182. neckWidth = getLength(options.neckWidth, plotWidth),
  183. neckHeight = getLength(options.neckHeight, plotHeight),
  184. neckY = (centerY - height / 2) + height - neckHeight,
  185. data = series.data,
  186. path,
  187. fraction,
  188. half = options.dataLabels.position === 'left' ? 1 : 0,
  189. x1,
  190. y1,
  191. x2,
  192. x3,
  193. y3,
  194. x4,
  195. y5;
  196. // Return the width at a specific y coordinate
  197. series.getWidthAt = getWidthAt = function (y) {
  198. var top = (centerY - height / 2);
  199. return (y > neckY || height === neckHeight) ?
  200. neckWidth :
  201. neckWidth + (width - neckWidth) *
  202. (1 - (y - top) / (height - neckHeight));
  203. };
  204. series.getX = function (y, half, point) {
  205. return centerX + (half ? -1 : 1) *
  206. ((getWidthAt(reversed ? 2 * centerY - y : y) / 2) +
  207. point.labelDistance);
  208. };
  209. // Expose
  210. series.center = [centerX, centerY, height];
  211. series.centerX = centerX;
  212. /*
  213. * Individual point coordinate naming:
  214. *
  215. * x1,y1 _________________ x2,y1
  216. * \ /
  217. * \ /
  218. * \ /
  219. * \ /
  220. * \ /
  221. * x3,y3 _________ x4,y3
  222. *
  223. * Additional for the base of the neck:
  224. *
  225. * | |
  226. * | |
  227. * | |
  228. * x3,y5 _________ x4,y5
  229. */
  230. // get the total sum
  231. each(data, function (point) {
  232. if (!ignoreHiddenPoint || point.visible !== false) {
  233. sum += point.y;
  234. }
  235. });
  236. each(data, function (point) {
  237. // set start and end positions
  238. y5 = null;
  239. fraction = sum ? point.y / sum : 0;
  240. y1 = centerY - height / 2 + cumulative * height;
  241. y3 = y1 + fraction * height;
  242. tempWidth = getWidthAt(y1);
  243. x1 = centerX - tempWidth / 2;
  244. x2 = x1 + tempWidth;
  245. tempWidth = getWidthAt(y3);
  246. x3 = centerX - tempWidth / 2;
  247. x4 = x3 + tempWidth;
  248. // the entire point is within the neck
  249. if (y1 > neckY) {
  250. x1 = x3 = centerX - neckWidth / 2;
  251. x2 = x4 = centerX + neckWidth / 2;
  252. // the base of the neck
  253. } else if (y3 > neckY) {
  254. y5 = y3;
  255. tempWidth = getWidthAt(neckY);
  256. x3 = centerX - tempWidth / 2;
  257. x4 = x3 + tempWidth;
  258. y3 = neckY;
  259. }
  260. if (reversed) {
  261. y1 = 2 * centerY - y1;
  262. y3 = 2 * centerY - y3;
  263. y5 = (y5 ? 2 * centerY - y5 : null);
  264. }
  265. // save the path
  266. path = [
  267. 'M',
  268. x1, y1,
  269. 'L',
  270. x2, y1,
  271. x4, y3
  272. ];
  273. if (y5) {
  274. path.push(x4, y5, x3, y5);
  275. }
  276. path.push(x3, y3, 'Z');
  277. // prepare for using shared dr
  278. point.shapeType = 'path';
  279. point.shapeArgs = { d: path };
  280. // for tooltips and data labels
  281. point.percentage = fraction * 100;
  282. point.plotX = centerX;
  283. point.plotY = (y1 + (y5 || y3)) / 2;
  284. // Placement of tooltips and data labels
  285. point.tooltipPos = [
  286. centerX,
  287. point.plotY
  288. ];
  289. // Slice is a noop on funnel points
  290. point.slice = noop;
  291. // Mimicking pie data label placement logic
  292. point.half = half;
  293. if (!ignoreHiddenPoint || point.visible !== false) {
  294. cumulative += fraction;
  295. }
  296. });
  297. },
  298. /**
  299. * Funnel items don't have angles (#2289)
  300. */
  301. sortByAngle: function (points) {
  302. points.sort(function (a, b) {
  303. return a.plotY - b.plotY;
  304. });
  305. },
  306. /**
  307. * Extend the pie data label method
  308. */
  309. drawDataLabels: function () {
  310. var series = this,
  311. data = series.data,
  312. labelDistance = series.options.dataLabels.distance,
  313. leftSide,
  314. sign,
  315. point,
  316. i = data.length,
  317. x,
  318. y;
  319. /**
  320. * In the original pie label anticollision logic, the slots are
  321. * distributed from one labelDistance above to one labelDistance
  322. * below the pie. In funnels we don't want this.
  323. */
  324. series.center[2] -= 2 * labelDistance;
  325. // Set the label position array for each point.
  326. while (i--) {
  327. point = data[i];
  328. leftSide = point.half;
  329. sign = leftSide ? 1 : -1;
  330. y = point.plotY;
  331. point.labelDistance = pick(
  332. point.options.dataLabels && point.options.dataLabels.distance,
  333. labelDistance
  334. );
  335. series.maxLabelDistance = Math.max(
  336. point.labelDistance,
  337. series.maxLabelDistance || 0
  338. );
  339. x = series.getX(y, leftSide, point);
  340. // set the anchor point for data labels
  341. point.labelPos = [
  342. // first break of connector
  343. 0,
  344. y,
  345. // second break, right outside point shape
  346. x + (point.labelDistance - 5) * sign,
  347. y,
  348. // landing point for connector
  349. x + point.labelDistance * sign,
  350. y,
  351. // alignment
  352. leftSide ? 'right' : 'left',
  353. // center angle
  354. 0
  355. ];
  356. }
  357. seriesTypes.pie.prototype.drawDataLabels.call(this);
  358. }
  359. });
  360. /**
  361. * A `funnel` series. If the [type](#series.funnel.type) option is
  362. * not specified, it is inherited from [chart.type](#chart.type).
  363. *
  364. * @type {Object}
  365. * @extends series,plotOptions.funnel
  366. * @excluding dataParser,dataURL,stack,xAxis,yAxis
  367. * @product highcharts
  368. * @apioption series.funnel
  369. */
  370. /**
  371. * An array of data points for the series. For the `funnel` series type,
  372. * points can be given in the following ways:
  373. *
  374. * 1. An array of numerical values. In this case, the numerical values
  375. * will be interpreted as `y` options. Example:
  376. *
  377. * ```js
  378. * data: [0, 5, 3, 5]
  379. * ```
  380. *
  381. * 2. An array of objects with named values. The objects are point
  382. * configuration objects as seen below. If the total number of data
  383. * points exceeds the series' [turboThreshold](#series.funnel.turboThreshold),
  384. * this option is not available.
  385. *
  386. * ```js
  387. * data: [{
  388. * y: 3,
  389. * name: "Point2",
  390. * color: "#00FF00"
  391. * }, {
  392. * y: 1,
  393. * name: "Point1",
  394. * color: "#FF00FF"
  395. * }]
  396. * ```
  397. *
  398. * @type {Array<Object|Number>}
  399. * @extends series.pie.data
  400. * @excluding sliced
  401. * @sample {highcharts} highcharts/chart/reflow-true/
  402. * Numerical values
  403. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  404. * Arrays of numeric x and y
  405. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  406. * Arrays of datetime x and y
  407. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  408. * Arrays of point.name and y
  409. * @sample {highcharts} highcharts/series/data-array-of-objects/
  410. * Config objects
  411. * @product highcharts
  412. * @apioption series.funnel.data
  413. */
  414. /**
  415. * Pyramid series type.
  416. */
  417. seriesType('pyramid', 'funnel',
  418. /**
  419. * A pyramid series is a special type of funnel, without neck and reversed by
  420. * default.
  421. *
  422. * @sample highcharts/demo/pyramid/
  423. * Pyramid chart
  424. * @extends plotOptions.funnel
  425. * @product highcharts
  426. * @optionparent plotOptions.pyramid
  427. */
  428. {
  429. /**
  430. * The pyramid neck width is zero by default, as opposed to the funnel,
  431. * which shares the same layout logic.
  432. *
  433. * @since 3.0.10
  434. * @product highcharts
  435. */
  436. neckWidth: '0%',
  437. /**
  438. * The pyramid neck width is zero by default, as opposed to the funnel,
  439. * which shares the same layout logic.
  440. *
  441. * @since 3.0.10
  442. * @product highcharts
  443. */
  444. neckHeight: '0%',
  445. /**
  446. * The pyramid is reversed by default, as opposed to the funnel, which
  447. * shares the layout engine, and is not reversed.
  448. *
  449. * @since 3.0.10
  450. * @product highcharts
  451. */
  452. reversed: true
  453. });
  454. /**
  455. * A `pyramid` series. If the [type](#series.pyramid.type) option is
  456. * not specified, it is inherited from [chart.type](#chart.type).
  457. *
  458. * @type {Object}
  459. * @extends series,plotOptions.pyramid
  460. * @excluding dataParser,dataURL,stack,xAxis,yAxis
  461. * @product highcharts
  462. * @apioption series.pyramid
  463. */
  464. /**
  465. * An array of data points for the series. For the `pyramid` series
  466. * type, points can be given in the following ways:
  467. *
  468. * 1. An array of numerical values. In this case, the numerical values
  469. * will be interpreted as `y` options. Example:
  470. *
  471. * ```js
  472. * data: [0, 5, 3, 5]
  473. * ```
  474. *
  475. * 2. An array of objects with named values. The objects are point
  476. * configuration objects as seen below. If the total number of data
  477. * points exceeds the series' [turboThreshold](#series.pyramid.turboThreshold),
  478. * this option is not available.
  479. *
  480. * ```js
  481. * data: [{
  482. * y: 9,
  483. * name: "Point2",
  484. * color: "#00FF00"
  485. * }, {
  486. * y: 6,
  487. * name: "Point1",
  488. * color: "#FF00FF"
  489. * }]
  490. * ```
  491. *
  492. * @type {Array<Object|Number>}
  493. * @extends series.pie.data
  494. * @excluding sliced
  495. * @sample {highcharts} highcharts/chart/reflow-true/
  496. * Numerical values
  497. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  498. * Arrays of numeric x and y
  499. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  500. * Arrays of datetime x and y
  501. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  502. * Arrays of point.name and y
  503. * @sample {highcharts} highcharts/series/data-array-of-objects/
  504. * Config objects
  505. * @product highcharts
  506. * @apioption series.pyramid.data
  507. */
  508. }(Highcharts));
  509. }));