Permalink
Browse files

Fixed issues with shadows and shadow animation

  • Loading branch information...
nvh committed Sep 28, 2017
1 parent 86e248f commit 6e1d21b569b4f03cf393d6b16fb697089eba8a80
Showing with 136 additions and 29 deletions.
  1. +10 −9 framer/Animation.coffee
  2. +22 −17 framer/Layer.coffee
  3. +63 −0 test/tests/LayerAnimationTest.coffee
  4. +41 −3 test/tests/LayerTest.coffee
View
@@ -350,15 +350,17 @@ class exports.Animation extends BaseClass
_updateShadows: (key, value) =>
result = []
for shadow, index in @_stateB[key]
if not shadow? and not @_stateA[key][index]?
for toShadow, index in @_stateB[key]
fromShadow = @_stateA[key]?[index]
if not toShadow? and not fromShadow?
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
fromShadow ?= _.defaults {color: null, type: toShadow.type}, Framer.Defaults.Shadow
if toShadow? and fromShadow?
result[index] = @_interpolateNumericObjectValues(["x", "y", "blur", "spread"], fromShadow, toShadow, value, false)
result[index].color = Color.mix(fromShadow.color, toShadow.color, value, false, @options.colorModel)
result[index].type = toShadow.type ? fromShadow.type
else
result[index] = shadow
result[index] = toShadow
@_target[key] = result
@@ -426,8 +428,7 @@ class exports.Animation extends BaseClass
shadowIndex = parseInt(matches[1]) - 1
if animatableProperties.shadows[shadowIndex]?
_.defaults v, animatableProperties.shadows[shadowIndex]
# else
animatableProperties.shadows[shadowIndex] = v
animatableProperties.shadows[shadowIndex] = _.defaults v, {color: null, type: null}, Framer.Defaults.Shadow
return animatableProperties
toInspect: ->
View
@@ -144,15 +144,6 @@ proxiedShadowValue = (layer, value, index = 0) ->
v?.color = new Color(v.color)
layerProxiedValue(v, layer, "shadow#{index+1}")
updateShadowsProperty = (prop) ->
(layer, value) ->
layer.shadows ?= []
if (layer.shadows.filter (s) -> s isnt null).length is 0
layer.shadows[0] = proxiedShadowValue(layer, Framer.Defaults.Shadow)
for shadow in layer.shadows
shadow?[prop] = value
layer.updateShadowStyle()
class exports.Layer extends BaseClass
constructor: (options={}) ->
@@ -360,24 +351,38 @@ class exports.Layer extends BaseClass
@define "backgroundGrayscale", layerProperty(@, "backgroundGrayscale", "webkitBackdropFilter", 0, _.isNumber)
@define "backgroundSepia", layerProperty(@, "backgroundSepia", "webkitBackdropFilter", 0, _.isNumber)
for i in [0...8]
for i in [0..8]
do (i) =>
@define "shadow#{i+1}",
depends: ["shadowX", "shadowY", "shadowBlur", "shadowSpread", "shadowColor", "shadowType"]
get: ->
@shadows?[i]
@shadows ?= []
@shadows[i] ?= proxiedShadowValue(@, {}, i)
@shadows[i]
set: (value) ->
@shadows ?= []
@shadows[i] = proxiedShadowValue(@, value, i)
@updateShadowStyle()
updateShadowsProperty: (prop, value) ->
@shadows ?= []
if (@shadows.filter (s) -> s isnt null).length is 0
@shadows[0] = proxiedShadowValue(@, Framer.Defaults.Shadow)
for shadow in @shadows
shadow?[prop] = value
@updateShadowStyle()
# Shadow properties
@define "shadowX", layerProperty(@, "shadowX", null, 0, _.isNumber, null, {}, updateShadowsProperty("x"))
@define "shadowY", layerProperty(@, "shadowY", null, 0, _.isNumber, null, {}, updateShadowsProperty("y"))
@define "shadowBlur", layerProperty(@, "shadowBlur", null, 0, _.isNumber, null, {}, updateShadowsProperty("blur"))
@define "shadowSpread", layerProperty(@, "shadowSpread", null, 0, _.isNumber, null, {}, updateShadowsProperty("spread"))
@define "shadowColor", layerProperty(@, "shadowColor", null, "", Color.validColorValue, Color.toColor, {}, updateShadowsProperty("color"))
@define "shadowType", layerProperty(@, "shadowType", null, undefined, null, null, {}, updateShadowsProperty("type"))
for shadowProp in ["X", "Y", "Blur", "Spread", "Color", "Type"]
do (shadowProp) =>
@define "shadow#{shadowProp}",
exportable: false
get: ->
return null if not @shadows? or @shadows.length is 0
@shadow1[shadowProp.toLowerCase()]
set: (value) ->
@updateShadowsProperty(shadowProp.toLowerCase(), value)
@define "shadows",
default: null
get: ->
@@ -1,4 +1,5 @@
assert = require "assert"
{expect} = require "chai"
AnimationTime = Framer.Defaults.Animation.time
AnimationProperties = ["x", "y", "midY", "rotation"]
@@ -269,6 +270,68 @@ describe "LayerAnimation", ->
equalShadows(shadow, template.shadows[index]).should.be.true
done()
it "should animate to null shadow nicely", (done) ->
layerA = new Layer
layerA.shadow1.x = 100
layerA.shadow1.color = "blue"
layerA.shadow1.type = "inset"
layerA.shadow1.blur = 10
a = layerA.animate
shadow1: null
a.onAnimationEnd ->
layerA.shadow1.x.should.equal 0
layerA.shadow1.y.should.equal 0
layerA.shadow1.blur.should.equal 0
layerA.shadow1.type.should.equal "inset"
transparentBlue = (new Color("blue")).alpha(0)
Color.equal(transparentBlue, layerA.shadow1.color).should.be.true
done()
it "should animate from null shadow nicely", (done) ->
layerA = new Layer
shadow1: null
a = layerA.animate
shadow1:
x: 100
color: "blue"
type: "inset"
blur: 10
a.onAnimationStart ->
shadow1 = layerA.shadows[0]
shadow1.type.should.equal "inset"
opaqueShadowColor = shadow1.color.alpha(1)
Color.equal(new Color("blue"), opaqueShadowColor).should.be.true
a.onAnimationEnd ->
layerA.shadow1.x.should.equal 100
layerA.shadow1.y.should.equal 0
layerA.shadow1.blur.should.equal 10
layerA.shadow1.type.should.equal "inset"
Color.equal(new Color("blue"), layerA.shadow1.color).should.be.true
done()
it "should animate from no shadows nicely", (done) ->
layerA = new Layer
expect(layerA.shadows).to.be.null
a = layerA.animate
shadow1:
x: 100
color: "blue"
type: "inset"
blur: 10
a.onAnimationStart ->
shadow1 = layerA.shadows[0]
shadow1.type.should.equal "inset"
opaqueShadowColor = shadow1.color.alpha(1)
Color.equal(new Color("blue"), opaqueShadowColor).should.be.true
a.onAnimationEnd ->
layerA.shadow1.x.should.equal 100
layerA.shadow1.y.should.equal 0
layerA.shadow1.blur.should.equal 10
layerA.shadow1.type.should.equal "inset"
Color.equal(new Color("blue"), layerA.shadow1.color).should.be.true
done()
describe "by setting shadow array", ->
it "should work when starting with no shadows", (done) ->
layer = new Layer
@@ -857,13 +857,21 @@ describe "Layer", ->
l.shadow1.x = 10
l.style.boxShadow.should.equal "rgba(123, 123, 123, 0.498039) 10px 0px 0px 0px"
it "should ignore the first shadow when the second shadow property is changed", ->
l = new Layer
l.shadow2.y = 10
l.style.boxShadow.should.equal "rgba(123, 123, 123, 0.498039) 0px 10px 0px 0px"
it "should animate shadows through a shadow property", (done) ->
l = new Layer
l.animate
a = l.animate
shadow1:
x: 20
blur: 100
Utils.delay a.time /2, ->
l.shadow1.blur.should.be.above 10
l.shadow1.blur.should.be.below 90
l.onAnimationEnd ->
l.shadow1.x.should.equal 20
l.shadow1.blur.should.equal 100
done()
it "should animate shadow colors", (done) ->
@@ -988,6 +996,36 @@ describe "Layer", ->
l.shadow1.type.should.equal "box"
l.style.boxShadow.should.equal "rgb(255, 0, 0) 0px 0px 10px 0px"
it "should reflect the current value throught the shadow<prop> properties", ->
layer = new Layer
shadow1:
x: 5
y: 20
color: "blue"
blur: 10
shadow2:
x: 10
y: 20
color: "red"
layer.shadowX.should.equal 5
layer.shadowY.should.equal 20
Color.equal(layer.shadowColor, "blue").should.be.true
layer.shadowBlur.should.equal 10
layer.shadowType.should.equal "box"
layer.shadowX = 2
layer.shadowX.should.equal 2
it "should return null for the shadow<prop> properties initially", ->
layer = new Layer
expect(layer.shadowX).to.equal null
expect(layer.shadowY).to.equal null
expect(layer.shadowColor).to.equal null
expect(layer.shadowBlur).to.equal null
expect(layer.shadowType).to.equal null
describe "Events", ->
it "should remove all events", ->

0 comments on commit 6e1d21b

Please sign in to comment.