ListView item animations - Windows store app - javascript

I create simple grid application using basic grid example in visual studio and this tutorial. I expected this animation will work on all item's, but it seems that it works only on first one. My question is, how can I animate this on all item's? And if it is possible to animate randomly(not all at once! Example: windows 8 start menu).
Item template:
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
<div class="item">
<img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
<img class="item-image-new" src="#" data-win-bind="src: backgroundImage; alt: title" />
<div class="item-overlay">
<h4 class="item-title" data-win-bind="textContent: title"></h4>
<h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
</div>
</div>
</div>
Js animation:
var darkGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY3B0cPoPAANMAcOba1BlAAAAAElFTkSuQmCC";
var lightGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
var mediumGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
// Play the Peek animation
function peekTile(tile1, tile2) {
// Create peek animation
var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
// Reposition tiles to their desired post-animation position
tile1.style.top = "-250px";
tile2.style.top = "0px";
// Execute animation
peekAnimation.execute();
}
function changeImage() {
// Get the two image elements
var images = document.querySelector(".item-image");
var imagesNew = document.querySelector(".item-image-new");
// Swap out the old image source and choose the new image source
images.src = imagesNew.src;
if (images.src == lightGray)
imagesNew.src = mediumGray;
else if (images.src == mediumGray)
imagesNew.src = darkGray;
else
imagesNew.src = lightGray;
// Reset the elements for the pre-animation position and trigger the animation
images.style.top = "0px";
imagesNew.style.top = "250px";
peekTile(images, imagesNew);
};
And interval, that changes images(it is written inside ready function):
setInterval(function () { changeImage() }, 4000);

When you call document.querySelector it will only return the first matching element, which in your case will be the first list item. If you want to animate any random item, just call document.querySelectorAll(".item"), pick a random item from the result list and then call querySelector('.item-image') on it, proceeding as you currently do.

Related

Rotating picture gallery

I am learning JS with a little website project and stumbled upon the following problem:
I have an image gallery with a couple of pictures
I can always see 5 pics at a time
one is big in the middle, left and right a second row and 2 more in the background
I already have two buttons to rotate through the gallery. now I want to make it possible to be able to rotate the gallery by clicking the pics on the left or right side of the middle picture.
The HTML gallery
<div class="gallery-container">
<img class="gallery-item gallery-item-1" src="pictures/pic1.jpg" data-index="1">
<img class="gallery-item gallery-item-2 prev-pic" src="pictures/pic2.jpg" data-index="2">
<img class="gallery-item gallery-item-3" src="pictures/pic3.jpg" data-index="3">
<img class="gallery-item gallery-item-4 next-pic" src="pictures/pic4.jpg" data-index="4">
<img class="gallery-item gallery-item-5" src="pictures/pic5.jpg" data-index="5">
</div>
my Javascript
const galleryContainer = document.querySelector('.gallery-container');
let galleryItems = document.querySelectorAll('.gallery-item');
let galleryArray = Array.prototype.slice.call(galleryItems);
let prevPic = document.querySelector('.gallery-item.gallery-item-2.prev-pic');
let listenerPrev = prevPic.addEventListener('click', function(prevEvent) {
galleryArray.unshift(galleryArray.pop());
updateGallery();
});
let nextPic = document.querySelector('.gallery-item.gallery-item-4.next-pic');
let listnerNext = nextPic.addEventListener('click', function(nextEvent) {
galleryArray.push(galleryArray.shift());
updateGallery();
});
// Update css classes for gallery
function updateGallery() {
galleryArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
el.classList.remove('prev-pic');
el.classList.remove('next-pic');
});
galleryArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
document.querySelector('.gallery-item.gallery-item-2').classList.add('prev-pic');
document.querySelector('.gallery-item.gallery-item-4').classList.add('next-pic');
prevPic = document.querySelector('.gallery-item.gallery-item-2.prev-pic');
nextPic = document.querySelector('.gallery-item.gallery-item-4.next-pic');
}
My plan is to click the 'prevPic' and rotate the gallery. The first time clicking it works fine: the gallery rotates and the classes are updated. But when I click the new 'prevPic' it does nothing. What i noticed in my browser is that the 'event'-tag thats added in the html in the devoloper console doesnt move.
I hope someone understands my attempt to explain the matter and can help me out.
Thanks in advance
I would completely rethink my approach and do something like this, where I don't even store any of the elements as references; when a click happens I just look at what was clicked and react based on that. Would something like this work for your case?
document.querySelector(".gallery-container").addEventListener("click", (e) => {
if (e.target.classList.contains("prev")) {
if (e.target.previousElementSibling) {
e.target.previousElementSibling.classList.toggle("prev");
e.target.classList.toggle("prev");
e.target.nextElementSibling.nextElementSibling.classList.toggle("next");
e.target.nextElementSibling.classList.toggle("next");
} else {
alert("Cannot go more previous than this, friendo")
}
}
if (e.target.classList.contains("next")) {
if (e.target.nextElementSibling) {
e.target.nextElementSibling.classList.toggle("next");
e.target.classList.toggle("next");
e.target.previousElementSibling.classList.toggle("prev");
e.target.previousElementSibling.previousElementSibling.classList.toggle("prev");
} else {
alert("Cannot go more next than this, friendo")
}
}
});
.prev {border: 2px solid red;}
.next {border: 2px solid blue;}
<div class="gallery-container">
<img class="gallery-item" src="http://placekitten.com/50/50">
<img class="gallery-item prev" src="http://placekitten.com/49/49">
<img class="gallery-item" src="http://placekitten.com/48/48">
<img class="gallery-item next" src="http://placekitten.com/47/48">
<img class="gallery-item" src="http://placekitten.com/46/46">
</div>
Thank you for your answer. I tried it out, but in the end found a slightly different way, that works better for me (but your approch gave me the idea):
I kept my function updateGallery() where I move the class name around my pics after the gallery got shifted
function updateGallery() {
galleryArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
el.classList.remove('next');
el.classList.remove('prev');
});
galleryArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
galleryArray[1].classList.add('prev');
galleryArray[3].classList.add('next');
}
But access it this time but looping through the gallery:
for (var i=0; i<galleryArray.length; i++) {
galleryArray[i].addEventListener ('click', function(e) {
if (this.classList.contains('prev')) {
galleryArray.unshift(galleryArray.pop());
updateGallery();
} else if (this.classList.contains('next')) {
galleryArray.push(galleryArray.shift());
updateGallery();
}
})
}

Replace main image with the clicked one

There's a main image, and right underneath it there are 10 smaller ones. When you click on the small picture number 6 for example, the main picture gets replaced by the picture 6, and the heading above it changes from 'Pic1.jpg' to 'Pic6.jpg'. What would be the most efficient way to do this with js?
Here's what I tried:
function changeImage() {
var m = document.getElementById("mainimgid");
m.src = document.getElementById(this.id).src;
}
And in HTML:
<img src="img/Pic2.jpg" class="imgmini" id="2" onclick="changeImage()"></img>
Use onClick event to pass the clicked img info and then change the main element with what you want. Here is my aproach with cute cats:
function changeImage(img) {
document.getElementById("mainimgid").src=img.src;
document.getElementById("text").innerText = img.alt
}
img {
width:100px;
}
<div>
<p id="text">Cute cat</p>
<img src="https://i.pinimg.com/originals/c8/27/78/c827782e12851cd2cf4c5161c4f5445a.jpg" class="imgmini" id="mainimgid" onclick="changeImage(this.src)"></img>
</div>
<div>
<img src="https://i.pinimg.com/originals/fc/ca/a0/fccaa0fb45fae275fa1b2dd147f1f189.jpg" class="imgmini" id="2" onclick="changeImage(this)" alt="Cute cat1"></img>
<img src="https://filmdaily.co/wp-content/uploads/2020/04/cute-cat-videos-lede-1300x882.jpg" class="imgmini" id="1" onclick="changeImage(this)" alt="Cute cat2"></img>
</div>
Try doing this
function changeImage(newMainImage) {
var m = document.getElementById("mainimgid");
m.src = newMainImage.src;
}
var newImage = document.getElementById("newImageID");
newImage.onclick = () => changeImage(newImage)
Make the link to pass the event object,
<img src="img/Pic2.jpg" class="imgmini" id="2" onclick="changeImage(event)"></img>
2.Change the event listener to recieve the passed event object
function changeImage(event) {
....
}
Now you can know which link has triggered the event
function changeImage(event) {
let clickedImage = event.target;
let clickedImageSrc = clickedImage.getAttribute("src");
let m = document.getElementById("mainimgid");
m.setAttribute("src",clickedImageSrc);
}

Click Through Var Images in a Loop

I'm currently learning basic JavaScript/JQuery but I'm in need of a quick fix to a problem which is slightly beyond what I'm capable of solving right now.
I'm looking to create a feature that allows me to click through images, and when I click on the last image it will return to the first image, in a loop.
(I'm trying to make something similar to this: https://www.antennebooks.com/product/east-end-of-europe/)
Any help would be greatly appreciated!
this is what I have so far:
<script>
var images = [
"images/img1.png",
"images/img2.png",
"images/img3.png",
"images/img4.png"
]
var step = 0;
changeImage();
function changeImage() {
document.getElementById('imgClickAndChange').src = images[step];
step++;
}
Assuming the function changeImage() is called when you click on the image displayed, you just have to change the step++; to step = (step + 1) % images.length; and place it as the first line of your function.
Each time step + 1 equals to images.length, step would be reset to 0.
We could use jQuery and manipulate the DOM via events, which would make more sense in this situation. A "click" event could be triggered when the user clicks on an image. You could store the images in a set, and when the number of clicks is greater than the length of the set, display the first card and start the process over again. Here is an example of the JavaScript code utilizing the jQuery libary:
$(document).ready(function (){
var card = $('.card'); //store each card with an image in it in a set
card.css('cursor', 'pointer'); //set the cursor to pointer to make a click obvious to user
card.not(':first').hide(); //hide all but the first image (card)
count = 1; //set the initial click count to one
card.on('click', function() { //listen for an image to be clicked
$(this).hide(); //hide the image that has been clicked
$(this).next().show(); //show the next image
count++; //increment the count
if(count > card.length) { //if the count is greater than the length of the set, you are out of images (cards)
count = 1; //reset the count
card.first().show(); //show the first card and start process over
}
});
});
This is the html code that I am using to simulate the events you are looking for:
<div class="card" style="max-width: 18rem;">
<img class="card-img-top" src="/path">
<div class="card-body">
<p>This is a random card and stuff</p>
</div>
</div>
<div class="card" style="max-width: 18rem;">
<img class="card-img-top" src="/path">
<div class="card-body">
<p>This is a random card and stuff</p>
</div>
</div>
<div class="card" style="max-width: 18rem;">
<img class="card-img-top" src="/path">
<div class="card-body">
<p>This is a random card and stuff</p>
</div>
</div>
As you can see, we have three cards that basically store our images. If you just want images and no cards, then do that, because that part of it is trivial. What matters here is the programming logic. I would simply set a counter and once that counter is greater than the length of the set (collection) of cards (a set/collection is an array-link object) then show the first card again and start the process over as I showed you in JavaScript.

Trigger event for an svg element that moves behind another one?

the desired output is for example: When the red masked rectangle is moving behind one of the "holes", the hole needs to change the fill (or some other attr).
Is it possible to add some sort of event that triggers when the moving_rect is entering/leaving the area of the hole element?
in action:
https://jsfiddle.net/qwertasyx/n9v7L95j/
also here as snippet:
var draw = SVG('myDrawing').size('100%',200);
var rect_group = draw.group()
//we dont want to see this
var background = rect_group.rect(200,150).center(250,100).fill('#000')
// we want too see through those 'holes'
var hole1 = rect_group.rect(40,40).center(290,70 ).fill('#fff')
var hole2 = rect_group.rect(40,40).center(290,130).fill('#fff')
var hole3 = rect_group.rect(40,40).center(220,70 ).fill('#fff')
var hole4 = rect_group.rect(40,40).center(220,130).fill('#fff')
// object that we see through the holes
var moving_rect = draw.rect(40,40).fill('red').center(250,100)
//mask obj
var mask = draw.mask()
$('#mask').on('click',function(e){
mask.add(rect_group)
moving_rect.maskWith(mask)
})
$('#animate').on('click',function(e){ moving_rect.animate(250).move(160,40).animate(250).move(250,40).animate(250).move(300,80).animate(250).move(250,160).animate(250).center(250,100)
})
svg{
border-style: solid;
border-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.5/svg.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--
Bootstrap docs: https://getbootstrap.com/docs
-->
<div class="container-fluid">
<div class="row">
<div class="col-12">
<h5>Example svg -> click button for animation </h5><button id="mask" class="btn btn-primary">mask rect</button> <button id="animate" class="btn btn-primary">animate</button>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div id="myDrawing"></div>
</div>
</div>
</div>
<hr>
So I crafted together a solution where on every animation step it is checked if one of the rectangles (holes) is intersecting with the moving rectangle.
If an intersection is detected, it changes the fill color of the "holes".
// animate()...
.duringAll(function () {
// get box of the rectangle
var bbox = this.bbox()
// intersection function. You should define it somewhere outside
// instead of redefining every time
var intersect = function(boxA, boxB) {
return (boxA.x < boxB.x2 && boxA.x2 > boxB.x &&
boxA.y < boxB.y2 && boxA.y2 > boxB.y)
}
// go trough the boxes of every hole defined before
boxes.forEach(function (el, index) {
if(intersect(bbox, el)) {
// change color of fill on intersection
rects[index].fill('#555')
} else {
rects[index].fill('#fff')
}
})
})
Working fiddle:
https://jsfiddle.net/Fuzzy/n9v7L95j/5/
It would be trivial to fire an event instead. You can just go:
this.fire('intersection', {index: index})
// then bind with
moving_rect.on('intersection', function (ev) {
var index = ev.detail.index
// do somthing
rects[index].fill('#333')
})

Background-Image fade jquery

I have a div and I want to fade in and out of 5 different background images at random.
I have downloaded a jquery plugin for this, but unfortunately it alternates - I'll explain.
You must set a default background image (for this case lets say "image1") and then load an array of images (say image2, image3, image4, and image5). What the plugin does is duplicate the div and place it directly over the original one, then fades in and then out one of the array of images. The undesirable effect that I'm getting from this is:
1,2,1,3,1,4,1,5
as opposed to:
1,2,3,4,5
Because the fade out simple reveals the default image once again.
Without re-inventing the wheel is there a way to modify the code to that when the fade-in animation is complete (the default is completely concealed) I swap out the image on the background div so that when the fade out begins there's a new image below? I'm relatively new to JQuery and so this is not my strength.
Heres the action part of the plugin:
var tempImage = new Image();
jQuery(tempImage).load( function(){
var newImage = ( helperElement.css('display') == 'block' ) ? jQuery(this) : jQuery(helperElement);
newImage.css('backgroundImage', 'url('+tempImage.src+')');
helperElement.animate( settings.effect, settings.duration, settings.easing, settings.callback );
});
tempImage.src = src;
And in my HTML:
<script>
document.getElementById('content_container_home').style.backgroundImage = "url('img/buttons.jpg')";
$( function(){
var bgImages = [ 'barker.jpg', 'boards.jpg', 'feet.jpg', 'glasses.jpg' ];
var currImage = 'buttons.jpg';
setInterval( function(){
do{
var randImage = bgImages[Math.ceil(Math.random()*(bgImages.length-1))];
}while( randImage == currImage )
currImage = randImage;
$('#content_container_home').BgImageTransition( 'img/'+currImage );
}, 5000)
});
</script>
Check out my answer to another question
This should do the trick:
HTML:
<div id="testers">
<div class="tester">
<img src="http://regmedia.co.uk/2008/03/18/google_adwords_machine.png" alt="" />
</div>
</div>
<div id="morework">
<div class="holderdiv">
<div class="tester">
<img src="http://www.swwebs.co.uk/images/google-pagerank.jpg" alt="" />
</div>
</div>
<div class="holderdiv">
<div class="tester">
<img src="http://jsfiddle.net/favicon.gif" alt="" />
</div>
</div>
</div>
CSS:
#morework{display:none;}
jQuery:
$(document).ready(function(){
function runIt(){
$('#morework').find('.holderdiv').each(function(i, elem) {
$("#testers").delay(5000).fadeOut(1000, function() {
$(this).html($(elem).html());
}).fadeIn(1000, runIt);
});
};
runIt()
});
Check it out in action here - http://jsfiddle.net/sfsPx/

Categories