<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">import { Controller } from "@hotwired/stimulus";
import "chartkick"

export default class extends Controller {
  static values = {
    id: String,
    prefix: Object,
    borderColor: String,
    backgroundColor: String,
    submitOnLoad: Boolean
  };

  static targets = ["form", "stat", "startDate", "endDate", "total", "exportLink"];

  connect() {
    if(this.submitOnLoadValue) {
      this.submit();
    }
  }

  dateRangeChanged([startDate, endDate]) {
    this.startDateTarget.value = startDate;
    this.endDateTarget.value = endDate;
    this.submit();
  };

  changeVariant(event) {
    this.statTarget.value = event.currentTarget.value;
    this.submit();
  }

  submit() {
    const exportURL = new URL(this.exportLinkTarget.href);
    exportURL.searchParams.set("stat", this.statTarget.value);
    exportURL.searchParams.set("chart_date_start", this.startDateTarget.value);
    exportURL.searchParams.set("chart_date_end", this.endDateTarget.value);
    this.exportLinkTarget.href = exportURL;

    const data = new FormData(this.formTarget);
    const url = new URL(this.formTarget.action, window.location.href);
    url.search = new URLSearchParams(data).toString();
    fetch(url)
      .then((response) =&gt; response.json())
      .then((json) =&gt; {
        const { grouped, total, min } = json;
        const prefix = this.prefixValue[this.statTarget.value];
        const areaChart = Chartkick.charts[this.idValue];
        this.originalDataLength = grouped.length;

        // Parse the grouped data dates so that we can possibly decimate later
        const parsedData = grouped.map(item =&gt; {
          const [dateStr, value] = item;
          let parts = dateStr.split('-');
          // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
          const timestamp = Date.parse(new Date(parts[0], parts[1]-1, parts[2])); // Note: months are 0-based
          return [timestamp, value];
        });

        // Initialize the canvas
        areaChart.updateData(parsedData, {
          dataset: {
            borderColor: this.borderColorValue,
            cubicInterpolationMode: "monotone",
            tension: 0.99,
          },
          library: {
            maintainAspectRatio: false,
            elements: {
              point: {
                pointStyle: false,
              },
              line: {
                borderCapStyle: "round",
              },
            },
            parsing: parsedData.length &gt; 31 ? false : true,
            plugins: {
              decimation: {
                enabled: parsedData.length &gt; 31,
                algorithm: "lttb",
                samples: 31,
                threshold: 31,
              },
              tooltip: {
                callbacks: {
                  title: (context) =&gt; {
                    const timestamp = context[0].raw.x;
                    return new Date(timestamp).toLocaleDateString("en-US", { day: "numeric", month: "short", year: "numeric" })
                  },
                  label: (context) =&gt; {
                    return prefix + context.formattedValue
                  }
                }
              }
            },
            scales: {
              x: {
                border: {
                  display: false,
                },
                grid: {
                  tickColor: "transparent",
                  tickLength: 16,
                },
                ticks: {
                  align: "inner",
                  callback: (value) =&gt; {
                    if (parsedData.length &gt; 90) {
                      return new Date(value).toLocaleDateString("en-GB", { month: "short", year: "numeric" })
                    } else {
                      return new Date(value).toLocaleDateString("en-GB", { day: "numeric", month: "short" })
                    }
                  },
                },
                type: "time",
              },
              y: {
                min: min,
                afterDataLimits: (scale) =&gt; {
                  this.yScaleMax = scale.end;
                },
                border: {
                  dash: [5, 5],
                  display: false,
                },
                grid: {
                  color: "#F0F0F2",
                  tickColor: "transparent",
                },
                ticks: {
                  callback: (value) =&gt; {
                    return prefix + value.toLocaleString();
                  },
                },
              }
            },
            onResize: (chart, size) =&gt; {
              const chartContainer = this.element.querySelector(`#${this.idValue}`);
              chart.canvas.style.height = 0;
              chartContainer.style.height = 0;
              let adjustedHeight = chartContainer.parentElement.offsetHeight - 99;
              if (adjustedHeight &lt; 300) adjustedHeight = 300;
              chart.canvas.style.height = `${adjustedHeight}px`;
              chartContainer.style.height = `${adjustedHeight}px`;
              this.setMaxTicksLimitX(chart, size.width);
              chart.update();
            },
          },
        });
        // Settings that depend on initialization
        const chartObject = areaChart.chart;
        const yValues = grouped.map(dataPoint =&gt; dataPoint[1]);
        const yScaleCoverage = (Math.max(...yValues) / this.yScaleMax) || 1;
        const gradient = chartObject.ctx.createLinearGradient(0, 0, 0, chartObject.chartArea.height / yScaleCoverage);
        const backgroundColor = this.backgroundColorValue;
        gradient.addColorStop(0.2, `rgba(${backgroundColor}, 0.20)`);
        gradient.addColorStop(0.5, `rgba(${backgroundColor}, 0.10)`);
        gradient.addColorStop(0.7, `rgba(${backgroundColor}, 0.04)`);
        gradient.addColorStop(1.0, `rgba(${backgroundColor}, 0.0)`);
        chartObject.data.datasets[0].backgroundColor = gradient;
        chartObject.update();

        if (isNaN(Number(total))) {
          this.totalTarget.innerHTML = total;
        }
        else {
          this.totalTarget.innerHTML = Number(total).toLocaleString();
        }
        chartObject.canvas.classList.add("!w-full");
      });
  }

  setMaxTicksLimitX(chart, width) {
    if (width &lt; 640) {
      chart.options.scales.x.ticks.maxTicksLimit = 3;
    }
    else {
      chart.options.scales.x.ticks.maxTicksLimit = this.originalDataLength &gt; 90 ? 5 : 8;
    }
  }
}
</pre></body></html>