Source

widgets/series.js

import processStructure from '@devoinc/applications-data-library/structures/series';
import objects from '@devoinc/applications-builder/utils/objects';
import highchartsHelper from './helpers/highchartsHelper';
import downloads from '@devoinc/applications-builder/libs/downloads';
import HCP from '@devoinc/applications-builder/widgets/helpers/exportDataSeries';
import { __ } from '@devoinc/applications-builder/i18n';
import widgetFactory from '@devoinc/applications-builder/widgetFactory';
import dependencies from '../data/dependencies';

const LineWidget = dependencies.require('widgets').LineWidget;

/**
 * Here all the methods of the widgets based on the
 * [Highchart]{@link https://www.highcharts.com/} library are available.
 * Most of them are widgets based on the representation of temporal data.
 *
 * The list of widgets that use these same methods is:
 * - [Area](module-area.html)
 * - [Column](module-column.html)
 * - [Histogram](module-histogram.html)
 * - [Lines](module-lines.html)
 * - [Stacked Bars](module-stacked-bars.html)
 *
 * @category Widgets
 * @module Series
 * @see [base](module-base.html)
 * @see [collapser](module-collapser.html)
 * @see [dataSearch](module-dataSearch.html)
 * @see [download](module-download.html)
 * @see [info](module-info.html)
 * @see [lifeCycle](module-lifeCycle.html)
 * @see [listeners](module-listeners.html)
 * @see [loading](module-loading.html)
 * @see [menu](module-menu.html)
 * @see [screenshot](module-screenshot.html)
 * @see [zoom](module-zoom.html)
 */
export function mixin(self) {
  HCP.highcharts();

  return {
    /**
     * Set the keys to show.
     * @paramĀ {string[]} key - Keys name.
     * @instance
     */
    setKeys(key) {
      self.settings.keyToShow = key;
    },

    /**
     * Set series names to display.
     * @param {string[]} series - Series names.
     * @instance
     */
    setSeriesNames(series) {
      self.settings.seriesNames = series;
    },

    /**
     * Set the column with timespamp key.
     * @param {string} tsKey - Timestamp column name.
     * @instance
     */
    setTimestampKey(tsKey) {
      self.settings.timestampKey = tsKey;
    },

    /**
     * Set the value to show.
     * @param {string} val - Column name with the value.
     * @instance
     */
    setValue(val) {
      self.settings.valToShow = val;
    },

    /**
     * Set the data grouping.
     *
     * It accepts the moment's get values:
     * - <b>date</b>
     * - <b>year</b>
     * - <b>month</b>
     * - <b>day</b>
     * - <b>hour</b>
     * - <b>minute'</b>
     * - <b>second</b>
     * - <b>millisecond</b>
     * @param {string} grouping - Data grouping.
     * @instance
     */
    setGrouped(grouping) {
      self.settings.groupped = grouping;
    },

    /**
     * Set the Y axis title.
     * @param {string} title - Title text.
     * @instance
     */
    setYAxisTitle(title) {
      self.settings.yaxis_title = title;
    },

    /**
     * Set the X axis title.
     * @param {string} title - Title text.
     * @instance
     */
    setXAxisTitle(title) {
      self.settings.xaxis_title = title;
    },

    /**
     * Fix the data, if it is true data can not be temporarily grouped
     * @param {boolean} bool - Fix the data.
     * @instance
     */
    setFixedData(bool) {
      self.settings.fixData = bool;
    },

    /**
     * Set decimal and thuousands separator.
     *
     * For example: <i>"##,###,###.00"</i>
     * @param {string} str - Format string.
     * @instance
     */
    setFormat(str) {
      self.settings.format = str;
    },

    /**
     * Set the legend visible.
     * @param {boolean} bool - Enable the legend.
     * @instance
     */
    setLegend(bool) {
      self.settings.legend = bool;
    },

    /**
     * Set the defautl widget legend format.
     *
     * The asigned function receives an object with <i>color</i> and
     * <i>name</i> values.
     * @param {Function} func - Function to set default legend format.
     * @instance
     */
    setDefaultFormaterLegend(func) {
      self.settings.defaultformaterlegend = func;
    },

    /**
     * Set the default tooltip format.
     *
     * The asigned function receives an object with <i>x</i> and
     * <i>y</i> values.
     * @param {Function} func - Function to set default tooltip format.
     * @instance
     */
    setDefaultFormater(func) {
      self.settings.defaultformater = func;
    },

    /**
     * Set data accumulation, sum a value with the previous value.
     * @param {boolean} bool - Enable the data accumulation.
     * @instance
     */
    setAccumulated(bool) {
      self.settings.accumulated = bool;
    },

    /**
     * Show an average line.
     * @param {boolean} bool - Enable the average line.
     * @instance
     */
    setShowAvgLine(bool) {
      self.settings.showAvgLine = bool;
    },

    /**
     * Discard values using a determined method.
     *
     * The following values are supported:
     * - <b>none</b>: Do not apply.
     * - <b>stdDev</b>: Discard values using standard deviation.
     * @param {String} str - Method to use.
     * @instance
     */
    setDiscardMethod(str) {
      self.settings.discardMethod = str;
    },

    /**
     * Discard values using a determined mode.
     *
     * The following values are supported:
     * - <b>plotBand</b>
     * - <b>extremes</b>
     * @param {string} str - Mode to use.
     * @instance
     */
    setDiscardMode(str) {
      self.settings.discardMode = str;
    },

    /**
     * Allows add regression series in the chart.
     * This function sets <i>fixData</i> to <i>false</i> as a requirement
     * to display a regression line.
     *
     * The following values are supported:
     * - <b>none</b>
     * - <b>linear</b>
     * - <b>exponential</b>
     * - <b>polynomial</b>
     * - <b>logarithmic</b>
     * - <b>loess</b>
     * @param {string} str - Regression type.
     * @instance
     */
    setRegressionLine(str) {
      self.settings.regressionLine = str;
      self.settings.fixData = false;
    },

    /**
     * Set the Y axis scale.
     *
     * The following values are supported:
     * - <b>none</b>
     * - <b>logarithmic</b>
     * @param {string} str - Scale type.
     * @instance
     */
    setYscaleType(str) {
      self.settings.yScaleType = str;
    },

    /**
     * Highlights max and min values.
     * @param {boolean} bool - Enbale the highlights.
     * @instance
     */
    setHighlightMaxMin(bool) {
      self.settings.highlightMaxMin = bool;
    },

    /**
     * Set the label formatter for the Y axis.
     * @param {Function} func - Callback JavaScript function to format the label.
     * @instance
     */
    setYAxisLabelsFormatter(func) {
      objects.set(self.settings, 'widgetTemplate.yAxis.labels.formatter', func);
    },

    /**
     * Set the label formatter for the X axis.
     * @param {Function} func -Callback JavaScript function to format the label.
     * @instance
     */
    setXAxisFormatter(func) {
      objects.set(self.settings, 'widgetTemplate.xAxis.labels.formatter', func);
    },

    /**
     * Set the widget start to first element.
     * @param {Boolean} bool - Enable to start with the first element.
     * @instance
     */
    setForceFirstElement(bool) {
      self.settings.forceFirstElement = bool;
    },

    /**
     * Set the widget end to last element.
     * @param {Boolean} bool - Enable to start with the first element.
     * @instance
     */
    setForceLastElement(bool) {
      self.settings.forceLastElement = bool;
    },

    /**
     * Set the allKeysLimit
     * Note: This is not used
     * @param {number} [limit=15] - Limit
     * @ignore
     */
    setAllKeysLimit(limit = 20) {
      self.settings.allKeysLimit = limit;
    },

    /**
     * Set the format of the x axis labels.
     *
     * Avaiable formats are:
     * {@link https://api.highcharts.com/highcharts/xAxis.dateTimeLabelFormats}
     * @param {Object} obj - Check the Highcharts documentation.
     * @instance
     */
    setDateTimeLabelFormats(obj) {
      objects.set(
        self.settings,
        'widgetTemplate.xAxis.dateTimeLabelFormats',
        obj
      );
    },

    /**
     * An array determining what time intervals the ticks are allowed to fall
     * on.
     * {@link https://api.highcharts.com/highcharts/xAxis.units}
     * @param {Array} arr - Check the Highcharts documentation.
     * @instance
     */
    setXAxisUnits(arr) {
      objects.set(self.settings, 'widgetTemplate.xAxis.units', arr);
    },

    /**
     * Set YAxis and values to the bytes format
     * @instance
     */
    setToBytes() {
      objects.set(
        self.settings,
        'widgetTemplate.yAxis.labels.formatter',
        highchartsHelper.axisFormatterByteSize(1, true)
      );
      objects.set(
        self.settings,
        'defaultformater',
        highchartsHelper.valueFormatterByteSize()
      );
    },

    /**
     * Set any settings to the widget.
     * For highchart properties use <i>'widgetTemplate'</i> as the base of the path.
     * @param {string} path - Path to the settings.
     * @param {*} val - Value to set.
     * @instance
     */
    setProperty(path, val) {
      objects.set(self.settings, path, val);
    },

    /**
     * Set the rest of series to a new grouped series called _other_.
     * @param {boolean} [bool=false] - Show grouped series.
     * @instance
     */
    setOthers(bool = false) {
      self.settings.others = bool;
    },

    /**
     * Set the number of series to be displayed.
     * @param {number} [num=10] - Number of series.
     * @instance
     */
    setTop(num = 10) {
      self.settings.top = num;
    },

    /**
     * Set the aggrupation for the data to add zeros.
     * @param {string | Function} string - Text with a unit of time of
     * <i>moment.js</i> library or a function that recive a object with
     * <i>from</i> and <i>to</i> key date.
     * @instance
     */
    setGrouping(str = 'days') {
      self.settings.grouping = str;
    },

    /**
     * Set the order type for the series.
     *
     * The following values are supported:
     * - <b>alphabetic</b>
     * - <b>total</b>
     * - Or a function
     * @param {string|Function} val - Text with the order type or a
     * function to order the series.
     * @instance
     */
    setSeriesOrder(val = 'alphabetic') {
      self.settings.seriesOrder = val;
    },

    /**
     * Set the parser function for the values.
     * @param {Function} func - The parser function.
     * @instance
     */
    setValuesParseFunction(func) {
      self.settings.valuesParseFunction = func;
    },

    /**
     * Filter the series by a custom function or using a number
     * to limit the number of series to display.
     * @param {Function|number} func - Callback function or number to filter.
     * the series.
     * @instance
     */
    setSeriesFilter(func = null) {
      self.settings.seriesFilter = func;
    },

    /**
     * Set a custom property available in Highchart for the chart.
     * @param {Object[]} props - Array the properties.
     * @instance
     */
    setSeriesProperties(props) {
      self.settings.seriesProperties = props;
    },

    // Common
    // -------------------------------------------------------------------------

    /**
     * Download in CSV format
     * @ignore
     */
    downloadCSV() {
      let s = self.widget.chart.getCSV();
      downloads.downloadCSV(s, `${self.id}-data`);
    },

    /**
     * Redraw function
     * @ignore
     */
    redraw() {
      if (self.widget) {
        self.widget.chart.reflow();
      }
    },

    /**
     * Resize function
     * @ignore
     */
    resize() {
      this.redraw();
    },

    // Life Cycle
    // -------------------------------------------------------------------------

    /**
     * Render function
     * @param {object} orig - Data for process
     * @ignore
     */
    render(orig) {
      if (!self.el) return; // If not have element not render
      // let cfg = Object.assign({}, defaultSettings, self.settings);
      let cfg = self.settings;

      let data = processStructure(orig, {
        keys: cfg.keyToShow || [],
        values: cfg.valToShow || [],
        seriesNames: cfg.seriesNames || [],
        seriesProperties: cfg.seriesProperties || null,
        forceFirstElement:
          cfg.forceFirstElement == null ? true : cfg.forceFirstElement,
        forceLastElement:
          cfg.forceLastElement == null ? true : cfg.forceLastElement,
        timestampKey: cfg.timestampKey || 'eventdate',
        order: cfg.seriesOrder || null,
        filter: cfg.seriesFilter || null,
        parseFunc: cfg.valuesParseFunction || parseFloat,
        zeroFill: cfg.grouping,
      });

      objects.set(
        cfg,
        'widgetTemplate.chart.renderTo',
        self.el.querySelector('.lt-vapp-widget-graphic')
      );
      for (let item of data) item.name = __(item.name);

      if (data) {
        // Default formatter
        if (!cfg.defaultformater) {
          cfg.defaultformater = highchartsHelper.valueFormatterCount();
        }

        self.widget = new LineWidget(cfg);
        self.widget.setData(data);
        self.widget.display({ force: true, data: true });
      } else {
        this.debugError({
          msg: 'NO DATA',
          console: {
            method: 'error',
            msg: 'No data arrive to render function',
          },
        });
      }
    },
  };
}

export default widgetFactory(mixin);