Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulransfield/4ca22754507a33d13e6301aa28029c57 to your computer and use it in GitHub Desktop.
Save paulransfield/4ca22754507a33d13e6301aa28029c57 to your computer and use it in GitHub Desktop.
Bubble Slideshow Component

Bubble Slideshow Component

This is a Vue component that uses clip-path for an interesting slideshow transition effect.

A Pen by Erik Jung on CodePen.

License.

<main id="main">
<gallery ref="gallery" v-bind:images="images" v-on:next="next">
</gallery>
</main>
<template id="gallery_template">
<transition-group tag="figure" class="Gallery" name="open">
<img v-for="(image, index) of images"
v-bind:src="image"
v-bind:key="index"
v-on:click="onClick"
v-bind:style="{'--circle-x': x, '--circle-y': y}">
</transition-group>
</template>
Vue.component('gallery', {
template: '#gallery_template',
props: {
images: Array
},
data() {
return {
x: '50%',
y: '50%'
}
},
methods: {
onClick(event) {
const x = event.offsetX - event.target.offsetLeft
const y = event.offsetY - event.target.offsetTop
const xPercent = `${Math.round(100 * x / event.target.offsetWidth)}%`
const yPercent = `${Math.round(100 * y / event.target.offsetHeight)}%`
this.x = xPercent
this.y = yPercent
this.$emit('next', {x: xPercent, y: yPercent})
}
}
})
const vm = new Vue({
el: '#main',
data: {
images: [
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/10488/woods-1.jpeg',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/10488/woods-2.jpeg',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/10488/woods-3.jpeg',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/10488/woods-4.jpeg'
]
},
methods: {
next() {
const image = this.images.shift()
this.$nextTick(() => this.images.push(image))
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.4/vue.min.js"></script>
@use postcss-cssnext;
* {
margin: 0;
box-sizing: border-box;
}
html {
background: black;
}
main {
min-height: 100vh;
display: flex;
flex-direction: column;
max-width: 1200px;
margin: auto;
}
main > * {
margin: auto 0;
}
.Gallery {
display: block;
position: relative;
padding-top: calc(2/3 * 100%);
transform-style: preserve-3d;
perspective: 100vw;
}
.Gallery > img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
--circle-x: 50%;
--circle-y: 50%;
}
@keyframes openup {
to {
clip-path: circle(100vw at var(--circle-x) var(--circle-y));
}
}
.open-enter-active {
clip-path: circle(0 at var(--circle-x) var(--circle-y));
}
.open-enter-to {
animation: openup 500ms ease-in;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment