Skip to content

Instantly share code, notes, and snippets.

@hpainter
Created December 11, 2014 19:53
Show Gist options
  • Save hpainter/a32e711d29da6e3de115 to your computer and use it in GitHub Desktop.
Save hpainter/a32e711d29da6e3de115 to your computer and use it in GitHub Desktop.
// Class to load a remote RSS feed and create DOM elements with a
// CSS parallax effect applied. Requires jQuery, Google jsapi
// Constructor. Accepts attributes hash, eg:
// {
// url: "http://foo.com", // Feed url
// qty: 40, // Items to fetch
// target: "#foo_feed", // Parent element selector
// template: "#bar" // Item template selector
// }
var ParallaxFeed = function(attrs) {
var attrs = attrs || {};
for(var key in attrs){
this.key = attrs[key];
}
};
ParallaxFeed.prototype = {
url: "http://rss.news.yahoo.com/rss/mostviewed",
qty: 40,
target: "#feed",
template: "#item_template",
// Render options
zLayers: 5, // Number of layers to stack
scaleFactor: 0.08, // Items will be scaled based on their z-index and this
cellFactorW: 1.25, // Grid cell width relative to item width
cellFactorH: 1.25, // Grid cell height relative to item height
// Private attrs
_feed: null, // google.feeds.Feed
_nextId: 0, // Item ID counter
// Callback for google.load() when feed api is ready. Loads feed,
// parses entries, and returns array of item data hashes
//
// @return Promise
load: function() {
var dfr = $.Deferred();
this._feed = new google.feeds.Feed(this.url);
this._feed.setNumEntries(this.qty);
this._feed.load( function(result){
if(result.error) {
// Reject the deferral with the error
dfr.reject(result.error);
return;
}
var items = [];
for (var i=0; i < result.feed.entries.length; i++){
//console.log(result.feed.entries[i]); //DEBUG
// Find jQuery img object in content
var $img = null;
try{
$img = $(result.feed.entries[i].content).find("img").first();
} catch(e) {
// No image for item
}
// Create new feed item
var item = {
title: result.feed.entries[i].title,
img: $img,
href: result.feed.entries[i].link
}
items.push(item);
}
// Resolve the deferral with the finished collection:
dfr.resolve(items);
});
return dfr.promise();
},
// Render items as DOM elements.
//
// @param Array items [{ title: "foo", img: bar},...]
// @return void
render: function(items) {
if(items.length == 0) return;
// Convert item hashes to dom elements:
var $target = $(this.target);
var $items = [];
for(var i =0; i < items.length; i++){
var item = items[i];
// Copy the template html:
var $itemEl = $(this.template).clone();
// Set element id
var itemId = "item-" + (this._nextId);
this._nextId++;
$itemEl.attr("id",itemId);
// Insert content from feed item
if(item.img !== null){
$itemEl.find(".item-image").empty().append(item.img);
}
$itemEl.find(".item-title").append(item.title);
$itemEl.find(".item-href").attr("href",item.href);
// Insert the element inside $target
$target.append($itemEl);
$items.push($itemEl);
}
// Divide container into a grid
var grid_attrs = this._computeGrid(
$target.width(),
$items[0].width(),
$items[0].height(),
items.length
);
//console.log(grid_attrs); // DEBUG
var grid = new Array(grid_attrs.num_rows);
for (var y=0; y < grid.length; y++){
grid[y] = new Array(grid_attrs.num_cols);
}
// Straight slot assignment
item_idx = 0;
for (var y = 0; y < grid.length; y++){
for (var x = 0; x < grid[y].length; x++){
for (var x = 0; x < grid[y].length; x++){
grid[y][x] = $items[item_idx];
item_idx++;
}
}
//console.log(grid); // DEBUG
// Travel grid and render items
for (var y = 0; y < grid.length; y++){
for (var x = 0; x < grid[y].length; x++){
if(grid[y][x] === undefined) continue;
var $item = grid[y][x];
// Skip if item already rendered
if($target.find($item.attr('id')).length != 0) continue;
// z-axis offset
var item_z = this._randInt(this.zLayers * -1, 0);
// scale factor
var item_s = 1 + (Math.abs(item_z) * this.scaleFactor);
// x,y position
var item_y = y * grid_attrs.col_h;
var item_x = (x * grid_attrs.col_w) + grid_attrs.col_p;
$item.css({
"top": item_y + 'px',
"left": item_x + 'px',
"transform": "translateZ(" + item_z + "px) scale(" + item_s + ")",
"-webkit-transform": "translateZ(" + item_z + "px) scale(" + item_s + ")"
});
// Show me the lana
$item.show();
}
}
},
// Get a random int
_randInt: function(min,max){
return Math.floor(Math.random() * (max - min)) + min;
},
// Compute row/column info for the feed container
_computeGrid: function(max_w,item_w,item_h,num_items){
var col_w, col_h, num_cols, num_rows, col_p;
col_w = Math.ceil(item_w * this.cellFactorW); // grid cell width
col_h = Math.ceil(item_h * this.cellFactorH); // grid cell height
num_cols = Math.max(1,Math.floor(max_w/col_w)); // grid columns
num_rows = Math.ceil(num_items / num_cols); // grid rows
col_p = 0; // container padding
if(max_w > col_w){
col_p = (max_w % col_w) / 2;
}
return {
"col_w":col_w,
"col_h":col_h,
"num_cols":num_cols,
"num_rows":num_rows,
"col_p":col_p
};
}
};
$( document ).ready(function() {
google.load("feeds", "1",{ // load feeds module
"callback": function() {
pxFeed = new ParallaxFeed();
pxFeed.load()
.done(function(items) {
pxFeed.render(items);
})
.fail(function(error) {
console.log("Error loading feed: %o",error);
});
},
"nocss":true
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment