I've gone through lots of masonry libraries before posting this question, but I could not find anything similar. So, I would greatly appreciate your advice.
What I'm trying to achieve is a perfect square masonry with just several (1-5) images - similar to Facebook images layout. E.g:
Also, I've been trying to build it myself from scratch, but there are some difficulties: As I understand, one can never know image height and width before it is partly or fully loaded. Even though, at first I need dimensions of only the first image to decide on a grid style, this waiting does not seem a good solution. On fb, the grid seems(?) to be determined from the beginning.
I have doubts that in case of FB the positions and sizes of these images are calculated in back-end and css is used only for masking, because server returns already resized images and maybe it even stores these alignment data to avoid repeated calculations.
Could you share your experience on this or redirect me to some library that solves this task? Actually, this algorithm should be easier than perfect masonry algorithms with many images, because only 1-5 images needs be shown here and all cases are determined based on whether first image is a portrait, landscape or square and whether it fills container width.
Thanks!
Related
I am developing a website with React which has what we called "snippets", basically a modal window displaying some kind of media (audios, videos, slides, text quotations, pdfs). These media have "positions", as a page number, an image number, a playback position, or a scroll position. If she likes the user may store these snippets together with their positions in a "locker" and come back later to whatever is in there. Visually the locker will hold a "thumbnail" of the snippet representing the appearance of the snippet at the time of storing it. My question is how to go about making such a on-the-fly thumbnail. Two approaches come to my mind, however, if you have other ideas I am eager to hear them.
Component approach: Since I already have the component, I could reuse or rather clone it, scale it down, disable it for mouse interaction. Would React.cloneElement() be the way to go?
Advantage: Easy to do.
Disadvantage: Too many duplicates of potentially resource-heavy components may slow down website. Styling may become non-trivial as some embedded media (audio, video) bring their own potentially inaccessible styling with them.
Image generation approach: Since I only need an image, I could take a screenshot of the snippet area, scale it down and use it. Can this be done fully (from generation to usage) on the client side? Is there a good library which does the heavy-work for me?
Advantage: Resource-heavy only during the making of the thumbnail, resource-light in the locker. Accessible for any styling.
Disadvantage: Potentially difficult to do?
After some research I found a solution. Interestingly, it is a mixture of the two approaches I was able to think of. It is possible to access and rasterize the DOM elements which make up the snippets, draw them on a canvas and turn it into an image. The most popular library for this seems to be html2canvas, however, there are a number of others among which rasterizeHTML and html-to-image seem to stand out. Often wrappers for React exist, in the case of html2canvas, for example, use-react-screenshot.
Sites like google image search display images of varying width in rows. Apparently, they select which images to group together, and which images to make a bit smaller, in order to achieve a fairly even spacing between the images.
I tried to search online for a library that implements such an algorithm.
I am asking here if anyone knows of such a solution and if not, I could use some pointers on how to write this code myself.
UPDATE: I found photowall using jquery.
this seems to be the answer. I am currently searching for an angular.js directive
There is the library Masonry (the one mplugjan also mentioned). This library is very flexible in the way you can set up a grid. See their options page.
If you want to do it your self, you have roughly two options:
The images have a fixed/max width
The images have a fixed/max height
Google Images give their images a max height, which allows them to creates rows, and position the images inside them.
The other option is to create columns of a fixed with and place the images in these columns. This option, however is a bit harder to implement, because you have to think harder about the order in which the images are placed.
Edit:
After a quick look at Photowall, it seems that Masonry is more flexible. The documentation on the Masonry site show far more examples in mixing various heights/widths.
I want to know if there's a way to show more than 3 images on this script. I already tried, but I couldn't do it.
Link: http://tympanus.net/Development/3DGallery/
If it's impossible, is there any other plugin in this same style?
Thanks.
No you can't with this plugin (well, obviously you can with vast amounts of changes, as in recoding it from scratch). And the reason is it basically spins through a left, center and right screen, so you can't add more "states". You will even see leftCSS, rightCSS and currentCSS, which applies to the 3 different states
About options to this, there are a lot of options, most of them paid, but you can check 3D Flow, which is free and has a lot of different view options
Ok so after some searching and not finding the real anwser I was looking for I came with the following question in this situation:
I have a trading website that loads about 2300 PNG images of 37x50 twice, once in a left column and once in a right column. The images and all information that comes with it is inserted using jQuery on the document on the onLoad event. However loading 2300 images (even when the html came straight from the server) takes just TOO much time and even hangs new versions of chrome!. So now the quick solution was just to remove the images and show in a dynamic tooltip. Works great but got angry website users and it is indeed ugly.
So... I thought of some possible solutions but I have no idea what is good/bad practice here:
Make all images JPEG and reduce quality.
With the above or not: Add all images to 1 very large image, load it and draw 4600 canvasses based on locations in an array like 'imageArray["someimageID"] = { x = 0, y = 40 }'
Convert all images to base64, add them in an array 'imageArray["someimageID"] = "base64"' and draw 4600 canvasses.
And to an extend where I must think of as well that of all those 2300 images I have a small, medium and large version. (of which only the small ones, 37x40, are shown all together in a page)
Hope to get some nice insights on how to correctly solve such a problem!
Greets
If your images are static (not generated for every request) I think you should use CSS sprites. (similar to your own suggestion of lots of canvases).
Basically you create a div for each image you want to show (or some other container element) and set a background on it that takes a small portion of the big image that contains all images.
Example css:
img.icon1
{
width:50px;
height:50px;
background:url(spritesheet.png) 50 0;
}
in this example the 50 and 0 indicate the offset of your 50x50 icon in the spritesheet.
Update: Here http://css-tricks.com/css-sprites/ is an explanation that goes a bit further than my simple example.
First off, consider whether or not you actually need this many images, and loaded on the page all at once. Assuming you do...
Make all images JPEG and reduce quality.
Use the right format for what you're doing. JPEG is for photos. My guess is that since you have 37x50 pixel images that you're not showing photos. PNG is likely smaller from a file-size perspective in this case. It doesn't matter a whole lot though because the speed issue you're having is probably 80% browser time, 20% network time.
With the above or not: Add all images to 1 very large image, load it and draw 4600 canvasses based on locations in an array like 'imageArray["someimageID"] = { x = 0, y = 40 }'
Try it and see. I don't think this is going to help you. A canvas will have more overhead than a simple image.
Convert all images to base64, add them in an array 'imageArray["someimageID"] = "base64"' and draw 4600 canvasses.
Don't do this. You're adding 33% overhead to the file size, and again the load problem is mostly in your browser.
What you can do
Really question again whether or not you need this many images in the first place.
Cut down on network requests by using several hostnames to load the images. image1.example.com, image2.example.com, image3.example.com, etc. This will allow for more network requests in parallel.
Use your developer tools to verify where the problem actually is. Again, I suspect it's mostly client-side. Once you know the real problem, you can solve it directly.
I would advise if you can, creating a very low resolution sprite of images that can be placed to make it look like everything is loaded, then replace this with the proper images. Without better code/samples/what your images contain/ are they dynamic I am unable to give you a real answer with solution but at least it can lead you in the correct direction.
If your images are static, this will work fine, if dynamic there is not much else that can be done. I think some examples of the webpage you are creating would be great
The reason you're having problems is simply a massive amount of HTTP requests - something you should always be trying to minimize.
Like others are saying here, you're going to want to use a spritesheet technique if possible (it sounds like it is). A spritesheet will condense all of your images into one, removing 2299 of your HTTP requests.
I'm working on a full page, flexible width image gallery.
https://weknowtoomuch.com/projects/nga/projects-grid
Now, you probably start to get an idea of what I'm trying to do. The page in it's current state is rather good, but the spaces between the images (blank spaces around the center of rows) are a bit too big.
The way I have implemented that is very simple, just distribute images by alternating their float property between left and right.
The effect that I'm trying to achieve, ideally, would be something closer to this:
http://images.search.yahoo.com/search/images;_ylt=AwrB8p4dRulSGDgAuCeZDWNH;_ylu=X3oDMTBwazJlZjZ1BHNlYwNzdHJtBHNsawN0aXRsZQRjcG9zAzA-?p=2014+Super+Bowl+pictures&aq=Trending&sid=743e5f15-0b3b-3483-ada1-c617f8754761&spos=0&norw=1&
I tried some research, but the solutions that I found involve fitting all images by changing row height, which I'm trying to avoid. Some tall images might also have to occupy two rows, which would also probably not work well with the changing row height technique.
What I'm hoping for, maybe, is an algorithm that would let me distribute images in a way that white spaces are minimized, and also randomize the location of white space blocks.
I am not using jQuery in this project, but I could do an exception if there is no other reasonable way!
A complete solution that fulfills all the above criteria would also be a good alternative to implementing an algorithm myself, in case you have a tip in that direction...
A final note: some minimal horizontal cropping of images is also acceptable.
Hoping to get some tips, leads, and other useful feedback, and that this would help someone else sometime.
Strangely, a similar question was asked yesterday. In my answer I have presented a draft for a layout engine that adjusts the height of each column to achieve a tile effect.
You don't want to adjust the heights, but the mechanism could perhaps be altered to fit your needs. If you don't update the heights, you can achieve justification by distributing the remaining space among the gaps between the photos. That can create very large gaps which don't look nice. Alternatively, you can achieve a more compact look by centering the rows at the cost of having ragged margins. Still, this looks better in my opinion.
I've created a scrappy prototype (that does not work in IE and has other issues). It centers the images, but you can download it and alter the gap and center parameters.
I know that this is not an answer to your question, more like a suggestion. There are bin-packing algorithms for evenly distributing the images over the rows. Also, the issue of the double-row images is not solved.
Are your photos of arbitrary size or do you use, say, three or four standard sizes? If so, possible layouts could be precalculated and then applied on the fly.