Control of video texture in A-Frame - html5-video

In A-Frame, how can I control a video (ie pause, play) which is being used as a texture on a cube utilizing the multisrc component (https://github.com/elbobo/aframe-multisrc-component) with the cursor?
Thanks!

<video id="src0">
<a-entity id="cube" multisrc="src0: #src0" handler>
AFRAME.registerComponent('handler', {
init: function () {
this.el.addEventListener('click', () => {
document.getElementById('src0').pause()
});
},
});

Related

IntersectionObserver not registering on iOS, but works on Android, in Nuxt

What I have
I have made use of IntersectionObserver on my feed page. It behaves like TikTok. Scroll up or down to see the next video. On enter the video plays. On exit, it stops playing.
The Problem
It works on Android and Windows perfectly. On iOS, not so much. The videos are not autoplaying as expected. A bit strange though, is if I click the video (which calls play() on that video), and then scroll it out of view, the video does stop. When I scroll it back into view, it auto plays again. So I know that IntersectionObserver is being recognized, just not triggered initially.
The Code
==================================
The Feed Page, where the Observer is being instantiated:
data() {
return {
observer: null,
}
};
mounted() {
let config = { threshold: 0.1 };
if (process.client) {
if (/iPhone|iPad/i.test(navigator.userAgent)) {
config.root = null;
}
}
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(({ target, isIntersecting }) => {
if (isIntersecting) {
target.play();
} else {
target.pause();
target.currentTime = 0;
}
});
}, config);
beforeDestroy() {
this.observer.disconnect();
},
HTML
<div
v-for="(post, index) in posts"
:key="index"
>
<MobileFeedItem :post="post" :observer="observer" />
</div>
=================================
The MobileFeedItem component
props: ["post", "observer"],
mounted() {
this.$nextTick(() => {
if (this.observer !== null && this.checkMediaTypeIsVideo(this.post)) {
this.observer.observe(
document.getElementById(
`video_${this.getContentId(this.post)}_mobile`
)
);
}
});
HTML
<video
:id="`video_${getContentId(post)}_mobile`"
:data-poster="getThumbnail(post)"
preload="none"
disablePictureInPicture
crossorigin
loop
playsinline
v-lazy-load
class="w-full h-full my-4"
>
<source :data-src="getMedia(post)" type="video/mp4" />
</video>
My Thoughts...
The observer is being instantiated and recognized, just not triggered. So is there a way that I can force the browser to wake up and become aware of the observer without having to click on each of the video elements first?
I found the answer. It wasn't anything wrong with the IntersectionObserver, but because my video was not muted.
"By default, autoplay executes only if the video doesn’t contain an audio track, or if the video element includes the muted attribute. Video playback pauses if the element gains an audio track, becomes unmuted without user interaction, or if the video is no longer onscreen"
source - https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari
It also appears that we don't need intersection observer at all for Safari, as it does this for us. Huh.

Resize button according to screen size

For a button, by default Bootstrap 4 allow you to set default button "size" between : xs, sm, md, lg, xl.
So, in my code, small screen first, i use sm size for screen <576px :
<button type="button" class="btn btn-success btn-sm"></button>
But for xl screen ≥1200px, need i to change size attribute or something else with Bootstrap to adjust button size ?
I don't really understand Bootstrap responsive behavior for button and 'size' attribute between small and large screen.
Thanks.
I don't think there's anything built out of the box for responsive buttons in bootstrap, you'd probably be better off extending the existing bootstrap button sizes in sass/media queries ie
.responsive-button {
#media (min-width: 576px) { #extend .btn-sm }
#media (min-width: 768px) { #extend .btn-md }
}
I haven't tested this so may need to research a bit further but hopefully this gets you on track :)
According to the Vue.js documentation, i had finally computed my CSS class dynamically according to window.onresizeevent call in mounted () function.
Example :
Here is my Bootstrap button :
<b-button :size="nsize" variant="outline-success" class="my-2 my-sm-0">
<font-awesome-icon icon="search"/>
</b-button>
Here is my function in App.vue file:
<script>
export default {
name: 'topnavbar',
data () {
return {
nsize: "sm",
mediaWidth: Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
}
},
mounted () {
if (window.addEventListener) {
window.addEventListener("resize", this.updateSize, false);
} else if (window.attachEvent) {
window.attachEvent("onresize", this.updateSize);
}
},
methods : {
updateSize: function (){
let sizeEl = "md";
let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(width <= 576){
sizeEl = "sm";
}
this.nsize = sizeEl;
}
}
}
</script>
Sources:
Get the browser viewport dimensions with JavaScript
https://fr.vuejs.org/v2/guide/class-and-style.html

How to change slider? Is there possibility to do it in that way?

how can I do 5 photos instead of 3, how to change their size, how to do that they will be change automatically becouse now I have to press play to start?
html:
<script>
$(function () {
// Unstyled Example
$.monte('#example1');
// Styled Buttons Example
// (see the CSS in the above style block)
$.monte('#example2', {auto:false});
// Callback Example
// Format and append the HTML:
$('#example3 > img').each(function(){
$(this)
.wrap('<div style="position:relative"/>')
.parent()
.append('<div><p>' + $(this).attr('alt') + '</p></div>')
.append('<img src="frame.png" alt="" class="frame"/>');
});
// Hide the text on all but the center slide:
$('#example3 div div').css({opacity: 0}).eq(0).css({opacity: 0.8});
// Using the callbacks to reveal and hide the text:
$.monte('#example3', {
auto:false,
callbackIn: function () {
$(this[0]).find('div').animate({opacity: 0.8}, 450);
},
callbackAway: function () {
$(this[0]).find('div').animate({opacity: 0}, 450);
}
});
});
</script>
Here is link to the source where I found it [https://github.com/paizai/monte][1]

Aframe Add Preloader to image loading in sky

I have a scene where I am changing the src for sky using buttons I created "outside the scene". Currently everything works fine but I would like to show a preloader while waiting for the next image to load.
Here you can see my scene: http://scriptstrainer.com/vr_training/
Below I have provided some of my code:
<a-scene>
<a-sky src="images/0-1.jpg" id="img-src">
</a-scene>
<div>
<img src="images/t1.png">
</div>
<div>
<img src="images/t2.png">
</div>
<div>
<img src="images/t3.png">
</div>
<script>
var sky = document.querySelector('#img-src');
var button1 = document.querySelector('#button1');
var button2 = document.querySelector('#button2');
var button3 = document.querySelector('#button3');
button1.addEventListener('click', function() {
sky.setAttribute('src', 'images/0-1.jpg');
});
button2.addEventListener('click', function() {
sky.setAttribute('src', 'images/2.JPG');
});
button3.addEventListener('click', function() {
sky.setAttribute('src', 'images/3.JPG');
});
</script>
Thanks for your assistance...
https://aframe.io/docs/0.4.0/components/material.html#events_materialtextureloaded
There's an event materialtextureloaded you can use to detect when the texture has loaded onto the mesh. In between the time you request to set the texture and the time the texture is set, you can display a loading graphic.
button1.addEventListener('click', function() {
sky.setAttribute('src', 'images/0-1.jpg');
// Display something in the meantime.
sky.addEventListener('materialtextureloaded', function () {
// Small timeout just in case?
setTimeout(function () { // Remove the placeholder. }, 100);
});
});
The loading graphic can be like a spinning object in the scene, a fade-in black mask around the camera (as used in https://github.com/aframevr/360-image-gallery-boilerplate). It depends on what you want it to be.
I had the same scenario where I wanted to add a preloader and only when the image is displayed, to remove the preloader.
I tried using events 'load' and 'loaded' but didn't work as I found out images are not displayed once they finish loading.
Eventually I got help from the AFrame GitHub page and that's how I did it:
<a-assets>
<img id='img-src' src='image.jpg'/>
</a-assets>
<a-sky src='#img-src' id='sky-id'></a-sky>
<script type='text/javascript'>
var skyEl = document.querySelector('#sky-id');
function loaded()
{
var preloader = document.querySelector('#preloader');
preloader.style.display = "none";
}
skyEl.addEventListener('materialtextureloaded', loaded);
</script>

Can't access this.props.navigator

I've been creating my views this way:
var SettingsView = React.createClass({
render: function() {
return (
<View>
<TouchableHighlight onPress={this.donePressed}>
//left out styling code for simplicity
</TouchableHighlight>
</View>
);
},
donePressed: function() {
this.props.navigator.pop();
},
});
This is working fine. donePressed is an event handler that's hooked up with a TouchableHighlight in render (not shown).
Today I tried to refactor it to this:
class SettingsView extend React.Component {
render() {
//same stuff as above
}
donePressed() {
this.props.navigator.pop();
}
}
This rendered the settings screen as normal. But when donePressed triggered, screen turned red saying they can't find this.props.navigator.
I'm not sure what is going on here, please help me out!
Edit:
This screen is brought up via another touch event handler from a different page via this method:
settingsTapped: function() {
this.props.navigator.push({
name: 'SettingsView',
component: SettingsView,
})
},
I've also tried to add passProps: this.props.navigator within settingsTapped too. What I'm most confused is why changing the way I create the class could suddenly make this.props.navigator invisible.
I think the reason it wasn't working is that because you are using Classes as opposed to the createClass function, this is no longer bound to the correct scope. You may need to use an es6 fat arrow function to get this lexically bound to the correct scope, like so:
onPress={ () => this.donePressed() }
You could also do this to get it to work:
onPress={ this.donePressed.bind(this) }