WindbarbSeries.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /* *
  2. *
  3. * Wind barb series module
  4. *
  5. * (c) 2010-2021 Torstein Honsi
  6. *
  7. * License: www.highcharts.com/license
  8. *
  9. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10. *
  11. * */
  12. 'use strict';
  13. var __extends = (this && this.__extends) || (function () {
  14. var extendStatics = function (d, b) {
  15. extendStatics = Object.setPrototypeOf ||
  16. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  17. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  18. return extendStatics(d, b);
  19. };
  20. return function (d, b) {
  21. extendStatics(d, b);
  22. function __() { this.constructor = d; }
  23. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  24. };
  25. })();
  26. import A from '../../Core/Animation/AnimationUtilities.js';
  27. var animObject = A.animObject;
  28. import H from '../../Core/Globals.js';
  29. var noop = H.noop;
  30. import OnSeriesMixin from '../../Mixins/OnSeries.js';
  31. import SeriesRegistry from '../../Core/Series/SeriesRegistry.js';
  32. var Series = SeriesRegistry.series, ColumnSeries = SeriesRegistry.seriesTypes.column;
  33. import U from '../../Core/Utilities.js';
  34. var extend = U.extend, merge = U.merge, pick = U.pick;
  35. import WindbarbPoint from './WindbarbPoint.js';
  36. /**
  37. * @private
  38. * @class
  39. * @name Highcharts.seriesTypes.windbarb
  40. *
  41. * @augments Highcharts.Series
  42. */
  43. var WindbarbSeries = /** @class */ (function (_super) {
  44. __extends(WindbarbSeries, _super);
  45. function WindbarbSeries() {
  46. /* *
  47. *
  48. * Static properties
  49. *
  50. * */
  51. var _this = _super !== null && _super.apply(this, arguments) || this;
  52. /* *
  53. *
  54. * Properties
  55. *
  56. * */
  57. _this.data = void 0;
  58. _this.options = void 0;
  59. _this.points = void 0;
  60. return _this;
  61. }
  62. /* *
  63. *
  64. * Static functions
  65. *
  66. * */
  67. // eslint-disable-next-line valid-jsdoc
  68. /**
  69. * Once off, register the windbarb approximation for data grouping. This can
  70. * be called anywhere (not necessarily in the translate function), but must
  71. * happen after the data grouping module is loaded and before the
  72. * wind barb series uses it.
  73. * @private
  74. */
  75. WindbarbSeries.registerApproximation = function () {
  76. if (H.approximations && !H.approximations.windbarb) {
  77. H.approximations.windbarb = function (values, directions) {
  78. var vectorX = 0, vectorY = 0, i, len = values.length;
  79. for (i = 0; i < len; i++) {
  80. vectorX += values[i] * Math.cos(directions[i] * H.deg2rad);
  81. vectorY += values[i] * Math.sin(directions[i] * H.deg2rad);
  82. }
  83. return [
  84. // Wind speed
  85. values.reduce(function (sum, value) {
  86. return sum + value;
  87. }, 0) / values.length,
  88. // Wind direction
  89. Math.atan2(vectorY, vectorX) / H.deg2rad
  90. ];
  91. };
  92. }
  93. };
  94. /* *
  95. *
  96. * Functions
  97. *
  98. * */
  99. WindbarbSeries.prototype.init = function (chart, options) {
  100. WindbarbSeries.registerApproximation();
  101. Series.prototype.init.call(this, chart, options);
  102. };
  103. // Get presentational attributes.
  104. WindbarbSeries.prototype.pointAttribs = function (point, state) {
  105. var options = this.options, stroke = point.color || this.color, strokeWidth = this.options.lineWidth;
  106. if (state) {
  107. stroke = options.states[state].color || stroke;
  108. strokeWidth =
  109. (options.states[state].lineWidth || strokeWidth) +
  110. (options.states[state].lineWidthPlus || 0);
  111. }
  112. return {
  113. 'stroke': stroke,
  114. 'stroke-width': strokeWidth
  115. };
  116. };
  117. // Create a single wind arrow. It is later rotated around the zero
  118. // centerpoint.
  119. WindbarbSeries.prototype.windArrow = function (point) {
  120. var knots = point.value * 1.943844, level = point.beaufortLevel, path, barbs, u = this.options.vectorLength / 20, pos = -10;
  121. if (point.isNull) {
  122. return [];
  123. }
  124. if (level === 0) {
  125. return this.chart.renderer.symbols.circle(-10 * u, -10 * u, 20 * u, 20 * u);
  126. }
  127. // The stem and the arrow head
  128. path = [
  129. ['M', 0, 7 * u],
  130. ['L', -1.5 * u, 7 * u],
  131. ['L', 0, 10 * u],
  132. ['L', 1.5 * u, 7 * u],
  133. ['L', 0, 7 * u],
  134. ['L', 0, -10 * u] // top
  135. ];
  136. // For each full 50 knots, add a pennant
  137. barbs = (knots - knots % 50) / 50; // pennants
  138. if (barbs > 0) {
  139. while (barbs--) {
  140. path.push(pos === -10 ? ['L', 0, pos * u] : ['M', 0, pos * u], ['L', 5 * u, pos * u + 2], ['L', 0, pos * u + 4]);
  141. // Substract from the rest and move position for next
  142. knots -= 50;
  143. pos += 7;
  144. }
  145. }
  146. // For each full 10 knots, add a full barb
  147. barbs = (knots - knots % 10) / 10;
  148. if (barbs > 0) {
  149. while (barbs--) {
  150. path.push(pos === -10 ? ['L', 0, pos * u] : ['M', 0, pos * u], ['L', 7 * u, pos * u]);
  151. knots -= 10;
  152. pos += 3;
  153. }
  154. }
  155. // For each full 5 knots, add a half barb
  156. barbs = (knots - knots % 5) / 5; // half barbs
  157. if (barbs > 0) {
  158. while (barbs--) {
  159. path.push(pos === -10 ? ['L', 0, pos * u] : ['M', 0, pos * u], ['L', 4 * u, pos * u]);
  160. knots -= 5;
  161. pos += 3;
  162. }
  163. }
  164. return path;
  165. };
  166. WindbarbSeries.prototype.translate = function () {
  167. var beaufortFloor = this.beaufortFloor, beaufortName = this.beaufortName;
  168. OnSeriesMixin.translate.call(this);
  169. this.points.forEach(function (point) {
  170. var level = 0;
  171. // Find the beaufort level (zero based)
  172. for (; level < beaufortFloor.length; level++) {
  173. if (beaufortFloor[level] > point.value) {
  174. break;
  175. }
  176. }
  177. point.beaufortLevel = level - 1;
  178. point.beaufort = beaufortName[level - 1];
  179. });
  180. };
  181. WindbarbSeries.prototype.drawPoints = function () {
  182. var chart = this.chart, yAxis = this.yAxis, inverted = chart.inverted, shapeOffset = this.options.vectorLength / 2;
  183. this.points.forEach(function (point) {
  184. var plotX = point.plotX, plotY = point.plotY;
  185. // Check if it's inside the plot area, but only for the X
  186. // dimension.
  187. if (this.options.clip === false ||
  188. chart.isInsidePlot(plotX, 0)) {
  189. // Create the graphic the first time
  190. if (!point.graphic) {
  191. point.graphic = this.chart.renderer
  192. .path()
  193. .add(this.markerGroup)
  194. .addClass('highcharts-point ' +
  195. 'highcharts-color-' +
  196. pick(point.colorIndex, point.series.colorIndex));
  197. }
  198. // Position the graphic
  199. point.graphic
  200. .attr({
  201. d: this.windArrow(point),
  202. translateX: plotX + this.options.xOffset,
  203. translateY: plotY + this.options.yOffset,
  204. rotation: point.direction
  205. });
  206. if (!this.chart.styledMode) {
  207. point.graphic
  208. .attr(this.pointAttribs(point));
  209. }
  210. }
  211. else if (point.graphic) {
  212. point.graphic = point.graphic.destroy();
  213. }
  214. // Set the tooltip anchor position
  215. point.tooltipPos = [
  216. plotX + this.options.xOffset +
  217. (inverted && !this.onSeries ? shapeOffset : 0),
  218. plotY + this.options.yOffset -
  219. (inverted ?
  220. 0 :
  221. shapeOffset + yAxis.pos - chart.plotTop)
  222. ]; // #6327
  223. }, this);
  224. };
  225. // Fade in the arrows on initializing series.
  226. WindbarbSeries.prototype.animate = function (init) {
  227. if (init) {
  228. this.markerGroup.attr({
  229. opacity: 0.01
  230. });
  231. }
  232. else {
  233. this.markerGroup.animate({
  234. opacity: 1
  235. }, animObject(this.options.animation));
  236. }
  237. };
  238. WindbarbSeries.prototype.markerAttribs = function (point, state) {
  239. return {};
  240. };
  241. WindbarbSeries.prototype.getExtremes = function () {
  242. return {};
  243. };
  244. WindbarbSeries.prototype.shouldShowTooltip = function (plotX, plotY, options) {
  245. if (options === void 0) { options = {}; }
  246. options.ignoreX = this.chart.inverted;
  247. options.ignoreY = !options.ignoreX;
  248. return _super.prototype.shouldShowTooltip.call(this, plotX, plotY, options);
  249. };
  250. /**
  251. * Wind barbs are a convenient way to represent wind speed and direction in
  252. * one graphical form. Wind direction is given by the stem direction, and
  253. * wind speed by the number and shape of barbs.
  254. *
  255. * @sample {highcharts|highstock} highcharts/demo/windbarb-series/
  256. * Wind barb series
  257. *
  258. * @extends plotOptions.column
  259. * @excluding boostThreshold, marker, connectEnds, connectNulls,
  260. * cropThreshold, dashStyle, dragDrop, gapSize, gapUnit,
  261. * linecap, shadow, stacking, step, boostBlending
  262. * @since 6.0.0
  263. * @product highcharts highstock
  264. * @requires modules/windbarb
  265. * @optionparent plotOptions.windbarb
  266. */
  267. WindbarbSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  268. /**
  269. * Data grouping options for the wind barbs. In Highcharts, this
  270. * requires the `modules/datagrouping.js` module to be loaded. In
  271. * Highcharts Stock, data grouping is included.
  272. *
  273. * @sample highcharts/plotoptions/windbarb-datagrouping
  274. * Wind barb with data grouping
  275. *
  276. * @since 7.1.0
  277. * @product highcharts highstock
  278. */
  279. dataGrouping: {
  280. /**
  281. * Whether to enable data grouping.
  282. *
  283. * @product highcharts highstock
  284. */
  285. enabled: true,
  286. /**
  287. * Approximation function for the data grouping. The default
  288. * returns an average of wind speed and a vector average direction
  289. * weighted by wind speed.
  290. *
  291. * @product highcharts highstock
  292. *
  293. * @type {string|Function}
  294. */
  295. approximation: 'windbarb',
  296. /**
  297. * The approximate data group width.
  298. *
  299. * @product highcharts highstock
  300. */
  301. groupPixelWidth: 30
  302. },
  303. /**
  304. * The line width of the wind barb symbols.
  305. */
  306. lineWidth: 2,
  307. /**
  308. * The id of another series in the chart that the wind barbs are
  309. * projected on. When `null`, the wind symbols are drawn on the X axis,
  310. * but offset up or down by the `yOffset` setting.
  311. *
  312. * @sample {highcharts|highstock} highcharts/plotoptions/windbarb-onseries
  313. * Projected on area series
  314. *
  315. * @type {string|null}
  316. */
  317. onSeries: null,
  318. states: {
  319. hover: {
  320. lineWidthPlus: 0
  321. }
  322. },
  323. tooltip: {
  324. /**
  325. * The default point format for the wind barb tooltip. Note the
  326. * `point.beaufort` property that refers to the Beaufort wind scale.
  327. * The names can be internationalized by modifying
  328. * `Highcharts.seriesTypes.windbarb.prototype.beaufortNames`.
  329. */
  330. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.value}</b> ({point.beaufort})<br/>'
  331. },
  332. /**
  333. * Pixel length of the stems.
  334. */
  335. vectorLength: 20,
  336. /**
  337. * @default value
  338. */
  339. colorKey: 'value',
  340. /**
  341. * Vertical offset from the cartesian position, in pixels. The default
  342. * value makes sure the symbols don't overlap the X axis when `onSeries`
  343. * is `null`, and that they don't overlap the linked series when
  344. * `onSeries` is given.
  345. */
  346. yOffset: -20,
  347. /**
  348. * Horizontal offset from the cartesian position, in pixels. When the
  349. * chart is inverted, this option allows translation like
  350. * [yOffset](#plotOptions.windbarb.yOffset) in non inverted charts.
  351. *
  352. * @since 6.1.0
  353. */
  354. xOffset: 0
  355. });
  356. return WindbarbSeries;
  357. }(ColumnSeries));
  358. extend(WindbarbSeries.prototype, {
  359. pointArrayMap: ['value', 'direction'],
  360. parallelArrays: ['x', 'value', 'direction'],
  361. beaufortName: ['Calm', 'Light air', 'Light breeze',
  362. 'Gentle breeze', 'Moderate breeze', 'Fresh breeze',
  363. 'Strong breeze', 'Near gale', 'Gale', 'Strong gale', 'Storm',
  364. 'Violent storm', 'Hurricane'],
  365. beaufortFloor: [0, 0.3, 1.6, 3.4, 5.5, 8.0, 10.8, 13.9, 17.2, 20.8,
  366. 24.5, 28.5, 32.7],
  367. trackerGroups: ['markerGroup'],
  368. getPlotBox: OnSeriesMixin.getPlotBox,
  369. // Don't invert the marker group (#4960)
  370. invertGroups: noop
  371. });
  372. WindbarbSeries.prototype.pointClass = WindbarbPoint;
  373. /* *
  374. *
  375. * Registry
  376. *
  377. * */
  378. WindbarbSeries.registerApproximation();
  379. SeriesRegistry.registerSeriesType('windbarb', WindbarbSeries);
  380. /* *
  381. *
  382. * Export default
  383. *
  384. * */
  385. export default WindbarbSeries;
  386. /* *
  387. *
  388. * API Options
  389. *
  390. * */
  391. /**
  392. * A `windbarb` series. If the [type](#series.windbarb.type) option is not
  393. * specified, it is inherited from [chart.type](#chart.type).
  394. *
  395. * @extends series,plotOptions.windbarb
  396. * @excluding dataParser, dataURL, boostThreshold, boostBlending
  397. * @product highcharts highstock
  398. * @requires modules/windbarb
  399. * @apioption series.windbarb
  400. */
  401. /**
  402. * An array of data points for the series. For the `windbarb` series type,
  403. * points can be given in the following ways:
  404. *
  405. * 1. An array of arrays with 3 values. In this case, the values correspond to
  406. * `x,value,direction`. If the first value is a string, it is applied as the
  407. * name of the point, and the `x` value is inferred.
  408. * ```js
  409. * data: [
  410. * [Date.UTC(2017, 0, 1, 0), 3.3, 90],
  411. * [Date.UTC(2017, 0, 1, 1), 12.1, 180],
  412. * [Date.UTC(2017, 0, 1, 2), 11.1, 270]
  413. * ]
  414. * ```
  415. *
  416. * 2. An array of objects with named values. The following snippet shows only a
  417. * few settings, see the complete options set below. If the total number of
  418. * data points exceeds the series'
  419. * [turboThreshold](#series.area.turboThreshold), this option is not
  420. * available.
  421. * ```js
  422. * data: [{
  423. * x: Date.UTC(2017, 0, 1, 0),
  424. * value: 12.1,
  425. * direction: 90
  426. * }, {
  427. * x: Date.UTC(2017, 0, 1, 1),
  428. * value: 11.1,
  429. * direction: 270
  430. * }]
  431. * ```
  432. *
  433. * @sample {highcharts} highcharts/chart/reflow-true/
  434. * Numerical values
  435. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  436. * Arrays of numeric x and y
  437. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  438. * Arrays of datetime x and y
  439. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  440. * Arrays of point.name and y
  441. * @sample {highcharts} highcharts/series/data-array-of-objects/
  442. * Config objects
  443. *
  444. * @type {Array<Array<(number|string),number,number>|*>}
  445. * @extends series.line.data
  446. * @product highcharts highstock
  447. * @apioption series.windbarb.data
  448. */
  449. /**
  450. * The wind speed in meters per second.
  451. *
  452. * @type {number|null}
  453. * @product highcharts highstock
  454. * @apioption series.windbarb.data.value
  455. */
  456. /**
  457. * The wind direction in degrees, where 0 is north (pointing towards south).
  458. *
  459. * @type {number}
  460. * @product highcharts highstock
  461. * @apioption series.windbarb.data.direction
  462. */
  463. ''; // adds doclets above to transpiled file