BuddhaNexus/buddhanexus-frontend

View on GitHub
src/views/visual/visual-view-graph.js

Summary

Maintainability
A
45 mins
Test Coverage
import { customElement, html, LitElement, property } from 'lit-element';

import { getDataForVisual } from '../../api/actions';
import '../utility/LoadingSpinner';
import {
  getGoogleGraphOptions,
  getGoogleGraphOptionsSource,
  getGoogleGraphOptionsTarget,
} from './visualViewUtils';

import { paginateGraphData, graphDataRemoveLowest } from './graphDataUtils';

import styles from './visual-view-graph.styles';

@customElement('visual-view-graph')
export class VisualViewGraph extends LitElement {
  @property({ type: String }) searchItem;
  @property({ type: String }) colorScheme = 'Gradient';
  @property({ type: String }) selectedCollections;
  @property({ type: Function }) setSelection;
  @property({ type: Array }) graphData;
  @property({ type: Array }) setOptions;
  @property({ type: Number }) pageSize = 30;
  @property({ type: Number }) lastPageSize;
  @property({ type: String }) language;
  @property({ type: String }) targetItem;
  @property({ type: Number }) currentPage = 0;
  @property({ type: Number }) totalPages;
  @property({ type: String }) chartHeight;
  @property({ type: String }) fetchLoading;
  @property({ type: String }) fetchError;

  static get styles() {
    return [styles];
  }

  updated(_changedProperties) {
    _changedProperties.forEach((oldValue, propName) => {
      if (
        ['searchItem', 'selectedCollections'].includes(propName) &&
        !this.fetchLoading
      ) {
        this.fetchData();
      }
      if (propName === 'currentPage' && !this.fetchLoading) {
        this.adjustChartHeight();
      }
      if (propName === 'colorScheme') {
        this.changeColorScheme();
      }
    });
  }

  changeColorScheme() {
    switch (this.colorScheme) {
      case 'Inquiry Collection':
        this.setOptions = getGoogleGraphOptionsSource;
        break;
      case 'Hit Collection':
        this.setOptions = getGoogleGraphOptionsTarget;
        break;
      default:
        this.setOptions = getGoogleGraphOptions;
    }
  }

  decreaseCurrentPage() {
    if (this.currentPage > 0) {
      this.currentPage -= 1;
    }
  }

  increaseCurrentPage() {
    if (this.currentPage < this.totalPages - 1) {
      this.currentPage += 1;
    }
  }

  createPageDisplay() {
    if (this.totalPages <= 1) {
      return;
    }
    let pages = [];
    for (let i = 0; i < this.totalPages; i++) {
      let currentClass = 'element';
      if (i == this.currentPage) {
        currentClass += ' active';
      }
      //prettier-ignore
      pages.push(
        html`<span class="${currentClass}" @click="${() => (this.currentPage = i)}">${i + 1}</span>`
      );
    }
    //prettier-ignore
    return html`
      <div id="pages-display">
        <div id="inner-pages">
          <span class="element" @click="${this.decreaseCurrentPage}">«</span>
          ${pages}
          <span class="element" @click="${this.increaseCurrentPage}">»</span>
        </div>
      </div>
    `;
  }

  async fetchData() {
    if (!this.searchItem) {
      this.fetchLoading = false;
      return;
    }
    this.currentPage = 0;
    this.fetchLoading = true;
    this.language = this.searchItem.split('_')[0];
    let searchTerm = this.searchItem
      .split('_')
      .slice(1)
      .join('_');
    let { graphdata, error } = await getDataForVisual({
      searchTerm: searchTerm,
      selected: this.selectedCollections,
      language: this.language,
    });
    let paginatedData = paginateGraphData(graphdata, this.pageSize);
    this.graphData = paginatedData[0];
    this.lastPageSize = paginatedData[1];
    this.graphData = graphDataRemoveLowest(this.graphData);
    this.totalPages = this.graphData.length;
    this.adjustChartHeight();
    this.fetchError = error;
    this.fetchLoading = false;
  }

  adjustChartHeight() {
    this.chartHeight = '84vh';
    if (!this.graphData || !this.graphData[this.currentPage]) {
      return;
    }

    // calculating the number of items on the right and the left of the chart
    let leftPageSize = this.pageSize;
    if (this.currentPage + 1 === this.graphData.length) {
      leftPageSize = this.lastPageSize;
    }
    let rightPageSize = this.graphData[this.currentPage].length / leftPageSize;

    let cutoffFactor = this.language === 'pli' ? this.pageSize : 10;

    // calculating graphheight based on pagesize.
    let factor;
    let windowHeight = window.innerHeight - 200;
    if (rightPageSize > cutoffFactor && rightPageSize >= leftPageSize) {
      factor = (windowHeight * rightPageSize) / cutoffFactor;
    } else if (leftPageSize > cutoffFactor) {
      factor = (windowHeight * leftPageSize) / cutoffFactor;
    } else {
      factor = windowHeight;
    }
    this.chartHeight = factor + 'px';
  }

  // When the chart is clicked, the value of it is checked. If is is on the left side, it opens when we are
  // in collection-view and shows the files underneath. If we already see the files it opens a new window
  // with the text-view for that file.
  selectSubCollection(e) {
    if (!e.detail.chart.getSelection()[0]) {
      return;
    }

    let targetItem = e.detail.chart.getSelection()[0].name;
    if (!targetItem || targetItem.match(/_\(/)) {
      return;
    }
    const selectedTarget = targetItem.match(/ \((.*?)\)/);
    const setSelectionTarget = selectedTarget ? selectedTarget[1] : targetItem;
    if (targetItem === this.targetItem) {
      let win = window.open(
        `../${this.language}/text/${setSelectionTarget}`,
        '_blank'
      );
      win.focus();
      return;
    }
    this.targetItem = targetItem;
    this.setSelection(
      this.language + '_' + setSelectionTarget,
      this.selectedCollections
    );
  }

  render() {
    if (this.fetchLoading) {
      return html`
        <bn-loading-spinner></bn-loading-spinner>
      `;
    }
    if (this.graphData) {
      return html`
        ${this.createPageDisplay()}
        <google-chart
          id="parallels-chart"
          type="sankey"
          .cols="${[
            { label: 'From', type: 'string' },
            { label: 'To', type: 'string' },
            { label: 'Weight', type: 'number' },
          ]}"
          style="height: ${this.chartHeight}; width: 100%"
          .rows="${this.graphData[this.currentPage]}"
          .options="${this.setOptions}"
          @google-chart-select="${this.selectSubCollection}"
        >
        </google-chart>
        ${this.createPageDisplay()}
      `;
    }
  }
}