Vuetify scroll after create element - javascript

I'm trying to do autoscroll by using vuetify inside bus event but this doesnt't work. I tried to reproduce my problem on codepen with just a click event (named clicked) I have the same behavior : https://codepen.io/anon/pen/MLgRBz?&editable=true&editors=101
So I took the scroll example from the doc. I use a function to trigger the click event and inside I set the show variable to true then I use goTo function to scroll.
The problem is, I have to click twice on the button to scroll because the DOM isn't created. how can I do ? There is another event to know when v-if directive create the element ?
const easings = {
linear: '',
easeInQuad: '',
easeOutQuad: '',
easeInOutQuad: '',
easeInCubic: '',
easeOutCubic: '',
easeInOutCubic: '',
easeInQuart: '',
easeOutQuart: '',
easeInOutQuart: '',
easeInQuint: '',
easeOutQuint: '',
easeInOutQuint: ''
}
new Vue({
el: '#app',
data () {
return {
type: 'number',
number: 9999,
selector: '#first',
selected: 'Button',
elements: ['Button', 'Radio group'],
duration: 300,
offset: 0,
easing: 'easeInOutCubic',
easings: Object.keys(easings),
show: false
}
},
methods: {
clicked: function() {
this.show = true;
this.$vuetify.goTo(this.target, this.options);
}
},
computed: {
target () {
const value = this[this.type]
if (!isNaN(value)) return Number(value)
else return value
},
options () {
return {
duration: this.duration,
offset: this.offset,
easing: this.easing
}
},
element () {
if (this.selected === 'Button') return this.$refs.button
else if (this.selected === 'Radio group') return this.$refs.radio
}
}
})
I tried to do it with setTimeout between this.show = true and this.$vuetify.goTo it works but it's ugly

You can use $nextTick to scroll after showing content:
clicked: function() {
this.show = true;
this.$nextTick(() => {
this.$vuetify.goTo(this.target, this.options);
});
}
Codepen demo

Below is My Implementation. Works great for me...
gotToSection(elementId = null) {
if (elementId) {
this.$nextTick().then(() => {
let scrollToElement = document.getElementById(elementId);
// console.log(elementId, scrollToElement);
if (scrollToElement) {
this.$vuetify.goTo(scrollToElement, {
duration: 200,
offset: 0,
easing: "easeInOutCubic",
container: "#target-scroll-container"
});
}
});
}
}

Related

Vue.js slider with local image doesn't work

Hi i find this image slider for Vue.js on "digitalocean.com" but works only with image uploaded on (imgbb, pixabay, etc). i try to set with local image (on assets) but doesn't work, some one can help me?
i already tried with ../assets/castelgandolfo.jpg or ./assets/castelgandolfo.jpg
sorry for my english!
This is the code:
export default {
name: "Slider",
data() {
return {
images: [
"https://i.ibb.co/6NJ7p6w/Castelgandolfo.jpg",
"https://i.ibb.co/QJN06cG/Grottaferrata.jpg",
"https://i.ibb.co/R3pHtGx/Ariccia.jpg",
],
timer: null,
currentIndex: 0
};
},
mounted: function() {
this.startSlide();
},
methods: {
startSlide: function() {
this.timer = setInterval(this.next, 10000);
},
next: function() {
this.currentIndex += 1;
},
prev: function() {
this.currentIndex -= 1;
}
},
computed: {
currentImg: function() {
return this.images[Math.abs(this.currentIndex) % this.images.length];
}
}
};
You can refer images directly using '#'
Example:
<img src="#/assets/images/home.png"/>

Vuejs Loses its #click binding handler when toggled on and off with v-if

I am working with vue-leaflet and esri-leaflet
I am rendering two seperate ESRIFeatureLayers in one vue component and switching between them via a v-if. on first page load. the map #click handlers work fine. but once they have been toggled off via v-if the click handlers no longer fire
This is the vue component
<LLayerGroup
name="Zones"
layer-type="overlay"
>
<EsriFeatureLayer v-if="this.hydroUnit === GROUNDWATER"
ref="gw-layer"
:url="GW_FEATURES_URL"
:token="ARCGIS_TOKEN"
:style-function="gwStyle"
:simplify-factor="0.5"
#mouseover="mouseover"
#mouseout="mouseout"
#click="clickGW"
#featureLayer="updateFeatureLayer"
/>
<LMarker v-if="markerLatLng"
name="clickMarker"
:lat-lng="markerLatLng">
<LTooltip :options="{ permanent: true }">{{ Markertooltip }}</LTooltip>
</LMarker>
<EsriFeatureLayer v-if="this.hydroUnit === SURFACE_WATER && this.sWSitesColors.length > 0"
ref="sw-layer"
:url="SW_FEATURES_URL"
:token="ARCGIS_TOKEN"
:style-function="swStyle"
:simplify-factor="0.5"
#mouseover="mouseover"
#mouseout="mouseout"
#click="clickSW"
#layerClicked="clickSW"
#featureLayer="updateFeatureLayer"
/>
</LLayerGroup>
this is the ESRIFeatureLayer plugin component
<template>
<div style="display: none;">
<slot #click="$event('layerClicked')" v-if="ready" />
</div>
</template>
<script>
import { findRealParent, propsBinder } from 'vue2-leaflet'
import { featureLayer } from 'esri-leaflet'
import * as L from 'leaflet'
const props = {
url: {
type: String,
required: true,
},
styleFunction: {
type: Function,
default: undefined,
},
simplifyFactor: {
type: Number,
default: undefined,
},
precision: {
type: Number,
default: undefined,
},
visible: {
type: Boolean,
default: true,
},
layerType: {
type: String,
default: undefined,
},
name: {
type: String,
default: undefined,
},
token: {
type: String,
default: undefined,
},
pane: {
type: String,
default: undefined,
},
}
export default {
name: 'EsriFeatureLayer',
props,
data () {
return {
ready: false,
}
},
watch: {
styleFunction (newVal) {
this.mapObject.setStyle(newVal)
},
url (newVal) {
this.parentContainer.removeLayer(this)
this.setOptions()
this.parentContainer.addLayer(this, !this.visible)
},
},
mounted () {
this.setOptions()
L.DomEvent.on(this.mapObject, this.$listeners)
propsBinder(this, this.mapObject, props)
this.ready = true
this.parentContainer = findRealParent(this.$parent)
this.parentContainer.addLayer(this, !this.visible)
},
beforeDestroy () {
this.parentContainer.removeLayer(this)
},
methods: {
setVisible (newVal, oldVal) {
if (newVal === oldVal) return
if (newVal) {
this.parentContainer.addLayer(this)
} else {
this.parentContainer.removeLayer(this)
}
},
setOptions () {
const options = {}
if (this.url) {
options.url = this.url
}
if (this.styleFunction) {
options.style = this.styleFunction
}
if (this.simplifyFactor) {
options.simplifyFactor = this.simplifyFactor
}
if (this.precision) {
options.precision = this.precision
}
if (this.token) {
options.token = this.token
}
if (this.pane) {
options.pane = this.pane
}
this.mapObject = featureLayer(options)
this.$emit('featureLayer', this.mapObject)
},
updateVisibleProp (value) {
this.$emit('update:visible', value)
},
},
}
</script>
I have tried adding a event click handler as you can see with #click="$event('layerClicked')"
but no click event is firing once they have been toggled off once.
how do i re-bind the #click handler to the ESRIFeatureLayer if a component is re-shown via the v-if binding?
I found a fix
all i had to do was re-initialize the listeners when a watched property (url) was changed on the child component
Parent
<EsriFeatureLayer
:url="this.hydroUnit === GROUNDWATER ? GW_FEATURES_URL : SW_FEATURES_URL"
:token="ARCGIS_TOKEN"
:style-function="this.hydroUnit === GROUNDWATER ? gwStyle : swStyle"
:simplify-factor="0.5"
#mouseover="mouseover"
#mouseout="mouseout"
#click="click"
#featureLayer="updateFeatureLayer"
/>
ternary operator changed the URL when the hydrounit is changed
the watched url variable in ESRIFeatureLayer re-inits the listeners
watch: {
styleFunction (newVal) {
this.mapObject.setStyle(newVal)
},
url (newVal) {
this.parentContainer.removeLayer(this)
this.setOptions()
this.parentContainer.addLayer(this, !this.visible)
L.DomEvent.on(this.mapObject, this.$listeners)
},
},
mounted () {
this.setOptions()
L.DomEvent.on(this.mapObject, this.$listeners)
propsBinder(this, this.mapObject, props)
this.ready = true
this.parentContainer = findRealParent(this.$parent)
this.parentContainer.addLayer(this, !this.visible)
},

aframe mobile <a-video> fully working but <a-sound> not working

this is a additional question to a (solved) question I had here
I have managed to get video for my project working on mobile & desktop using the component from this glitch project
init: function () {
this.onClick = this.onClick.bind(this);
},
play: function () {
window.addEventListener('click', this.onClick);
},
pause: function () {
window.removeEventListener('click', this.onClick);
},
onClick: function (evt) {
var videoEl = this.el.getAttribute('material').src;
if (!videoEl) { return; }
this.el.object3D.visible = true;
videoEl.play();
}
});
however, on mobile devices, a separate component to play sound from an entity is not working (it works on chrome and safari)
init: function () {
this.onClick = this.onClick.bind(this);
},
play: function () {
window.addEventListener('click', this.onClick);
},
pause: function () {
window.removeEventListener('click', this.onClick);
},
onClick: function (evt) {
let entity = document.querySelectorAll('[sound]');
for (let item of entity) {
item.components.sound.playSound();
}
}
});
I am really confused, I have tried a few separate solutions but nothing seems to be working.
The only time I can get audio to play on mobile is by using this component however it is unsuitable as it only plays audio when the individual objects/entities are clicked, and I need all my sounds to play at once, by a click on the document window.
any help would be appreciated !!
EDIT
here is a code snippet of my project to show issue
UPDATE
I have managed to get the component working on mobile but now spatial sound is broken:
JS:
AFRAME.registerComponent('singleton-sound', {
schema: {
src: {type: 'string'},
autoplay: {default: false},
distanceModel: {default: 'inverse', oneOf: ['linear', 'inverse', 'exponential']},
loop: {default: false},
maxDistance: {default: 10000},
on: {default: ''},
poolSize: {default: 1},
positional: {default: true},
refDistance: {default: 1},
rolloffFactor: {default: 1},
volume: {default: 1}
},
multiple: true,
init: function () {
var audio = document.querySelector(this.data.src);
window.addEventListener('click', playIfFree);
// window.addEventListener('mouseenter', playIfFree);
audio.addEventListener('ended', function () {
window.isPlaying = true
})
function playIfFree () {
if(!window.isPlaying) {
audio.play();
window.isPlaying = false
} else {
return false
}
}
}
});
document.addEventListener("DOMContentLoaded", function(event) {
document.querySelector('#overlay').style.display = 'flex';
document.querySelector('#overlay').addEventListener('click', function () {
let sounds = document.querySelectorAll('audio');
sounds.forEach (function (sound) {
sound.play();
sound.pause();
})
this.style.display = 'none';
})
});
HTML
<a-entity
gltf-model="#alice"
navigate-on-click="url: alice.html"
singleton-sound="
src: #aliceaudio;
volume: 1;
distanceModel: inverse;
rolloffFactor: 2"
position="-0.06 1.5 11.594"
rotation="90 180 0"
scale="0.4 0.4 0.4"
foo
></a-entity>

How can I use javascript to make it so the user can only trigger the hover event once the Lottie animation has played in full?

How can I make it so the user is only able to trigger the mouse hover & mouse left events, once the Lottie animation has initially played in full.
Currently the user is able to cause the hover event when the animation is mid-playing, something I don't want to be able to happen.
Thanks
var anim4;
var anim5 = document.getElementById('lottie5')
var animation5 = {
container: anim5,
renderer: 'svg',
loop: true,
autoplay: false, /*MAKE SURE THIS IS FALSE*/
rendererSettings: {
progressiveLoad: false},
path: 'https://assets1.lottiefiles.com/packages/lf20_H2PpYV.json',
name: 'myAnimation',
};
anim4 = lottie.loadAnimation(animation5);
// SCROLLING DOWN
var waypoint5 = new Waypoint({
element: document.getElementById('lottie5'),
handler: function(direction) {
if (direction === 'down') {
anim4.playSegments([[130,447],[358,447]], true);
this.destroy()
}
},
offset: '50%'
})
anim5.addEventListener("mouseenter", myScript1);
anim5.addEventListener("mouseleave", myScript2);
function myScript1(){
anim4.goToAndStop(500, true);
}
function myScript2(){
anim4.playSegments([358,447],true);
};
var anim4;
var anim5 = document.getElementById('lottie5')
var animation5 = {
container: anim5,
renderer: 'svg',
loop: false,
autoplay: true, /*MAKE SURE THIS IS FALSE*/
rendererSettings: {
progressiveLoad: false},
path: 'https://assets1.lottiefiles.com/packages/lf20_H2PpYV.json',
name: 'myAnimation',
};
anim4 = lottie.loadAnimation(animation5);
// SCROLLING DOWN
var waypoint5 = new Waypoint({
element: document.getElementById('lottie5'),
handler: function(direction) {
if (direction === 'down') {
anim4.playSegments([[130,447],[358,447]], true);
this.destroy()
}
},
offset: '50%'
})
anim4.addEventListener("complete", function(){
console.log('Animation completed!!');
anim5.addEventListener("mouseenter", myScript1);
anim5.addEventListener("mouseleave", myScript2);
});
function myScript1(){
anim4.goToAndStop(500, true);
}
function myScript2(){
anim4.playSegments([358,447],true);
};
Figure it out in case anyone is interested.
This might not be the most efficient way, but worked for me!
anim4.addEventListener('complete', function(e) {
console.log('Animation completed');
});
anim4.addEventListener('complete', function(e) {
var elem = document.getElementById('lottie5');
elem.addEventListener('mouseover', mouseElem)
elem.addEventListener('mouseleave', mouseElem2)
function mouseElem() {
anim4.goToAndStop(150, true);
}
function mouseElem2() {
anim4.goToAndStop(30, true);
}

Why can't I see my neon-animeted tags, moving/fading-out/etc.?

The code is working properly, but somehow it does not show any animations.
I mean using fade-out-animation, it only disappears, no matter what is the duration.
I've imported all the stuff I needed (fade-out-animation,polymer,webcomponents,neon-animation-runner-behavior)
Polymer({
is: 'test-animation',
behaviors: [Polymer.NeonAnimationRunnerBehavior,Polymer.NeonAnimationBehavior],
properties: {
opened: {
type: Boolean
},
animationConfig: {
value: function() {
return {
'entry': {
name: 'slide-from-right-animation',
node: this,
timing: {delay: 2000, duration: 6000}
},
'exit': {
name: 'fade-out-animation',
node: this,
}
}
}
}
},
listeners: {
'neon-animation-finish': '_onNeonAnimationFinish'
},
show: function() {
this.opened = true;
//this.cancelAnimation();
this.playAnimation('entry');
},
hide: function() {
this.opened = false;
// this.cancelAnimation();
this.playAnimation('exit');
},
_onNeonAnimationFinish: function() {
if (!this.opened) {
this.style.display = 'none';
}
}
});
I think you made a mistake in the imported behaviors.
You are using :
-Polymer.NeonAnimationRunnerBehavior, which is correct since your component is running an animation.
-Polymer.NeonAnimationBehavior, which is incorrect: this behavior is meant for creating an animation (fade, slide, whatever you wish). You, on the other hand, want your component to be animatable (meaning, having a Polymer.NeonAnimationBehavior applied to it). The correct behavior for that is Polymer.NeonAnimatableBehavior
So you should change:
behaviors: [Polymer.NeonAnimationRunnerBehavior,Polymer.NeonAnimationBehavior]
to :
behaviors: [Polymer.NeonAnimationRunnerBehavior,Polymer.NeonAnimatableBehavior]
Edit :
I can confirm this was indeed the problem, as I tested this solution successfully.
However, you also have some coma and semi-colon problems in the declaration of your animation. It should be as follows :
animationConfig: {
value: function() {
return {
'entry': {
name: 'slide-from-right-animation',
node: this,
timing: {
delay: 2000, duration: 6000
}
},
'exit': {
name: 'fade-out-animation',
node: this
}
};
}
}

Categories

Resources