PageSourceSearch

https://gv-lastfm-playground.vercel.app/js/charts/JoyDivision.js

js gv-lastfm-playground.vercel.app collected 2026-10-03 07:02:37 UTC 6,396 bytes, 270 lines download raw bytes

1var hoursEachWeek = dummyData["weekly_listening_clock"]
2  ? dummyData["weekly_listening_clock"]["hours_each_week"]
3  : null;
4
5let weekIndicator = `
6  <div class="indicator-container">
7    <span id="joy-division-first-week-label">Week 1</span>
8    <span id="joy-division-indicator">0</span>
9  <div>
10  `;
11
12let generateChartHTML = () => {
13  let lines = hoursEachWeek.map((item, index) => {
14    return `
15      <tr>
16        <td class="joy-division-sparkline" data-sparkline="${item.join(", ")}"/>
17      </tr>
18      `;
19  });
20
21  return lines;
22};
23
24// Add all listening hours from every week together
25let sumForEveryHour = hoursEachWeek[0].map((item, index) =>
26  hoursEachWeek.reduce((sum, curr) => sum + curr[index], 0)
27);
28let hourOfDayMostListendTo = sumForEveryHour.indexOf(
29  Math.max(...sumForEveryHour)
30);
31
32if (hoursEachWeek) {
33  let elements = document.querySelectorAll("#joy-division-hour-of-day");
34  elements.forEach((element) => {
35    element.innerHTML = calcTimeOfDay(hourOfDayMostListendTo);
36  });
37
38  let items = weekIndicator + generateChartHTML().join("");
39  document.getElementById("tbody-sparkline").innerHTML = items;
40}
41
42let renderChart = () => {
43  Highcharts.SparkLine = function (a, b, c) {
44    const hasRenderToArg = typeof a === "string" || a.nodeName;
45    let options = arguments[hasRenderToArg ? 1 : 0];
46
47    const defaultOptions = {
48      chart: {
49        type: "area",
50        renderTo:
51          (options.chart && options.chart.renderTo) || (hasRenderToArg && a),
52        backgroundColor: null,
53        borderWidth: 0,
54        width: 233,
55        margin: [0, 0, 0, 0],
56        height: 18,
57        style: {
58          overflow: "visible",
59        },
60        // Saves some render time for every item
61        skipClone: true,
62      },
63
64      title: {
65        text: null,
66      },
67
68      credits: {
69        enabled: false,
70      },
71
72      xAxis: {
73        endOnTick: true,
74        startOnTick: true,
75        labels: {
76          enabled: false,
77        },
78        title: {
79          text: null,
80        },
81        tickPositions: [1, 7, 13, 19, 24],
82      },
83
84      yAxis: {
85        endOnTick: false,
86        startOnTick: false,
87        labels: {
88          enabled: false,
89        },
90        title: {
91          text: null,
92        },
93      },
94      legend: {
95        enabled: false,
96      },
97      tooltip: {
98        hideDelay: 0,
99        outside: true,
100        shared: true,
101      },
102      plotOptions: {
103        series: {
104          fillColor: "#000",
105          cursor: "pointer",
106          animation: false,
107          lineWidth: 1,
108          color: "transparent",
109          connectNulls: true,
110          label: {
111            enabled: false,
112          },
113          marker: {
114            enabled: false,
115            states: {
116              hover: {
117                enabled: true,
118                radius: 4,
119              },
120            },
121          },
122          fillOpacity: 0,
123        },
124      },
125    };
126
127    options = Highcharts.merge(defaultOptions, options);
128
129    return hasRenderToArg
130      ? new Highcharts.Chart(a, options, c)
131      : new Highcharts.Chart(options, b);
132  };
133
134  let tds = Array.from(document.querySelectorAll("td[data-sparkline]"));
135  tds.forEach((td, i) => {
136    const stringData = td.dataset.sparkline;
137    const arr = stringData.split("; ");
138    const data = arr[0].split(", ").map(parseFloat);
139    const chart = {};
140    if (arr[1]) {
141      chart.type = arr[1];
142    }
143    Highcharts.SparkLine(td, {
144      chart: {
145        style: {
146          overflow: "visible",
147        },
148      },
149      series: [
150        {
151          data: data,
152          pointStart: 1,
153          point: {
154            events: {
155              mouseOver() {
156                tds.forEach((item, index) => {
157                  i !== index ? item.classList.add("opaque") : null;
158                });
159              },
160              mouseOut() {
161                tds.forEach((item) => {
162                  item.classList.remove("opaque");
163                });
164              },
165            },
166          },
167        },
168      ],
169      yAxis: {
170        gridLineWidth: 0,
171        minorGridLineWidth: 0,
172      },
173      tooltip: {
174        backgroundColor: null,
175        shadow: null,
176        style: {
177          color: "#FAFAFA",
178        },
179        pointFormatter: function () {
180          let point = this;
181
182          return `<span>
182Week ${i + 1}, ${calcTimeOfDay(
183            point.category - 1
184          )} </span><br/><b>${point.y} Scrobbles </b>`;
185        },
186        headerFormat: null,
187      },
188      chart: chart,
189    });
190  });
191
192  let doChunk = () => {
193    const time = +new Date(),
194      len = tds.length;
195
196    for (let i = 0; i < len; i += 1) {
197      const td = tds[i];
198      const stringdata = td.dataset.sparkline;
199      const arr = stringdata.split("; ");
200      const data = arr[0].split(", ").map(parseFloat);
201      const chart = {};
202
203      if (arr[1]) {
204        chart.type = arr[1];
205      }
206
207      Highcharts.SparkLine(td, {
208        chart: {
209          style: {
210            overflow: "visible",
211          },
212        },
213        series: [
214          {
215            data: data,
216            pointStart: 1,
217            point: {
218              events: {
219                mouseOver() {
220                  tds.forEach((item, index) => {
221                    i !== index ? item.classList.add("opaque") : null;
222                  });
223                },
224                mouseOut() {
225                  tds.forEach((item) => {
226                    item.classList.remove("opaque");
227                  });
228                },
229              },
230            },
231          },
232        ],
233        yAxis: {
234          gridLineWidth: 0,
235          minorGridLineWidth: 0,
236        },
237        tooltip: {
238          backgroundColor: null,
239          shadow: null,
240          style: {
241            color: "#FAFAFA",
242          },
243          pointFormatter: () => {
244            let point = this;
245
246            return `<span>Week ${i + 1}, ${calcTimeOfDay(
247              point.category - 1
248            )} </span><br/><b>${point.y} Scrobbles </b>`;
249          },
250          headerFormat: null,
251        },
252        chart: chart,
253      });
254
255      n += 1;
256
257      // If the process takes too much time, run a timeout
258      // to allow interaction with the browser
259      if (new Date() - time > 500) {
260        tds.splice(0, i + 1);
261        setTimeout(doChunk, 0);
262        break;
263      }
264    }
265  };
266};
267
268export const renderJoyDivision = () => {
269  renderChart();
270};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.