funnel3d.src.js 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. /**
  2. * @license Highcharts JS v9.1.1 (2021-06-04)
  3. *
  4. * Highcharts funnel module
  5. *
  6. * (c) 2010-2021 Kacper Madej
  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/funnel3d', ['highcharts', 'highcharts/highcharts-3d', 'highcharts/modules/cylinder'], 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/Funnel3D/Funnel3DComposition.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Renderer/SVG/SVGRenderer3D.js'], _modules['Core/Utilities.js']], function (Color, H, SVGRenderer3D, U) {
  32. /* *
  33. *
  34. * Highcharts funnel3d series module
  35. *
  36. * (c) 2010-2021 Highsoft AS
  37. *
  38. * Author: Kacper Madej
  39. *
  40. * License: www.highcharts.com/license
  41. *
  42. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43. *
  44. * */
  45. var color = Color.parse;
  46. var charts = H.charts;
  47. var error = U.error,
  48. extend = U.extend,
  49. merge = U.merge;
  50. /* *
  51. *
  52. * Composition
  53. *
  54. * */
  55. var Funnel3DComposition;
  56. (function (Funnel3DComposition) {
  57. /* *
  58. *
  59. * Functions
  60. *
  61. * */
  62. /* eslint-disable require-jsdoc, valid-jsdoc */
  63. function compose(SVGRendererClass) {
  64. SVGRenderer3D.compose(SVGRendererClass);
  65. wrapElement3D(SVGRendererClass.prototype.elements3d);
  66. wrapRenderer3D(SVGRendererClass);
  67. }
  68. Funnel3DComposition.compose = compose;
  69. function wrapElement3D(elements3d) {
  70. elements3d.funnel3d = merge(elements3d.cuboid, {
  71. parts: [
  72. 'top', 'bottom',
  73. 'frontUpper', 'backUpper',
  74. 'frontLower', 'backLower',
  75. 'rightUpper', 'rightLower'
  76. ],
  77. mainParts: ['top', 'bottom'],
  78. sideGroups: [
  79. 'upperGroup', 'lowerGroup'
  80. ],
  81. sideParts: {
  82. upperGroup: ['frontUpper', 'backUpper', 'rightUpper'],
  83. lowerGroup: ['frontLower', 'backLower', 'rightLower']
  84. },
  85. pathType: 'funnel3d',
  86. // override opacity and color setters to control opacity
  87. opacitySetter: function (opacity) {
  88. var funnel3d = this,
  89. parts = funnel3d.parts,
  90. chart = H.charts[funnel3d.renderer.chartIndex],
  91. filterId = 'group-opacity-' + opacity + '-' + chart.index;
  92. // use default for top and bottom
  93. funnel3d.parts = funnel3d.mainParts;
  94. funnel3d.singleSetterForParts('opacity', opacity);
  95. // restore
  96. funnel3d.parts = parts;
  97. if (!chart.renderer.filterId) {
  98. chart.renderer.definition({
  99. tagName: 'filter',
  100. attributes: {
  101. id: filterId
  102. },
  103. children: [{
  104. tagName: 'feComponentTransfer',
  105. children: [{
  106. tagName: 'feFuncA',
  107. attributes: {
  108. type: 'table',
  109. tableValues: '0 ' + opacity
  110. }
  111. }]
  112. }]
  113. });
  114. funnel3d.sideGroups.forEach(function (groupName) {
  115. funnel3d[groupName].attr({
  116. filter: 'url(#' + filterId + ')'
  117. });
  118. });
  119. // styled mode
  120. if (funnel3d.renderer.styledMode) {
  121. chart.renderer.definition({
  122. tagName: 'style',
  123. textContent: '.highcharts-' + filterId +
  124. ' {filter:url(#' + filterId + ')}'
  125. });
  126. funnel3d.sideGroups.forEach(function (group) {
  127. group.addClass('highcharts-' + filterId);
  128. });
  129. }
  130. }
  131. return funnel3d;
  132. },
  133. fillSetter: function (fill) {
  134. // extract alpha channel to use the opacitySetter
  135. var funnel3d = this,
  136. fillColor = color(fill),
  137. alpha = fillColor.rgba[3],
  138. partsWithColor = {
  139. // standard color for top and bottom
  140. top: color(fill).brighten(0.1).get(),
  141. bottom: color(fill).brighten(-0.2).get()
  142. };
  143. if (alpha < 1) {
  144. fillColor.rgba[3] = 1;
  145. fillColor = fillColor.get('rgb');
  146. // set opacity through the opacitySetter
  147. funnel3d.attr({
  148. opacity: alpha
  149. });
  150. }
  151. else {
  152. // use default for full opacity
  153. fillColor = fill;
  154. }
  155. // add gradient for sides
  156. if (!fillColor.linearGradient &&
  157. !fillColor.radialGradient &&
  158. funnel3d.gradientForSides) {
  159. fillColor = {
  160. linearGradient: { x1: 0, x2: 1, y1: 1, y2: 1 },
  161. stops: [
  162. [0, color(fill).brighten(-0.2).get()],
  163. [0.5, fill],
  164. [1, color(fill).brighten(-0.2).get()]
  165. ]
  166. };
  167. }
  168. // gradient support
  169. if (fillColor.linearGradient) {
  170. // color in steps, as each gradient will generate a key
  171. funnel3d.sideGroups.forEach(function (sideGroupName) {
  172. var box = funnel3d[sideGroupName].gradientBox,
  173. gradient = fillColor.linearGradient,
  174. alteredGradient = merge(fillColor, {
  175. linearGradient: {
  176. x1: box.x + gradient.x1 * box.width,
  177. y1: box.y + gradient.y1 * box.height,
  178. x2: box.x + gradient.x2 * box.width,
  179. y2: box.y + gradient.y2 * box.height
  180. }
  181. });
  182. funnel3d.sideParts[sideGroupName].forEach(function (partName) {
  183. partsWithColor[partName] = alteredGradient;
  184. });
  185. });
  186. }
  187. else {
  188. merge(true, partsWithColor, {
  189. frontUpper: fillColor,
  190. backUpper: fillColor,
  191. rightUpper: fillColor,
  192. frontLower: fillColor,
  193. backLower: fillColor,
  194. rightLower: fillColor
  195. });
  196. if (fillColor.radialGradient) {
  197. funnel3d.sideGroups.forEach(function (sideGroupName) {
  198. var gradBox = funnel3d[sideGroupName].gradientBox,
  199. centerX = gradBox.x + gradBox.width / 2,
  200. centerY = gradBox.y + gradBox.height / 2,
  201. diameter = Math.min(gradBox.width,
  202. gradBox.height);
  203. funnel3d.sideParts[sideGroupName].forEach(function (partName) {
  204. funnel3d[partName].setRadialReference([
  205. centerX, centerY, diameter
  206. ]);
  207. });
  208. });
  209. }
  210. }
  211. funnel3d.singleSetterForParts('fill', null, partsWithColor);
  212. // fill for animation getter (#6776)
  213. funnel3d.color = funnel3d.fill = fill;
  214. // change gradientUnits to userSpaceOnUse for linearGradient
  215. if (fillColor.linearGradient) {
  216. [funnel3d.frontLower, funnel3d.frontUpper].forEach(function (part) {
  217. var elem = part.element,
  218. grad = elem && funnel3d.renderer.gradients[elem.gradient];
  219. if (grad && grad.attr('gradientUnits') !== 'userSpaceOnUse') {
  220. grad.attr({
  221. gradientUnits: 'userSpaceOnUse'
  222. });
  223. }
  224. });
  225. }
  226. return funnel3d;
  227. },
  228. adjustForGradient: function () {
  229. var funnel3d = this,
  230. bbox;
  231. funnel3d.sideGroups.forEach(function (sideGroupName) {
  232. // use common extremes for groups for matching gradients
  233. var topLeftEdge = {
  234. x: Number.MAX_VALUE,
  235. y: Number.MAX_VALUE
  236. },
  237. bottomRightEdge = {
  238. x: -Number.MAX_VALUE,
  239. y: -Number.MAX_VALUE
  240. };
  241. // get extremes
  242. funnel3d.sideParts[sideGroupName].forEach(function (partName) {
  243. var part = funnel3d[partName];
  244. bbox = part.getBBox(true);
  245. topLeftEdge = {
  246. x: Math.min(topLeftEdge.x, bbox.x),
  247. y: Math.min(topLeftEdge.y, bbox.y)
  248. };
  249. bottomRightEdge = {
  250. x: Math.max(bottomRightEdge.x, bbox.x + bbox.width),
  251. y: Math.max(bottomRightEdge.y, bbox.y + bbox.height)
  252. };
  253. });
  254. // store for color fillSetter
  255. funnel3d[sideGroupName].gradientBox = {
  256. x: topLeftEdge.x,
  257. width: bottomRightEdge.x - topLeftEdge.x,
  258. y: topLeftEdge.y,
  259. height: bottomRightEdge.y - topLeftEdge.y
  260. };
  261. });
  262. },
  263. zIndexSetter: function () {
  264. // this.added won't work, because zIndex is set after the prop
  265. // is set, but before the graphic is really added
  266. if (this.finishedOnAdd) {
  267. this.adjustForGradient();
  268. }
  269. // run default
  270. return this.renderer.Element.prototype.zIndexSetter.apply(this, arguments);
  271. },
  272. onAdd: function () {
  273. this.adjustForGradient();
  274. this.finishedOnAdd = true;
  275. }
  276. });
  277. }
  278. function wrapRenderer3D(SVGRendererClass) {
  279. var rendererProto = SVGRendererClass.prototype;
  280. extend(rendererProto, {
  281. funnel3d: function (shapeArgs) {
  282. var renderer = this,
  283. funnel3d = renderer.element3d('funnel3d',
  284. shapeArgs),
  285. styledMode = renderer.styledMode,
  286. // hide stroke for Firefox
  287. strokeAttrs = {
  288. 'stroke-width': 1,
  289. stroke: 'none'
  290. };
  291. // create groups for sides for oppacity setter
  292. funnel3d.upperGroup = renderer.g('funnel3d-upper-group').attr({
  293. zIndex: funnel3d.frontUpper.zIndex
  294. }).add(funnel3d);
  295. [
  296. funnel3d.frontUpper,
  297. funnel3d.backUpper,
  298. funnel3d.rightUpper
  299. ].forEach(function (upperElem) {
  300. if (!styledMode) {
  301. upperElem.attr(strokeAttrs);
  302. }
  303. upperElem.add(funnel3d.upperGroup);
  304. });
  305. funnel3d.lowerGroup = renderer.g('funnel3d-lower-group').attr({
  306. zIndex: funnel3d.frontLower.zIndex
  307. }).add(funnel3d);
  308. [
  309. funnel3d.frontLower,
  310. funnel3d.backLower,
  311. funnel3d.rightLower
  312. ].forEach(function (lowerElem) {
  313. if (!styledMode) {
  314. lowerElem.attr(strokeAttrs);
  315. }
  316. lowerElem.add(funnel3d.lowerGroup);
  317. });
  318. funnel3d.gradientForSides = shapeArgs.gradientForSides;
  319. return funnel3d;
  320. },
  321. /**
  322. * Generates paths and zIndexes.
  323. * @private
  324. */
  325. funnel3dPath: function (shapeArgs // @todo: Type it. It's an extended SVGAttributes.
  326. ) {
  327. // Check getCylinderEnd for better error message if
  328. // the cylinder module is missing
  329. if (!this.getCylinderEnd) {
  330. error('A required Highcharts module is missing: cylinder.js', true, charts[this.chartIndex]);
  331. }
  332. var renderer = this,
  333. chart = charts[renderer.chartIndex],
  334. // adjust angles for visible edges
  335. // based on alpha, selected through visual tests
  336. alphaCorrection = shapeArgs.alphaCorrection = 90 -
  337. Math.abs((chart.options.chart.options3d.alpha % 180) - 90),
  338. // set zIndexes of parts based on cubiod logic, for
  339. // consistency
  340. cuboidData = rendererProto.cuboidPath.call(renderer,
  341. merge(shapeArgs, {
  342. depth: shapeArgs.width,
  343. width: (shapeArgs.width + shapeArgs.bottom.width) / 2
  344. })),
  345. isTopFirst = cuboidData.isTop,
  346. isFrontFirst = !cuboidData.isFront,
  347. hasMiddle = !!shapeArgs.middle,
  348. //
  349. top = renderer.getCylinderEnd(chart,
  350. merge(shapeArgs, {
  351. x: shapeArgs.x - shapeArgs.width / 2,
  352. z: shapeArgs.z - shapeArgs.width / 2,
  353. alphaCorrection: alphaCorrection
  354. })),
  355. bottomWidth = shapeArgs.bottom.width,
  356. bottomArgs = merge(shapeArgs, {
  357. width: bottomWidth,
  358. x: shapeArgs.x - bottomWidth / 2,
  359. z: shapeArgs.z - bottomWidth / 2,
  360. alphaCorrection: alphaCorrection
  361. }),
  362. bottom = renderer.getCylinderEnd(chart,
  363. bottomArgs,
  364. true),
  365. //
  366. middleWidth = bottomWidth,
  367. middleTopArgs = bottomArgs,
  368. middleTop = bottom,
  369. middleBottom = bottom,
  370. ret,
  371. // masking for cylinders or a missing part of a side shape
  372. useAlphaCorrection;
  373. if (hasMiddle) {
  374. middleWidth = shapeArgs.middle.width;
  375. middleTopArgs = merge(shapeArgs, {
  376. y: shapeArgs.y + shapeArgs.middle.fraction * shapeArgs.height,
  377. width: middleWidth,
  378. x: shapeArgs.x - middleWidth / 2,
  379. z: shapeArgs.z - middleWidth / 2
  380. });
  381. middleTop = renderer.getCylinderEnd(chart, middleTopArgs, false);
  382. middleBottom = renderer.getCylinderEnd(chart, middleTopArgs, false);
  383. }
  384. ret = {
  385. top: top,
  386. bottom: bottom,
  387. frontUpper: renderer.getCylinderFront(top, middleTop),
  388. zIndexes: {
  389. group: cuboidData.zIndexes.group,
  390. top: isTopFirst !== 0 ? 0 : 3,
  391. bottom: isTopFirst !== 1 ? 0 : 3,
  392. frontUpper: isFrontFirst ? 2 : 1,
  393. backUpper: isFrontFirst ? 1 : 2,
  394. rightUpper: isFrontFirst ? 2 : 1
  395. }
  396. };
  397. ret.backUpper = renderer.getCylinderBack(top, middleTop);
  398. useAlphaCorrection = (Math.min(middleWidth, shapeArgs.width) /
  399. Math.max(middleWidth, shapeArgs.width)) !== 1;
  400. ret.rightUpper = renderer.getCylinderFront(renderer.getCylinderEnd(chart, merge(shapeArgs, {
  401. x: shapeArgs.x - shapeArgs.width / 2,
  402. z: shapeArgs.z - shapeArgs.width / 2,
  403. alphaCorrection: useAlphaCorrection ? -alphaCorrection : 0
  404. }), false), renderer.getCylinderEnd(chart, merge(middleTopArgs, {
  405. alphaCorrection: useAlphaCorrection ? -alphaCorrection : 0
  406. }), !hasMiddle));
  407. if (hasMiddle) {
  408. useAlphaCorrection = (Math.min(middleWidth, bottomWidth) /
  409. Math.max(middleWidth, bottomWidth)) !== 1;
  410. merge(true, ret, {
  411. frontLower: renderer.getCylinderFront(middleBottom, bottom),
  412. backLower: renderer.getCylinderBack(middleBottom, bottom),
  413. rightLower: renderer.getCylinderFront(renderer.getCylinderEnd(chart, merge(bottomArgs, {
  414. alphaCorrection: useAlphaCorrection ?
  415. -alphaCorrection : 0
  416. }), true), renderer.getCylinderEnd(chart, merge(middleTopArgs, {
  417. alphaCorrection: useAlphaCorrection ?
  418. -alphaCorrection : 0
  419. }), false)),
  420. zIndexes: {
  421. frontLower: isFrontFirst ? 2 : 1,
  422. backLower: isFrontFirst ? 1 : 2,
  423. rightLower: isFrontFirst ? 1 : 2
  424. }
  425. });
  426. }
  427. return ret;
  428. }
  429. });
  430. }
  431. })(Funnel3DComposition || (Funnel3DComposition = {}));
  432. /* *
  433. *
  434. * Default Export
  435. *
  436. * */
  437. return Funnel3DComposition;
  438. });
  439. _registerModule(_modules, 'Series/Funnel3D/Funnel3DPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  440. /* *
  441. *
  442. * Highcharts funnel3d series module
  443. *
  444. * (c) 2010-2021 Highsoft AS
  445. *
  446. * Author: Kacper Madej
  447. *
  448. * License: www.highcharts.com/license
  449. *
  450. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  451. *
  452. * */
  453. var __extends = (this && this.__extends) || (function () {
  454. var extendStatics = function (d,
  455. b) {
  456. extendStatics = Object.setPrototypeOf ||
  457. ({ __proto__: [] } instanceof Array && function (d,
  458. b) { d.__proto__ = b; }) ||
  459. function (d,
  460. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  461. return extendStatics(d, b);
  462. };
  463. return function (d, b) {
  464. extendStatics(d, b);
  465. function __() { this.constructor = d; }
  466. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  467. };
  468. })();
  469. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  470. var extend = U.extend;
  471. /* *
  472. *
  473. * Class
  474. *
  475. * */
  476. var Funnel3DPoint = /** @class */ (function (_super) {
  477. __extends(Funnel3DPoint, _super);
  478. function Funnel3DPoint() {
  479. /* *
  480. *
  481. * Properties
  482. *
  483. * */
  484. var _this = _super !== null && _super.apply(this,
  485. arguments) || this;
  486. _this.dlBoxRaw = void 0;
  487. _this.options = void 0;
  488. _this.series = void 0;
  489. _this.y = void 0;
  490. return _this;
  491. }
  492. return Funnel3DPoint;
  493. }(ColumnSeries.prototype.pointClass));
  494. extend(Funnel3DPoint.prototype, {
  495. shapeType: 'funnel3d'
  496. });
  497. /* *
  498. *
  499. * Default Export
  500. *
  501. * */
  502. return Funnel3DPoint;
  503. });
  504. _registerModule(_modules, 'Series/Funnel3D/Funnel3DSeries.js', [_modules['Series/Funnel3D/Funnel3DComposition.js'], _modules['Series/Funnel3D/Funnel3DPoint.js'], _modules['Core/Globals.js'], _modules['Extensions/Math3D.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Funnel3DComposition, Funnel3DPoint, H, Math3D, SeriesRegistry, U) {
  505. /* *
  506. *
  507. * Highcharts funnel3d series module
  508. *
  509. * (c) 2010-2021 Highsoft AS
  510. *
  511. * Author: Kacper Madej
  512. *
  513. * License: www.highcharts.com/license
  514. *
  515. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  516. *
  517. * */
  518. var __extends = (this && this.__extends) || (function () {
  519. var extendStatics = function (d,
  520. b) {
  521. extendStatics = Object.setPrototypeOf ||
  522. ({ __proto__: [] } instanceof Array && function (d,
  523. b) { d.__proto__ = b; }) ||
  524. function (d,
  525. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  526. return extendStatics(d, b);
  527. };
  528. return function (d, b) {
  529. extendStatics(d, b);
  530. function __() { this.constructor = d; }
  531. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  532. };
  533. })();
  534. var noop = H.noop;
  535. var perspective = Math3D.perspective;
  536. var Series = SeriesRegistry.series,
  537. ColumnSeries = SeriesRegistry.seriesTypes.column;
  538. var extend = U.extend,
  539. merge = U.merge,
  540. pick = U.pick,
  541. relativeLength = U.relativeLength;
  542. /* *
  543. *
  544. * Class
  545. *
  546. * */
  547. /**
  548. * The funnel3d series type.
  549. *
  550. * @constructor seriesTypes.funnel3d
  551. * @augments seriesTypes.column
  552. * @requires highcharts-3d
  553. * @requires modules/cylinder
  554. * @requires modules/funnel3d
  555. */
  556. var Funnel3DSeries = /** @class */ (function (_super) {
  557. __extends(Funnel3DSeries, _super);
  558. function Funnel3DSeries() {
  559. /* *
  560. *
  561. * Static Properties
  562. *
  563. * */
  564. var _this = _super !== null && _super.apply(this,
  565. arguments) || this;
  566. /* *
  567. *
  568. * Properties
  569. *
  570. * */
  571. _this.center = void 0;
  572. _this.data = void 0;
  573. _this.options = void 0;
  574. _this.points = void 0;
  575. return _this;
  576. /* eslint-enable valid-jsdoc */
  577. }
  578. /* *
  579. *
  580. * Functions
  581. *
  582. * */
  583. /* eslint-disable valid-jsdoc */
  584. /**
  585. * @private
  586. */
  587. Funnel3DSeries.prototype.alignDataLabel = function (point, _dataLabel, options) {
  588. var series = this,
  589. dlBoxRaw = point.dlBoxRaw,
  590. inverted = series.chart.inverted,
  591. below = point.plotY > pick(series.translatedThreshold,
  592. series.yAxis.len),
  593. inside = pick(options.inside, !!series.options.stacking),
  594. dlBox = {
  595. x: dlBoxRaw.x,
  596. y: dlBoxRaw.y,
  597. height: 0
  598. };
  599. options.align = pick(options.align, !inverted || inside ? 'center' : below ? 'right' : 'left');
  600. options.verticalAlign = pick(options.verticalAlign, inverted || inside ? 'middle' : below ? 'top' : 'bottom');
  601. if (options.verticalAlign !== 'top') {
  602. dlBox.y += dlBoxRaw.bottom /
  603. (options.verticalAlign === 'bottom' ? 1 : 2);
  604. }
  605. dlBox.width = series.getWidthAt(dlBox.y);
  606. if (series.options.reversed) {
  607. dlBox.width = dlBoxRaw.fullWidth - dlBox.width;
  608. }
  609. if (inside) {
  610. dlBox.x -= dlBox.width / 2;
  611. }
  612. else {
  613. // swap for inside
  614. if (options.align === 'left') {
  615. options.align = 'right';
  616. dlBox.x -= dlBox.width * 1.5;
  617. }
  618. else if (options.align === 'right') {
  619. options.align = 'left';
  620. dlBox.x += dlBox.width / 2;
  621. }
  622. else {
  623. dlBox.x -= dlBox.width / 2;
  624. }
  625. }
  626. point.dlBox = dlBox;
  627. ColumnSeries.prototype.alignDataLabel.apply(series, arguments);
  628. };
  629. /**
  630. * Override default axis options with series required options for axes.
  631. * @private
  632. */
  633. Funnel3DSeries.prototype.bindAxes = function () {
  634. Series.prototype.bindAxes.apply(this, arguments);
  635. extend(this.xAxis.options, {
  636. gridLineWidth: 0,
  637. lineWidth: 0,
  638. title: void 0,
  639. tickPositions: []
  640. });
  641. merge(true, this.yAxis.options, {
  642. gridLineWidth: 0,
  643. title: void 0,
  644. labels: {
  645. enabled: false
  646. }
  647. });
  648. };
  649. /**
  650. * @private
  651. */
  652. Funnel3DSeries.prototype.translate = function () {
  653. Series.prototype.translate.apply(this, arguments);
  654. var sum = 0,
  655. series = this,
  656. chart = series.chart,
  657. options = series.options,
  658. reversed = options.reversed,
  659. ignoreHiddenPoint = options.ignoreHiddenPoint,
  660. plotWidth = chart.plotWidth,
  661. plotHeight = chart.plotHeight,
  662. cumulative = 0, // start at top
  663. center = options.center,
  664. centerX = relativeLength(center[0],
  665. plotWidth),
  666. centerY = relativeLength(center[1],
  667. plotHeight),
  668. width = relativeLength(options.width,
  669. plotWidth),
  670. tempWidth,
  671. getWidthAt,
  672. height = relativeLength(options.height,
  673. plotHeight),
  674. neckWidth = relativeLength(options.neckWidth,
  675. plotWidth),
  676. neckHeight = relativeLength(options.neckHeight,
  677. plotHeight),
  678. neckY = (centerY - height / 2) + height - neckHeight,
  679. data = series.data,
  680. fraction,
  681. tooltipPos,
  682. //
  683. y1,
  684. y3,
  685. y5,
  686. //
  687. h,
  688. shapeArgs; // @todo: Type it. It's an extended SVGAttributes.
  689. // Return the width at a specific y coordinate
  690. series.getWidthAt = getWidthAt = function (y) {
  691. var top = (centerY - height / 2);
  692. return (y > neckY || height === neckHeight) ?
  693. neckWidth :
  694. neckWidth + (width - neckWidth) *
  695. (1 - (y - top) / (height - neckHeight));
  696. };
  697. // Expose
  698. series.center = [centerX, centerY, height];
  699. series.centerX = centerX;
  700. /*
  701. * Individual point coordinate naming:
  702. *
  703. * _________centerX,y1________
  704. * \ /
  705. * \ /
  706. * \ /
  707. * \ /
  708. * \ /
  709. * ___centerX,y3___
  710. *
  711. * Additional for the base of the neck:
  712. *
  713. * | |
  714. * | |
  715. * | |
  716. * ___centerX,y5___
  717. */
  718. // get the total sum
  719. data.forEach(function (point) {
  720. if (!ignoreHiddenPoint || point.visible !== false) {
  721. sum += point.y;
  722. }
  723. });
  724. data.forEach(function (point) {
  725. // set start and end positions
  726. y5 = null;
  727. fraction = sum ? point.y / sum : 0;
  728. y1 = centerY - height / 2 + cumulative * height;
  729. y3 = y1 + fraction * height;
  730. tempWidth = getWidthAt(y1);
  731. h = y3 - y1;
  732. shapeArgs = {
  733. // for fill setter
  734. gradientForSides: pick(point.options.gradientForSides, options.gradientForSides),
  735. x: centerX,
  736. y: y1,
  737. height: h,
  738. width: tempWidth,
  739. z: 1,
  740. top: {
  741. width: tempWidth
  742. }
  743. };
  744. tempWidth = getWidthAt(y3);
  745. shapeArgs.bottom = {
  746. fraction: fraction,
  747. width: tempWidth
  748. };
  749. // the entire point is within the neck
  750. if (y1 >= neckY) {
  751. shapeArgs.isCylinder = true;
  752. }
  753. else if (y3 > neckY) {
  754. // the base of the neck
  755. y5 = y3;
  756. tempWidth = getWidthAt(neckY);
  757. y3 = neckY;
  758. shapeArgs.bottom.width = tempWidth;
  759. shapeArgs.middle = {
  760. fraction: h ? (neckY - y1) / h : 0,
  761. width: tempWidth
  762. };
  763. }
  764. if (reversed) {
  765. shapeArgs.y = y1 = centerY + height / 2 -
  766. (cumulative + fraction) * height;
  767. if (shapeArgs.middle) {
  768. shapeArgs.middle.fraction = 1 -
  769. (h ? shapeArgs.middle.fraction : 0);
  770. }
  771. tempWidth = shapeArgs.width;
  772. shapeArgs.width = shapeArgs.bottom.width;
  773. shapeArgs.bottom.width = tempWidth;
  774. }
  775. point.shapeArgs = extend(point.shapeArgs, shapeArgs);
  776. // for tooltips and data labels context
  777. point.percentage = fraction * 100;
  778. point.plotX = centerX;
  779. if (reversed) {
  780. point.plotY = centerY + height / 2 -
  781. (cumulative + fraction / 2) * height;
  782. }
  783. else {
  784. point.plotY = (y1 + (y5 || y3)) / 2;
  785. }
  786. // Placement of tooltips and data labels in 3D
  787. tooltipPos = perspective([{
  788. x: centerX,
  789. y: point.plotY,
  790. z: reversed ?
  791. -(width - getWidthAt(point.plotY)) / 2 :
  792. -(getWidthAt(point.plotY)) / 2
  793. }], chart, true)[0];
  794. point.tooltipPos = [tooltipPos.x, tooltipPos.y];
  795. // base to be used when alignment options are known
  796. point.dlBoxRaw = {
  797. x: centerX,
  798. width: getWidthAt(point.plotY),
  799. y: y1,
  800. bottom: shapeArgs.height || 0,
  801. fullWidth: width
  802. };
  803. if (!ignoreHiddenPoint || point.visible !== false) {
  804. cumulative += fraction;
  805. }
  806. });
  807. };
  808. Funnel3DSeries.compose = Funnel3DComposition.compose;
  809. /**
  810. * A funnel3d is a 3d version of funnel series type. Funnel charts are
  811. * a type of chart often used to visualize stages in a sales project,
  812. * where the top are the initial stages with the most clients.
  813. *
  814. * It requires that the `highcharts-3d.js`, `cylinder.js` and
  815. * `funnel3d.js` module are loaded.
  816. *
  817. * @sample highcharts/demo/funnel3d/
  818. * Funnel3d
  819. *
  820. * @extends plotOptions.column
  821. * @excluding allAreas, boostThreshold, colorAxis, compare, compareBase,
  822. * dataSorting, boostBlending
  823. * @product highcharts
  824. * @since 7.1.0
  825. * @requires highcharts-3d
  826. * @requires modules/cylinder
  827. * @requires modules/funnel3d
  828. * @optionparent plotOptions.funnel3d
  829. */
  830. Funnel3DSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  831. /** @ignore-option */
  832. center: ['50%', '50%'],
  833. /**
  834. * The max width of the series compared to the width of the plot area,
  835. * or the pixel width if it is a number.
  836. *
  837. * @type {number|string}
  838. * @sample {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
  839. * @product highcharts
  840. */
  841. width: '90%',
  842. /**
  843. * The width of the neck, the lower part of the funnel. A number defines
  844. * pixel width, a percentage string defines a percentage of the plot
  845. * area width.
  846. *
  847. * @type {number|string}
  848. * @sample {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
  849. * @product highcharts
  850. */
  851. neckWidth: '30%',
  852. /**
  853. * The height of the series. If it is a number it defines
  854. * the pixel height, if it is a percentage string it is the percentage
  855. * of the plot area height.
  856. *
  857. * @type {number|string}
  858. * @sample {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
  859. * @product highcharts
  860. */
  861. height: '100%',
  862. /**
  863. * The height of the neck, the lower part of the funnel. A number
  864. * defines pixel width, a percentage string defines a percentage
  865. * of the plot area height.
  866. *
  867. * @type {number|string}
  868. * @sample {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
  869. * @product highcharts
  870. */
  871. neckHeight: '25%',
  872. /**
  873. * A reversed funnel has the widest area down. A reversed funnel with
  874. * no neck width and neck height is a pyramid.
  875. *
  876. * @product highcharts
  877. */
  878. reversed: false,
  879. /**
  880. * By deafult sides fill is set to a gradient through this option being
  881. * set to `true`. Set to `false` to get solid color for the sides.
  882. *
  883. * @product highcharts
  884. */
  885. gradientForSides: true,
  886. animation: false,
  887. edgeWidth: 0,
  888. colorByPoint: true,
  889. showInLegend: false,
  890. dataLabels: {
  891. align: 'right',
  892. crop: false,
  893. inside: false,
  894. overflow: 'allow'
  895. }
  896. });
  897. return Funnel3DSeries;
  898. }(ColumnSeries));
  899. extend(Funnel3DSeries.prototype, {
  900. pointClass: Funnel3DPoint,
  901. translate3dShapes: noop
  902. });
  903. SeriesRegistry.registerSeriesType('funnel3d', Funnel3DSeries);
  904. /* *
  905. *
  906. * Default Export
  907. *
  908. * */
  909. /* *
  910. *
  911. * API Options
  912. *
  913. * */
  914. /**
  915. * A `funnel3d` series. If the [type](#series.funnel3d.type) option is
  916. * not specified, it is inherited from [chart.type](#chart.type).
  917. *
  918. * @sample {highcharts} highcharts/demo/funnel3d/
  919. * Funnel3d demo
  920. *
  921. * @since 7.1.0
  922. * @extends series.funnel,plotOptions.funnel3d
  923. * @excluding allAreas,boostThreshold,colorAxis,compare,compareBase
  924. * @product highcharts
  925. * @requires highcharts-3d
  926. * @requires modules/cylinder
  927. * @requires modules/funnel3d
  928. * @apioption series.funnel3d
  929. */
  930. /**
  931. * An array of data points for the series. For the `funnel3d` series
  932. * type, points can be given in the following ways:
  933. *
  934. * 1. An array of numerical values. In this case, the numerical values
  935. * will be interpreted as `y` options. The `x` values will be automatically
  936. * calculated, either starting at 0 and incremented by 1, or from `pointStart`
  937. * and `pointInterval` given in the series options. If the axis has
  938. * categories, these will be used. Example:
  939. *
  940. * ```js
  941. * data: [0, 5, 3, 5]
  942. * ```
  943. *
  944. * 2. An array of objects with named values. The following snippet shows only a
  945. * few settings, see the complete options set below. If the total number of data
  946. * points exceeds the series' [turboThreshold](#series.funnel3d.turboThreshold),
  947. * this option is not available.
  948. *
  949. * ```js
  950. * data: [{
  951. * y: 2,
  952. * name: "Point2",
  953. * color: "#00FF00"
  954. * }, {
  955. * y: 4,
  956. * name: "Point1",
  957. * color: "#FF00FF"
  958. * }]
  959. * ```
  960. *
  961. * @sample {highcharts} highcharts/chart/reflow-true/
  962. * Numerical values
  963. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  964. * Arrays of numeric x and y
  965. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  966. * Arrays of datetime x and y
  967. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  968. * Arrays of point.name and y
  969. * @sample {highcharts} highcharts/series/data-array-of-objects/
  970. * Config objects
  971. *
  972. * @type {Array<number|Array<number>|*>}
  973. * @extends series.column.data
  974. * @product highcharts
  975. * @apioption series.funnel3d.data
  976. */
  977. /**
  978. * By deafult sides fill is set to a gradient through this option being
  979. * set to `true`. Set to `false` to get solid color for the sides.
  980. *
  981. * @type {boolean}
  982. * @product highcharts
  983. * @apioption series.funnel3d.data.gradientForSides
  984. */
  985. ''; // keeps doclets above in transpiled file
  986. return Funnel3DSeries;
  987. });
  988. _registerModule(_modules, 'masters/modules/funnel3d.src.js', [_modules['Core/Renderer/RendererRegistry.js'], _modules['Series/Funnel3D/Funnel3DSeries.js']], function (RendererRegistry, Funnel3DSeries) {
  989. Funnel3DSeries.compose(RendererRegistry.getRendererType());
  990. return Funnel3DSeries;
  991. });
  992. }));