charts-8.x-4.x-dev/modules/charts_google/js/charts_google.js

modules/charts_google/js/charts_google.js
/**
 * @file
 * JavaScript integration between Google and Drupal.
 */

/* global google */
(function (Drupal, drupalSettings, once) {
  Drupal.googleCharts = Drupal.googleCharts || { charts: [] };

  /**
   * Behavior to initialize Google Charts.
   *
   * @type {{attach: Drupal.behaviors.chartsGooglecharts.attach}}
   */
  Drupal.behaviors.chartsGooglecharts = {
    attach() {
      // Define a fallback value for globalOptions;
      const globalOptions =
        drupalSettings.charts === undefined
          ? {
              useMaterialDesign: false,
              chartType: 'bar',
            }
          : drupalSettings.charts.google.global_options;
      const useMaterialDesign = globalOptions.useMaterialDesign;
      let chartType = globalOptions.chartType;
      const materialDesignPackages = [
        'bar',
        'line',
        'spline',
        'scatter',
        'column',
      ];
      const packages = ['corechart', 'gauge', 'table'];
      if (
        useMaterialDesign === 'true' &&
        materialDesignPackages.includes(chartType)
      ) {
        if (chartType === 'spline') {
          chartType = 'line';
        }
        if (chartType === 'column') {
          chartType = 'bar';
        }
        packages.push(chartType);
      }
      // Load Google Charts API.
      google.charts.load('current', { packages });

      // Re-draw charts if viewport size has been changed.
      window.addEventListener('resize', function () {
        Drupal.googleCharts.waitForFinalEvent(
          function () {
            // Re-draw Google Charts.
            Drupal.googleCharts.drawCharts();
          },
          200,
          'reload-google-charts',
        );
      });

      // Draw Google Charts.
      Drupal.googleCharts.drawCharts();
    },
  };

  /**
   * Helper function to draw Google Charts.
   */
  Drupal.googleCharts.drawCharts = function () {
    const contents = new Drupal.Charts.Contents();
    once('load-google-charts-item', '.charts-google').forEach(
      function (element) {
        if (element.dataset.hasOwnProperty('chart')) {
          const chartId = element.id;
          const dataAttributes = contents.getData(chartId);
          google.charts.setOnLoadCallback(
            Drupal.googleCharts.drawChart(
              chartId,
              dataAttributes.visualization,
              dataAttributes.data,
              dataAttributes.options,
            ),
          );
          if (
            element.nextElementSibling &&
            element.nextElementSibling.hasAttribute(
              'data-charts-debug-container',
            )
          ) {
            element.nextElementSibling.querySelector('code').innerText =
              JSON.stringify(dataAttributes, null, ' ');
          }
        }
      },
    );
  };

  /**
   * Helper function to draw a Google Chart.
   *
   * @param {string} chartId - Chart Id.
   * @param {string} chartType - Chart Type.
   * @param {string} dataTable - Data.
   * @param {string} googleChartOptions - Options.
   *
   * @return {function} Draw Chart.
   */
  Drupal.googleCharts.drawChart = function (
    chartId,
    chartType,
    dataTable,
    googleChartOptions,
  ) {
    return function () {
      // If we're dealing with a box plot using a LineChart and the data
      // is provided as an array with 6 columns in this order:
      // ['X Value', 'Min', 'First Quartile', 'Median', 'Third Quartile', 'Max'],
      // then transform it into a new table that:
      // 1. Reorders the columns so that the median becomes the primary (non-interval) value.
      // 2. Appends new columns for interval data.
      // The final header will be:
      // [
      //   "X Value",
      //   "Median",
      //   "Min",
      //   "First Quartile",
      //   "Third Quartile",
      //   "Max",
      //   { label: "max", role: "interval", type: "number" },
      //   { label: "min", role: "interval", type: "number" },
      //   { label: "firstQuartile", role: "interval", type: "number" },
      //   { label: "median", role: "interval", type: "number" },
      //   { label: "thirdQuartile", role: "interval", type: "number" }
      // ]
      // And each data row transforms accordingly.
      if (
        chartType === 'LineChart' &&
        Array.isArray(dataTable) &&
        dataTable[0].length === 6
      ) {
        const oldHeader = dataTable[0];
        // Rearrange the header without adding a duplicate column.
        // New header: [ "X Value", "Median", "Min", "First Quartile", "Third Quartile", "Max" ]
        let newHeader = [
          oldHeader[0], // X Value
          oldHeader[3], // Median becomes the primary series
          oldHeader[1], // Min
          oldHeader[2], // First Quartile
          oldHeader[4], // Third Quartile
          oldHeader[5], // Max
        ];
        // Append new columns for interval data.
        newHeader = newHeader.concat([
          { label: 'max', role: 'interval', type: 'number' },
          { label: 'min', role: 'interval', type: 'number' },
          { label: 'firstQuartile', role: 'interval', type: 'number' },
          { label: 'median', role: 'interval', type: 'number' },
          { label: 'thirdQuartile', role: 'interval', type: 'number' },
        ]);
        dataTable[0] = newHeader;
        // Transform each data row.
        // Original row format: [X, Min, First Quartile, Median, Third Quartile, Max]
        // New row format: [X, Median, Min, First Quartile, Third Quartile,
        // Max, max, min, firstQuartile, median, thirdQuartile]
        // Where the interval values are:
        //   max: original index 5,
        //   min: original index 1,
        //   firstQuartile: original index 2,
        //   median: original index 3,
        //   thirdQuartile: original index 4.
        for (let i = 1; i < dataTable.length; i++) {
          const oldRow = dataTable[i];
          let newRow = [
            oldRow[0],
            oldRow[3],
            oldRow[1],
            oldRow[2],
            oldRow[4],
            oldRow[5],
          ];
          newRow = newRow.concat([
            oldRow[5],
            oldRow[1],
            oldRow[2],
            oldRow[3],
            oldRow[4],
          ]);
          dataTable[i] = newRow;
        }
      }
      const data = google.visualization.arrayToDataTable(dataTable);
      const options = googleChartOptions;
      const googleChartTypeFormatted = chartType;

      let visualizationNamespace = 'visualization';
      let visualizationClass = chartType;
      // Replace the 'Spline' chart type with 'Line'.
      if (visualizationClass === 'SplineChart') {
        visualizationClass = 'LineChart';
      }
      if (options.theme === 'material') {
        // Material Design wants to use the 'charts' namespace.
        visualizationNamespace = 'charts';
        // Strip the 'Chart' suffix from the chart type.
        visualizationClass = visualizationClass.replace('Chart', '');
        // Replace the 'Column' chart type with 'Bar'.
        if (visualizationClass === 'Column') {
          visualizationClass = 'Bar';
        }
      }

      let chart;
      switch (googleChartTypeFormatted) {
        case 'BarChart':
        case 'ColumnChart':
        case 'LineChart':
        case 'SplineChart':
        case 'ScatterChart':
          chart = new google[visualizationNamespace][visualizationClass](
            document.getElementById(chartId),
          );
          break;

        case 'DonutChart':
        case 'PieChart':
          chart = new google.visualization.PieChart(
            document.getElementById(chartId),
          );
          break;

        case 'BubbleChart':
          chart = new google.visualization.BubbleChart(
            document.getElementById(chartId),
          );
          break;

        case 'CandlestickChart':
          chart = new google.visualization.CandlestickChart(
            document.getElementById(chartId),
          );
          break;

        case 'AreaChart':
          chart = new google.visualization.AreaChart(
            document.getElementById(chartId),
          );
          break;

        case 'Gauge':
          chart = new google.visualization.Gauge(
            document.getElementById(chartId),
          );
          break;

        case 'ComboChart':
          chart = new google.visualization.ComboChart(
            document.getElementById(chartId),
          );
          break;

        case 'GeoChart':
          chart = new google.visualization.GeoChart(
            document.getElementById(chartId),
          );
          break;

        case 'TableChart':
          chart = new google.visualization.Table(
            document.getElementById(chartId),
          );
      }

      const colorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
      if (options.colors && options.colors.length > 10) {
        Object.keys(options.colors).forEach((i) => {
          if (!colorRegex.test(options.colors[i])) {
            options.colors[i] = '#FFFFFF';
          }
        });
      }

      // Rewrite the colorAxis item to include the colors: key
      if (typeof options.colorAxis !== 'undefined') {
        const colors = options.colorAxis;
        const numColors = colors.length;
        options.colorAxis = colors.splice(numColors);
        options.colorAxis = { colors };
      }
      chart.draw(data, options);
    };
  };

  /**
   * Helper function to run a callback function once when triggering an event
   * multiple times.
   *
   * Example usage:
   * @code
   *  window.addEventListener('resize', function () {
   *    Drupal.googleCharts.waitForFinalEvent(function(){
   *      alert('Resize...');
   *    }, 500, "some unique string");
   *  });
   * @endcode
   */
  Drupal.googleCharts.waitForFinalEvent = (function () {
    const timers = {};
    return function (callback, ms, uniqueId) {
      if (!uniqueId) {
        uniqueId = "Don't call this twice without a uniqueId";
      }
      if (timers[uniqueId]) {
        clearTimeout(timers[uniqueId]);
      }
      timers[uniqueId] = setTimeout(callback, ms);
    };
  })();
})(Drupal, drupalSettings, once);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc