Skip to content

Commit

Permalink
Merge pull request #525 from koenbok/feature/animate-objects
Browse files Browse the repository at this point in the history
Make borderRadius and borderWidth animatable when using object values.
  • Loading branch information
eelco committed Jul 5, 2017
2 parents 3430da7 + b234d8c commit b3764ff
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 2 deletions.
2 changes: 1 addition & 1 deletion extras/Studio.framer/framer/version
@@ -1 +1 @@
7
8
30 changes: 29 additions & 1 deletion framer/Animation.coffee
Expand Up @@ -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

Expand All @@ -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)

Expand All @@ -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 = {}
Expand All @@ -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
Expand Down
96 changes: 96 additions & 0 deletions test/tests/LayerAnimationTest.coffee
Expand Up @@ -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.