WindbarbSeries.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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, false)) {
  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. /**
  245. * Wind barbs are a convenient way to represent wind speed and direction in
  246. * one graphical form. Wind direction is given by the stem direction, and
  247. * wind speed by the number and shape of barbs.
  248. *
  249. * @sample {highcharts|highstock} highcharts/demo/windbarb-series/
  250. * Wind barb series
  251. *
  252. * @extends plotOptions.column
  253. * @excluding boostThreshold, marker, connectEnds, connectNulls,
  254. * cropThreshold, dashStyle, dragDrop, gapSize, gapUnit,
  255. * linecap, shadow, stacking, step, boostBlending
  256. * @since 6.0.0
  257. * @product highcharts highstock
  258. * @requires modules/windbarb
  259. * @optionparent plotOptions.windbarb
  260. */
  261. WindbarbSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  262. /**
  263. * Data grouping options for the wind barbs. In Highcharts, this
  264. * requires the `modules/datagrouping.js` module to be loaded. In
  265. * Highstock, data grouping is included.
  266. *
  267. * @sample highcharts/plotoptions/windbarb-datagrouping
  268. * Wind barb with data grouping
  269. *
  270. * @since 7.1.0
  271. * @product highcharts highstock
  272. */
  273. dataGrouping: {
  274. /**
  275. * Whether to enable data grouping.
  276. *
  277. * @product highcharts highstock
  278. */
  279. enabled: true,
  280. /**
  281. * Approximation function for the data grouping. The default
  282. * returns an average of wind speed and a vector average direction
  283. * weighted by wind speed.
  284. *
  285. * @product highcharts highstock
  286. *
  287. * @type {string|Function}
  288. */
  289. approximation: 'windbarb',
  290. /**
  291. * The approximate data group width.
  292. *
  293. * @product highcharts highstock
  294. */
  295. groupPixelWidth: 30
  296. },
  297. /**
  298. * The line width of the wind barb symbols.
  299. */
  300. lineWidth: 2,
  301. /**
  302. * The id of another series in the chart that the wind barbs are
  303. * projected on. When `null`, the wind symbols are drawn on the X axis,
  304. * but offset up or down by the `yOffset` setting.
  305. *
  306. * @sample {highcharts|highstock} highcharts/plotoptions/windbarb-onseries
  307. * Projected on area series
  308. *
  309. * @type {string|null}
  310. */
  311. onSeries: null,
  312. states: {
  313. hover: {
  314. lineWidthPlus: 0
  315. }
  316. },
  317. tooltip: {
  318. /**
  319. * The default point format for the wind barb tooltip. Note the
  320. * `point.beaufort` property that refers to the Beaufort wind scale.
  321. * The names can be internationalized by modifying
  322. * `Highcharts.seriesTypes.windbarb.prototype.beaufortNames`.
  323. */
  324. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.value}</b> ({point.beaufort})<br/>'
  325. },
  326. /**
  327. * Pixel length of the stems.
  328. */
  329. vectorLength: 20,
  330. /**
  331. * @default value
  332. */
  333. colorKey: 'value',
  334. /**
  335. * Vertical offset from the cartesian position, in pixels. The default
  336. * value makes sure the symbols don't overlap the X axis when `onSeries`
  337. * is `null`, and that they don't overlap the linked series when
  338. * `onSeries` is given.
  339. */
  340. yOffset: -20,
  341. /**
  342. * Horizontal offset from the cartesian position, in pixels. When the
  343. * chart is inverted, this option allows translation like
  344. * [yOffset](#plotOptions.windbarb.yOffset) in non inverted charts.
  345. *
  346. * @since 6.1.0
  347. */
  348. xOffset: 0
  349. });
  350. return WindbarbSeries;
  351. }(ColumnSeries));
  352. extend(WindbarbSeries.prototype, {
  353. pointArrayMap: ['value', 'direction'],
  354. parallelArrays: ['x', 'value', 'direction'],
  355. beaufortName: ['Calm', 'Light air', 'Light breeze',
  356. 'Gentle breeze', 'Moderate breeze', 'Fresh breeze',
  357. 'Strong breeze', 'Near gale', 'Gale', 'Strong gale', 'Storm',
  358. 'Violent storm', 'Hurricane'],
  359. beaufortFloor: [0, 0.3, 1.6, 3.4, 5.5, 8.0, 10.8, 13.9, 17.2, 20.8,
  360. 24.5, 28.5, 32.7],
  361. trackerGroups: ['markerGroup'],
  362. getPlotBox: OnSeriesMixin.getPlotBox,
  363. // Don't invert the marker group (#4960)
  364. invertGroups: noop
  365. });
  366. WindbarbSeries.prototype.pointClass = WindbarbPoint;
  367. /* *
  368. *
  369. * Registry
  370. *
  371. * */
  372. WindbarbSeries.registerApproximation();
  373. SeriesRegistry.registerSeriesType('windbarb', WindbarbSeries);
  374. /* *
  375. *
  376. * Export default
  377. *
  378. * */
  379. export default WindbarbSeries;
  380. /* *
  381. *
  382. * API Options
  383. *
  384. * */
  385. /**
  386. * A `windbarb` series. If the [type](#series.windbarb.type) option is not
  387. * specified, it is inherited from [chart.type](#chart.type).
  388. *
  389. * @extends series,plotOptions.windbarb
  390. * @excluding dataParser, dataURL, boostThreshold, boostBlending
  391. * @product highcharts highstock
  392. * @requires modules/windbarb
  393. * @apioption series.windbarb
  394. */
  395. /**
  396. * An array of data points for the series. For the `windbarb` series type,
  397. * points can be given in the following ways:
  398. *
  399. * 1. An array of arrays with 3 values. In this case, the values correspond to
  400. * `x,value,direction`. If the first value is a string, it is applied as the
  401. * name of the point, and the `x` value is inferred.
  402. * ```js
  403. * data: [
  404. * [Date.UTC(2017, 0, 1, 0), 3.3, 90],
  405. * [Date.UTC(2017, 0, 1, 1), 12.1, 180],
  406. * [Date.UTC(2017, 0, 1, 2), 11.1, 270]
  407. * ]
  408. * ```
  409. *
  410. * 2. An array of objects with named values. The following snippet shows only a
  411. * few settings, see the complete options set below. If the total number of
  412. * data points exceeds the series'
  413. * [turboThreshold](#series.area.turboThreshold), this option is not
  414. * available.
  415. * ```js
  416. * data: [{
  417. * x: Date.UTC(2017, 0, 1, 0),
  418. * value: 12.1,
  419. * direction: 90
  420. * }, {
  421. * x: Date.UTC(2017, 0, 1, 1),
  422. * value: 11.1,
  423. * direction: 270
  424. * }]
  425. * ```
  426. *
  427. * @sample {highcharts} highcharts/chart/reflow-true/
  428. * Numerical values
  429. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  430. * Arrays of numeric x and y
  431. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  432. * Arrays of datetime x and y
  433. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  434. * Arrays of point.name and y
  435. * @sample {highcharts} highcharts/series/data-array-of-objects/
  436. * Config objects
  437. *
  438. * @type {Array<Array<(number|string),number,number>|*>}
  439. * @extends series.line.data
  440. * @product highcharts highstock
  441. * @apioption series.windbarb.data
  442. */
  443. /**
  444. * The wind speed in meters per second.
  445. *
  446. * @type {number|null}
  447. * @product highcharts highstock
  448. * @apioption series.windbarb.data.value
  449. */
  450. /**
  451. * The wind direction in degrees, where 0 is north (pointing towards south).
  452. *
  453. * @type {number}
  454. * @product highcharts highstock
  455. * @apioption series.windbarb.data.direction
  456. */
  457. ''; // adds doclets above to transpiled file