GaugeSeries.js 18 KB

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