Skip to content

Instantly share code, notes, and snippets.

@simple10
Created June 3, 2014 02:38
Show Gist options
  • Save simple10/4045cd8dff2756dbcd12 to your computer and use it in GitHub Desktop.
Save simple10/4045cd8dff2756dbcd12 to your computer and use it in GitHub Desktop.
Famo.us masonry style layout in coffeescript – handles reflowing elements when window or container size changes
FloatLayout = require 'layouts/FloatLayout'
layout = new FloatLayout
layout.sequenceFrom surfaces
layout.on 'afterAnimate', =>
console.log 'animate finished'
surfaces = [
# Array of surfaces
]
ReflowLayout = require 'layouts/ReflowLayout'
# Float items in a responsive layout
class FloatLayout extends ReflowLayout
@DEFAULT_OPTIONS:
resizeDelay: 200
transition:
duration: 200
getSize: ->
@_size
reflow: (size) ->
i = 0
col = 0
row = 0
len = @getSequenceLength()
# assume items are all the same size for now
itemSize = @getSequence().getSize()
while i < len
x = col * itemSize[0]
col++
if x + itemSize[0] > size[0]
x = 0
col = 1
row++
y = row * itemSize[1]
if @_modifiers[i] is undefined
@_createModifier i, itemSize, [x, y, 0], 1
else
@_animateModifier i, itemSize, [x, y, 0], 1
i++
@_size = [size[0], itemSize[1]*(row+1)]
module.exports = FloatLayout
ContextualView = require 'famous/views/ContextualView'
ViewSequence = require 'famous/core/ViewSequence'
OptionsManager = require 'famous/core/OptionsManager'
Modifier = require 'famous/core/Modifier'
Transform = require 'famous/core/Transform'
Transitionable = require 'famous/transitions/Transitionable'
TransitionableTransform = require 'famous/transitions/TransitionableTransform'
Timer = require 'famous/utilities/Timer'
# TODO: make sure pull request for ContextView is applied: https://github.com/Famous/views/pull/50
class ReflowLayout extends ContextualView
@DEFAULT_OPTIONS:
# Amount of milliseconds to debounce resize events before calling reflow
resizeDelay: 200
# Transition settings for repositioning items
transition:
duration: 200
_nodes: null
_modifiers: []
_states: []
_contextSizeCache: [undefined, undefined]
_size: null
_animationCount: 0
constructor: (options) ->
super
# TODO: make sure pull request is in master https://github.com/Famous/core/pull/32
@_debouncedReflow = Timer.debounce @_reflow, @options.resizeDelay or 200
getSize: ->
@_size or @options.size
###
# Sets the collection of renderables.
#
# @method sequenceFrom
# @param {Array|ViewSequence} sequence Either an array of renderables or a Famous viewSequence.
# @chainable
###
sequenceFrom: (sequence) ->
@_nodes = if sequence instanceof Array then new ViewSequence(sequence) else sequence
@
getSequence: ->
@_nodes
# TODO: ANSWER THIS ....
# Why does ViewSequence create a new node when getNext is called on the last node?
# Felix is fixing this.
getSequenceLength: ->
@_nodes._.array.length
###
# Recalculate layout.
#
# Do reflow math here in subclass.
# See GridLayout for example.
###
reflow: (size) ->
# Override in subclass
_beforeReflow: (size) ->
return false if size[0] is @_contextSizeCache[0] and size[1] is @_contextSizeCache[1]
# reflow immediately the first time
if @_contextSizeCache[0] == undefined
@_reflow size
else
@_debouncedReflow size
@_contextSizeCache = size.slice 0
_reflow: (size) ->
@_animationCount = 0
@reflow size
@_eventOutput.emit 'reflow'
###
# Apply changes from this component to the corresponding document element.
# This includes changes to classes, styles, size, content, opacity, origin,
# and matrix transforms.
#
# @private
# @method commit
# @param {Context} context commit context
###
commit: (context) ->
return false unless @getSequenceLength()
transform = context.transform
opacity = context.opacity
origin = context.origin
size = context.size
return false unless size
@_beforeReflow size
sequence = @getSequence()
result = []
i = 0
len = @_modifiers.length
while sequence and i < len
item = sequence.get()
modifier = @_modifiers[i]
result.push modifier.modify
origin: origin
target: item.render()
sequence = sequence.getNext()
i++
transform = Transform.moveThen [ -size[0] * origin[0], -size[1] * origin[1], 0 ], transform
{
transform: transform
opacity: opacity
size: size
target: result
}
###
# Call from reflow.
# See GridLayout for example.
###
_createModifier: (index, size, position, opacity) ->
trans =
transform: new TransitionableTransform Transform.translate position...
opacity: new Transitionable opacity
size: new Transitionable size
@_states[index] = trans
@_modifiers[index] = new Modifier trans
###
# Call from reflow.
# See GridLayout for example.
###
_animateModifier: (index, size, position, opacity) ->
@_animationCount++
currState = @_states[index]
currSize = currState.size
currOpacity = currState.opacity
currTransform = currState.transform
transition = @options.transition
currTransform.halt()
currOpacity.halt()
currSize.halt()
currTransform.setTranslate position, transition, @_afterAnimate
currSize.set size, transition
currOpacity.set opacity, transition
_afterAnimate: =>
@_animationCount -= 1
@_eventOutput.emit 'afterAnimate' if @_animationCount <= 0
module.exports = ReflowLayout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment