I have a simple script which allows user to click on GIF to make it play and after 8 seconds it should stop on the last frame so user have time to read all information. But the thing is that after 8 seconds when GIF is stopping and it shows picture of last frame, for a very short time it shows thumbnail (firstGIF). Is there any way to fix this code so after 8 seconds it just shows image without any interruptions?
let GIF = document.querySelector('#firstGIF');
let firstFrame = GIF.src;
GIF.addEventListener('click', function() {
GIF.src = 'https://assets.zyrosite.com/AVLWGRP9gOI4Ey6O/1-situacija_1-AVLWq8XV0Lc90EWN.gif';
setTimeout(() => {
GIF.src = 'https://assets.zyrosite.com/AVLWGRP9gOI4Ey6O/situacija_stop-m6Lq6718rLcr4K7b.png';
document.querySelector('https://assets.zyrosite.com/AVLWGRP9gOI4Ey6O/1-situacija_1-
AVLWq8XV0Lc90EWN.gif ').style.display ='
none ';
}, 8000);
})
#firstGIF {
width: 100%;
height: 100%;
}
<img id="firstGIF" src="https://assets.zyrosite.com/AVLWGRP9gOI4Ey6O/3d-
korteles_01.00_00_00_00.still006-mxBEqOj1MXFN5Nvq.jpg">
Related
I've tried google and it just doesnt help me right now. I am trying to make a rickroll that happens after you click on an image 20 times, but I have no idea where to start, can anyone help me? or even better present some code that works in stack overflow so I can see.
You can keep a counter that you increment in the click event handler.
let counter = 0;
document.querySelector('img').addEventListener('click', e => {
++counter;
if (counter === 5) { //change to any number you want
//do something
console.log('clicked 5 times');
}
});
<img src="https://www.w3schools.com/images/html5.gif" />
I'm using these style for suggested actions. When the number of suggested actions are more, i want the suggested actions to be in a container with fixed height and overflow hidden with scrollable.
It looks like there are no style options to do the currently. Could you please check if this can done?
const styleOptions = {
suggestedActionBackground: 'White',
suggestedActionBorder: 0,
suggestedActionBorderRadius: 4,
suggestedActionBorderStyle: 'solid',
suggestedActionBorderWidth: 1,
suggestedActionHeight: 32,
suggestedActionLayout: 'stacked', // either "carousel" or "stacked"
};
enter image description here
This is achievable thru use of CSS, Web Chat's store, and an event listener. A couple things to note, however.
One, this requires manipulating the DOM directly. Generally, this is frowned upon in a React environment. Whether you are using the React version of Web Chat or not, Web Chat is built upon React. Because of this, components may change in the future which could break this setup. Please bare this in mind.
Two, the example below is a simple setup. You will need to adjust it to meet your needs. For instance, you may need to further isolate certain buttons or specific suggested actions as they arrive.
First, we setup our CSS. I have two classes. hideSuggestedActionsContainer is used to, initially, hide any suggested actions. If we don't set this immediately, then the CSS changes made to suggested actions will be momentarily visible to the user as they are rendered. suggestedActionContainer sets the container styling, including enabling (but hiding) scrolling in the container.
.hideSuggestedActionContainer {
display: none;
}
.suggestedActionContainer {
background: white;
width: 300px;
height: 200px;
display: flex;
flex-direction: column;
justify-content: flex-start;
overflow-y: scroll;
-ms-overflow-style: none;
}
.suggestedActionContainer::-webkit-scrollbar {
display: none;
}
In Web Chat, we utilize the store to manage what actions we take and when. The store is passed in as a parameter into Web Chat.
When Web Chat first connects (DIRECT_LINE/CONNECT_FULFILLED), we assign the hideSuggestedActionContainer class to the suggested actions DIV wrapper.
As the suggested action arrives (WEB_CHAT/SET_SUGGESTED_ACTIONS), we remove the hideSuggestedActionContainer class and assign the suggestedActionContainer class allowing the suggested action to be viewed.
At the same time, we monitor the incoming activities (DIRECT_LINE/INCOMING_ACTIVITY) looking for the associated HTML element that houses the suggested action. As Web Chat only allows for one suggested action to be displayed at a time, this should be the first object in the [role=status] array (again, things could change in the future). From that array, we collect the various suggested action buttons and, when one is clicked, we dispatch an event.
const store = window.WebChat.createStore( {}, ({dispatch}) => next => action => {
if ( action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
setTimeout( () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.add( 'hideSuggestedActionContainer' );
}, 20 )
}
if ( action.type === 'WEB_CHAT/SET_SUGGESTED_ACTIONS' ) {
const { suggestedActions } = action.payload;
if ( suggestedActions.length > 0 ) {
setTimeout( () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.remove('hideSuggestedActionContainer');
suggestedAction.classList.add( 'suggestedActionContainer' );
}, 20 )
}
}
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.type === 'message') {
const actions = document.querySelectorAll( '[role=status]' );
const buttons = actions[0].querySelectorAll('button');
buttons.forEach( button => {
button.onclick = function() {
const buttonClick = new Event('buttonClick');
window.dispatchEvent( buttonClick )
};
} )
}
}
next(action);
} );
[ ... ]
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine( {
token: token
} ),
store: store,
styleOptions: styleOptions
},
document.getElementById( 'webchat' )
);
Below the Web Chat renderer, we place our event listener. As a suggested action button is clicked, we remove the suggestedActionContainer class and re-assign the hideSuggestedActionContainer class.
const buttonClickEvent = ( function () {
window.addEventListener( 'buttonClick', () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.remove( 'suggestedActionContainer' );
suggestedAction.classList.add( 'hideSuggestedActionContainer' );
} );
} )()
A note about the setTimeout() functions used in the store. The store processes every activity as it arrives before displaying it. Because of this, a slight delay needs to be applied to the changes we are pushing to the DOM. Without setTimeout(), the page tries to render our changes before the store is able to display the activity's associated HTML. I set the time outs to 20 milliseconds, but you may find you will need to adjust this. I have found that if I set the time out to too low a number then the changes occur before the activity is rendered. If it's too long (300+ ms or thereabouts), then the changes become visible to the user.
Hope of help!
I have a program that keeps track of a number. If you get above your goal number, you visit a page that shows how much extra you have stored up. On that page is a gumball machine, and depending on the number of excess you have stored up, a certain number of gumballs appear in side the machine. Everything works fine, but about 1 out of every 3 page loads, the gumballs appear first, and then the machine appears, covering all of the gumball images first.
This is being done through vue.js Here is the code I have:
created () {
this.$http.get('/gumballs/' + this.$auth.user().id).then(res => {)
this.createCanvas()
})
}
*******
createCanvas () {
// general canvas properties...
// gumball machine properties
this.createGumbllMachine(canvas.width, ctx, (err, succ) => {
if (err) {
console.log(err)
} else if (succ) {
this.createGumballs(canvas.width, ctx)
}
})
}
**********
createGumballMachine (width, ctx, cb) {
const imgObj = document.createElement('img')
imgObj.src = machineImg
imgObj.onload = () => {
ctx.drawImage(imgObj, (width / 2) - 350, 100)
}
return cb(null, 'ok')
}
I have tried to use a callback function as the last argument in createGumballMachine() so that the machine is drawn first and then the gumballs are drawn afterwards, but this doesn't work.
I also tried using async and await but I coudn't get the image to render at all that way. Something was happening where vue could never get past the created portion of it's lifecycle.
I have tried reading about this on other SO questions, but I can't figure it out. I know it has something to do the way ctx.dtawImage() works, but I'm stuck.
Any help is appreciated. If you need to see the code for createGumballs() let me know, but I don't see how that is causing the problem.
Linking a relevant answer which also explains the inconsistent behavior. Essentially, you can use naturalWidth to ensure that the gumball machine has loaded.
https://stackoverflow.com/a/51023755/4409088
I'm writing sort of a chat application using Angular 8 and here's what I want to achieve:
My dialogue component that represents a chat between two users gets one page of last messages that consists of 10 messages after initiating. The div that contains these messages scrolls down to the very last message. When a user scrolls up and reaches a certain point the next page loads. The two arrays join and the user sees now 20 messages. Here's what I have so far:
HTML:
<div>
<div #scrollMe [scrollTop]="scrollMe.scrollHeight" (scroll)="onScroll($event)" style="overflow-y: scroll; height: 400px;">
<ul>
<li *ngFor="let message of messages?.reverse()">
</ul>
</div>
</div>
Typescipt:
loadMessages(page: number, itemsPerPage?: number) {
this.messageService.getMessageThread(page, itemsPerPage || 10)
.subscribe((res: PaginatedResult<MessageThread>) => {
if (this.messages == null) {
this.messages = res.result.messages;
} else {
this.messages = this.messages.concat(res.result.messages);
}
});
}
onScroll(event) {
if (event.target.scrollTop < 100) {
if (this.pagination.currentPage >= this.pagination.totalPages) {
return;
}
this.loadMessages(++this.pagination.currentPage);
}
}
It works, but the problem is that when I join these two arrays, my scrollbar jumps very ugly and since I hold the scrollbar it stays at the same position and keeps loading next pages. I am very new to Angular and front-end in general so I have a feeling that I'm missing something. I tried to find any ready-to-go solutions but could not. Any help would be appreciated.
Please note that I don't want to use JQuery.
Several things:
First, we need a loading flag:
loading = false;
Then we make loadMessages return an observable instead of handle the result:
loadMessages(page: number, itemsPerPage?: number) {
this.loading = true;
return this.messageService.getMessageThread(page, itemsPerPage || 10);
}
A separate method handleResponse handles the response by setting loading to false and concatenating the messages.
Then we can account for the request delay in the scroll handler and use the loading flag to prevent multiple requests:
onScroll(event) {
// get the scroll height before adding new messages
const startingScrollHeight = event.target.scrollHeight;
if (event.target.scrollTop < 100) {
if (this.pagination.currentPage >= this.pagination.totalPages) {
return;
}
else if (!this.loading) {
this.loadMessages(this.pagination.currentPage).subscribe((res) => {
this.handleResponse(res);
// using setTimeout lets the app "wait a beat" so it can measure
// new scroll height *after* messages are added
setTimeout(() => {
const newScrollHeight = this.scrollDiv.nativeElement.scrollHeight;
// set the scroll height from the difference of the new and starting scroll height
this.scrollDiv.nativeElement.scrollTo(0, newScrollHeight - startingScrollHeight);
});
});
}
}
}
Stackblitz (updated)
Hello I make simple site but I have a little trouble with loading images. As you can see with new category there is new image. There is a problem, beacause only then img is loading, and I want to load all images when my site is loading.
sample code how I operate with those img.
imgUrls.push("img/01.jpg");
imgUrls.push("img/02.jpg");
var k3:Boolean=false;
btn1.addEventListener(MouseEvet.CLICK, clickFunc);
function clickFunc(e:MouseEvent):void
if (k3==false)
{
img1.myUILoader.source = imgUrls[0];
k3=true;
}else
{
img2.myUILoader.source = imgUrls[0];
k3=false;
}
btn2.addEventListener(MouseEvet.CLICK, clickFunc2);
function clickFunc2(e:MouseEvent):void
if (k3==false)
{
img1.myUILoader.source = imgUrls[1];
k3=true;
}else
{
img2.myUILoader.source = imgUrls[1];
k3=false;
}
So my question is: How can I load all img with site.?
Your code currently is telling the program to load the images when either btn1 or btn2 is clicked. You need to tell the program to load the images right away, before user input, then have btn1 and btn2 display them.