I'm trying to randomize a gallery of images. The HTML contains only the images, the idea is to then get the array, shuffle it and add them to divs acting as thumbnails. I took the shuffling code from here (the Durstenfeld version): How to randomize (shuffle) a JavaScript array?
My code:
var pics = document.getElementsByTagName("img");
//the Durstenfeld shuffle
for (m = pics.length - 1; m > 0; m--) {
var k = Math.floor(Math.random() * (m + 1));
var temp = pics[m];
pics[m] = pics[k];
pics[k] = temp;
}
//giving ID to each image and adding them to a thumbnail div
for (e = 0; e < pics.length; e++) {
pics[e].id = e;
var photo = document.getElementById(e);
var parent_section = photo.parentNode;
var new_div = document.createElement("div");
new_div.classList.add("thumbnail");
new_div.appendChild(photo);
parent_section.appendChild(new_div);
}
The thing is, this works perfectly fine in IE, but in all of the other browsers I tried, the images are simply placed in the default order (the order in which they are written in the HTML). The shuffling itself should be correct so I'm sure there's something wrong with my implementation of it, but I can't figure it out.
Your Array isnt an Array. Do this:
var pics = Array.from(document.getElementsByTagName("img"));
Related
I would like to control each image I have in my const imgURLArray, if possible via class or id.
If this is only possible via JS, could someone help me or teach me how to do it?
I have created a CodePen to see the infinite gallery in action.
const imgURLArray = [
"url(img1)",
"url(img2)",
"url(img3)",
"url(img4)",
];
Try editing your createImageGrid function to this:
function createImageGrid() {
for(let y = 0; y < rowNum; y++) {
let row = document.createElement("div");
row.className = rowClass;
for(let x = 0; x < imgNum; x++) {
let image = document.createElement("div");
image.className = imageClass;
// This gives it id
image.id = `image${y}-${x}`
row.appendChild(image);
}
document.querySelector(containerSelector).appendChild(row);
// Add the images to our representation
imgRep.push(gsap.utils.toArray(row.querySelectorAll(imageSelector)));
}
rows = document.querySelectorAll(rowSelector),
imgMidIndex = Math.floor(imgNum / 2),
rowMidIndex = Math.floor(rowNum / 2);
}
With that your images will have id of image${ITS_ROW}-${ITS_COLUMN} and you will be able to pinpoint the exact image this way.
Edit
(Based on comment.)
Just replace your function createImageGrid() {} with this one and it will give your images property id that is = image${y}-${x}.
Output shown here:
I have this project in paperjs:
var url = "http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png";
raster = new Raster(url);
raster.rotate(10);
raster.scale(0.4);
var url2 = "https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png";
secondRaster = new Raster(url);
secondRaster.scale(0.9);
var count = 150;
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 0; i < count; i++) {
// The center position is a random point in the view:
var center = Point.random() * view.size;
var placedSymbol = symbol.place(center);
placedSymbol.scale(i / count);
}
function onFrame(event) {
// Run through the active layer's children list and change
// the position of the placed symbols:
for (var i = 0; i < count; i++) {
var item = project.activeLayer.children[i];
// Move the item 1/20th of its width to the right. This way
// larger circles move faster than smaller circles:
item.position.y += item.bounds.width / 80;
// If the item has left the view on the right, move it back
// to the left:
if (item.bounds.bottom > view.size.width) {
item.position.y = -item.bounds.width;
}
}
}
The first raster has a symbol works good, but the second can't make it work... I read about to add more than one symbol to project.activeLayer.children but don't work. Even if I do a group of an array with both symbols also don't show up.
I read in a post that symbols can't be added as a group. Being that be true, it should be ok to be added even though isolated...
Anybody had done something similar?
Thank you
There are some mistakes in your code:
The most important one, that make you think that the second raster doesn't work, is that you are creating the second raster with the variable url instead of url2. So both rasters use the same image as source...
You need to place the second symbol like you do with the first one otherwise it will never get rendered.
When iterating through active layer children, make sure to iterate over all children by using project.activeLayer.children.length (as you are placing count * 2 symbols).
When checking for bottom reaching items, use height instead of width.
Here is a sketch demonstrating the solution.
var COUNT = 10;
var raster = new Raster('http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png');
raster.rotate(10);
raster.scale(0.4);
var secondRaster = new Raster('https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png');
secondRaster.scale(0.15);
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 1; i <= COUNT; i++) {
// first symbol
symbol.place(Point.random() * view.size).scale(i / COUNT);
// second symbol
secondSymbol.place(Point.random() * view.size).scale(i / COUNT);
}
function onFrame(event) {
for (var i = 0; i < project.activeLayer.children.length; i++) {
var item = project.activeLayer.children[i];
item.position.y += item.bounds.height / 80;
if (item.bounds.bottom > view.size.height) {
item.position.y = -item.bounds.height;
}
}
}
Ultimately I'm making a slider puzzle with a table, but at the moment I am generating a new puzzle and shuffling the tiles, but it appears that something in my code is making this work incorrectly. (not all the table cells are populated, etc.) Any idea what could be causing this?
In the program I am writing, I am using body onload to build the puzzle but for some reason that won't work in the Fiddle:
</head>
<body onload="newPuzzle(_r, _c)">
</body>
Fiddle Example
Try changing
//declare and populate array
var _array = new Array();
for (var i = 0; i <= r*c; i++)
{
_array[i] = i;
}
to
//declare and populate array
var _array = new Array();
for (var i = 1; i < r*c; i++)
{
_array[i] = i;
}
_array[0] = "";
AND changing this:
var rand = Math.floor(Math.random() * _array.length) + i;
to this:
var rand = Math.floor(Math.random() * _array.length);
Just a note, as you're shuffling with a new array, there is not point in the first configuration (0 to 8), that way you can remove two FORs and just set a fixed value when generating it (before shuffle).
Like so:
gridTable[0].rows[i].cells[j].innerHTML = "0";
I am creating images flip game in jquery. I am having trouble with images. In image flip game we have only two images of the same type. I have 44 img tags and 22 images. I am taking images randomly.
Q1. How to take two images only of the same type?
Q2. If one image is clicked it should be displayed as it is working now but when any other image is clicked then if the sources (src) of both the images are same, both should be hidden forever. If not both should turn over again.
Here is my code of the script.
<script>
var imgSources = new Array();
var twoImagesOnly = [];
for(var c = 1; c < 22; c++){
imgSources.push(c + ".png");
}
$('#add').click(function(){
addElements(44);
$('#add').attr('disabled', 'true');
});
function addElements(times){
var main = $('#main');
for(j = 1; j <= times; j++){
var div = $("<div>");
var img = $("<img>");
img.attr('src', getImage());
img.attr('width', '100');
img.attr('height', '100');
img.click(function(event){
$(this).slideUp();
event.stopPropagation();
});
div.click(function(){
$(this).children('img').slideDown();
});
div.addClass('div');
div.append(img);
img.addClass('myimg');
main.append(div);
img.slideUp('fast');
}
}
var counter;
function getImage(){
var rand = Math.floor(Math.random() * 22) + 1;
var str = '';
if($.inArray(rand, twoImagesOnly) == -1){
str = rand + '.png';
twoImagesOnly[counter] = rand;
counter++;
}else{
getImage();
}
return str;
}
</script>
and here JSFiddle
Seems someone beat me to the punch with half of my solution while I was editing the fiddle, but I'll post this just because the second half should help you a bit with ensuring that only 2 of each card are posted.
First off, to initialize the array, use the following:
for(var c = 1; c < 23; c++){
imgSources.push(c + ".png");
imgSources.push(c + ".png");
}
This will iterate 22 times, adding files 1.png through 22.png twice each.
Then, to ensure only two of each image are used:
function getImage(){
var rand = Math.floor(Math.random() * imgSources.length);
var str = imgSources[rand];
imgSources.splice(rand,1);
return str;
}
What this will do is remove each array item as they are used, sort of like drawing cards from a deck, ensuring that only two of each image are used and avoiding the "keep trying until it works" approach you had.
Fiddle
Q1. A quick solution to be sure that exactly two images are present, could be to push twice to your array:
for(var c = 1; c < 22; c++){
imgSources.push(c + ".png");
imgSources.push(c + ".png");
}
And then randomize it (see https://stackoverflow.com/a/2450976/3207406 for function example)
And then fetch the image in order with a function like
getImage(i)
Q2. Regarding the "two clicks",
you could use one global variable:
first_image
Which will be null if no image was previously shown.
Otherwise, it will contain the details of the currently show image (like source and id). If the sources don't match, then you can turn back the two pictures after some time.
I am trying to iterate over the list and create the rectangle boxes, and on click of each user should be redirected to specific page, though struggling to understand the click handler. Please help me to refine below code, so that it redirects to corresponding url instead of the last one. (I think its my lack of knowledge in JS itself.)
var items = [{'url': 'http://google.com'}, {'url': 'http://stackoverflow.com'}];
var bh = 120;
var bw = 120;
var br = 8;
var start_x = 100;
var start_y = 80;
r = Raphael("holder", 840, 780)
for (var i = 0; i < items.length; i++){
group = r.set()
group.push(r.rect(start_x, start_y, bh, bw, br));
start_x = start_x+200;
group[0].node.onclick = function(){
alert(items[i].url);
};
}
jsFiddle Demo
Above code is kind of version what I am working on and it renders multiple rects on SVG, the problem I am running into is on click of the rect, it returns the last one only.
Thanks.
The problem is that there's one variable called i, and after the loop is over its value is items.length. You need to remember the correct value for each node. Try this:
for (var i = 0; i < items.length; i++){
...
var rect = r.rect(start_x, start_y, bh, bw, br);
rect.node.setAttribute('data-index', i);
group.push(rect);
...
rect.node.onclick = function(event) {
alert(items[event.target.getAttribute('data-index')].url);
};
}