使用Claude重构动画

This commit is contained in:
CN-JS-HuiBai
2026-04-06 02:29:25 +08:00
parent 217510c07d
commit 61748b8959
2 changed files with 66 additions and 34 deletions

View File

@@ -1998,12 +1998,6 @@ input:checked+.slider:before {
display: flex !important; display: flex !important;
flex-direction: column; flex-direction: column;
border-color: var(--accent-indigo); border-color: var(--accent-indigo);
animation: globeExpandIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
/* Collapse animation (plays while .expanded is still active to keep fixed positioning) */
.globe-card.expanded.globe-collapsing {
animation: globeCollapseOut 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
} }
/* Ensure children are visible */ /* Ensure children are visible */
@@ -2011,28 +2005,6 @@ input:checked+.slider:before {
opacity: 1 !important; opacity: 1 !important;
} }
@keyframes globeExpandIn {
from {
opacity: 0;
transform: scale(0.82);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes globeCollapseOut {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.82);
}
}
.globe-card.expanded .globe-body { .globe-card.expanded .globe-body {
height: calc(90vh - 120px) !important; /* Explicit calc height for ECharts reliability */ height: calc(90vh - 120px) !important; /* Explicit calc height for ECharts reliability */
width: 100% !important; width: 100% !important;

View File

@@ -207,25 +207,85 @@
dom.btnChangePassword.addEventListener('click', saveChangePassword); dom.btnChangePassword.addEventListener('click', saveChangePassword);
} }
// Globe expansion // Globe expansion (FLIP animation)
let savedGlobeRect = null;
function expandGlobe() { function expandGlobe() {
if (dom.globeCard.classList.contains('expanded')) return; if (dom.globeCard.classList.contains('expanded')) return;
// FLIP Step 1 — First: save original rect
savedGlobeRect = dom.globeCard.getBoundingClientRect();
// FLIP Step 2 — Last: apply expanded state
dom.globeCard.classList.add('expanded'); dom.globeCard.classList.add('expanded');
dom.btnExpandGlobe.classList.add('active'); dom.btnExpandGlobe.classList.add('active');
dom.globeCard.addEventListener('animationend', function onExpand() {
dom.globeCard.removeEventListener('animationend', onExpand); // Resize ECharts IMMEDIATELY so the map renders at full size
// This prevents the "flash" — content is correctly sized throughout
if (myMap2D) myMap2D.resize(); if (myMap2D) myMap2D.resize();
// FLIP Step 3 — Invert: calculate and apply inverse transform
const endRect = dom.globeCard.getBoundingClientRect();
const scaleX = savedGlobeRect.width / endRect.width;
const scaleY = savedGlobeRect.height / endRect.height;
const dx = (savedGlobeRect.left + savedGlobeRect.width / 2) - (endRect.left + endRect.width / 2);
const dy = (savedGlobeRect.top + savedGlobeRect.height / 2) - (endRect.top + endRect.height / 2);
dom.globeCard.style.willChange = 'transform, box-shadow';
dom.globeCard.style.transition = 'none';
dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`;
dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent';
// Force reflow to commit the inverse state
dom.globeCard.offsetHeight;
// FLIP Step 4 — Play: animate to final state
dom.globeCard.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease';
dom.globeCard.style.transform = '';
dom.globeCard.style.boxShadow = '';
dom.globeCard.addEventListener('transitionend', function onEnd(e) {
if (e.propertyName !== 'transform') return;
dom.globeCard.removeEventListener('transitionend', onEnd);
dom.globeCard.style.transition = '';
dom.globeCard.style.willChange = '';
}); });
} }
function collapseGlobe() { function collapseGlobe() {
if (!dom.globeCard.classList.contains('expanded')) return; if (!dom.globeCard.classList.contains('expanded')) return;
if (dom.globeCard.classList.contains('globe-collapsing')) return; if (dom.globeCard.classList.contains('globe-collapsing')) return;
if (!savedGlobeRect) {
dom.globeCard.classList.remove('expanded');
dom.btnExpandGlobe.classList.remove('active');
if (myMap2D) requestAnimationFrame(() => myMap2D.resize());
return;
}
dom.globeCard.classList.add('globe-collapsing'); dom.globeCard.classList.add('globe-collapsing');
dom.globeCard.addEventListener('animationend', function onCollapse() {
dom.globeCard.removeEventListener('animationend', onCollapse); // Calculate transform from expanded back to original position
const expandedRect = dom.globeCard.getBoundingClientRect();
const scaleX = savedGlobeRect.width / expandedRect.width;
const scaleY = savedGlobeRect.height / expandedRect.height;
const dx = (savedGlobeRect.left + savedGlobeRect.width / 2) - (expandedRect.left + expandedRect.width / 2);
const dy = (savedGlobeRect.top + savedGlobeRect.height / 2) - (expandedRect.top + expandedRect.height / 2);
dom.globeCard.style.willChange = 'transform, box-shadow';
dom.globeCard.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s ease';
dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`;
dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent';
dom.globeCard.addEventListener('transitionend', function onEnd(e) {
if (e.propertyName !== 'transform') return;
dom.globeCard.removeEventListener('transitionend', onEnd);
dom.globeCard.classList.remove('expanded', 'globe-collapsing'); dom.globeCard.classList.remove('expanded', 'globe-collapsing');
dom.btnExpandGlobe.classList.remove('active'); dom.btnExpandGlobe.classList.remove('active');
dom.globeCard.style.transition = '';
dom.globeCard.style.transform = '';
dom.globeCard.style.boxShadow = '';
dom.globeCard.style.willChange = '';
if (myMap2D) requestAnimationFrame(() => myMap2D.resize()); if (myMap2D) requestAnimationFrame(() => myMap2D.resize());
}); });
} }