thinkwee commited on
Commit
7247a32
·
1 Parent(s): 845705b

update animation

Browse files
Files changed (4) hide show
  1. benchmarking.js +23 -1
  2. charts.js +77 -20
  3. index.html +38 -7
  4. styles.css +51 -0
benchmarking.js CHANGED
@@ -5,9 +5,31 @@ document.addEventListener('DOMContentLoaded', function () {
5
  return;
6
  }
7
 
8
- renderBenchmarkingChart();
9
  });
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  function renderBenchmarkingChart() {
12
  const container = document.getElementById('benchmarking-chart');
13
  if (!container) return;
 
5
  return;
6
  }
7
 
8
+ initBenchmarkingChart();
9
  });
10
 
11
+ function initBenchmarkingChart() {
12
+ const container = document.getElementById('benchmarking-chart');
13
+ if (!container) return;
14
+
15
+ // Use Intersection Observer to trigger animation when chart comes into view
16
+ let hasAnimated = false;
17
+
18
+ const observer = new IntersectionObserver((entries) => {
19
+ entries.forEach(entry => {
20
+ if (entry.isIntersecting && !hasAnimated) {
21
+ hasAnimated = true;
22
+ renderBenchmarkingChart();
23
+ observer.disconnect(); // Stop observing after animation starts
24
+ }
25
+ });
26
+ }, {
27
+ threshold: 0.2 // Trigger when 20% of the chart is visible
28
+ });
29
+
30
+ observer.observe(container);
31
+ }
32
+
33
  function renderBenchmarkingChart() {
34
  const container = document.getElementById('benchmarking-chart');
35
  if (!container) return;
charts.js CHANGED
@@ -106,8 +106,8 @@ const lazyLoadObserver = new IntersectionObserver((entries) => {
106
  }
107
  });
108
  }, {
109
- rootMargin: '100px 0px', // Start loading 100px before entering viewport
110
- threshold: 0.01
111
  });
112
 
113
  // Debounce utility for hover effects
@@ -252,15 +252,16 @@ function initScalingCharts() {
252
  const modelNormX = normTurns.slice(offset, offset + len);
253
  offset += len;
254
 
 
255
  traces.push({
256
  x: modelNormX,
257
  y: data[model].accuracy,
258
- mode: 'lines+markers',
259
- name: model, // CRITICAL: Set model name for legend
260
  line: { color: DDR_DATA.modelColors[model] || '#888', width: 2 },
261
  marker: { size: 6, color: DDR_DATA.modelColors[model] || '#888' },
262
  hovertemplate: `<b>${model}</b><br>Turn: %{customdata}<br>Accuracy: %{y:.2f}%<extra></extra>`,
263
- customdata: data[model].turns // Store real values for hover
264
  });
265
  });
266
 
@@ -273,9 +274,9 @@ function initScalingCharts() {
273
  ...darkLayout,
274
  xaxis: {
275
  ...darkLayout.xaxis,
276
- title: { text: 'Number of Interaction Turns', font: { size: 15, color: '#1d1d1f' } }, // Explicit larger font
277
- type: 'linear', // ALWAYS LINEAR
278
- range: [-0.05, 1.05], // FIXED RANGE
279
  tickmode: 'array',
280
  tickvals: tickVals,
281
  ticktext: tickText,
@@ -283,14 +284,20 @@ function initScalingCharts() {
283
  },
284
  yaxis: {
285
  ...darkLayout.yaxis,
286
- title: { text: 'Accuracy (%)', font: { size: 15, color: '#1d1d1f' } }, // Explicit larger font
287
  dtick: dtickVal,
288
  range: yRange
289
  },
290
- showlegend: false // Use shared legend instead
291
  };
292
 
293
- Plotly.newPlot(`scaling-${scenario}`, traces, layout, plotlyConfig);
 
 
 
 
 
 
294
  });
295
 
296
  // Populate shared legend with models from first scenario
@@ -301,7 +308,64 @@ function initScalingCharts() {
301
  }
302
 
303
  // Apply hover effects after charts are rendered
304
- setTimeout(() => applyHoverEffectsForSection('scaling'), 100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
306
 
307
  function updateScalingCharts(dimension) {
@@ -1228,18 +1292,11 @@ function renderEntropyCharts(scenario) {
1228
  // ============================================================================
1229
  document.addEventListener('DOMContentLoaded', () => {
1230
  // Register all sections for lazy loading
 
1231
  const sections = document.querySelectorAll('section.section');
1232
  sections.forEach(section => {
1233
  lazyLoadObserver.observe(section);
1234
  });
1235
-
1236
- // Immediately initialize the first visible section (scaling) for instant feedback
1237
- // Other sections will be lazy-loaded as user scrolls
1238
- if (document.getElementById('scaling')) {
1239
- initializedCharts.add('scaling');
1240
- // Use setTimeout to not block the main thread
1241
- setTimeout(() => initScalingCharts(), 0);
1242
- }
1243
  });
1244
 
1245
  // Handle window resize with longer debounce for better performance
 
106
  }
107
  });
108
  }, {
109
+ rootMargin: '0px 0px', // Start exactly when entering viewport
110
+ threshold: 0.15 // Trigger when 15% visible
111
  });
112
 
113
  // Debounce utility for hover effects
 
252
  const modelNormX = normTurns.slice(offset, offset + len);
253
  offset += len;
254
 
255
+ // Start with markers only (lines will be animated in)
256
  traces.push({
257
  x: modelNormX,
258
  y: data[model].accuracy,
259
+ mode: 'markers', // Start with markers only
260
+ name: model,
261
  line: { color: DDR_DATA.modelColors[model] || '#888', width: 2 },
262
  marker: { size: 6, color: DDR_DATA.modelColors[model] || '#888' },
263
  hovertemplate: `<b>${model}</b><br>Turn: %{customdata}<br>Accuracy: %{y:.2f}%<extra></extra>`,
264
+ customdata: data[model].turns
265
  });
266
  });
267
 
 
274
  ...darkLayout,
275
  xaxis: {
276
  ...darkLayout.xaxis,
277
+ title: { text: 'Number of Interaction Turns', font: { size: 15, color: '#1d1d1f' } },
278
+ type: 'linear',
279
+ range: [-0.05, 1.05],
280
  tickmode: 'array',
281
  tickvals: tickVals,
282
  ticktext: tickText,
 
284
  },
285
  yaxis: {
286
  ...darkLayout.yaxis,
287
+ title: { text: 'Accuracy (%)', font: { size: 15, color: '#1d1d1f' } },
288
  dtick: dtickVal,
289
  range: yRange
290
  },
291
+ showlegend: false
292
  };
293
 
294
+ // Create chart with markers only first
295
+ Plotly.newPlot(`scaling-${scenario}`, traces, layout, plotlyConfig).then(() => {
296
+ // After a short delay, animate in the lines
297
+ setTimeout(() => {
298
+ animateScalingLinesIn(`scaling-${scenario}`, models, data, normTurns);
299
+ }, 300);
300
+ });
301
  });
302
 
303
  // Populate shared legend with models from first scenario
 
308
  }
309
 
310
  // Apply hover effects after charts are rendered
311
+ setTimeout(() => applyHoverEffectsForSection('scaling'), 500);
312
+ }
313
+
314
+ // Animate lines drawing in for scaling charts
315
+ function animateScalingLinesIn(containerId, models, data, normTurns) {
316
+ const graphDiv = document.getElementById(containerId);
317
+ if (!graphDiv) return;
318
+
319
+ // Update to show lines+markers
320
+ let offset = 0;
321
+ const tracesWithLines = models.map(model => {
322
+ const len = data[model].turns.length;
323
+ const modelNormX = normTurns.slice(offset, offset + len);
324
+ offset += len;
325
+
326
+ return {
327
+ x: modelNormX,
328
+ y: data[model].accuracy,
329
+ mode: 'lines+markers',
330
+ name: model,
331
+ line: { color: DDR_DATA.modelColors[model] || '#888', width: 2 },
332
+ marker: { size: 6, color: DDR_DATA.modelColors[model] || '#888' },
333
+ hovertemplate: `<b>${model}</b><br>Turn: %{customdata}<br>Accuracy: %{y:.2f}%<extra></extra>`,
334
+ customdata: data[model].turns
335
+ };
336
+ });
337
+
338
+ // First, add lines with opacity 0
339
+ Plotly.react(containerId, tracesWithLines, graphDiv.layout, plotlyConfig).then(() => {
340
+ // Get all line paths
341
+ const paths = graphDiv.querySelectorAll('.scatterlayer .trace .lines path');
342
+
343
+ // Set initial state: lines hidden via stroke-dashoffset
344
+ paths.forEach((path) => {
345
+ const len = path.getTotalLength();
346
+ if (len > 0) {
347
+ path.style.transition = 'none';
348
+ path.style.strokeDasharray = len + ' ' + len;
349
+ path.style.strokeDashoffset = len;
350
+ }
351
+ });
352
+
353
+ // Force reflow
354
+ graphDiv.getBoundingClientRect();
355
+
356
+ // Animate the lines drawing in with staggered delay
357
+ requestAnimationFrame(() => {
358
+ paths.forEach((path, index) => {
359
+ const len = path.getTotalLength();
360
+ if (len > 0) {
361
+ // Stagger the animation for each line
362
+ const delay = index * 80; // 80ms delay between each line
363
+ path.style.transition = `stroke-dashoffset 0.8s ease-out ${delay}ms`;
364
+ path.style.strokeDashoffset = '0';
365
+ }
366
+ });
367
+ });
368
+ });
369
  }
370
 
371
  function updateScalingCharts(dimension) {
 
1292
  // ============================================================================
1293
  document.addEventListener('DOMContentLoaded', () => {
1294
  // Register all sections for lazy loading
1295
+ // Charts will only be initialized when they become visible
1296
  const sections = document.querySelectorAll('section.section');
1297
  sections.forEach(section => {
1298
  lazyLoadObserver.observe(section);
1299
  });
 
 
 
 
 
 
 
 
1300
  });
1301
 
1302
  // Handle window resize with longer debounce for better performance
index.html CHANGED
@@ -137,8 +137,12 @@
137
  </div>
138
  <div class="framework-grid">
139
  <div class="framework-card">
140
- <img src="assets/framework_task.png" alt="Task Formulation Framework"
141
- style="border-radius: var(--radius-md);">
 
 
 
 
142
  <h3>Task Formulation</h3>
143
  <p class="framework-description">A case of Claude Sonnet 4.5's trajectory and evaluation checklist
144
  in the MIMIC scenario of DDR-Bench. Verified fact and supporting insights are
@@ -147,8 +151,12 @@
147
  </p>
148
  </div>
149
  <div class="framework-card">
150
- <img src="assets/framework_pipeline.png" alt="Evaluation Pipeline Framework"
151
- style="border-radius: var(--radius-md);">
 
 
 
 
152
  <h3>Evaluation Pipeline</h3>
153
  <p class="framework-description"><b>Left</b>: Compared with previous tasks, <i>DDR</i> maximises
154
  exploration openness and agency, focusing on the direct evaluation of insight quality.
@@ -597,6 +605,7 @@
597
  const cards = Array.from(track.querySelectorAll('.carousel-card'));
598
  const cardCount = cards.length;
599
  let currentIndex = 0;
 
600
 
601
  // Create dots
602
  for (let i = 0; i < cardCount; i++) {
@@ -689,12 +698,34 @@
689
  const carouselWrapper = document.querySelector('.carousel-wrapper');
690
  if (carouselWrapper) {
691
  carouselWrapper.addEventListener('mouseenter', stopAutoPlay);
692
- carouselWrapper.addEventListener('mouseleave', startAutoPlay);
 
 
693
  }
694
 
695
- // Initialize
696
  updateCarousel();
697
- startAutoPlay();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
698
  });
699
  </script>
700
 
 
137
  </div>
138
  <div class="framework-grid">
139
  <div class="framework-card">
140
+ <div class="framework-img-wrapper">
141
+ <div class="skeleton-loader"></div>
142
+ <img src="assets/framework_task.png" alt="Task Formulation Framework" class="framework-img"
143
+ loading="lazy"
144
+ onload="this.classList.add('loaded'); this.previousElementSibling.style.display='none';">
145
+ </div>
146
  <h3>Task Formulation</h3>
147
  <p class="framework-description">A case of Claude Sonnet 4.5's trajectory and evaluation checklist
148
  in the MIMIC scenario of DDR-Bench. Verified fact and supporting insights are
 
151
  </p>
152
  </div>
153
  <div class="framework-card">
154
+ <div class="framework-img-wrapper">
155
+ <div class="skeleton-loader"></div>
156
+ <img src="assets/framework_pipeline.png" alt="Evaluation Pipeline Framework"
157
+ class="framework-img" loading="lazy"
158
+ onload="this.classList.add('loaded'); this.previousElementSibling.style.display='none';">
159
+ </div>
160
  <h3>Evaluation Pipeline</h3>
161
  <p class="framework-description"><b>Left</b>: Compared with previous tasks, <i>DDR</i> maximises
162
  exploration openness and agency, focusing on the direct evaluation of insight quality.
 
605
  const cards = Array.from(track.querySelectorAll('.carousel-card'));
606
  const cardCount = cards.length;
607
  let currentIndex = 0;
608
+ let hasStartedAutoPlay = false;
609
 
610
  // Create dots
611
  for (let i = 0; i < cardCount; i++) {
 
698
  const carouselWrapper = document.querySelector('.carousel-wrapper');
699
  if (carouselWrapper) {
700
  carouselWrapper.addEventListener('mouseenter', stopAutoPlay);
701
+ carouselWrapper.addEventListener('mouseleave', () => {
702
+ if (hasStartedAutoPlay) startAutoPlay();
703
+ });
704
  }
705
 
706
+ // Initialize carousel position (but don't auto-play yet)
707
  updateCarousel();
708
+
709
+ // Use Intersection Observer to start auto-play only when visible
710
+ const resultsSection = document.getElementById('results');
711
+ if (resultsSection) {
712
+ const carouselObserver = new IntersectionObserver((entries) => {
713
+ entries.forEach(entry => {
714
+ if (entry.isIntersecting) {
715
+ if (!hasStartedAutoPlay) {
716
+ hasStartedAutoPlay = true;
717
+ }
718
+ startAutoPlay();
719
+ } else {
720
+ stopAutoPlay();
721
+ }
722
+ });
723
+ }, {
724
+ threshold: 0.3 // Start when 30% visible
725
+ });
726
+
727
+ carouselObserver.observe(resultsSection);
728
+ }
729
  });
730
  </script>
731
 
styles.css CHANGED
@@ -495,6 +495,12 @@ img {
495
  width: 100%;
496
  }
497
 
 
 
 
 
 
 
498
  /* ========================= */
499
  /* FRAMEWORK SECTION */
500
  /* ========================= */
@@ -558,6 +564,51 @@ img {
558
  backface-visibility: hidden;
559
  }
560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  .framework-description {
562
  font-size: 16px;
563
  line-height: 1.6;
 
495
  width: 100%;
496
  }
497
 
498
+ .chart-container-benchmarking {
499
+ height: 850px;
500
+ width: 100%;
501
+ }
502
+
503
+
504
  /* ========================= */
505
  /* FRAMEWORK SECTION */
506
  /* ========================= */
 
564
  backface-visibility: hidden;
565
  }
566
 
567
+ /* Framework Image Loading Effect */
568
+ .framework-img-wrapper {
569
+ position: relative;
570
+ width: 100%;
571
+ min-height: 400px;
572
+ border-radius: var(--radius-md);
573
+ overflow: hidden;
574
+ }
575
+
576
+ .framework-img {
577
+ opacity: 0;
578
+ transition: opacity 0.6s ease-in-out;
579
+ }
580
+
581
+ .framework-img.loaded {
582
+ opacity: 1;
583
+ }
584
+
585
+ /* Skeleton Loader Animation */
586
+ .skeleton-loader {
587
+ position: absolute;
588
+ top: 0;
589
+ left: 0;
590
+ right: 0;
591
+ bottom: 0;
592
+ background: linear-gradient(90deg,
593
+ #f0f0f2 0%,
594
+ #e8e8ed 20%,
595
+ #f0f0f2 40%,
596
+ #f0f0f2 100%);
597
+ background-size: 200% 100%;
598
+ animation: skeleton-shimmer 1.5s ease-in-out infinite;
599
+ border-radius: var(--radius-md);
600
+ }
601
+
602
+ @keyframes skeleton-shimmer {
603
+ 0% {
604
+ background-position: 200% 0;
605
+ }
606
+
607
+ 100% {
608
+ background-position: -200% 0;
609
+ }
610
+ }
611
+
612
  .framework-description {
613
  font-size: 16px;
614
  line-height: 1.6;