add bottom bound to message visualizer
This commit is contained in:
parent
f0a89bd5e4
commit
2831c11de3
6 changed files with 66 additions and 106 deletions
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue