Error with a Vue.js "calc(...)" attribute binding - vue.js

I want to draw a line in an SVG. This line must be vertical and its length must correspond to the height of the SVG that contains it. As the SVG is responsive I can't use pixel coordinates. Instead I put a rect of width 1px and height 100%.
The problem is that when I try to position it on the x axis in relation to a reference, Vue.js gives me an error, (even though it works: the result)
Error: Invalid value for <rect> attribute x="calc( 100% / 5 * 2 )"
The problem comes from:
:x="'calc( 100% / ' + props.max + ' * ' + props.x + ' )'"
Code
<script setup lang="ts">
import { defineProps } from "vue";
const props = defineProps<{
x: number,
max: number
}>();
</script>
<template>
<rect :x="'calc( 100% / ' + props.max + ' * ' + props.x + ' )'" />
</template>
<style scoped>
rect {
width: 1px;
height: 100%;
stroke: none;
fill: #000000;
}
</style>
I also tried
<script setup lang="ts">
import { defineProps, Ref, ref, onMounted } from "vue";
const props = defineProps<{
x: number,
max: number
}>();
const vertical_line: Ref<HTMLElement | null> = ref(null);
onMounted(() => {
vertical_line.value?.focus();
if (vertical_line.value !== null && typeof vertical_line.value === "object" &&
"setAttribute" in vertical_line.value)
vertical_line.value
.setAttribute("x", "calc( 100% / " + props.max + " * " + props.x + " )");
});
</script>
<template>
<rect ref="vertical_line" />
</template>
<style scoped>
rect {
width: 1px;
height: 100%;
stroke: none;
fill: #000000;
}
</style>

Looks like your code works, maybe wrong props?
const { ref } = Vue
const app = Vue.createApp({
setup() {
const x = ref(6)
const max = ref(30)
return { x, max }
}
})
app.component('lineI', {
template: `
<rect :x="'calc( 100% / ' + max + ' * ' + x + ' )'" />
`,
props: {
x: { type: Number },
max: { type: Number }
},
})
app.mount('#demo')
rect {
width: 1px;
height: 100%;
stroke: none;
fill: #000000;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<svg>
<line-i :x="x" :max="max"></line-i>
</svg>
<br>
<input type="number" v-model="x" />
<input type="number" v-model="max" />
</div>

Related

Dynamically update div size on resize

I'm trying to set a height in px on my container when the size updates. I can display the size as text, and it updates when my container resizes.
However, the height attribute on my container does not update.
Js:
setup() {
const el = ref(null);
const { height, width } = useElementSize(el);
return {height, width, el,}
}
Html:
{{ height }}
<div>
:style="{ height: `${height}px` }"
ref="el"
>
Resizeable items whoopwhoop
</div>
In this case my {{ height }} updates if I remove the :style attribute, but it says 0px with the :style attribute. How can I fix this?
I am not sure about what useElementSize is.
but if you try this:
<script setup>
import { ref , computed} from 'vue'
const el = ref(null);
const height = ref(100);
const width = ref(200);
const dynamicStyle = computed(()=>{
return {
height: height.value + "px",
width: width.value + "px"
}
})
</script>
<template>
<div>
<input v-model="height" type="number" />
<input v-model="width" type="number" />
<div class="resizable"
:style="dynamicStyle"
ref="el"
>
{{dynamicStyle}}
</div>
</div>
</template>
<style>
.resizable{
display: inline-block;
background-color: royalblue;
}
</style>
you can modify the size of the element by changing the inputs values.
Here is the Example above.

styles in composition API can hide the object

hi i used to use Options API and i converted my code completely to composition API but now im having a problem with styles which hides the original object i dunno what differs between these APIs but it should not affect the styling this is my both examples in both APIs
first is composition api
<script setup>
import {
QCalendarDay,
addToDate,
parseTimestamp,
isBetweenDates,
today,
parsed,
parseTime
} from '#quasar/quasar-ui-qcalendar/src/index.js'
import '#quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarTransitions.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarDay.sass'
import { ref ,computed} from 'vue'
import NavigationBar from '../components/NavigationBar.vue'
const calendar=ref(null)
const selectedDate=ref(today())
const events=ref([
{
id: 1,
title: 'Meeting',
details: 'Time to pitch my idea to the company',
date: today(),
time: '09:00',
duration: 120,
bgcolor: 'red',
icon: 'fas fa-handshake'
},
{
id: 2,
title: 'Lunch',
details: 'Company is paying!',
date: today(),
time: '12:00',
duration: 60,
bgcolor: 'teal',
icon: 'fas fa-hamburger'
},
{
id: 3,
title: 'Conference',
details: 'Teaching Javascript 101',
date: today(),
time: '13:00',
duration: 240,
bgcolor: 'blue',
icon: 'fas fa-chalkboard-teacher'
},
{
id: 4,
title: 'Girlfriend',
details: 'Meet GF for dinner at Swanky Restaurant',
date: today(),
time: '19:00',
duration: 180,
bgcolor: 'teal-2',
icon: 'fas fa-utensils'
}
]
)
// computed: {
// convert the events into a map of lists keyed by date
const eventsMap = computed(() => {
const map = {}
// this.events.forEach(event => (map[ event.date ] = map[ event.date ] || []).push(event))
events.value.forEach(event => {
if (!map[ event.date ]) {
map[ event.date ] = []
}
map[ event.date ].push(event)
if (event.days) {
let timestamp = parseTimestamp(event.date)
let days = event.days
do {
timestamp = addToDate(timestamp, { day: 1 })
if (!map[ timestamp.date ]) {
map[ timestamp.date ] = []
}
map[ timestamp.date ].push(event)
} while (--days > 0)
}
})
return map
})
// methods: {
const badgeClasses =(event, type)=> {
let isHeader = type === 'header'
return {
[ `text-white bg-${ event.bgcolor }` ]: true,
'full-width': !isHeader && (!event.side || event.side === 'full'),
'left-side': !isHeader && event.side === 'left',
'right-side': !isHeader && event.side === 'right',
'rounded-border': true
}
}
const badgeStyles = (event, type, timeStartPos = undefined, timeDurationHeight = undefined) =>{
const s = {}
if (timeStartPos && timeDurationHeight) {
s.top = timeStartPos(event.time) + 'px'
s.height = timeDurationHeight(event.duration) + 'px'
}
s[ 'align-items' ] = 'flex-start'
return s
}
const getEvents =(dt) =>{
// get all events for the specified date
const events = eventsMap[ dt ] || []
if (events.length === 1) {
events[ 0 ].side = 'full'
}
else if (events.length === 2) {
// this example does no more than 2 events per day
// check if the two events overlap and if so, select
// left or right side alignment to prevent overlap
const startTime = addToDate(parsed(events[ 0 ].date), { minute: parseTime(events[ 0 ].time) })
const endTime = addToDate(startTime, { minute: events[ 0 ].duration })
const startTime2 = addToDate(parsed(events[ 1 ].date), { minute: parseTime(events[ 1 ].time) })
const endTime2 = addToDate(startTime2, { minute: events[ 1 ].duration })
if (isBetweenDates(startTime2, startTime, endTime, true) || isBetweenDates(endTime2, startTime, endTime, true)) {
events[ 0 ].side = 'left'
events[ 1 ].side = 'right'
}
else {
events[ 0 ].side = 'full'
events[ 1 ].side = 'full'
}
}
return events
}
const scrollToEvent =(event) => {
calendar.value.scrollToTime(event.time, 350)
}
const onToday= ()=> {
calendar.value.moveToToday()
}
const onPrev =() =>{
calendar.value.prev()
}
const onNext =() =>{
calendar.value.next()
}
const onMoved =(data)=> {
console.log('onMoved', data)
}
const onChange =(data)=> {
console.log('onChange', data)
}
const onClickDate =(data) =>{
console.log('onClickDate', data)
}
const onClickTime= (data)=> {
console.log('onClickTime', data)
}
const onClickInterval =(data)=> {
console.log('onClickInterval', data)
}
const onClickHeadIntervals =(data) =>{
console.log('onClickHeadIntervals', data)
}
const onClickHeadDay =(data)=> {
console.log('onClickHeadDay', data)
}
</script>
<style lang="sass" >
.my-event
position: absolute
font-size: 12px
justify-content: center
margin: 0 1px
text-overflow: ellipsis
overflow: hidden
cursor: pointer
.title
position: relative
display: flex
justify-content: center
align-items: center
height: 100%
.text-white
color: white
.bg-blue
background: blue
.bg-green
background: green
.bg-orange
background: orange
.bg-red
background: red
.bg-teal
background: teal
.bg-grey
background: grey
.bg-purple
background: purple
.full-width
left: 0
width: calc(100% - 2px)
.left-side
left: 0
width: calc(50% - 3px)
.right-side
left: 50%
width: calc(50% - 3px)
.rounded-border
border-radius: 2px
</style>
<template>
<div class="subcontent">
<navigation-bar
#today="onToday"
#prev="onPrev"
#next="onNext"
/>
<div class="row justify-center">
<div style="display: flex; max-width: 800px; width: 100%; height: 400px;">
<q-calendar-day
ref="calendar"
v-model="selectedDate"
view="day"
animated
bordered
transition-next="slide-left"
transition-prev="slide-right"
no-active-date
:interval-minutes="15"
:interval-start="24"
:interval-count="68"
:interval-height="28"
#change="onChange"
#moved="onMoved"
#click-date="onClickDate"
#click-time="onClickTime"
#click-interval="onClickInterval"
#click-head-intervals="onClickHeadIntervals"
#click-head-day="onClickHeadDay"
>
<template #head-day-event="{ scope: { timestamp } }">
<div style="display: flex; justify-content: center; flex-wrap: wrap; padding: 2px;">
<template
v-for="event in eventsMap[timestamp.date]"
:key="event.id"
>
<q-badge
v-if="!event.time"
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="width: 100%; cursor: pointer; height: 12px; font-size: 10px; margin: 1px;"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.details }}</q-tooltip>
</div>
</q-badge>
<q-badge
v-else
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="margin: 1px; width: 100px; max-width: 100px; height: 100px; max-height: 100px; cursor: pointer"
#click="scrollToEvent(event)"
>
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</q-badge>
</template>
</div>
</template>
<template #day-body="{ scope: { timestamp, timeStartPos, timeDurationHeight } }">
<template
v-for="event in getEvents(timestamp.date)"
:key="event.id"
>
<div
class="my-event"
:class="badgeClasses(event, 'body')"
:style="badgeStyles(event, 'body', timeStartPos, timeDurationHeight)"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</div>
</div>
</template>
</template>
</q-calendar-day>
</div>
</div>
</div>
</template>
Now options api which has styles(badgestyle method only) run flawlessly
<script>
import {
QCalendarDay,
addToDate,
parseTimestamp,
isBetweenDates,
today,
parsed,
parseTime
} from '#quasar/quasar-ui-qcalendar/src/index.js'
import '#quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarTransitions.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarDay.sass'
import { defineComponent } from 'vue'
import NavigationBar from '../components/NavigationBar.vue'
export default defineComponent({
name: 'WeekSlotDayBody',
components: {
NavigationBar,
QCalendarDay
},
data () {
return {
selectedDate: today(),
events: [
{
id: 1,
title: 'Meeting',
details: 'Time to pitch my idea to the company',
date: today(),
time: '09:00',
duration: 120,
bgcolor: 'red',
icon: 'fas fa-handshake'
},
{
id: 2,
title: 'Lunch',
details: 'Company is paying!',
date: today(),
time: '12:00',
duration: 60,
bgcolor: 'teal',
icon: 'fas fa-hamburger'
},
{
id: 3,
title: 'Conference',
details: 'Teaching Javascript 101',
date: today(),
time: '13:00',
duration: 240,
bgcolor: 'blue',
icon: 'fas fa-chalkboard-teacher'
},
{
id: 4,
title: 'Girlfriend',
details: 'Meet GF for dinner at Swanky Restaurant',
date: today(),
time: '19:00',
duration: 180,
bgcolor: 'teal-2',
icon: 'fas fa-utensils'
}
]
}
},
computed: {
// convert the events into a map of lists keyed by date
eventsMap () {
const map = {}
// this.events.forEach(event => (map[ event.date ] = map[ event.date ] || []).push(event))
this.events.forEach(event => {
if (!map[ event.date ]) {
map[ event.date ] = []
}
map[ event.date ].push(event)
if (event.days) {
let timestamp = parseTimestamp(event.date)
let days = event.days
do {
timestamp = addToDate(timestamp, { day: 1 })
if (!map[ timestamp.date ]) {
map[ timestamp.date ] = []
}
map[ timestamp.date ].push(event)
} while (--days > 0)
}
})
return map
}
},
methods: {
badgeClasses (event, type) {
const isHeader = type === 'header'
return {
[ `text-white bg-${ event.bgcolor }` ]: true,
'full-width': !isHeader && (!event.side || event.side === 'full'),
'left-side': !isHeader && event.side === 'left',
'right-side': !isHeader && event.side === 'right',
'rounded-border': true
}
},
badgeStyles (event, type, timeStartPos = undefined, timeDurationHeight = undefined) {
const s = {}
if (timeStartPos && timeDurationHeight) {
s.top = timeStartPos(event.time) + 'px'
s.height = timeDurationHeight(event.duration) + 'px'
}
s[ 'align-items' ] = 'flex-start'
return s
},
getEvents (dt) {
// get all events for the specified date
const events = this.eventsMap[ dt ] || []
if (events.length === 1) {
events[ 0 ].side = 'full'
}
else if (events.length === 2) {
// this example does no more than 2 events per day
// check if the two events overlap and if so, select
// left or right side alignment to prevent overlap
const startTime = addToDate(parsed(events[ 0 ].date), { minute: parseTime(events[ 0 ].time) })
const endTime = addToDate(startTime, { minute: events[ 0 ].duration })
const startTime2 = addToDate(parsed(events[ 1 ].date), { minute: parseTime(events[ 1 ].time) })
const endTime2 = addToDate(startTime2, { minute: events[ 1 ].duration })
if (isBetweenDates(startTime2, startTime, endTime, true) || isBetweenDates(endTime2, startTime, endTime, true)) {
events[ 0 ].side = 'left'
events[ 1 ].side = 'right'
}
else {
events[ 0 ].side = 'full'
events[ 1 ].side = 'full'
}
}
return events
},
scrollToEvent (event) {
this.$refs.calendar.scrollToTime(event.time, 350)
},
onToday () {
this.$refs.calendar.moveToToday()
},
onPrev () {
this.$refs.calendar.prev()
},
onNext () {
this.$refs.calendar.next()
},
onMoved (data) {
console.log('onMoved', data)
},
onChange (data) {
console.log('onChange', data)
},
onClickDate (data) {
console.log('onClickDate', data)
},
onClickTime (data) {
console.log('onClickTime', data)
},
onClickInterval (data) {
console.log('onClickInterval', data)
},
onClickHeadIntervals (data) {
console.log('onClickHeadIntervals', data)
},
onClickHeadDay (data) {
console.log('onClickHeadDay', data)
}
}
})
</script>
<style lang="sass" scoped>
.my-event
position: absolute
font-size: 12px
justify-content: center
margin: 0 1px
text-overflow: ellipsis
overflow: hidden
cursor: pointer
.title
position: relative
display: flex
justify-content: center
align-items: center
height: 100%
.text-white
color: white
.bg-blue
background: blue
.bg-green
background: green
.bg-orange
background: orange
.bg-red
background: red
.bg-teal
background: teal
.bg-grey
background: grey
.bg-purple
background: purple
.full-width
left: 0
width: calc(100% - 2px)
.left-side
left: 0
width: calc(50% - 3px)
.right-side
left: 50%
width: calc(50% - 3px)
.rounded-border
border-radius: 2px
</style>
<template>
<div class="subcontent">
<navigation-bar
#today="onToday"
#prev="onPrev"
#next="onNext"
/>
<div class="row justify-center">
<div style="display: flex; max-width: 800px; width: 100%; height: 400px;">
<q-calendar-day
ref="calendar"
v-model="selectedDate"
view="day"
animated
bordered
transition-next="slide-left"
transition-prev="slide-right"
no-active-date
:interval-minutes="15"
:interval-start="24"
:interval-count="68"
:interval-height="28"
#change="onChange"
#moved="onMoved"
#click-date="onClickDate"
#click-time="onClickTime"
#click-interval="onClickInterval"
#click-head-intervals="onClickHeadIntervals"
#click-head-day="onClickHeadDay"
>
<template #head-day-event="{ scope: { timestamp } }">
<div style="display: flex; justify-content: center; flex-wrap: wrap; padding: 2px;">
<template
v-for="event in eventsMap[timestamp.date]"
:key="event.id"
>
<q-badge
v-if="!event.time"
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="width: 100%; cursor: pointer; height: 12px; font-size: 10px; margin: 1px;"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.details }}</q-tooltip>
</div>
</q-badge>
<q-badge
v-else
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="margin: 1px; width: 10px; max-width: 10px; height: 10px; max-height: 10px; cursor: pointer"
#click="scrollToEvent(event)"
>
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</q-badge>
</template>
</div>
</template>
<template #day-body="{ scope: { timestamp, timeStartPos, timeDurationHeight } }">
<template
v-for="event in getEvents(timestamp.date)"
:key="event.id"
>
<div
v-if="event.time !== undefined"
class="my-event"
:class="badgeClasses(event, 'body')"
:style="badgeStyles(event, 'body', timeStartPos, timeDurationHeight)"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</div>
</div>
</template>
</template>
</q-calendar-day>
</div>
</div>
</div>
</template>
fixed by adding .value to const events = eventsMap.value[ dt ] || []

How to save local values from inside onMounted hook - Vue 3

how do I save assigned values from inside onMounted hook in Vue 3? My intention of saving the width and height values is so that can use to manipulate the values inside a custom-directive outside of the setup function later on.
I realised that it is only possible manipulating inside the onMounted and using watch see if there is a change to the value. But even so, after assigning the values, it is still undefined.
Is using Vuex the way to go for my current solution?
Because I can only access DOM properties inside onMounted hook and not anywhere else.
<template>
<div class="outer">
<div class="container">
<div>
<div class="border">
<img
id="image"
ref="image"
src="#/assets/1.jpg"
class="image"
/>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { ref, defineComponent, onMounted, watch } from "vue";
const widthVal = ref<number>()
const heightVal = ref<number>()
export default defineComponent({
setup() {
const image = ref<HTMLElement | null>(null)
onMounted(() => {
if (image.value) {
widthVal.value = image.value.offsetWidth;
heightVal.value = image.value.offsetHeight;
console.log('width: ', widthVal.value)
console.log('height: ', heightVal.value)
}
})
watch([widthVal, heightVal], (newVal, oldVal) => {
widthVal.value = newVal[0];
heightVal.value = newVal[1];
console.log(widthVal.value)
console.log(heightVal.value)
})
// becomes undedefined
console.log('width: ', widthVal.value)
return { image }
}
});
</script>
<style>
p {
color: yellow;
}
.outer {
margin: 1em;
display: flex;
justify-content: center;
height: 100vh;
}
.container {
background: rgb(98, 98, 98);
border-radius: 5px;
width: 950px;
height: 650px;
padding: 1em;
overflow: hidden;
font-family: "Trebuchet Ms", helvetica, sans-serif;
}
img {
width: 950px;
height: 650px;
/* remove margins */
margin-left: -18px;
margin-top: -18px;
}
</style>
If you inspect widthVal inside setup() and not inside the watch or onMounted function it gets called BEFORE the values are assigned cause assignments inside setup happen even before the beforeCreate hook.
See: lifecycle hooks
EDIT:
If you really want to use widthVal/heightVal inside setup I'd recommend using it within a function (or a watcher, whatever you need) and calling that inside onMounted after you initialized widthVal/heightVal. E.g.:
const doSomethingElse = () => {
// Use widthVal and heightVal here...
}
onMounted(() => {
widthVal.value = newVal[0];
heightVal.value = newVal[1];
doSomethingElse();
})
...

Create Konvajs Shapes and Connections creating dynamically based on button click events

I would like to create Rectangle Shapes and Connections using the Vue-Konva/Konvajs within my application. I do not want to create load the Static values rather I would like to create the Shapes when the user clicks on the Add Node button and create Connectors when the user clicks on the Add Connector button and build the connections between Shapes.
I looked into a few things and was able to do it using the mouse events but was unable to convert it to button clicks.
Following is the current code I have: CodeSandbox
Can someone please guide me on how to create shapes and connectors on click of the button events? Any suggestion or guidance is much appreciated.
I am looking something like this:
After trying a few things I was able to get it working. Posting here as it can be useful to someone in the future:
<template>
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<button class="btn btn-primary btn-sm" #click="addEvent()">
Add Event
</button>
<button class="btn btn-success btn-sm" #click="submitNodes()">
Submit
</button>
</div>
</div>
<div class="row root">
<div class="col-sm-12 body">
<v-stage
ref="stage"
class="stage"
:config="stageSize"
#mouseup="handleMouseUp"
#mousemove="handleMouseMove"
#mousedown="handleMouseDown"
>
<v-layer ref="layer">
<v-rect
v-for="(rec, index) in nodeArray"
:key="index"
:config="{
x: Math.min(rec.startPointX, rec.startPointX + rec.width),
y: Math.min(rec.startPointY, rec.startPointY + rec.height),
width: Math.abs(rec.width),
height: Math.abs(rec.height),
fill: 'rgb(0,0,0,0)',
stroke: 'black',
strokeWidth: 3,
}"
/>
</v-layer>
</v-stage>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
stageSize: {
width: null,
height: 900
},
lines: [],
isDrawing: false,
eventFlag: false,
nodeCounter: 0,
nodeArray: []
}
},
mounted () {
if (process.browser && window !== undefined) {
this.stageSize.width = window.innerWidth
// this.stageSize.height = window.innerHeight
}
},
methods: {
handleMouseDown (event) {
if (this.eventFlag) {
this.isDrawing = true
const pos = this.$refs.stage.getNode().getPointerPosition()
const nodeInfo = this.nodeArray[this.nodeArray.length - 1]
nodeInfo.startPointX = pos.x
nodeInfo.startPointY = pos.y
console.log(JSON.stringify(nodeInfo, null, 4))
}
},
handleMouseUp () {
this.isDrawing = false
this.eventFlag = false
},
setNodes (element) {
this.nodeArray = element
},
handleMouseMove (event) {
if (!this.isDrawing) {
return
}
// console.log(event);
const point = this.$refs.stage.getNode().getPointerPosition()
// Handle rectangle part
const curRec = this.nodeArray[this.nodeArray.length - 1]
curRec.width = point.x - curRec.startPointX
curRec.height = point.y - curRec.startPointY
},
// Function to read the Nodes after add all the nodes
submitNodes () {
console.log('ALL NODE INFO')
console.log(JSON.stringify(this.nodeArray, null, 4))
this.handleDragstart()
},
addEvent () {
this.eventFlag = true
this.setNodes([
...this.nodeArray,
{
width: 0,
height: 0,
draggable: true,
name: 'Event ' + this.nodeCounter
}
])
this.nodeCounter++
}
}
}
</script>
<style scoped>
.root {
--bg-color: #fff;
--line-color-1: #D5D8DC;
--line-color-2: #a9a9a9;
}
.body {
height: 100vh;
margin: 0;
}
.stage {
height: 100%;
background-color: var(--bg-color);
background-image: conic-gradient(at calc(100% - 2px) calc(100% - 2px),var(--line-color-1) 270deg, #0000 0),
conic-gradient(at calc(100% - 1px) calc(100% - 1px),var(--line-color-2) 270deg, #0000 0);
background-size: 100px 100px, 20px 20px;
}
</style>

Window.resize or document.resize which works & which doesn't? VueJS

I am using Vuetable and its awesome.
I am trying to create a top horizontal scroll, which I have done and its working fine. But I need to assign some events on the window.resize.
I created a component such as
<template>
<div class="top-scrollbar">
<div class="top-horizontal-scroll"></div>
</div>
</template>
<style scoped>
.top-scrollbar {
width: 100%;
height: 20px;
overflow-x: scroll;
overflow-y: hidden;
margin-left: 14px;
.top-horizontal-scroll {
height: 20px;
}
}
</style>
<script>
export default {
mounted() {
document.querySelector("div.top-scrollbar").addEventListener('scroll', this.handleScroll);
document.querySelector("div.vuetable-body-wrapper").addEventListener('scroll', this.tableScroll);
},
methods: {
handleScroll () {
document.querySelector("div.vuetable-body-wrapper").scrollLeft = document.querySelector("div.top-scrollbar").scrollLeft
},
tableScroll() {
document.querySelector("div.top-scrollbar").scrollLeft = document.querySelector("div.vuetable-body-wrapper").scrollLeft
}
}
}
</script>
I am calling it above the table such as <v-horizontal-scroll />
I created a mixin as
Vue.mixin({
methods: {
setScrollBar: () => {
let tableWidth = document.querySelector("table.vuetable").offsetWidth;
let tableWrapper = document.querySelector("div.vuetable-body-wrapper").offsetWidth;
document.querySelector("div.top-horizontal-scroll").style.width = tableWidth + "px";
document.querySelector("div.top-scrollbar").style.width = tableWrapper + "px"
}
}
})
And I am calling it when the user component on which Vuetable is being created
beforeUpdate() {
document.addEventListener("resize", this.setScrollBar());
},
mounted() {
this.$nextTick(function() {
window.addEventListener('resize', this.setScrollBar);
this.setScrollBar()
});
},
I want to understand how this resizing event working.
If I change even a single thing in the above code. I am starting to have issues.
Either it doesn't set the width of scroll main div correctly or even this.setScrollBar don't work on resizing.
I am not clear what is the logic behind this and how it is working?