wr-history-graph

Show graph for Mario Kart WR History

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name            wr-history-graph
// @namespace       npm/vite-plugin-monkey
// @version         0.0.4
// @author          monkey
// @description:en  Show graph of Mario Kart WR History
// @description:ja  マリオカートのWR Historyのグラフを表示します
// @license         MIT
// @icon            https://vitejs.dev/logo.svg
// @match           https://mkwrs.com/*
// @require         https://cdnjs.cloudflare.com/ajax/libs/apexcharts/4.3.0/apexcharts.min.js
// @description Show graph for Mario Kart WR History
// ==/UserScript==

(function () {
  'use strict';

  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  const toMilliseconds = (time) => {
    const regex = /(?:([\d]+)')?([\d]+)"([\d]+)/;
    const match = time.match(regex);
    if (!match) {
      return null;
    }
    const minutes = match[1] ? parseInt(match[1], 10) : 0;
    const seconds = parseInt(match[2], 10);
    const milliseconds = match[3].length === 3 ? parseInt(match[3], 10) : parseInt(match[3], 10) * 10;
    return minutes * 6e4 + seconds * 1e3 + milliseconds;
  };
  const toDateTime = (date) => {
    const dateTime = new Date(date).getTime();
    if (isNaN(dateTime)) {
      return null;
    }
    return dateTime;
  };
  class History {
    constructor(seriesName) {
      __publicField(this, "config");
      __publicField(this, "getTableData", () => {
        var _a;
        const rowIndexes = this.config.rowIndexes;
        const h2Elements = document.querySelectorAll("h2");
        let targetH2 = null;
        for (const h2 of Array.from(h2Elements)) {
          const h2Text = ((_a = h2.textContent) == null ? undefined : _a.trim()) ?? "";
          if (h2Text.includes("History") && !h2Text.includes("Graph")) {
            targetH2 = h2;
            break;
          }
        }
        if (!targetH2) {
          return [];
        }
        let nextElem = targetH2.nextElementSibling;
        if (!nextElem || !(nextElem instanceof HTMLTableElement)) {
          return [];
        }
        const tableData = [];
        const rows = nextElem.querySelectorAll("tr");
        rows.forEach((tr) => {
          const cells = tr.querySelectorAll("td");
          const rowData = Array.from(cells).map((td, index) => {
            var _a2, _b;
            if (index !== rowIndexes[3]) {
              return ((_a2 = td.textContent) == null ? undefined : _a2.trim()) ?? "";
            }
            return ((_b = td.querySelector("img")) == null ? undefined : _b.src) ?? "";
          });
          if (rowData.length === 0) {
            return;
          }
          const dateTime = toDateTime(rowData[rowIndexes[0]]);
          if (dateTime === null) {
            return;
          }
          tableData.push([
            dateTime,
            toMilliseconds(rowData[rowIndexes[1]]),
            rowData[rowIndexes[2]],
            rowData[rowIndexes[3]],
            rowData[rowIndexes[4]]
          ]);
        });
        tableData.push([
          (/* @__PURE__ */ new Date()).getTime(),
          tableData.at(-1)[1],
          tableData.at(-1)[2],
          tableData.at(-1)[3],
          tableData.at(-1)[4]
        ]);
        return tableData;
      });
      __publicField(this, "insertChartDiv", () => {
        var _a;
        const mainElement = document.querySelector("#main");
        if (!mainElement) {
          return null;
        }
        const h2Elements = document.querySelectorAll("h2");
        let targetH2 = null;
        for (const h2 of Array.from(h2Elements)) {
          if ((((_a = h2.textContent) == null ? undefined : _a.trim()) ?? "").endsWith(":")) {
            targetH2 = h2;
            break;
          }
        }
        if (!targetH2) {
          return null;
        }
        const chartTitle = document.createElement("h2");
        chartTitle.textContent = "WR History Graph";
        mainElement.insertBefore(chartTitle, targetH2);
        const chartDiv = document.createElement("div");
        chartDiv.id = "chart";
        mainElement.insertBefore(chartDiv, targetH2);
        return chartDiv;
      });
      let rowIndexes;
      switch (seriesName) {
        case "mkwii":
          rowIndexes = [0, 1, 2, 4, 11];
          break;
        case "mk64":
          rowIndexes = [0, 1, 3, 4, 6];
          break;
        default:
          rowIndexes = [0, 1, 2, 3, 4];
          break;
      }
      this.config = {
        rowIndexes
      };
    }
  }
  let ApexChartsLocal;
  const millisecondsToString = (value) => {
    const milliseconds = value % 1e3;
    const seconds = Math.floor(value / 1e3 % 60);
    const minutes = Math.floor(value / 6e4 % 60);
    return `${minutes}'${String(seconds).padStart(2, "0")}"${String(
    milliseconds.toFixed(0)
  ).padStart(3, "0")}`;
  };
  const getHistory = () => {
    const url = window.location.href;
    const seriesName = url.split("/")[3];
    return new History(seriesName);
  };
  const drawChart = (data) => {
    const options = {
      chart: {
        type: "line",
        height: 400,
        width: "90%",
        zoom: {
          enabled: true,
          type: "x",
          autoScaleYaxis: true
        }
      },
      markers: {
        size: 5
      },
      stroke: {
        curve: "stepline"
      },
      series: [
        {
          name: "history",
          data: data.map((d) => ({
            x: d[0],
            y: d[1],
            player: d[2],
            nation: d[3],
            duration: d[4]
          }))
        }
      ],
      tooltip: {
        custom: function({ seriesIndex, dataPointIndex, w }) {
          const data2 = w.globals.initialSeries[seriesIndex].data[dataPointIndex];
          const date = new Date(data2.x).toLocaleDateString();
          const time = data2.y;
          const player = data2.player;
          const nation = data2.nation;
          const duration = data2.duration;
          return `
          <div style="padding:10px; top:1000px">
            <strong>Date:</strong> ${date}<br/>
            <strong>Time:</strong> ${millisecondsToString(time)}<br/>
            <strong>Player:</strong> ${player}<br/>
            <strong>Nation:</strong> <img src="${nation}"><br/>
            <strong>Duration:</strong> ${duration}
          </div>
        `;
        },
        followCursor: true
      },
      xaxis: {
        type: "datetime",
        tooltip: {
          enabled: false
        }
      },
      yaxis: {
        title: {
          text: "Time"
        },
        labels: {
          formatter: millisecondsToString
        }
      },
      grid: {
        xaxis: {
          lines: {
            show: true
          }
        }
      }
    };
    const chart = new ApexChartsLocal(document.querySelector("#chart"), options);
    chart.render();
  };
  const main = () => {
    const history = getHistory();
    const chartDiv = history.insertChartDiv();
    if (!chartDiv) {
      return;
    }
    const tableData = history.getTableData();
    drawChart(tableData);
  };
  {
    ApexChartsLocal = ApexCharts;
    main();
  }

})();