controllers/dashboard/data_visualisation_controller.js

import { Controller } from "@hotwired/stimulus"
import { debounce } from "debounce"
import { subscription } from "~/javascripts/store/mixins/subscription"
import LineChart from "~/javascripts/dashboard/LineChart"

/**
 * @class Dashboard.DataVisualisationController
 * @classdesc Stimulus controller that handles the line chart data visualisation.
 * @extends Controller
 **/
export default class extends Controller {
  static targets = [ "loading", "visualisation" ]
  static values = {
    date: String,
    storeId: String,
    timeFormat: String,
    xAxis: String,
    yAxis: String
  }

  /** 
   * Subscribe to the store. Debounces the method for handling window resizes
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  connect() {
    subscription(this)
    this.subscribe()
    this.editStore("frameLoaded", true)
    this.reconnect()
    this.resize = debounce(this.resize, 250).bind(this)
  }

  /** 
   * Handles a repeated Turbo visit to the dashboard page.
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  reconnect() {
    if (this.store("selectedContextData")) {
      this.storeUpdated("selectedContextData", this.storeIdValue)
    }
  }

  /** 
   * Checks if the visualisation has been created yet
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  isDataVizEmpty() {
    return document.querySelector("[data-viz='wrapper']").getElementsByTagName("svg").length === 0
  }

  /** 
   * Creates a new instance of the LineChart class if not created, otherwise returns the instance of
   * the class
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  lineChart() {
    if (this._lineChart === undefined) {
      this._windowWidth = window.innerWidth
      this._lineChart = new LineChart(
        this.store("selectedContextData"),
        this.store("contextSelected"),
        this.yAxisValue,
        this.xAxisValue,
        this.dateValue,
        this.timeFormatValue,
        "[data-viz='wrapper']",
        "[data-viz='tooltip']"
      )
    }
    return this._lineChart
  }

  /** 
   * Handles a resize of the screen by width but ignores height changes. Deletes the current
   * visualisation and the instance of the LineChart class so it will be created from scratch again.
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  resize() {
    if (window.innerWidth === this._windowWidth) return

    this._windowWidth = window.innerWidth
    this._lineChart = undefined
    const wrapper = document.querySelector("[data-viz='wrapper']")
    wrapper.removeChild(wrapper.lastChild)
    this.lineChart().createDataVis()
  }

  /** 
   * When the context is selected the data visualisation will either be creted or updated
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  storeUpdated(prop, storeId) {
    if (this.store("fetchingDataVizData")) {
      this.loadingTarget.style.display = "block"
      this.visualisationTarget.style.display = "none"
    } else {
      if (prop !== "selectedContextData" && storeId === this.storeIdValue) return

      this.loadingTarget.style.display = "none"
      this.visualisationTarget.style.display = "block"
      if(this.isDataVizEmpty()) {
        this.lineChart().createDataVis()
      } else {
        this.lineChart().updateDataVis(this.store("selectedContextData"), this.store("contextSelected"))
      }
    }
  }

  /** 
   * Unsubscribe from the store
   * 
   * @instance
   * @memberof Dashboard.DataVisualisationController
   **/
  disconnect() {
    this.unsubscribe()
  }
}