add scroll animate

This commit is contained in:
riqo 2020-10-31 17:04:55 -05:00
commit 47025c3ac4
2 changed files with 104 additions and 81 deletions

View file

@ -4,6 +4,7 @@
version="1.1" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
@click="renderMessage"
> >
<defs> <defs>
<linearGradient <linearGradient
@ -40,6 +41,7 @@
<g <g
v-for="(item, index) in renderArr" v-for="(item, index) in renderArr"
:key="index" :key="index"
:id="index"
class="test" class="test"
transform="translate(0, 0)" transform="translate(0, 0)"
> >
@ -83,7 +85,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, inject, onMounted, reactive } from "vue"; import { defineComponent, ref, inject, onMounted, reactive } from "vue";
import MessageItem from './UIDetails/messageItem.vue'; import MessageItem from './UIDetails/messageItem.vue';
import InputItem from "./UIDetails/inputItem.vue"; import InputItem from "./UIDetails/inputItem.vue";
import Messages from "./UIDetails/messages"; import Messages from "./UIDetails/messages";
@ -94,30 +96,24 @@ export default defineComponent({
setup() { setup() {
const renderArr: Message[] = reactive([]) const renderArr: Message[] = reactive([])
const messages = Messages; const messages = Messages;
const count = ref(0);
const { beforeEnter, enter, msgOffset } = useUIindexAnims(); const { beforeEnter, enter, msgOffset } = useUIindexAnims();
function renderMsg(i: number): void {
setTimeout(() => {
renderArr.push(messages[i]);
}, 2000);
}
function runAnim(): void {
for (let i = 0; i < messages.length; i++) {
renderMsg(i);
}
}
// TODO implemeant Undo animation // TODO implemeant Undo animation
function leave() { function leave() {
} }
const renderMessage = () => {
if (count.value < messages.length) {
renderArr.push(messages[count.value])
count.value++;
return;
}
}
onMounted(() => {
runAnim();
});
return { return {
renderMessage,
renderArr, renderArr,
msgOffset, msgOffset,
beforeEnter, beforeEnter,

View file

@ -1,27 +1,28 @@
import { inject, onMounted } from "vue"; import { inject, onMounted, ref } from "vue";
export default function useUIindexAnims() { export default function useUIindexAnims() {
const anime: any = inject("animejs"); const anime: any = inject("animejs");
const timeline = anime.timeline({ loop: true });
const msgOffset = { const msgOffset = {
x: 0, x: 0,
y: 0 y: 0
}; };
let winW: number; let winW: number;
let modifier: string; let modifier: string;
let msg: any; let msg: HTMLElement | null;
let cardsDiv: any;
let prevCardH = 0; let prevCardH = 0;
let totalHeight = 0; let totalHeight = 0;
let messenger: any; let messenger: HTMLElement | null;
let currentCard: Element;
let renderList: NodeList; let renderList: NodeList;
let scrollAnim = false;
let scroll = 0;
onMounted(() => { onMounted(() => {
messenger = document.getElementById("messenger"); messenger = document.getElementById("messenger");
winW = messenger.clientWidth; if (messenger) {
winW = messenger.clientWidth;
}
}); });
function getCardHeight(el: any) { function getSVGElHeight(el: SVGGElement) {
const cardHeight = el.getBBox().height; const cardHeight = el.getBBox().height;
return cardHeight; return cardHeight;
} }
@ -30,93 +31,119 @@ export default function useUIindexAnims() {
const cards = document.querySelectorAll(".test"); const cards = document.querySelectorAll(".test");
if (cards.length) { if (cards.length) {
renderList = cards; renderList = cards;
currentCard = cards.item(cards.length - 1);
for (const card of cards) { for (const card of cards) {
const height = getCardHeight(card); const el = card as SVGGElement;
const height = getSVGElHeight(el);
totalHeight += height; totalHeight += height;
} }
scrollAnim = totalHeight > 500 ? true : false;
} }
} }
async function beforeEnter(el: SVGGElement) { async function beforeEnter(el: SVGGElement) {
modifier = el.className.baseVal.substring(0, 2); modifier = el.className.baseVal.substring(0, 2);
calculateAllCardsHeight(); if (!scrollAnim) calculateAllCardsHeight();
} }
async function stackAnimate(el: any, done: any) { function scrollOffset(l: NodeList, height: number) {
const paddingLeft = 40; for (const card of l) {
msg = await document.getElementById(el.id); const c = card.parentNode as HTMLElement;
const rect = msg.getBoundingClientRect(); anime({
const msgW = rect.width; targets: c,
const msgH = rect.height; transform: `translate(0 ${height})`,
cardsDiv = document.getElementById("cardsDiv"); easing: "easeInOutQuad",
const cdBox = cardsDiv.getBBox(); duration: 500,
})
if (prevCardH === 0) {
msgOffset.y += cdBox.height;
} else if (prevCardH > msgH) {
// cardsDiv is offset by 17.5
msgOffset.y += prevCardH + msgH / 2 + 17.5;
} else {
msgOffset.y += cdBox.height - 20;
} }
prevCardH = msgH; }
function scrollAnimate(el: SVGGElement) {
anime({
targets: el,
transform: `translate(${msgOffset.x} ${msgOffset.y})`,
easing: "easeInOutQuad",
duration: 500,
begin: function() {
scrollOffset(renderList, scroll);
},
complete: function() {
anime({
targets: el,
transform: `translate(${msgOffset.x} ${msgOffset.y + 5})`,
offset: 1000
});
}
});
}
function stackAnimate(el: SVGGElement) {
const translateUp = `translate(${msgOffset.x} ${msgOffset.y})`;
const translateDown = `translate(${msgOffset.x} ${msgOffset.y + 5})`;
anime({
targets: el,
transform: translateUp,
easing: "easeInOutQuad",
duration: 1000,
complete: function() {
anime({
targets: el,
transform: translateDown,
easing: "easeInOutQuad",
duration: 500,
offset: 1000
});
}
});
}
function addMessage(el: SVGGElement) {
scrollAnim ? scrollAnimate(el) : stackAnimate(el)
}
function setXoffset(messageWidth: number) {
const paddingLeft = 40;
switch (modifier) { switch (modifier) {
case "sf": case "sf":
msgOffset.x = winW - msgW; msgOffset.x = winW - messageWidth;
break; break;
case "ai": case "ai":
msgOffset.x = (winW - msgW) / 2; msgOffset.x = (winW - messageWidth) / 2;
break; break;
default: default:
msgOffset.x = paddingLeft; msgOffset.x = paddingLeft;
} }
const translateUp = `translate(${msgOffset.x} ${msgOffset.y})`;
const translateDown = `translate(${msgOffset.x} ${msgOffset.y + 5})`;
timeline
.add({
targets: el,
transform: translateUp,
easing: "easeInOutQuad",
duration: 1000
})
.add({
targets: el,
transform: translateDown,
easing: "easeInOutQuad",
duration: 500,
offset: 1000
});
done;
} }
function OffsetMessage() { function setYoffset(messageHeight: number) {
// TODO implement individual offset function if (prevCardH === 0) {
msgOffset.y += messageHeight;
}
function scrollOffset(l: NodeList) {
}
async function scrollAnimate(el: any, done: any) {
// get incoming card height
const height = getCardHeight(el);
scrollOffset(renderList)
}
async function enter(el: SVGGElement, done: any) {
if (totalHeight < 500) {
stackAnimate(el, done)
} else { } else {
scrollAnimate(el, done); msgOffset.y += prevCardH + messageHeight / 2 + 17.5;
} }
prevCardH = messageHeight;
} }
function calculateMessageOffsets(msg: any) {
const msgRect = msg.getBoundingClientRect();
if (scrollAnim) {
// update scroll
scroll -= msgRect.height + msgRect.height / 2;
}
setXoffset(msgRect.width)
setYoffset(msgRect.height)
}
async function enter(el: SVGGElement) {
msg = await document.getElementById(el.id);
calculateMessageOffsets(msg)
addMessage(el);
}
return { return {
beforeEnter, beforeEnter,
enter, enter,
msgOffset msgOffset,
addMessage
}; };
} }