Added animation pinning to shortcode
This commit is contained in:
parent
1775310408
commit
cfdc5aaee8
5 changed files with 170 additions and 4 deletions
|
|
@ -43,6 +43,8 @@ All parameters are optional with sensible defaults:
|
|||
- **slideInRight** - Slide in from right side
|
||||
- **parallax** - Subtle vertical parallax effect
|
||||
- **stagger** - Sequential animation for multiple items
|
||||
- **zoomIn** - Start with full image, zoom into focal point
|
||||
- **zoomOut** - Start zoomed into focal point, pull back to full image
|
||||
|
||||
## Image Format
|
||||
|
||||
|
|
@ -124,6 +126,36 @@ Images are automatically optimized via Eleventy Image plugin (WebP/JPEG, respons
|
|||
{% endgsapScrollAnim %}
|
||||
```
|
||||
|
||||
### Zoom In to Focal Point
|
||||
|
||||
Draw attention to a specific detail in a high-resolution photograph:
|
||||
|
||||
```markdown
|
||||
{% gsapScrollAnim {
|
||||
"animationType": "zoomIn",
|
||||
"focalX": 75,
|
||||
"focalY": 25,
|
||||
"startZoom": 1,
|
||||
"endZoom": 2.5
|
||||
} %}
|
||||
[{
|
||||
"src": "/images/detail-photo.jpg",
|
||||
"alt": "Macro photography showing fine detail"
|
||||
}]
|
||||
{% endgsapScrollAnim %}
|
||||
```
|
||||
|
||||
**Zoom Parameters:**
|
||||
- `focalX` (0-100): Horizontal focal point percentage from left (default: 50)
|
||||
- `focalY` (0-100): Vertical focal point percentage from top (default: 50)
|
||||
- `startZoom`: Initial scale (default: 1 = 100%)
|
||||
- `endZoom`: Final scale (default: 2.5 = 250%)
|
||||
|
||||
**zoomIn**: Starts with full image visible, zooms into the focal point
|
||||
**zoomOut**: Starts zoomed into focal point, pulls back to show full image
|
||||
|
||||
High-resolution images (up to 3200px) are automatically loaded for zoom animations to preserve detail when scaled.
|
||||
|
||||
## ScrollTrigger Settings
|
||||
|
||||
### scrollStart / scrollEnd
|
||||
|
|
|
|||
|
|
@ -66,18 +66,24 @@ export const gsapScrollAnim = async function(content, configString = '{}') {
|
|||
// Parse images from content
|
||||
const images = parseImagesFromContent(content);
|
||||
|
||||
// Detect if this is a zoom animation (needs high-res images)
|
||||
const isZoomAnimation = animationType === 'zoomIn' || animationType === 'zoomOut' ||
|
||||
animationType.includes('zoom');
|
||||
|
||||
// Process images using existing image shortcode
|
||||
const processedImages = await Promise.all(
|
||||
images.map(async (img, index) => {
|
||||
if (img.src) {
|
||||
// Use existing image processing
|
||||
// Use existing image processing with higher resolutions for zoom
|
||||
const imageHtml = await imageKeysShortcode({
|
||||
src: img.src,
|
||||
alt: img.alt || '',
|
||||
caption: img.caption || '',
|
||||
loading: index === 0 ? 'eager' : 'lazy',
|
||||
imageClass: 'gsap-image',
|
||||
containerClass: 'gsap-image-wrapper'
|
||||
containerClass: 'gsap-image-wrapper',
|
||||
// Inject high-res widths for zoom animations
|
||||
...(isZoomAnimation && { widths: [960, 1400, 2400, 3200] })
|
||||
});
|
||||
return `<div class="gsap-item" data-image-index="${index}">${imageHtml}</div>`;
|
||||
} else if (img.content) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,29 @@
|
|||
margin-top: var(--space-m, 1.5rem);
|
||||
}
|
||||
|
||||
/* Zoom animation specific styles */
|
||||
.gsap-container[data-gsap-scroll-anim*='zoom'] {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gsap-container[data-gsap-scroll-anim*='zoom'] .gsap-image-wrapper {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gsap-container[data-gsap-scroll-anim*='zoom'] .gsap-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
/* Ensure smooth scaling */
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
|
||||
/* When animations are disabled (prefers-reduced-motion) */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.gsap-image,
|
||||
|
|
|
|||
|
|
@ -111,7 +111,65 @@ const animations = {
|
|||
ease: 'power2.out',
|
||||
stagger: 0.2
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
||||
/**
|
||||
* Zoom In: Start with full image visible, zoom into focal point
|
||||
* Requires: focalX, focalY (0-100%), startZoom, endZoom
|
||||
*/
|
||||
zoomIn: (element, config) => {
|
||||
const {
|
||||
focalX = 50,
|
||||
focalY = 50,
|
||||
startZoom = 1,
|
||||
endZoom = 2.5
|
||||
} = config || {};
|
||||
|
||||
return {
|
||||
from: {
|
||||
scale: startZoom,
|
||||
transformOrigin: `${focalX}% ${focalY}%`,
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
to: {
|
||||
scale: endZoom,
|
||||
transformOrigin: `${focalX}% ${focalY}%`,
|
||||
x: 0,
|
||||
y: 0,
|
||||
ease: 'power2.inOut'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Zoom Out: Start zoomed into focal point, pull back to show full image
|
||||
* Requires: focalX, focalY (0-100%), startZoom, endZoom
|
||||
*/
|
||||
zoomOut: (element, config) => {
|
||||
const {
|
||||
focalX = 50,
|
||||
focalY = 50,
|
||||
startZoom = 2.5,
|
||||
endZoom = 1
|
||||
} = config || {};
|
||||
|
||||
return {
|
||||
from: {
|
||||
scale: startZoom,
|
||||
transformOrigin: `${focalX}% ${focalY}%`,
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
to: {
|
||||
scale: endZoom,
|
||||
transformOrigin: `${focalX}% ${focalY}%`,
|
||||
x: 0,
|
||||
y: 0,
|
||||
ease: 'power2.inOut'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -156,7 +214,12 @@ function initGsapAnimations() {
|
|||
|
||||
// Create GSAP context for this container
|
||||
const ctx = gsap.context(() => {
|
||||
const anim = animationPreset(items);
|
||||
// For zoom animations, apply to images directly
|
||||
const targetElements = (animationType === 'zoomIn' || animationType === 'zoomOut')
|
||||
? container.querySelectorAll('.gsap-image')
|
||||
: items;
|
||||
|
||||
const anim = animationPreset(targetElements, config);
|
||||
|
||||
// Create timeline with ScrollTrigger
|
||||
const timeline = gsap.timeline({
|
||||
|
|
|
|||
|
|
@ -53,3 +53,45 @@ Nullam congue lectus a convallis dictum. Nunc rhoncus, ante id porta tempor, lor
|
|||
|
||||
Suspendisse eu rutrum dolor. Mauris semper, eros quis dapibus euismod, ante mi tempor libero, vel mollis ipsum dolor vel nulla. Sed cursus aliquam luctus. Suspendisse egestas erat ante, fringilla aliquam urna ullamcorper ac. Aliquam facilisis sed magna et bibendum. Nam sed justo a sapien vulputate dignissim vitae imperdiet enim. Integer mi ex, imperdiet porttitor posuere ut, placerat id magna. Pellentesque imperdiet porta blandit. Mauris eget rutrum sapien, luctus consequat ligula. Nullam sed ipsum in velit commodo rutrum. Aenean eu massa in dolor accumsan commodo. Sed vitae fermentum dolor, non vestibulum mi. Sed ac orci ac metus porta finibus.
|
||||
|
||||
## Zoom Animation Test
|
||||
|
||||
Testing the `zoomIn` effect to draw attention to album artwork details:
|
||||
|
||||
{% gsapScrollAnim {
|
||||
"animationType": "zoomIn",
|
||||
"focalX": 50,
|
||||
"focalY": 50,
|
||||
"startZoom": 1,
|
||||
"endZoom": 2.5,
|
||||
"scrollStart": "top top",
|
||||
"scrollEnd": "+=100%",
|
||||
"scrub": true,
|
||||
"pin": true
|
||||
} %}
|
||||
[{
|
||||
"src": "/pages/projects/mixes/tomorrowsbacon/radiohead-ok-computer.jpg",
|
||||
"alt": "Radiohead OK Computer album cover - zoom to center detail"
|
||||
}]
|
||||
{% endgsapScrollAnim %}
|
||||
|
||||
Mauris dignissim nisl et sem condimentum, eu molestie enim cursus. Proin varius tincidunt odio, ac varius ex faucibus quis. Cras ultrices dolor in mauris varius, eu vehicula nisi fringilla.
|
||||
|
||||
{% gsapScrollAnim {
|
||||
"animationType": "zoomOut",
|
||||
"focalX": 75,
|
||||
"focalY": 25,
|
||||
"startZoom": 3,
|
||||
"endZoom": 1,
|
||||
"scrollStart": "top top",
|
||||
"scrollEnd": "+=100%",
|
||||
"scrub": true,
|
||||
"pin": true
|
||||
} %}
|
||||
[{
|
||||
"src": "/pages/projects/mixes/tomorrowsbacon/the-clash-london-calling.jpeg",
|
||||
"alt": "The Clash London Calling - zoom out from top-right detail"
|
||||
}]
|
||||
{% endgsapScrollAnim %}
|
||||
|
||||
Nullam quis facilisis mi. Sed dignissim tellus ut nisi tempor, eu ultrices libero consectetur. Integer et augue vitae nunc consequat elementum.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue