]> git.openstreetmap.org Git - rails.git/blobdiff - app/assets/javascripts/heatmap.js
Merge remote-tracking branch 'upstream/pull/5863'
[rails.git] / app / assets / javascripts / heatmap.js
index 058f71cfe4b88c05e8f23c27af657ce9ec550b90..831ac4b6e18df2a2b0348741aa61edd671feecb0 100644 (file)
@@ -11,11 +11,13 @@ document.addEventListener("DOMContentLoaded", () => {
     return;
   }
 
+  /** @type {{date: string; max_id: number; total_changes: number}[]} */
   const heatmapData = heatmapElement.dataset.heatmap ? JSON.parse(heatmapElement.dataset.heatmap) : [];
+  const displayName = heatmapElement.dataset.displayName;
   const colorScheme = document.documentElement.getAttribute("data-bs-theme") ?? "auto";
-  const rangeColors = ["#14432a", "#166b34", "#37a446", "#4dd05a"];
+  const rangeColorsDark = ["#14432a", "#4dd05a"];
+  const rangeColorsLight = ["#4dd05a", "#14432a"];
   const startDate = new Date(Date.now() - (365 * 24 * 60 * 60 * 1000));
-  const monthNames = I18n.t("date.abbr_month_names");
 
   const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
 
@@ -33,7 +35,7 @@ document.addEventListener("DOMContentLoaded", () => {
         type: "month",
         gutter: 4,
         label: {
-          text: (timestamp) => monthNames[new Date(timestamp).getMonth() + 1],
+          text: (timestamp) => new Date(timestamp).toLocaleString(OSM.i18n.locale, { timeZone: "UTC", month: "short" }),
           position: "top",
           textAlign: "middle"
         },
@@ -58,9 +60,9 @@ document.addEventListener("DOMContentLoaded", () => {
       },
       scale: {
         color: {
-          type: "threshold",
-          range: currentTheme === "dark" ? rangeColors : Array.from(rangeColors).reverse(),
-          domain: [10, 20, 30, 40]
+          type: "sqrt",
+          range: currentTheme === "dark" ? rangeColorsDark : rangeColorsLight,
+          domain: [0, Math.max(0, ...heatmapData.map(d => d.total_changes))]
         }
       }
     }, [
@@ -68,16 +70,32 @@ document.addEventListener("DOMContentLoaded", () => {
         text: (date, value) => getTooltipText(date, value)
       }]
     ]);
+
+    cal.on("mouseover", (event, timestamp, value) => {
+      if (!displayName || !value) return;
+      if (event.target.parentElement.nodeName === "a") return;
+
+      for (const { date, max_id } of heatmapData) {
+        if (!max_id) continue;
+        if (timestamp !== Date.parse(date)) continue;
+
+        const params = new URLSearchParams({ before: max_id + 1 });
+        const a = document.createElementNS("http://www.w3.org/2000/svg", "a");
+        a.setAttribute("href", `/user/${encodeURIComponent(displayName)}/history?${params}`);
+        $(event.target).wrap(a);
+        break;
+      }
+    });
   }
 
   function getTooltipText(date, value) {
-    const localizedDate = I18n.l("date.formats.long", date);
+    const localizedDate = OSM.i18n.l("date.formats.long", date);
 
     if (value > 0) {
-      return I18n.t("javascripts.heatmap.tooltip.contributions", { count: value, date: localizedDate });
+      return OSM.i18n.t("javascripts.heatmap.tooltip.contributions", { count: value, date: localizedDate });
     }
 
-    return I18n.t("javascripts.heatmap.tooltip.no_contributions", { date: localizedDate });
+    return OSM.i18n.t("javascripts.heatmap.tooltip.no_contributions", { date: localizedDate });
   }
 
   function getTheme() {