add bottom bound to message visualizer

This commit is contained in:
riqo 2021-02-15 16:24:33 -06:00
commit 2831c11de3
6 changed files with 66 additions and 106 deletions

View file

@ -19,8 +19,8 @@ export async function main() {
}); });
// Instantiate socket session with crimata-platorm. // Instantiate socket session with crimata-platorm.
// if (!socket) initSession(); if (!socket) initSession();
// socket = true; socket = true;
// Begin audio stream. // Begin audio stream.
// initRecorder(); // initRecorder();

View file

@ -4,13 +4,12 @@
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"
:viewBox="scrollView" :viewBox="scrollView"
id="test"
> >
<g id="messageView" transform="translate(0, 5)"> <g id="messageView" transform="translate(0, 20)">
<g <g
v-for="(item, index) in renderArr" v-for="(item, index) in renderArr"
:key="index" :key="index"
class="messageList"
transform="translate(0, 25)"
preserverAspectRatio="none" preserverAspectRatio="none"
> >
<transition <transition
@ -31,7 +30,7 @@ import useMessageView from "./viewDetails/visualizer";
import useScrollView from "@/modules/scrollView"; import useScrollView from "@/modules/scrollView";
import TextBubble from "@/components/textBubble/index.vue"; import TextBubble from "@/components/textBubble/index.vue";
import { Message } from "@/types/message/index"; import { Message } from "@/types/message/index";
import { defineComponent, reactive, onMounted, onUnmounted } from "vue"; import { defineComponent, reactive, onMounted, onUnmounted, watch, ref, computed } from "vue";
import useMitt from "@/modules/mitt"; import useMitt from "@/modules/mitt";
import { useIpc } from "@/modules/ipc"; import { useIpc } from "@/modules/ipc";
@ -51,9 +50,9 @@ export default defineComponent({
emitter.on("animateSend", async (message) => { emitter.on("animateSend", async (message) => {
try { try {
renderArr.push(message) // renderArr.push(message)
// await invoke(message); await invoke(message);
// renderArr.push(data.value); renderArr.push(data.value);
} catch (e) { } catch (e) {
console.log("No response. Do not render."); console.log("No response. Do not render.");
} }
@ -80,13 +79,3 @@ export default defineComponent({
}, },
}); });
</script> </script>
<style lang="scss" scoped>
svg {
height: 1%;
overflow: hidden;
}
#messageRenderer {
margin: 0;
}
</style>

View file

@ -5,76 +5,47 @@ import { MessageAnimeFunc } from '@/types/message/index';
/** /**
* anime js animations used by message renderer * anime js animations used by message renderer
*/ */
export default function useMessageViewAnims(): { export default function useMessageViewAnims() {
shiftAnimate: MessageAnimeFunc;
stackAnimate: MessageAnimeFunc;
} {
// imports animejs safely // imports animejs safely
let anime: AnimeFunc; let anime: AnimeFunc;
const animeInject: AnimeFunc | undefined = inject("animejs"); const animeInject: AnimeFunc | undefined = inject("animejs");
if (animeInject) anime = animeInject; if (animeInject) anime = animeInject;
// shifts message list by a given value
function shiftList({ targetList, sv }: { targetList: NodeList | undefined; sv: number | undefined }) {
if (targetList) {
for (const element of targetList) {
const el = element.parentNode as HTMLElement;
anime({
targets: el,
transform: `translate(0 ${sv})`,
easing: "easeInOutQuad",
duration: 500,
});
}
}
}
// adds new message at the bottom of the list and shifts existing message list // adds new message at the bottom of the list and shifts existing message list
const shiftAnimate: MessageAnimeFunc = (el, transform, shiftValue, targetList) => { const shiftAnimate = (el: Element, transform: string, view: SVGGElement, viewTransform: string) => {
anime({ anime({
targets: el, targets: el,
transform: transform.initialTranslate, transform: transform,
easing: "easeInOutQuad", easing: "easeInOutQuad",
duration: 500, duration: 800,
begin: function() { begin: function() {
shiftList({ shiftView(view, viewTransform);
targetList,
sv: shiftValue
});
}, },
complete: function() {
anime({
targets: el,
transform: transform.finalTranslate,
easing: "easeInOutQuad",
duration: 500,
offset: 1000
});
}
}); });
} }
// stacks message from top to bottom // stacks message from top to bottom
const stackAnimate: MessageAnimeFunc = (el, transform) => { const stackAnimate = (el: Element, transform: string) => {
anime({ anime({
targets: el, targets: el,
transform: transform.initialTranslate, transform: transform,
easing: "easeInOutQuad", easing: "easeInOutQuad",
duration: 1000, duration: 1000,
complete: function() { });
anime({ }
targets: el,
transform: transform.finalTranslate, // update message View bottom bound
easing: "easeInOutQuad", const shiftView = (el: SVGGElement, transform: string) => {
duration: 500, anime({
offset: 1000 targets: el,
}); transform: transform,
} easing: "easeInOutQuad",
duration: 500,
}); });
} }
return { return {
shiftAnimate, shiftAnimate,
stackAnimate stackAnimate,
}; };
} }

View file

@ -9,7 +9,7 @@ export default function useOffsetCalculator() {
let previousMessageHeight = 0; let previousMessageHeight = 0;
const messagePadding = 15; const messagePadding = 15;
function calculateX(message: HTMLElement): void { function calculateX(message: HTMLElement| SVGGElement): void {
const computedQuery = window.getComputedStyle(message); const computedQuery = window.getComputedStyle(message);
const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform); const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform);
xOffset.value = matrix.m41; xOffset.value = matrix.m41;

View file

@ -7,60 +7,62 @@ import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index'
import useMessageViewAnims from "./anime"; import useMessageViewAnims from "./anime";
import useOffsetCalculator from './offsetCalculator'; import useOffsetCalculator from './offsetCalculator';
export default function useMessageView(): { const wH = 500; // window Height
beforeEnter: VueTransitionCallback; const vP = 10; // view padding
enter: VueTransitionCallback; const mP = 15; // message padding
afterEnter: VueTransitionCallback; let mH: number; // message Height
} { let vH: number; // view Height
// uses offsetCalculator logic and renderer animations let vB: number; // view Bottom Bound
let message: HTMLElement | null;
let messageOffset = { x: 0, y: 0 };
let shift = false;
let beforeEnterVH: number;
let messageView: SVGGElement;
export default function useMessageView() {
const { calculateMessageOffsets } = useOffsetCalculator(); const { calculateMessageOffsets } = useOffsetCalculator();
const { shiftAnimate, stackAnimate } = useMessageViewAnims(); const { shiftAnimate, stackAnimate } = useMessageViewAnims();
const messagePadding = 15;
let messageList: NodeList;
let message: HTMLElement | null;
let messageOffset = { x: 0, y: 0 };
let shift = false;
let shiftOffset = 0;
// animates message item to 'enter' renderView
const animateMessage = (el: SVGGElement): void => { const animateMessage = (el: SVGGElement): void => {
const transform = { const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`;
initialTranslate: `translate(${messageOffset.x} ${messageOffset.y})`, const viewTransform = `translate(0 ${-vB})`;
finalTranslate: `translate(${messageOffset.x} ${messageOffset.y})`
if (shift) {
shiftAnimate(el, elTransform, messageView, viewTransform);
} else {
stackAnimate(el, elTransform)
} }
shift ? shiftAnimate(el, transform, shiftOffset, messageList) : stackAnimate(el, transform);
} }
const beforeEnter: VueTransitionCallback = () => { const beforeEnter: VueTransitionCallback = () => {
const queryResult = document.querySelectorAll(".messageList"); // query DOM for messageView element
console.log(queryResult) const messageViewQuery = document.querySelectorAll("#messageView");
if (queryResult.length) messageList = queryResult; messageView = messageViewQuery[0] as SVGGElement;
if (messageViewQuery){
beforeEnterVH = messageView.getBBox().height;
}
} }
const enter: VueTransitionCallback = (el) => { const enter: VueTransitionCallback = (el) => {
// query DOM for latest message as soon as it enters // query DOM for latest message
if (el) { if (el) {
message = document.getElementById(el.id); message = document.getElementById(el.id);
} }
} }
const afterEnter: VueTransitionCallback = (el) => { const afterEnter: VueTransitionCallback = async (el) => {
// get message positioning & shift state before animating
if (message) { if (message) messageOffset = calculateMessageOffsets(message);
messageOffset = calculateMessageOffsets(message);
shift = messageOffset.y > 400 ? true : false;
}
if (el) { if (el) {
if (shift) { // calculate message & view heights, as well as view bottom bound
shiftOffset -= el.getBBox().height + messagePadding; mH = el.getBoundingClientRect().height;
// if (messageOffset.y < 445) { vH = mH + beforeEnterVH + mP;
// shiftOffset -= 15; vB = Math.abs(vH - wH) + vP;
// } else {
// shiftOffset -= el.getBBox().height + messagePadding; shift = vH > wH ? true : false;
// }
}
animateMessage(el); animateMessage(el);
} }
} }
@ -68,6 +70,6 @@ export default function useMessageView(): {
return { return {
beforeEnter, beforeEnter,
enter, enter,
afterEnter afterEnter,
}; };
} }

View file

@ -4,7 +4,6 @@
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="emittMessage"
> >
<MessageView /> <MessageView />
<TextAudioInput /> <TextAudioInput />
@ -26,7 +25,6 @@ export default defineComponent({
const counter = ref(0); const counter = ref(0);
const emittMessage = () => { const emittMessage = () => {
console.log('testing')
emitter.emit('animateSend', Messages[counter.value]) emitter.emit('animateSend', Messages[counter.value])
counter.value++; counter.value++;
} }