message positioning for svgs

This commit is contained in:
Andrew Gundersen 2021-02-25 19:31:00 -06:00
commit a9fdf8f1b2
6 changed files with 172 additions and 104 deletions

View file

@ -0,0 +1,33 @@
import {computed} from "vue";
// Size of "side-gutters" of message window.
const margin = 20;
const messagePadding = 15;
const firstChildMargin = 45;
function calcXPosition(messageWidth: number, windowWidth: number, modifier: string) {
let offset = margin;
if (modifier == "sf") {
offset = windowWidth - messageWidth - margin;
}
return offset
}
function calcMessagePosition(modifier: string, messageWidth: number,
windowWidth: number, anchorPosition: any) {
const X = calcXPosition(messageWidth, windowWidth, modifier);
// Depends on if first child.
let Y = firstChildMargin;
if (anchorPosition != "none") {
Y = anchorPosition + messagePadding;
}
return `translate(${X} ${Y})`;
}
export default calcMessagePosition;

View file

@ -0,0 +1,101 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
width="100"
height="46"
:transform="position"
>
<rect
:id="message.id"
:class="message.modifier"
width="100" height="46" rx="10" fill="#58c4fd"
/>
</svg>
</template>
<script lang="ts">
import { defineComponent, computed, onMounted, ref, reactive } from "vue";
import calcMessagePosition from "./calcPosition";
export default defineComponent({
name: "MessageBubble",
props: {
// DOM ID of the previous message.
// Null if message is first child.
anchor: {
type: String,
required: true
},
// Passing in the message contents.
message: {
type: Object,
required: true
},
},
setup(props) {
// e.g. "translate(20 200)"
const position = ref("");
let anchorPosition: any;
// Call to update the position variable.
const updatePosition = () => {
// First get anchor's position.
if (props.anchor == "none") {
anchorPosition = "none";
}
const m = document.getElementById(props.anchor)
if (m) {
anchorPosition = m.getBoundingClientRect().bottom
}
position.value = calcMessagePosition(
props.message.modifier,
100,
window.innerWidth,
anchorPosition
);
console.log(
`Message: ${props.message.id}: \n
Anchor: ${props.anchor}: ${anchorPosition} \n
Position: ${position.value}`
)
}
// Assign initial position.
updatePosition();
onMounted(() => {
// We gotta know when the message above us changes position.
// Add listener for window resize.
window.addEventListener("resize", updatePosition);
})
return {
position
}
},
});
</script>

View file

@ -1,83 +0,0 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
width="width"
height="height"
viewBox="0 0 100 46"
>
<rect
:id="item.id"
:class="item.modifier"
:transform="position"
width="width" height="height" rx="10" fill="#58c4fd"
/>
</svg>
</template>
<script lang="ts">
import { defineComponent, computed, onMounted, ref, reactive } from "vue";
export default defineComponent({
name: "TextBubble",
props: {
// Passing in the message contents.
message: {
type: Object,
required: true,
},
},
setup(props) {
// The position of the bubble.
const position = ref()
// Calculate the position.
computed(() => {
const calculateX = () => {
let x = 20 // side-padding
if (props.message.modifier == 'sf') {
x = window.innerWidth - 100 - 20
}
return x
}
const calculateY = () => {
let y = 45 // top-padding
if (previousMessage) {
prev = document.getElementById(previousMessage)
prevPosition = prev.getBoundingClientRect().height
y = prevPosition + 15 // message-message padding
}
return y
}
let X = calculateX();
let Y = calculateY();
position.value = `translate(${X} ${Y})`;
})
return {
position
}
},
});
</script>

View file

@ -65,8 +65,8 @@ export default function useComputedBubble(m: string, id: string) {
if (parentView) {
const dimensions = parentView.getBoundingClientRect();
let X = calculateXoffset(dimensions.width);
let Y = calculateYoffset(dimensions.height);
const X = calculateXoffset(dimensions.width);
const Y = calculateYoffset(dimensions.height);
return `translate(${X} ${Y})`;
}

View file

@ -29,7 +29,6 @@ export default function useInputController() {
audio: 0,
text: input
};
<<<<<<< Updated upstream
// trigger send animation
emitter.emit("animate-send");
@ -40,13 +39,6 @@ export default function useInputController() {
const {
visualizeStreamAsPaths,
=======
emitter.emit("animate-send", message);
}
const {
visualizeStreamAsPaths,
>>>>>>> Stashed changes
expandBubble
} = useAudioVisualizer(visualizeStream);

View file

@ -2,38 +2,56 @@
<TextAudioInput />
<!-- List of text bubbles. -->
<div id="messenger" v-for="message in messages">
<!-- <TextBubble :message="message"/> -->
<div>Hello</div>
<!-- List of message bubbles. -->
<div id="messenger">
<MessageBubble id="message" v-for="(message, index) in messages"
:message="message"
:anchor="getAnchor(index)"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, onMounted } from "vue";
import { defineComponent, computed, reactive, onMounted, ref } from "vue";
import TextAudioInput from "@/components/taInput/index.vue";
// import TextBubble from "@/components/messageView/textBubble.vue";
import MessageBubble from "@/components/messageView/message/message.vue";
import { Message } from "@/types/message/index";
export default defineComponent({
name: "Messenger",
components: {
// TextBubble
components: {
MessageBubble,
TextAudioInput
},
setup() {
setup(props) {
// List of messages in the view.
// Oldest message first.
const messages: Message[] = reactive([])
// Render a message.
const render = (message: Message) => {
messages.push(message)
console.log(`Pushing: ${message.modifier}: ${message.content}`)
}
// Get the "anchor" message for a given message.
const getAnchor = (index: number) => {
let anchor = "none";
// If not the first message.
if (index > 0) {
anchor = messages[index - 1].id
}
return anchor
}
onMounted(() => {
@ -46,7 +64,8 @@ export default defineComponent({
})
return {
messages
messages,
getAnchor
}
}
@ -59,9 +78,15 @@ export default defineComponent({
#messenger {
width: 100vw;
height: 100vh;
min-height: 100vh;
overflow: scroll;
background-color: #EBEBEB;
}
#message {
position: absolute;
}
</style>