PageSourceSearch

https://gv-lastfm-playground.vercel.app/js/animations/LineBubbleChart.anime.js

js gv-lastfm-playground.vercel.app collected 2026-10-03 07:02:49 UTC 5,202 bytes, 198 lines download raw bytes

1import {delay, panChart} from "./settings.anime.js";
2
3export const lineBubbleChartAnimation = (
4  element,
5  slide,
6  animationDirection
7) => {
8  let series = element.querySelectorAll(
9    ".highcharts-bubble-series .highcharts-point"
10  );
11  let chartSeries = Array.from(series);
12  let footer = element.querySelector(".highcharts-axis-labels");
13  let chartRoot = element.querySelector(".highcharts-container");
14  let indicators = document.querySelectorAll(
15    ".line-bubble-chart-container .indicator .mask-wrapper span"
16  );
17
18  // split series into four arrays based on the category
19  let chunkSize = chartSeries.length / 4;
20  let splitSeries = [...Array(Math.ceil(series.length / chunkSize))]
21    .map((_) => chartSeries.splice(0, chunkSize))
22    .reverse();
23
24  let animateInInit = () => {
25    if (!slide.className.includes("stop-animation")) {
26      slide.classList.add("stop-animation");
27    }
28    splitSeries.forEach((series, index) => {
29      // wait for indicator and start at the same time as footer
30      let base = 1734;
31      let delay = () => {
32        switch (index) {
33          case 0:
34            return base + 633;
35          case 1:
36            return base + 467;
37          case 2:
38            return base + 301;
39          case 3:
40            return base + 133;
41        }
42      };
43
44      setTimeout(() => {
45        anime({
46          targets: series,
47          duration: 330,
48          delay: anime.stagger(50),
49          scale: [0, 1],
50          easing: "cubicBezier(0.15,0.00,0.14,1.00)",
51          complete: function () {
52            if (index == 3) {
53              panChart(chartRoot, 919);
54            }
55          },
56        });
57      }, delay());
58    });
59
60    // Indicator Animations
61    anime({
62      targets: indicators,
63      translateY: [10, 0],
64      duration: 667,
65      delay: (target, index, length) => {
66        let base = 1000;
67        let firstIteration = 400;
68        let subsequentIterations = 167;
69        switch (index) {
70          case 0:
71            return base;
72          case 1:
73            return base + firstIteration;
74          case 2:
75            return base + firstIteration + subsequentIterations;
76          case 3:
77            return base + firstIteration + subsequentIterations * 2;
78        }
79      },
80      easing: "cubicBezier(0.17,0.24,0.06,1.00)",
81      begin: () => {
82        // Fade in Indicators
83        // opacity has to be handles seperatly because the delay is different
84        anime({
85          targets: indicators,
86          opacity: [1, 0],
87          duration: 1150,
88          easing: "linear",
89          delay: (target, index, length) => {
90            let base = 1750;
91            switch (index) {
92              case 0:
93                return base + 150;
94              case 1:
95                return base + 317;
96              case 2:
97                return base + 483;
98              case 3:
99                return base + 651;
100            }
101          },
102        });
103      },
104    });
105
106    // Animate the Footer
107    anime({
108      targets: footer,
109      duration: 550,
110      translateY: [25, 0],
111      opacity: [0, 1],
112      delay: 1734,
113      easing: "cubicBezier(0.17,0.24,0.06,1.00)",
114    });
115  };
116
117  let footerAnimation = () => {
118    if (animationDirection === "animateIn") {
119      anime({
120        targets: footer,
121        duration: 383,
122        translateY: [-10, 0],
123        opacity: [0, 1],
124        delay:
125          animationDirection === "animateIn"
126            ? delay + 383 + 38
127            : 38 * (splitSeries[0].length + 1),
128        direction: animationDirection === "animateIn" ? "normal" : "reverse",
129        easing: "cubicBezier(0.84, 0.00, 0.81, 1.00)",
130      });
131    } else {
132      anime({
133        targets: footer,
134        duration: 383,
135        delay: 38,
136        translateY: [0, -20],
137        opacity: [1, 0],
138      });
139    }
140  };
141
142  let tooltipAnimation = () => {
143    if (animationDirection !== "animateIn") {
144      let tooltip = document.querySelector(".line-bubble-chart-tooltip");
145      anime({
146        targets: tooltip,
147        duration: 383,
148        delay: 38,
149        translateY: [0, -20],
150        opacity: [1, 0],
151      });
152    }
153  };
154
155  let seriesAnimation = () => {
156    let animate = (series) => {
157      if (animationDirection === "animateIn") {
158        anime({
159          targets: series,
160          duration: 383,
161          delay: delay + 383,
162          easing: "cubicBezier(0.84, 0.00, 0.81, 1.00)",
163          opacity: [0, 1],
164          translateY: [-10, 0],
165        });
166      } else {
167        anime({
168          targets: series,
169          duration: 383,
170          easing: "cubicBezier(0.84, 0.00, 0.81, 1.00)",
171          opacity: [1, 0],
172          translateY: [0, -300],
173        });
174      }
175    };
176
177    let data =
178      animationDirection === "animateIn" ? splitSeries : splitSeries.reverse();
179
180    data.forEach((series, index) => {
181      let seriesDelay = 38 * index;
182
183      setTimeout(() => {
184        animate(series);
185      }, seriesDelay);
186    });
187  };
188
189  if (!slide.className.includes("stop-animation")) {
190    setTimeout(() => {
191      animateInInit();
192    }, delay);
193  } else {
194    seriesAnimation(animationDirection);
195    footerAnimation(animationDirection);
196    tooltipAnimation(animationDirection);
197  }
198};

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.