anime.js
From their website:
Anime.js (/ˈæn.ə.meɪ/) is a lightweight JavaScript animation library with a simple, yet powerful API. It works with CSS properties, SVG, DOM attributes and JavaScript Objects.
Much of the library appears to be a wrapper for CSS Animations.
For the first example, click on the title of this blog. Code is below:
<!-- load the library to the webpage from a cdn -->
<script src='https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js'>
</script>
<script type=module>
// get the h1 element containing the title of the blog
const title = document.getElementsByClassName ("post-title p-name").item(0)
// start it off the right edge of the view portal
title.style.marginLeft = `${ title.offsetWidth }px`
// the anime () function is how we animate
// we pass it an object specifying what we
// want to animate, and how
anime ({
// the targets property specifies
// what is being animated. in this
// case it is the title element
targets: title,
// this is the CSS property of that element
// we are animating. We are going to 0 from
// its starting position, window.innerWidth
marginLeft: title.offsetWidth,
// the duration of the animation
// in milliseconds
duration: 3000,
})
// assign to the elements onclock property
// when a user clicks on the title element
// the browser will call this function
title.onclick = () => {
// animate
anime ({
// the title element
targets: title,
// assign the .style.marginLeft property
// to the value of the .offsetWidth property
marginLeft: title.offsetWidth,
// animate over 3 seconds
duration: 3000,
})
}
</script>
Rotating a div element:
<div id=rotating_square></div>
<script type=module>
// getting and formatting the outer div
const div = document.getElementById (`rotating_square`)
div.width = div.parentNode.scrollWidth
div.height = div.width * 9 / 16
div.style.height = `${ div.height }px`
div.style.backgroundColor = `turquoise`
// making a square pink div
const square = document.createElement (`div`)
square.style.width = `100px`
square.style.height = `100px`
square.style.backgroundColor = `hotpink`
square.style.position = `relative`
// using the style.transform property to move the div
const trans_x = `translateX(${ div.width /2 - 50 }px)`
const trans_y = `translateY(${ div.height/2 - 50 }px)`
square.style.transform = `${ trans_x } ${ trans_y }`
// attaching the square div to the outer div
div.append (square)
// the anime () function will return an object
// we can use to control the animation
const square_mover = anime ({
// remember the s at the end of targets!
targets: square,
duration: 3000,
// this will rotate the div
// via its style.transform property
rotate: `315deg`,
// this will scale the div
// via its style.transform property
scale: 2,
// makes it animate in both directions
direction: `alternate`,
// will not autoplay
autoplay: false,
})
// registering the square_mover.play () method
// to the onclick event listener
div.onclick = () => square_mover.play ()
</script>
An array of divs:
<div id=many_squares></div>
<script type=module>
const div = document.getElementById (`many_squares`)
div.width = div.parentNode.scrollWidth
div.height = div.width * 9 / 16
div.style.height = `${ div.height }px`
div.style.backgroundColor = `turquoise`
// quick maths to work out the centred coordinates
const x_off = (div.width / 2) - (260 / 2) - 5
const y_off = (div.height / 2) - (20 / 2) - 5
// making 7 pink, square divs
for (let i = 0; i < 7; i++) {
const square = document.createElement (`div`)
square.style.width = `20px`
square.style.height = `20px`
square.style.backgroundColor = `hotpink`
square.style.position = `relative`
// tells them to line up next to each other
// (instead of underneath each other)
square.style.display = `inline-block`
// spread them out a bit
square.style.margin = `10px`
// center them in the outer div
square.style.transform = `translate(${ x_off }px, ${ y_off }px)`
// attach them to the outer div
div.append (square)
}
// creating the animation interface object
const animator = anime ({
// passing all the outer div's
// child nodes as targets
targets: div.childNodes,
// do the same animation as in
// the previous example
duration: 3000,
rotate: `315deg`,
scale: 2,
direction: `alternate`,
autoplay: false,
// but this time stagger the timing
delay: anime.stagger (100),
})
// when click -> .play () method on the
// animation interface object
div.onclick = () => animator.play ()
</script>
Grid Example 1
<div id=grid_example_1></div>
<script type=module>
// get and format grid
const div = document.getElementById (`grid_example_1`)
div.width = div.parentNode.scrollWidth
div.height = div.width * 9 / 16
div.style.height = `${ div.height }px`
div.style.backgroundColor = `turquoise`
// set display mode to grid
div.style.display = `grid`
// fr means fraction ie. equal divisions
// 16 even devisions across
div.style.gridTemplateColumns = `1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr`
// 9 even devisions down
div.style.gridTemplateRows = `1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr`
// 16 * 9 = 144
// this for loop will make 144 pink square divs
for (let i = 0; i < 144; i++) {
// create a div element
const square = document.createElement (`div`)
// set width and height to 1fr
square.style.width = `1fr`
square.style.height = `1fr`
// make pink
square.style.backgroundColor = `hotpink`
// assign the play function of the object
// returned by the anime function to the
// onmouseover property of the div
square.onmouseover = anime ({
// target the div
targets: square,
// shrink to 0
scale: 0,
// shrink and then grow
direction: `alternate`,
// simple movement envelope
easing: `linear`,
// 1.4 seconds each way
duration: 1400,
// don't animate right away
autoplay: false,
// return the the play method
// of the object returned
// by the anime function
}).play
// append the pink square div
// to the turquoise div
div.append (square)
}
</script>
Grid Example 2
<div id=grid_example_2></div>
<script type=module>
// get and format grid
const div = document.getElementById (`grid_example_2`)
div.width = div.parentNode.scrollWidth
div.height = div.width * 9 / 16
div.style.height = `${ div.height }px`
div.style.backgroundColor = `turquoise`
// set display mode to grid
div.style.display = `grid`
// fr means fraction ie. equal divisions
// 16 even devisions across
div.style.gridTemplateColumns = `1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr`
// 9 even devisions down
div.style.gridTemplateRows = `1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr`
// 16 * 9 = 144
// this for loop will make 144 pink square divs
for (let i = 0; i < 144; i++) {
// create a div element
const square = document.createElement (`div`)
// set width and height to 1fr
square.style.width = `1fr`
square.style.height = `1fr`
// make pink
square.style.backgroundColor = `hotpink`
// append the pink square div
// to the turquoise div
div.append (square)
}
div.onclick = e => {
// e.offsetX was not working for some reason
// here we arecalculating from .pageX
// and .pageY as a workaround
const x_off = e.pageX - div.offsetLeft
const y_off = e.pageY - div.offsetTop
// x and y coordinates expressed between 0 - 1
const x_phase = x_off / div.width
const y_phase = y_off / div.height
// finding the column and row of the click
const col = Math.floor (x_phase * 16)
const row = Math.floor (y_phase * 9)
// finding the index of the square that was clicked
const i = row * 16 + col
anime ({
// pass in all the pink squares
targets: div.childNodes,
// linear shrinking and growing movement
easing: `linear`,
// 3 second animation each
duration: 3000,s
// specifying 2 keyframes:
// the shrinking, and then the growing
keyframes: [
{
scale: 0,
rotate: `45deg`,
},
{
scale: 1,
rotate: `0deg`,
},
],
// ripple effect over a grid style staggering
// passing the index of the square that goes first
delay: anime.stagger(300, {grid: [16, 9], from: i}),
})
}
</script>