Permalink
Browse files

Merge pull request #525 from koenbok/feature/animate-objects

Make borderRadius and borderWidth animatable when using object values.
  • Loading branch information...
eelco committed Jul 5, 2017
2 parents 3430da7 + b234d8c commit b3764ff064632107e1eba3c605dd72e78b318369
Showing with 126 additions and 2 deletions.
  1. +1 −1 extras/Studio.framer/framer/version
  2. +29 −1 framer/Animation.coffee
  3. +96 −0 test/tests/LayerAnimationTest.coffee
@@ -1 +1 @@
7
8
View
@@ -282,6 +282,10 @@ class exports.Animation extends BaseClass
@_valueUpdaters[k] = @_updateGradientValue
# If the begin state is not set, animate from the same state but with alpha 0
@_stateA[k] ?= Gradient.multiplyAlpha(v, 0)
else if k is "borderWidth"
@_valueUpdaters[k] = @_updateNumericObjectValue.bind(this, ["top", "left", "bottom", "right"])
else if k is "borderRadius"
@_valueUpdaters[k] = @_updateNumericObjectValue.bind(this, ["topLeft", "topRight", "bottomRight", "bottomLeft"])
else
@_valueUpdaters[k] = @_updateNumberValue
@@ -292,6 +296,26 @@ class exports.Animation extends BaseClass
_updateNumberValue: (key, value) =>
@_target[key] = Utils.mapRange(value, 0, 1, @_stateA[key], @_stateB[key])
_updateNumericObjectValue: (propKeys, key, value) =>
valueA = @_stateA[key]
valueB = @_stateB[key]
result = {}
for propKey in propKeys
keyValueA = if _.isNumber(valueA) then valueA else valueA[propKey]
keyValueB = if _.isNumber(valueB) then valueB else valueB[propKey]
# If the key value is undefined in one state, use the value from the other
keyValueA ?= keyValueB
keyValueB ?= keyValueA
result[propKey] = Utils.mapRange(value, 0, 1, keyValueA, keyValueB)
# Flatten to a single number if all properties have the same value
if _.uniq(_.values(result)).length is 1
result = result[propKeys[0]]
@_target[key] = result
_updateColorValue: (key, value) =>
@_target[key] = Color.mix(@_stateA[key], @_stateB[key], value, false, @options.colorModel)
@@ -317,6 +341,10 @@ class exports.Animation extends BaseClass
@isAnimatable = (v) ->
_.isNumber(v) or _.isFunction(v) or isRelativeProperty(v) or Color.isColorObject(v) or Gradient.isGradientObject(v)
# Special cases that animate with different types of objects
@isAnimatableKey = (k) ->
k in ["gradient", "borderWidth", "borderRadius"]
@filterAnimatableProperties = (properties) ->
# Function to filter only animatable properties out of a given set
animatableProperties = {}
@@ -338,7 +366,7 @@ class exports.Animation extends BaseClass
animatableProperties[k] = v
else if Color.isValidColorProperty(k, v)
animatableProperties[k] = new Color(v)
else if k is "gradient"
else if @isAnimatableKey(k)
animatableProperties[k] = v
return animatableProperties
@@ -879,3 +879,99 @@ describe "LayerAnimation", ->
done()
layer.animate
gradient: null
describe "Border radius animations", (done) ->
it "should animate border radius from number to number", (done) ->
layer = new Layer
borderRadius: 20
layer.on Events.AnimationEnd, ->
layer.borderRadius.should.equal 40
done()
layer.animate
borderRadius: 40
it "should animate border radius from number to object", (done) ->
layer = new Layer
borderRadius: 20
layer.on Events.AnimationEnd, ->
layer.borderRadius.bottomLeft.should.equal 40
layer.borderRadius.bottomRight.should.equal 20
done()
layer.animate
borderRadius:
bottomLeft: 40
it "should animate border radius from object to object", (done) ->
layer = new Layer
borderRadius:
bottomLeft: 40
bottomRight: 20
layer.on Events.AnimationEnd, ->
layer.borderRadius.bottomLeft.should.equal 10
layer.borderRadius.bottomRight.should.equal 20
layer.borderRadius.topLeft.should.equal 0
layer.borderRadius.topRight.should.equal 20
done()
layer.animate
borderRadius:
bottomLeft: 10
topRight: 20
it "should animate border radius from object to number", (done) ->
layer = new Layer
borderRadius:
bottomLeft: 40
layer.on Events.AnimationEnd, ->
layer.borderRadius.should.equal 20
done()
layer.animate
borderRadius: 20
describe "Border width animations", (done) ->
it "should animate border width from number to number", (done) ->
layer = new Layer
borderWidth: 10
layer.on Events.AnimationEnd, ->
layer.borderWidth.should.equal 30
done()
layer.animate
borderWidth: 30
it "should animate border width from number to object", (done) ->
layer = new Layer
borderWidth: 10
layer.on Events.AnimationEnd, ->
layer.borderWidth.top.should.equal 30
layer.borderWidth.bottom.should.equal 10
done()
layer.animate
borderWidth:
top: 30
it "should animate border width from object to object", (done) ->
layer = new Layer
borderWidth:
top: 30
bottom: 10
layer.on Events.AnimationEnd, ->
layer.borderWidth.top.should.equal 10
layer.borderWidth.bottom.should.equal 10
layer.borderWidth.left.should.equal 20
layer.borderWidth.right.should.equal 0
done()
layer.animate
borderWidth:
top: 10
left: 20
it "should animate border width from object to number", (done) ->
layer = new Layer
borderWidth:
top: 30
layer.on Events.AnimationEnd, ->
layer.borderWidth.should.equal 10
done()
layer.animate
borderWidth: 10

0 comments on commit b3764ff

Please sign in to comment.