GaugeSeries.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /* *
  2. *
  3. * (c) 2010-2020 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. import H from '../Core/Globals.js';
  12. import U from '../Core/Utilities.js';
  13. var clamp = U.clamp, isNumber = U.isNumber, merge = U.merge, pick = U.pick, pInt = U.pInt, seriesType = U.seriesType;
  14. import '../Core/Options.js';
  15. import '../Core/Series/Point.js';
  16. import '../Core/Series/Series.js';
  17. import '../Core/Interaction.js';
  18. var noop = H.noop, Series = H.Series, TrackerMixin = H.TrackerMixin;
  19. /**
  20. * Gauges are circular plots displaying one or more values with a dial pointing
  21. * to values along the perimeter.
  22. *
  23. * @sample highcharts/demo/gauge-speedometer/
  24. * Gauge chart
  25. *
  26. * @extends plotOptions.line
  27. * @excluding animationLimit, boostThreshold, colorAxis, colorKey,
  28. * connectEnds, connectNulls, cropThreshold, dashStyle, dragDrop,
  29. * findNearestPointBy, getExtremesFromAll, marker, negativeColor,
  30. * pointPlacement, shadow, softThreshold, stacking, states, step,
  31. * threshold, turboThreshold, xAxis, zoneAxis, zones, dataSorting,
  32. * boostBlending
  33. * @product highcharts
  34. * @requires highcharts-more
  35. * @optionparent plotOptions.gauge
  36. */
  37. seriesType('gauge', 'line', {
  38. /**
  39. * When this option is `true`, the dial will wrap around the axes. For
  40. * instance, in a full-range gauge going from 0 to 360, a value of 400
  41. * will point to 40\. When `wrap` is `false`, the dial stops at 360.
  42. *
  43. * @see [overshoot](#plotOptions.gauge.overshoot)
  44. *
  45. * @type {boolean}
  46. * @default true
  47. * @since 3.0
  48. * @product highcharts
  49. * @apioption plotOptions.gauge.wrap
  50. */
  51. /**
  52. * Data labels for the gauge. For gauges, the data labels are enabled
  53. * by default and shown in a bordered box below the point.
  54. *
  55. * @since 2.3.0
  56. * @product highcharts
  57. */
  58. dataLabels: {
  59. borderColor: '#cccccc',
  60. borderRadius: 3,
  61. borderWidth: 1,
  62. crop: false,
  63. defer: false,
  64. enabled: true,
  65. verticalAlign: 'top',
  66. y: 15,
  67. zIndex: 2
  68. },
  69. /**
  70. * Options for the dial or arrow pointer of the gauge.
  71. *
  72. * In styled mode, the dial is styled with the
  73. * `.highcharts-gauge-series .highcharts-dial` rule.
  74. *
  75. * @sample {highcharts} highcharts/css/gauge/
  76. * Styled mode
  77. *
  78. * @type {*}
  79. * @since 2.3.0
  80. * @product highcharts
  81. */
  82. dial: {},
  83. /**
  84. * The length of the dial's base part, relative to the total radius
  85. * or length of the dial.
  86. *
  87. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  88. * Dial options demonstrated
  89. *
  90. * @type {string}
  91. * @default 70%
  92. * @since 2.3.0
  93. * @product highcharts
  94. * @apioption plotOptions.gauge.dial.baseLength
  95. */
  96. /**
  97. * The pixel width of the base of the gauge dial. The base is the part
  98. * closest to the pivot, defined by baseLength.
  99. *
  100. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  101. * Dial options demonstrated
  102. *
  103. * @type {number}
  104. * @default 3
  105. * @since 2.3.0
  106. * @product highcharts
  107. * @apioption plotOptions.gauge.dial.baseWidth
  108. */
  109. /**
  110. * The radius or length of the dial, in percentages relative to the
  111. * radius of the gauge itself.
  112. *
  113. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  114. * Dial options demonstrated
  115. *
  116. * @type {string}
  117. * @default 80%
  118. * @since 2.3.0
  119. * @product highcharts
  120. * @apioption plotOptions.gauge.dial.radius
  121. */
  122. /**
  123. * The length of the dial's rear end, the part that extends out on the
  124. * other side of the pivot. Relative to the dial's length.
  125. *
  126. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  127. * Dial options demonstrated
  128. *
  129. * @type {string}
  130. * @default 10%
  131. * @since 2.3.0
  132. * @product highcharts
  133. * @apioption plotOptions.gauge.dial.rearLength
  134. */
  135. /**
  136. * The width of the top of the dial, closest to the perimeter. The pivot
  137. * narrows in from the base to the top.
  138. *
  139. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  140. * Dial options demonstrated
  141. *
  142. * @type {number}
  143. * @default 1
  144. * @since 2.3.0
  145. * @product highcharts
  146. * @apioption plotOptions.gauge.dial.topWidth
  147. */
  148. /**
  149. * The background or fill color of the gauge's dial.
  150. *
  151. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  152. * Dial options demonstrated
  153. *
  154. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  155. * @default #000000
  156. * @since 2.3.0
  157. * @product highcharts
  158. * @apioption plotOptions.gauge.dial.backgroundColor
  159. */
  160. /**
  161. * The border color or stroke of the gauge's dial. By default, the
  162. * borderWidth is 0, so this must be set in addition to a custom border
  163. * color.
  164. *
  165. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  166. * Dial options demonstrated
  167. *
  168. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  169. * @default #cccccc
  170. * @since 2.3.0
  171. * @product highcharts
  172. * @apioption plotOptions.gauge.dial.borderColor
  173. */
  174. /**
  175. * The width of the gauge dial border in pixels.
  176. *
  177. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  178. * Dial options demonstrated
  179. *
  180. * @type {number}
  181. * @default 0
  182. * @since 2.3.0
  183. * @product highcharts
  184. * @apioption plotOptions.gauge.dial.borderWidth
  185. */
  186. /**
  187. * Allow the dial to overshoot the end of the perimeter axis by this
  188. * many degrees. Say if the gauge axis goes from 0 to 60, a value of
  189. * 100, or 1000, will show 5 degrees beyond the end of the axis when this
  190. * option is set to 5.
  191. *
  192. * @see [wrap](#plotOptions.gauge.wrap)
  193. *
  194. * @sample {highcharts} highcharts/plotoptions/gauge-overshoot/
  195. * Allow 5 degrees overshoot
  196. *
  197. * @type {number}
  198. * @since 3.0.10
  199. * @product highcharts
  200. * @apioption plotOptions.gauge.overshoot
  201. */
  202. /**
  203. * Options for the pivot or the center point of the gauge.
  204. *
  205. * In styled mode, the pivot is styled with the
  206. * `.highcharts-gauge-series .highcharts-pivot` rule.
  207. *
  208. * @sample {highcharts} highcharts/css/gauge/
  209. * Styled mode
  210. *
  211. * @type {*}
  212. * @since 2.3.0
  213. * @product highcharts
  214. */
  215. pivot: {},
  216. /**
  217. * The pixel radius of the pivot.
  218. *
  219. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  220. * Pivot options demonstrated
  221. *
  222. * @type {number}
  223. * @default 5
  224. * @since 2.3.0
  225. * @product highcharts
  226. * @apioption plotOptions.gauge.pivot.radius
  227. */
  228. /**
  229. * The border or stroke width of the pivot.
  230. *
  231. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  232. * Pivot options demonstrated
  233. *
  234. * @type {number}
  235. * @default 0
  236. * @since 2.3.0
  237. * @product highcharts
  238. * @apioption plotOptions.gauge.pivot.borderWidth
  239. */
  240. /**
  241. * The border or stroke color of the pivot. In able to change this,
  242. * the borderWidth must also be set to something other than the default
  243. * 0.
  244. *
  245. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  246. * Pivot options demonstrated
  247. *
  248. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  249. * @default #cccccc
  250. * @since 2.3.0
  251. * @product highcharts
  252. * @apioption plotOptions.gauge.pivot.borderColor
  253. */
  254. /**
  255. * The background color or fill of the pivot.
  256. *
  257. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  258. * Pivot options demonstrated
  259. *
  260. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  261. * @default #000000
  262. * @since 2.3.0
  263. * @product highcharts
  264. * @apioption plotOptions.gauge.pivot.backgroundColor
  265. */
  266. tooltip: {
  267. headerFormat: ''
  268. },
  269. /**
  270. * Whether to display this particular series or series type in the
  271. * legend. Defaults to false for gauge series.
  272. *
  273. * @since 2.3.0
  274. * @product highcharts
  275. */
  276. showInLegend: false
  277. // Prototype members
  278. }, {
  279. // chart.angular will be set to true when a gauge series is present,
  280. // and this will be used on the axes
  281. angular: true,
  282. directTouch: true,
  283. drawGraph: noop,
  284. fixedBox: true,
  285. forceDL: true,
  286. noSharedTooltip: true,
  287. trackerGroups: ['group', 'dataLabelsGroup'],
  288. /* eslint-disable valid-jsdoc */
  289. /**
  290. * Calculate paths etc
  291. * @private
  292. */
  293. translate: function () {
  294. var series = this, yAxis = series.yAxis, options = series.options, center = yAxis.center;
  295. series.generatePoints();
  296. series.points.forEach(function (point) {
  297. var dialOptions = merge(options.dial, point.dial), radius = ((pInt(pick(dialOptions.radius, '80%')) * center[2]) /
  298. 200), baseLength = ((pInt(pick(dialOptions.baseLength, '70%')) * radius) /
  299. 100), rearLength = ((pInt(pick(dialOptions.rearLength, '10%')) * radius) /
  300. 100), baseWidth = dialOptions.baseWidth || 3, topWidth = dialOptions.topWidth || 1, overshoot = options.overshoot, rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
  301. // Handle the wrap and overshoot options
  302. if (isNumber(overshoot) || options.wrap === false) {
  303. overshoot = isNumber(overshoot) ?
  304. (overshoot / 180 * Math.PI) : 0;
  305. rotation = clamp(rotation, yAxis.startAngleRad - overshoot, yAxis.endAngleRad + overshoot);
  306. }
  307. rotation = rotation * 180 / Math.PI;
  308. point.shapeType = 'path';
  309. var d = dialOptions.path || [
  310. ['M', -rearLength, -baseWidth / 2],
  311. ['L', baseLength, -baseWidth / 2],
  312. ['L', radius, -topWidth / 2],
  313. ['L', radius, topWidth / 2],
  314. ['L', baseLength, baseWidth / 2],
  315. ['L', -rearLength, baseWidth / 2],
  316. ['Z']
  317. ];
  318. point.shapeArgs = {
  319. d: d,
  320. translateX: center[0],
  321. translateY: center[1],
  322. rotation: rotation
  323. };
  324. // Positions for data label
  325. point.plotX = center[0];
  326. point.plotY = center[1];
  327. });
  328. },
  329. /**
  330. * Draw the points where each point is one needle
  331. * @private
  332. */
  333. drawPoints: function () {
  334. var series = this, chart = series.chart, center = series.yAxis.center, pivot = series.pivot, options = series.options, pivotOptions = options.pivot, renderer = chart.renderer;
  335. series.points.forEach(function (point) {
  336. var graphic = point.graphic, shapeArgs = point.shapeArgs, d = shapeArgs.d, dialOptions = merge(options.dial, point.dial); // #1233
  337. if (graphic) {
  338. graphic.animate(shapeArgs);
  339. shapeArgs.d = d; // animate alters it
  340. }
  341. else {
  342. point.graphic =
  343. renderer[point.shapeType](shapeArgs)
  344. .attr({
  345. // required by VML when animation is false
  346. rotation: shapeArgs.rotation,
  347. zIndex: 1
  348. })
  349. .addClass('highcharts-dial')
  350. .add(series.group);
  351. }
  352. // Presentational attributes
  353. if (!chart.styledMode) {
  354. point.graphic[graphic ? 'animate' : 'attr']({
  355. stroke: dialOptions.borderColor || 'none',
  356. 'stroke-width': dialOptions.borderWidth || 0,
  357. fill: dialOptions.backgroundColor ||
  358. '#000000'
  359. });
  360. }
  361. });
  362. // Add or move the pivot
  363. if (pivot) {
  364. pivot.animate({
  365. translateX: center[0],
  366. translateY: center[1]
  367. });
  368. }
  369. else {
  370. series.pivot =
  371. renderer.circle(0, 0, pick(pivotOptions.radius, 5))
  372. .attr({
  373. zIndex: 2
  374. })
  375. .addClass('highcharts-pivot')
  376. .translate(center[0], center[1])
  377. .add(series.group);
  378. // Presentational attributes
  379. if (!chart.styledMode) {
  380. series.pivot.attr({
  381. 'stroke-width': pivotOptions.borderWidth || 0,
  382. stroke: pivotOptions.borderColor ||
  383. '#cccccc',
  384. fill: pivotOptions.backgroundColor ||
  385. '#000000'
  386. });
  387. }
  388. }
  389. },
  390. /**
  391. * Animate the arrow up from startAngle
  392. * @private
  393. */
  394. animate: function (init) {
  395. var series = this;
  396. if (!init) {
  397. series.points.forEach(function (point) {
  398. var graphic = point.graphic;
  399. if (graphic) {
  400. // start value
  401. graphic.attr({
  402. rotation: series.yAxis.startAngleRad * 180 / Math.PI
  403. });
  404. // animate
  405. graphic.animate({
  406. rotation: point.shapeArgs.rotation
  407. }, series.options.animation);
  408. }
  409. });
  410. }
  411. },
  412. /**
  413. * @private
  414. */
  415. render: function () {
  416. this.group = this.plotGroup('group', 'series', this.visible ? 'visible' : 'hidden', this.options.zIndex, this.chart.seriesGroup);
  417. Series.prototype.render.call(this);
  418. this.group.clip(this.chart.clipRect);
  419. },
  420. /**
  421. * Extend the basic setData method by running processData and generatePoints
  422. * immediately, in order to access the points from the legend.
  423. * @private
  424. */
  425. setData: function (data, redraw) {
  426. Series.prototype.setData.call(this, data, false);
  427. this.processData();
  428. this.generatePoints();
  429. if (pick(redraw, true)) {
  430. this.chart.redraw();
  431. }
  432. },
  433. /**
  434. * Define hasData function for non-cartesian series.
  435. * Returns true if the series has points at all.
  436. * @private
  437. */
  438. hasData: function () {
  439. return !!this.points.length; // != 0
  440. },
  441. // If the tracking module is loaded, add the point tracker
  442. drawTracker: TrackerMixin && TrackerMixin.drawTrackerPoint
  443. /* eslint-enable valid-jsdoc */
  444. }, {
  445. // Point members
  446. /* eslint-disable valid-jsdoc */
  447. /**
  448. * Don't do any hover colors or anything
  449. * @private
  450. */
  451. setState: function (state) {
  452. this.state = state;
  453. }
  454. /* eslint-enable valid-jsdoc */
  455. });
  456. /**
  457. * A `gauge` series. If the [type](#series.gauge.type) option is not
  458. * specified, it is inherited from [chart.type](#chart.type).
  459. *
  460. * @extends series,plotOptions.gauge
  461. * @excluding animationLimit, boostThreshold, connectEnds, connectNulls,
  462. * cropThreshold, dashStyle, dataParser, dataURL, findNearestPointBy,
  463. * getExtremesFromAll, marker, negativeColor, pointPlacement, shadow,
  464. * softThreshold, stack, stacking, states, step, threshold,
  465. * turboThreshold, zoneAxis, zones, dataSorting, boostBlending
  466. * @product highcharts
  467. * @requires highcharts-more
  468. * @apioption series.gauge
  469. */
  470. /**
  471. * An array of data points for the series. For the `gauge` series type,
  472. * points can be given in the following ways:
  473. *
  474. * 1. An array of numerical values. In this case, the numerical values will be
  475. * interpreted as `y` options. Example:
  476. * ```js
  477. * data: [0, 5, 3, 5]
  478. * ```
  479. *
  480. * 2. An array of objects with named values. The following snippet shows only a
  481. * few settings, see the complete options set below. If the total number of
  482. * data points exceeds the series'
  483. * [turboThreshold](#series.gauge.turboThreshold), this option is not
  484. * available.
  485. * ```js
  486. * data: [{
  487. * y: 6,
  488. * name: "Point2",
  489. * color: "#00FF00"
  490. * }, {
  491. * y: 8,
  492. * name: "Point1",
  493. * color: "#FF00FF"
  494. * }]
  495. * ```
  496. *
  497. * The typical gauge only contains a single data value.
  498. *
  499. * @sample {highcharts} highcharts/chart/reflow-true/
  500. * Numerical values
  501. * @sample {highcharts} highcharts/series/data-array-of-objects/
  502. * Config objects
  503. *
  504. * @type {Array<number|null|*>}
  505. * @extends series.line.data
  506. * @excluding drilldown, marker, x
  507. * @product highcharts
  508. * @apioption series.gauge.data
  509. */
  510. ''; // adds the doclets above in the transpiled file