Last active
January 24, 2016 21:44
-
-
Save f1code/1026ba0468b8d1c5adce to your computer and use it in GitHub Desktop.
Responsive thumbnail gallery using the Wordpress API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .image-container { | |
| width: 100%; | |
| position: relative; | |
| } | |
| figure { | |
| transition: left 0.5s, top 0.5s, width 0.5s, height 0.5s; | |
| } | |
| figure img { | |
| width: 100%; | |
| /*height: calc(100% - 20px);*/ | |
| } | |
| figure figcaption { | |
| width: 100%; | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| height: 20px; | |
| background-color: white; | |
| opacity: 0; | |
| transition: opacity 1s; | |
| } | |
| figure:hover figcaption { | |
| opacity: 0.8; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| jQuery(document).ready(function ($) { | |
| function constrain(size, width, minWidth) { | |
| if (width < size.w || | |
| // don't let them leave just a tiny bit | |
| width - size.w < width / 3 || | |
| width - size.w < minWidth) { | |
| return { | |
| h: (width / size.w) * size.h, | |
| w: width | |
| }; | |
| } | |
| return size; | |
| } | |
| function getNextInsert(bottom, preferredSize, maxRight, minWidth) { | |
| var next = bottom[0], | |
| size = preferredSize; | |
| if (bottom.length > 1) { | |
| console.assert(bottom[1].y == bottom[0].y && bottom[1].x > bottom[0].x); | |
| size = constrain(size, bottom[1].x - bottom[0].x, minWidth); | |
| } | |
| for (var i = 0; i < bottom.length; i++) { | |
| var b = bottom[i]; | |
| if (b.y < next.y && b.x < maxRight) { | |
| next = b; | |
| var right = (i + 1 < bottom.length) ? bottom[i + 1].x : maxRight; | |
| size = constrain(size, right - bottom[i].x, minWidth); | |
| } | |
| } | |
| return { | |
| pos: next, | |
| size: size | |
| }; | |
| } | |
| function merge(bottom, pos, size) { | |
| var right = pos.x + size.w, | |
| left = pos.x, | |
| low = pos.y + size.h, | |
| top = pos.y; | |
| for (var i = 0; i < bottom.length; i++) { | |
| // find merge point | |
| if (bottom[i].x == left && bottom[i].y == top) { | |
| bottom[i].y = low; | |
| bottom.splice(i + 1, 0, { | |
| x: right, y: low | |
| }, { | |
| x: right, y: top | |
| }); | |
| // compact similar points (either identical points, or 3 in a row) | |
| for (var j = Math.max(i - 2, 0); j < bottom.length - 2; j++) { | |
| // note that we know the last 2 points won't be identical, since they will | |
| // always have different y | |
| if (bottom[j].x == bottom[j + 1].x && bottom[j].y == bottom[j + 1].y) { | |
| bottom.splice(j + 1, 1); | |
| j--; | |
| } else if ((bottom[j].x == bottom[j + 1].x && bottom[j + 1].x == bottom[j + 2].x) || | |
| (bottom[j].y == bottom[j + 1].y && bottom[j + 1].y == bottom[j + 2].y)) { | |
| bottom.splice(j + 1, 1); | |
| j--; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| // console.log("BOTTOM AFTER MERGE:") | |
| // for (var i = 0; i < bottom.length; i++) { | |
| // console.log(bottom[i]); | |
| // } | |
| } | |
| function sizeAndPositionItem($container, gridColumns, colRange, minWidth, bottom, $item) { | |
| var colWidth = $container.width() / gridColumns; | |
| if (!colRange) | |
| colRange = [1, gridColumns]; | |
| var ncol = colRange[0] + Math.floor(Math.random() * (colRange[1] - colRange[0])); | |
| var originalSize = {w: Number($item.data('width')), h: Number($item.data('height'))}; | |
| while (ncol > colRange[0] && ncol * colWidth > originalSize.w) { | |
| ncol--; | |
| } | |
| var randomSize = constrain(originalSize, ncol * colWidth, minWidth); | |
| var next = getNextInsert(bottom, randomSize, $container.width(), minWidth); | |
| var pos = next.pos, | |
| size = next.size; | |
| $item.css({ | |
| position: 'absolute', | |
| width: Math.ceil(size.w) + 'px', | |
| height: Math.ceil(size.h) + 'px', | |
| top: Math.floor(pos.y) + 'px', | |
| left: Math.floor(pos.x) + 'px' | |
| }); | |
| merge(bottom, pos, size); | |
| return bottom; | |
| } | |
| function addBrick($container, gridColumns, colRange, minWidth, bottom, $item) { | |
| bottom = sizeAndPositionItem($container, gridColumns, colRange, minWidth, bottom, $item); | |
| $container.append($item); | |
| return bottom; | |
| } | |
| function resetContainerHeight($container, bottom) { | |
| var lowest = 0; | |
| bottom.forEach(function (b) { | |
| if (b.y > lowest) | |
| lowest = b.y; | |
| }); | |
| $container.height(lowest); | |
| } | |
| function resizeAll($container, gridColumns, colRange, minWidth) { | |
| var bottom = [{x: 0, y: 0}]; | |
| $('.image-container figure').css({left: '-2000px'}).each(function () { | |
| bottom = sizeAndPositionItem($container, gridColumns, colRange, minWidth, bottom, $(this)); | |
| }); | |
| resetContainerHeight($container, bottom); | |
| return bottom; | |
| } | |
| var bottom = [{x: 0, y: 0}], | |
| currentPage = 1, | |
| today = (new Date()).toISOString(), | |
| apiUrl = '/wp-json/wp/v2/event?per_page=30&meta_key=event_date&filter[meta_value]=' + today + '&filter[meta_key]=event_date&filter[meta_compare]=%3C', | |
| doingRequest = false, | |
| $container = $('.image-container'), | |
| numColumns = 15, minWidth = 150, colRange = [3, 5]; | |
| function displayNextPage() { | |
| if (doingRequest) { | |
| return; | |
| } | |
| doingRequest = true; | |
| var url = apiUrl + '&page=' + currentPage; | |
| currentPage++; | |
| $.get(url, null, function (data) { | |
| for (var i = 0; i < data.length; i++) { | |
| var $brick = $('<figure data-width="720" data-height="400">' + | |
| '<a href="' + data[i].link + '#event-gallery">' + | |
| '<img src="' + data[i].featured_image_thumbnail_url + '" alt="' + data[i].title.rendered + '"/>' + | |
| '<figcaption>' + data[i].title.rendered + '</figcaption>' + | |
| '</a>' + | |
| '</figure>'); | |
| bottom = addBrick($container, numColumns, colRange, minWidth, bottom, $brick); | |
| } | |
| resetContainerHeight($container, bottom); | |
| doingRequest = false; | |
| }, 'json'); | |
| } | |
| function calculateBestWidth(minWidth) { | |
| var w = $container.width(); | |
| numColumns = Math.ceil(w / (minWidth / 2)); | |
| colRange = [Math.ceil(numColumns / 5), Math.ceil(numColumns / 3)]; | |
| // console.log('num cols', numColumns); | |
| // console.log('col range', colRange); | |
| } | |
| // Returns a function, that, as long as it continues to be invoked, will not | |
| // be triggered. The function will be called after it stops being called for | |
| // N milliseconds. If `immediate` is passed, trigger the function on the | |
| // leading edge, instead of the trailing. | |
| function debounce(func, wait, immediate) { | |
| var timeout; | |
| return function () { | |
| var context = this, args = arguments; | |
| var later = function () { | |
| timeout = null; | |
| if (!immediate) func.apply(context, args); | |
| }; | |
| var callNow = immediate && !timeout; | |
| clearTimeout(timeout); | |
| timeout = setTimeout(later, wait); | |
| if (callNow) func.apply(context, args); | |
| }; | |
| }; | |
| $(window).scroll(debounce(function () { | |
| var containerHeight = $container.height(), | |
| windowHeight = $(window).height(), | |
| // fixed top navigation bar | |
| topBar = $container.offset().top, | |
| scrollPosition = window.scrollY, | |
| remaining = containerHeight - (windowHeight - topBar) - scrollPosition; | |
| if (remaining < windowHeight - topBar) { | |
| // less than 1 page left | |
| displayNextPage(); | |
| } | |
| }, 350)); | |
| $(window).resize(debounce(function () { | |
| calculateBestWidth(minWidth); | |
| bottom = resizeAll($container, numColumns, colRange, minWidth); | |
| }, 350)); | |
| calculateBestWidth(minWidth); | |
| displayNextPage(); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // customize to add the thumbnail to the returned data | |
| add_filter( 'rest_prepare_event', function($data, $post, $request) { | |
| $_data = $data->data; | |
| $thumbnail_id = get_post_thumbnail_id( $post->ID ); | |
| $thumbnail = wp_get_attachment_image_src( $thumbnail_id ); | |
| $_data['featured_image_thumbnail_url'] = $thumbnail[0]; | |
| $data->data = $_data; | |
| return $data; | |
| }, 10, 3 ); | |
| // allow filtering by meta fields | |
| add_filter('query_vars', function($qv) { | |
| $qv[] = 'meta_key'; | |
| $qv[] = 'meta_value'; | |
| $qv[] = 'meta_compare'; | |
| return $qv; | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <style> | |
| .image-container { | |
| width: 100%; | |
| position: relative; | |
| } | |
| figure { | |
| } | |
| figure img { | |
| width: 100%; | |
| /*height: calc(100% - 20px);*/ | |
| } | |
| figure figcaption { | |
| width: 100%; | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| height: 20px; | |
| background-color: white; | |
| opacity: 0; | |
| transition: opacity 1s; | |
| } | |
| figure:hover figcaption { | |
| opacity: 0.8; | |
| } | |
| </style> | |
| <div class="image-container" style="width: 100%; height: 2000px"> | |
| </div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment