Source

widgets/heatCalendar.js

  1. import processStructure from '@devoinc/applications-data-library/structures/heatCalendar';
  2. import downloads from '@devoinc/applications-builder/libs/downloads';
  3. import widgetFactory from '@devoinc/applications-builder/widgetFactory';
  4. import dependencies from '../data/dependencies';
  5. const HeatCalendarWidget = dependencies.require('widgets').HeatCalendarWidget;
  6. const defaultSettings = {
  7. on: [],
  8. valueExtent: [Infinity, -Infinity],
  9. monthLabelColour: 'none',
  10. title: null,
  11. weekDayFontColor: 'white',
  12. legendSelectorColor: 'white',
  13. weekDaysLabels: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
  14. moveDaysLabels: true,
  15. mondayFirst: false,
  16. toBytes: false,
  17. displayWeekDays: false,
  18. displayDayLegend: false,
  19. displayMark: true,
  20. opacity: 1,
  21. leftmargin: 12,
  22. topmargin: 50,
  23. labermargin: 35,
  24. displayScale: false,
  25. scalemargin: 30,
  26. scaleheight: 15,
  27. scalesize: [0.25, 0.75],
  28. dataOperation: 'none',
  29. drawZero: true,
  30. minPercentil: null,
  31. maxPercentil: null,
  32. discardMethod: 'none',
  33. displaySelectors: false,
  34. };
  35. /**
  36. * The heat calendar widget shows a calendar with the days marked in
  37. * different colors.
  38. * These colors depend on the amount of data per day and a gradient scale
  39. * that you can see below.
  40. * @category Widgets
  41. * @module HeatCalendar
  42. * @see [base](module-base.html)
  43. * @see [collapser](module-collapser.html)
  44. * @see [dataSearch](module-dataSearch.html)
  45. * @see [download](module-download.html)
  46. * @see [info](module-info.html)
  47. * @see [lifeCycle](module-lifeCycle.html)
  48. * @see [listeners](module-listeners.html)
  49. * @see [loading](module-loading.html)
  50. * @see [menu](module-menu.html)
  51. * @see [screenshot](module-screenshot.html)
  52. * @see [zoom](module-zoom.html)
  53. * @tutorial widgets-heat-calendar
  54. */
  55. function mixin(self) {
  56. return {
  57. /**
  58. * Set a custum timespamp key.
  59. * The data should be ordered by this column.
  60. * @param {string} timestampKey - Column name.
  61. * @instance
  62. */
  63. setTimestampKey: (timestampKey) => {
  64. self.settings.timestampKey = timestampKey;
  65. },
  66. /**
  67. * Set the value to show.
  68. * @param {string} value - Column name.
  69. * @instance
  70. */
  71. setValue: (val) => {
  72. self.settings.valToShow = val;
  73. },
  74. /**
  75. * To develop
  76. * @param {number[]} valueExtend - Max and min values
  77. * @instance
  78. * @ignore
  79. */
  80. setValueExtent: (valueExtent) => {
  81. self.settings.valueExtent = valueExtent;
  82. },
  83. /**
  84. * Attach an event handler function for one event to the widget.
  85. * @param {string} str - Name of the event to listen.
  86. * @param {Function} func - Callback JavaScript function.
  87. * @instance
  88. */
  89. setEvent(event, func) {
  90. if (self.settings.on) {
  91. self.settings.on = [];
  92. }
  93. self.settings.on.push([event, func]);
  94. },
  95. /**
  96. * Set a custom color of the internal lines of the calendar that
  97. * delimit the days.
  98. * @param {string} color - Color.
  99. * @default '#555555'
  100. * @instance
  101. */
  102. setDayLineColor(color) {
  103. self.settings.dayLineColor = color;
  104. },
  105. /**
  106. * Set a custom color of the internal lines of the calendar that
  107. * delimit the months.
  108. * @param {string} color - Color.
  109. * @default '#eeeeee'
  110. * @instance
  111. */
  112. setMonthLineColor(color) {
  113. self.settings.monthLineColor = color;
  114. },
  115. /**
  116. * Set the date label color.
  117. * @param {string} color - Color.
  118. * @default 'none'
  119. * @instance
  120. */
  121. setMonthLabelColor(color) {
  122. self.settings.monthLabelColour = color;
  123. },
  124. /**
  125. * Set the custom color for the legend maximun value.
  126. * @param {string} color - Color.
  127. * @default '#dddddd'
  128. * @instance
  129. */
  130. setLeyendMaxValColor(color) {
  131. self.settings.leyendMaxValColor = color;
  132. },
  133. /**
  134. * Set the custom color for the legend minimun value.
  135. * @param {Object} color - Color.
  136. * @default '#dddddd'
  137. * @instance
  138. */
  139. setLeyendMinValColor(color) {
  140. self.settings.leyendMinValColor = color;
  141. },
  142. /**
  143. * Set the color for week days labels.
  144. * @param {string} color - Color.
  145. * @default '#ffffff'
  146. * @instance
  147. */
  148. setWeekDayFontColor(color) {
  149. self.settings.weekDayFontColor = color;
  150. },
  151. /**
  152. * Set the color for the legend selector.
  153. * @param {string} color - Color
  154. * @default 'white'
  155. * @instance
  156. */
  157. setLegendSelectorColor(color) {
  158. self.settings.legendSelectorColor = color;
  159. },
  160. /**
  161. * Set custom labels for days of weeks.
  162. * @param {string[]} days - Days of week labels.
  163. * @default ['S', 'M', 'T', 'W', 'T', 'F', 'S']
  164. * @instance
  165. */
  166. setWeekDaysLabels(days) {
  167. self.settings.weekDaysLabels = days;
  168. },
  169. /**
  170. * Allow to shift the days of the week.
  171. * @param {boolean} bool
  172. * @default true
  173. * @instance
  174. */
  175. setMoveDaysLabels: (bool) => (self.settings.moveDaysLabels = bool),
  176. /**
  177. * Set Monday as firts day of week.
  178. * @param {boolean} bool
  179. * @default false
  180. * @instance
  181. */
  182. setMondayFirst(bool) {
  183. self.settings.mondayFirst = bool;
  184. },
  185. /**
  186. * Set the values as units of bytes.
  187. * @param {boolean} bool
  188. * @default false
  189. * @instance
  190. */
  191. setToBytes: (bool) => (self.settings.toBytes = bool),
  192. /**
  193. * Shows the days of the week.
  194. * @param {boolean} bool
  195. * @default false
  196. * @instance
  197. */
  198. setDisplayWeekDays(bool) {
  199. self.settings.displayWeekDays = bool;
  200. },
  201. /**
  202. * Set visible days legend.
  203. * @param {boolean} bool
  204. * @default false
  205. * @instance
  206. */
  207. setDisplayDayLegend(bool) {
  208. self.settings.displayDayLegend = bool;
  209. },
  210. /**
  211. * Set enable display marks.
  212. * @param {boolean} bool
  213. * @default true
  214. * @instance
  215. */
  216. setDisplayMark(bool) {
  217. self.settings.displayMark = bool;
  218. },
  219. /**
  220. * Set the opacity for colors.
  221. * @param {number} opacity - Opacity. Number between 0 and 1.
  222. * @default 1
  223. * @instance
  224. */
  225. setOpacity(opacity) {
  226. self.settings.opacity = opacity;
  227. },
  228. /**
  229. * Set left margin to wrap the chart.
  230. * @param {number} margin - Margin value.
  231. * @default 12
  232. * @instance
  233. */
  234. setLeftmargin(margin) {
  235. self.settings.leftmargin = margin;
  236. },
  237. /**
  238. * Set the top margin of the chart.
  239. * @param {number} margin - Margin value.
  240. * @default 50
  241. * @instance
  242. */
  243. setTopmargin(margin) {
  244. self.settings.topmargin = margin;
  245. },
  246. /**
  247. * Set the margin for the label.
  248. * @param {number} margin - Margin value.
  249. * @default 35
  250. * @instance
  251. */
  252. setLabelMargin(margin) {
  253. self.settings.labermargin = margin;
  254. },
  255. /**
  256. * Set display the scale
  257. * @param {boolean} bool
  258. * @default false
  259. * @instance
  260. */
  261. setDisplayScale(bool) {
  262. self.settings.displayScale = bool;
  263. },
  264. /**
  265. * Set a custom margin for the scale.
  266. * @param {number} scale - Scale value.
  267. * @default 15
  268. * @instance
  269. */
  270. setScaleMargin(scale) {
  271. self.settings.scalemargin = scale;
  272. },
  273. /**
  274. * Set a custom scale height.
  275. * @param {number} scale - Scale value.
  276. * @default 15
  277. * @instance
  278. */
  279. setScaleHeight(scale) {
  280. self.settings.scaleheight = scale;
  281. },
  282. /**
  283. * Set a custom scale size.
  284. * @param {number[]} scale - Scale size.
  285. * @default [0.25, 0.75]
  286. * @instance
  287. */
  288. setScaleSize(scale) {
  289. self.settings.scalesize = scale;
  290. },
  291. /**
  292. * Set a color scale.
  293. * Currently it has to be an array of colors in d3.
  294. * The first color is used for tables without data.
  295. * The rest, to map from the minimum to the maximum value in a linear way.
  296. * @param {string[]} scale - Colors scale.
  297. * @default ["#006837", "#1A9863", "#66BD63","#A6D96A", "#D9EF8B", "#FFFFBF","#FEE08B", "#FDAE61", "#F46D43","#D73027", "#A50026"]
  298. * @instance
  299. */
  300. setColorScale(scale) {
  301. self.settings.colorScale = scale;
  302. },
  303. /**
  304. * Apply an operation for data.
  305. *
  306. * Allowed values are:
  307. * - <b>arctag</b>: Arctangent.
  308. * - <b>log</b>: Logarithm.
  309. * - <b>none</b>: No operation
  310. * @param {string} dataOperation - Operation name.
  311. * @default 'none'
  312. * @instance
  313. */
  314. setDataOperation(dataOperation) {
  315. self.settings.dataOperation = dataOperation;
  316. },
  317. /**
  318. * Set the minimum percentile color.
  319. * @param {string} color - Color.
  320. * @default #87CEEB
  321. * @instance
  322. */
  323. setMinPercentilColor(color) {
  324. self.settings.minPercentilColor = color;
  325. },
  326. /**
  327. * Set the maximun percentile color.
  328. * @param {string} color - Color.
  329. * @default #BA55D3
  330. * @instance
  331. */
  332. setMaxPercentilColor(color) {
  333. self.settings.maxPercentilColor = color;
  334. },
  335. /**
  336. * Set the minimun percentile score.
  337. * @param {number} percentil - Percentil value. Value between 0 and 1.
  338. * @default null
  339. * @instance
  340. */
  341. setMinPercentil(percentil) {
  342. self.settings.minPercentil = percentil;
  343. },
  344. /**
  345. * Set the maximun percentile score.
  346. * @param {number} percentil - Percentil value. Value between 0 and 1.
  347. * @default null
  348. * @instance
  349. */
  350. setMaxPercentil(percentil) {
  351. self.settings.maxPercentil = percentil;
  352. },
  353. /**
  354. * Method to discard maximums and minimums.
  355. *
  356. * Methods allowed:
  357. * - <b>stdDev</b>: Standard deviation.
  358. * - <b>5percent</b>: Percentile 5%-95%.
  359. * - <b>10percent</b>: Percentile 10%-90%.
  360. * - <b>20percent</b>: Percentile 20%-20%.
  361. * - <b>none</b>: None.
  362. * @param {string} discardMethod - Method name.
  363. * @default 'none'
  364. * @instance
  365. */
  366. setDiscardMethod(discardMethod) {
  367. self.settings.discardMethod = discardMethod;
  368. },
  369. /**
  370. * Set visible the selectors.
  371. * @param {boolean} bool
  372. * @default false
  373. * @instance
  374. */
  375. setDisplaySelectors(bool) {
  376. self.settings.displaySelectors = bool;
  377. },
  378. // Common
  379. // -------------------------------------------------------------------------
  380. /**
  381. * Download CSV
  382. * @ignore
  383. */
  384. downloadCSV() {
  385. let s = null;
  386. let isCorrectData =
  387. self.widget &&
  388. self.widget.data &&
  389. self.widget.data.days &&
  390. Array.isArray(self.widget.data.days);
  391. if (isCorrectData) {
  392. let dayss = self.widget.data.days;
  393. let valss = self.widget.data.values;
  394. let nams = self.widget.data.tags[0];
  395. let totSeries = self.widget.data.days.length;
  396. let header = '"name","timestamp","value"\r\n';
  397. let content = '';
  398. for (var i = 0; i < totSeries; i += 1) {
  399. let days = dayss[i];
  400. let vals = valss[i];
  401. var serieTot = days.length;
  402. for (var j = 0; j < serieTot; j += 1) {
  403. content += nams + ',' + days[j] + ',' + vals[j] + ',\r\n';
  404. }
  405. }
  406. s = header + content;
  407. } else {
  408. console.error(`No data for download in widget "${self.id}"`);
  409. }
  410. if (s) downloads.downloadCSV(s, `${self.id}-data`);
  411. },
  412. /**
  413. * Redraw function
  414. * @ignore
  415. */
  416. redraw() {
  417. if (self.widget) {
  418. self.widget.display({ size: true }, 300, $(self.graphic).height());
  419. }
  420. },
  421. /**
  422. * Resize function
  423. * @ignore
  424. */
  425. resize() {
  426. this.redraw();
  427. },
  428. // Life Cycle
  429. // -------------------------------------------------------------------------
  430. /**
  431. * Render function
  432. * @param {object} orig - Data for process
  433. * @ignore
  434. */
  435. render: (orig) => {
  436. if (!self.el) return; // If not have element not render
  437. let cfg = Object.assign({}, defaultSettings, self.settings);
  438. let data = processStructure(
  439. orig,
  440. cfg.timestampKey,
  441. cfg.valToShow,
  442. cfg.valToShow,
  443. cfg.seriesNames,
  444. cfg.timestampKey,
  445. cfg.forceFirstElement,
  446. cfg.forceLastElement
  447. );
  448. if (data) {
  449. self.widget = new HeatCalendarWidget(cfg);
  450. self.widget.setData(data);
  451. self.widget.display({
  452. force: true,
  453. data: true,
  454. });
  455. } else {
  456. this.debugError({
  457. msg: 'NO DATA',
  458. console: {
  459. method: 'error',
  460. msg: 'No data arrive to render function',
  461. },
  462. });
  463. }
  464. },
  465. };
  466. }
  467. export default widgetFactory(mixin);