Permalink
Browse files

Animating all shadows through the setting of the shadows array

  • Loading branch information...
nvh committed Sep 13, 2017
1 parent 5b6867b commit adda6dd8e0d5f3693cf7a5bc00bc7a5916b6979b
Showing with 161 additions and 11 deletions.
  1. +30 −11 framer/Animation.coffee
  2. +131 −0 test/tests/LayerAnimationTest.coffee
View
@@ -291,8 +291,8 @@ class exports.Animation extends BaseClass
@_valueUpdaters[k] = @_updateNumericObjectValue.bind(this, ["topLeft", "topRight", "bottomRight", "bottomLeft"])
else if k is "template"
@_valueUpdaters[k] = @_updateTemplateValue
else if /^shadow[1-9]$/.test(k)
@_valueUpdaters[k] = @_updateShadowValue
else if k is "shadows"
@_valueUpdaters[k] = @_updateShadows
else
@_valueUpdaters[k] = @_updateNumberValue
@@ -303,10 +303,7 @@ class exports.Animation extends BaseClass
_updateNumberValue: (key, value) =>
@_target[key] = Utils.mapRange(value, 0, 1, @_stateA[key], @_stateB[key])
_updateNumericObjectValue: (propKeys, key, value, flatten=true) =>
valueA = @_stateA[key]
valueB = @_stateB[key]
_interpolateNumericObjectValues: (propKeys, valueA, valueB, value, flatten=true) ->
result = {}
for propKey in propKeys
@@ -320,7 +317,16 @@ class exports.Animation extends BaseClass
# Flatten to a single number if all properties have the same value
if flatten and _.uniq(_.values(result)).length is 1
result = result[propKeys[0]]
return result
_calculateNumericObjectValue: (propKeys, key, value, flatten=true) =>
valueA = @_stateA[key]
valueB = @_stateB[key]
return @_interpolateNumericObjectValues(propKeys, valueA, valueB, value, flatten)
_updateNumericObjectValue: (propKeys, key, value, flatten=true) =>
result = @_calculateNumericObjectValue(propKeys, key, value, flatten)
@_target[key] = result
_updateColorValue: (key, value) =>
@@ -342,9 +348,19 @@ class exports.Animation extends BaseClass
@options.colorModel
)
_updateShadowValue: (key, value) =>
@_updateNumericObjectValue(["x", "y", "blur", "spread"], key, value, false)
@_target[key].color = Color.mix(@_stateA[key].color, @_stateB[key].color, value, false, @options.colorModel)
_updateShadows: (key, value) =>
result = []
for shadow, index in @_stateB[key]
if shadow is @_stateA[key][index]
continue
if shadow? and @_stateA[key][index]?
result[index] = @_interpolateNumericObjectValues(["x", "y", "blur", "spread"], @_stateA[key][index], shadow, value, false)
result[index].color = Color.mix(@_stateA[key][index].color, shadow.color, value, false, @options.colorModel)
result[index].type = shadow.type
else
result[index] = shadow
@_target[key] = result
# shallow mix all end state `{key: value}`s if `value` is a number, otherwise just takes `value`
_updateTemplateValue: (key, value) =>
@@ -380,7 +396,7 @@ class exports.Animation extends BaseClass
# Special cases that animate with different types of objects
@isAnimatableKey = (k) ->
k in ["gradient", "borderWidth", "borderRadius", "template"] or /^shadow[1-9]$/.test(k)
k in ["gradient", "borderWidth", "borderRadius", "template", "shadows"]
@filterAnimatableProperties = (properties) ->
# Function to filter only animatable properties out of a given set
@@ -405,7 +421,10 @@ class exports.Animation extends BaseClass
animatableProperties[k] = new Color(v)
else if @isAnimatableKey(k)
animatableProperties[k] = v
else if matches = k.match(/^shadow([1-9])$/)
animatableProperties.shadows ?= []
shadowIndex = parseInt(matches[1]) - 1
animatableProperties.shadows[shadowIndex] = v
return animatableProperties
toInspect: ->
@@ -3,6 +3,15 @@ assert = require "assert"
AnimationTime = Framer.Defaults.Animation.time
AnimationProperties = ["x", "y", "midY", "rotation"]
equalShadows = (shadow1, shadow2) ->
equal = true
for key, value of shadow1
if Color.isColor(value)
equal = equal and Color.equal(value, shadow2[key])
else
equal = equal and _.eq(value, shadow2[key])
return equal
describe "LayerAnimation", ->
it "should use defaults", ->
@@ -162,6 +171,128 @@ describe "LayerAnimation", ->
assert.equal(layerB.parent, layerA)
describe "Shadows", ->
template = null
beforeEach ->
template = new Layer
shadows: [
{spread: 0, x: 0, type: 'box', y: 10, blur: 5, color: 'rgb(238, 68, 68)'}
{spread: 10, x: 10, type: 'box', y: 0, blur: 30, color: 'rgba(17, 153, 238, 0.67)'}
{spread: 0, x: 10, type: 'inset', y: 5, blur: 0, color: 'rgb(102, 187, 102)'}
{spread: 0, x: -10, type: 'inset', y: -5, blur: 0, color: 'rgb(204, 221, 51)'}
{spread: 0, x: 0, type: 'inset', y: 0, blur: 30, color: 'rgb(255, 238, 102)'}
]
describe "by setting individual shadows", ->
it "should work when starting with no shadows", (done) ->
layer = new Layer
a = layer.animate
shadow1: template.shadow1
shadow2: template.shadow2
shadow3: template.shadow3
shadow4: template.shadow4
shadow5: template.shadow5
shadow6: template.shadow6
shadow7: template.shadow7
shadow8: template.shadow8
shadow9: template.shadow9
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
it "should work when using the same kind of shadows", (done) ->
layer = new Layer
shadows: [
{spread: 0, x: 0, type: 'box', y: 10, blur: 0, color: 'rgb(238, 68, 68)'}
{spread: 10, x: 10, type: 'box', y: 0, blur: 30, color: 'rgb(187, 102, 204)'}
{spread: 0, x: 0, type: 'inset', y: 0, blur: 0, color: 'rgb(102, 187, 102)'}
{spread: 0, x: -10, type: 'inset', y: -5, blur: 0, color: 'rgb(85, 204, 255)'}
{spread: 0, x: 0, type: 'inset', y: 0, blur: 0, color: 'rgb(255, 238, 102)'}
]
layer = new Layer
a = layer.animate
shadow1: template.shadow1
shadow2: template.shadow2
shadow3: template.shadow3
shadow4: template.shadow4
shadow5: template.shadow5
shadow6: template.shadow6
shadow7: template.shadow7
shadow8: template.shadow8
shadow9: template.shadow9
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
it "should work when using different shadows", (done) ->
layer = new Layer
shadows: [
{spread: 0, x: 10, type: 'box', y: 10, blur: 0, color: 'rgb(0, 204, 187)'}
{spread: 13, x: 0, type: 'inset', y: 0, blur: 10, color: 'rgb(255, 170, 34)'}
]
layer = new Layer
a = layer.animate
shadow1: template.shadow1
shadow2: template.shadow2
shadow3: template.shadow3
shadow4: template.shadow4
shadow5: template.shadow5
shadow6: template.shadow6
shadow7: template.shadow7
shadow8: template.shadow8
shadow9: template.shadow9
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
describe "by setting shadow array", ->
it "should work when starting with no shadows", (done) ->
layer = new Layer
a = layer.animate
shadows: template.shadows
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
it "should work when using the same kind of shadows", (done) ->
layer = new Layer
shadows: [
{spread: 0, x: 0, type: 'box', y: 10, blur: 0, color: 'rgb(238, 68, 68)'}
{spread: 10, x: 10, type: 'box', y: 0, blur: 30, color: 'rgb(187, 102, 204)'}
{spread: 0, x: 0, type: 'inset', y: 0, blur: 0, color: 'rgb(102, 187, 102)'}
{spread: 0, x: -10, type: 'inset', y: -5, blur: 0, color: 'rgb(85, 204, 255)'}
{spread: 0, x: 0, type: 'inset', y: 0, blur: 0, color: 'rgb(255, 238, 102)'}
]
layer = new Layer
a = layer.animate
shadows: template.shadows
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
it "should work when using different shadows", (done) ->
layer = new Layer
shadows: [
{spread: 0, x: 10, type: 'box', y: 10, blur: 0, color: 'rgb(0, 204, 187)'}
{spread: 13, x: 0, type: 'inset', y: 0, blur: 10, color: 'rgb(255, 170, 34)'}
]
layer = new Layer
a = layer.animate
shadows: template.shadows
a.onAnimationEnd ->
layer.shadows.length.should.eql template.shadows.length
layer.shadows.map (shadow, index) ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
describe "Basic", ->

0 comments on commit adda6dd

Please sign in to comment.