基于JSON数据反应JS动画

koj*_*ow7 13 javascript animation reactjs redux

我正在使用React/Redux并将动画数据存储在JSON中并尝试将其显示在React页面上.

我正在使用setTimeout(暂停)和setInterval(用于动画运动).但是,我似乎无法理解如何正确实现动画,并认为我的事情完全是错误的.

JSON数据:

"objects": [

    {
        "title": "puppy",
        "image_set": [
            {
                "image": "images/puppy_sitting.png",
                "startx": 520,
                "starty": 28,
                "pause": 1000

            },
            {
                "image": "images/puppy_walking.png",
                "startx": 520,
                "starty": 28,
                "endx": 1,
                "endy": 1,
                "time": 1000
            },
            {
                "image": "images/puppy_crouching.png",
                "startx": 1,
                "starty": 1,
                "endx": 500,
                "endy": 400,
                "time": 2000
            }

        ]
    },
    {
        "title": "scorpion",
        "image_set": [
            {
                "image": "images/scorping_sleeping.png",
                "startx": 100,
                "starty": 400,
                "pause": 5000

            },
            {
                "image": "images/scorpion_walking.png",
                "startx": 100,
                "starty": 400,
                "endx": 500,
                "endy": 400,
                "time": 7000
            },
            {
                "image": "images/scorpion_walking.png",
                "startx": 500,
                "starty": 400,
                "endx": 100,
                "endy": 400,
                "time": 2000
            },
            {
                "image": "images/scorpion_walking.png",
                "startx": 100,
                "starty": 400,
                "endx": 200,
                "endy": 400,
                "time": 7000
            },
            {
                "image": "images/scorpion_walking.png",
                "startx": 200,
                "starty": 400,
                "endx": 100,
                "endy": 400,
                "time": 1000
            }
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

每个对象可以有几个与它们相关的图像.动画将继续不间断地重复.每个对象应与其他每个对象同时移动,以便我可以创建各种动物和物体在其周围移动的场景.

动画代码:

我很确定我在这里咆哮错误的树,但我的代码看起来像这样:

  // image_set is the list of images for a specific object
  // object_num is the array index corresponding to the JSON objects array
  // selected is the array index corresponding to which image in the image_set will be displayed
  runAnimation(image_set, object_num, selected){

        // Uses prevState so that we keep state immutable
        this.setState(prevState => {
            let images = [...prevState.images];

            if (!images[object_num]){
                images.push({image: null, x: 0, y: 0})

            }

            images[object_num].image = image_set[selected].image;
            images[object_num].x = this.getFactoredX(image_set[selected].startx);
            images[object_num].y = this.getFactoredY(image_set[selected].starty);
            return {images: images};
        })

        if (image_set[selected].endx && image_set[selected].endy && image_set[selected].time){
                let x = this.getFactoredX(image_set[selected].startx)
                let y = this.getFactoredY(image_set[selected].starty)
                let startx = x
                let starty = y
                let endx = this.getFactoredX(image_set[selected].endx)
                let endy = this.getFactoredY(image_set[selected].endy)
                let time = image_set[selected].time

                let x_increment = (endx - x) / (time / 50)
                let y_increment = (endy - y) / (time / 50)



                let int = setInterval(function(){

                        x += x_increment
                        y += y_increment


                        if (x > endx || y > endy){
                                clearInterval(int)
                        }

                        this.setState(prevState => {
                                let images = [...prevState.images]

                                if (images[object_num]){
                                        images[object_num].x = x
                                        images[object_num].y = y
                                }


                                return {images: images};


                        })


                }.bind(this),
                 50
                )

        }

        if (image_set[selected].pause && image_set[selected].pause > 0){
                selected++

                if (selected == image_set.length){
                        selected = 0
                }

                setTimeout(function() {
                        this.runAnimation(image_set, object_num, selected)

                }.bind(this),
                  image_set[selected].pause
                )

        }
        else {
                selected++

                if (selected == image_set.length){
                        selected = 0
                }
                setTimeout(function() {
                        this.runAnimation(image_set, object_num, selected)

                }.bind(this),
                        50
                )
        }


  }
Run Code Online (Sandbox Code Playgroud)

Redux和this.props.data

Redux将数据作为道具引入.所以,我有一个从我的componentDidMount和componentWillReceiveProps函数调用的函数,它将原始图像集传递给loadAnimationFunction.

我的渲染()

在我的render()功能中,我有这样的事情:

if (this.state.images.length > 1){
    animated = this.state.images.map((image, i) => {
            let x_coord = image.x
            let y_coord = image.y
            return (
                     <div key={i} style={{transform: "scale(" + this.state.x_factor + ")", transformOrigin: "top left", position: "absolute", left: x_coord, top: y_coord}}>
                            <img src={`/api/get_image.php?image=${image.image}`} />
                    </div>
            )

    })
}
Run Code Online (Sandbox Code Playgroud)

x_factor/y_factor

在我的代码中,还提到了x和y因子.这是因为动画出现的背景可以缩小或缩小.因此,我还缩放每个动画的起始和结束x/y坐标的位置,以及缩放动画图像本身.

时间和暂停时间

时间表示动画应采用的以ms为单位的时间.暂停时间表示在移动到下一个动画之前要暂停多长时间.

问题

代码不能平滑地移动动画,它们似乎偶尔会跳动.

此外,当我在页面上的任何位置单击鼠标时,它会导致动画跳转到另一个位置.为什么单击鼠标会影响动画?

我注意到的一件事是,如果我打开控制台进行调试,这确实会减慢动画的速度.

我可以对代码执行哪些操作,以便动画按预期工作?

Bal*_*zar 8

您尝试使用到动画的元素setInterval做一个setState坐标,并用一个absolute位置.所有这些都无法实现卓越的性能.

首先,setInterval永远不应该用于动画,你应该更喜欢requestAnimationFrame,因为它将允许60fps动画,因为动画将在下次重新绘制浏览器之前运行.

其次,做一个setState会重新渲染你的整个组件,这可能会对渲染时间产生影响,因为我认为你的组件不会只渲染你的图像.您应该尽量避免重新渲染未更改的内容,因此请尝试隔离动画中的图像.

最后,当您使用和属性定位元素时,您应该坚持使用,定位,而不是动画,因为浏览器将逐像素地执行动画,并且无法创建良好的性能.相反,你应该使用CSS ,因为它可以进行子像素计算,而不是在GPU上工作,允许你实现60fps的动画.Paul Irish 有一篇很好的文章.lefttoptranslate()


话虽这么说,你应该使用react-motion来让你获得流畅的动画:

import { Motion, spring } from 'react-motion'

<Motion defaultStyle={{ x: 0 }} style={{ x: spring(image.x), y: spring(image.y) }}>
  {({ x, y }) => (
    <div style={{
       transform: `translate(${x}px, ${y}px)`
    }}>
      <img src={`/api/get_image.php?image=${image.image}`} />
    </div>
  )}
</Motion>
Run Code Online (Sandbox Code Playgroud)

还有React Transition Group,Transition可以使用translate如上所述的动画移动元素.你还应该看看这里的反应动画文档.

值得一试的是React Pose,它非常易于使用,并且在使用干净的API时性能也很好.是React的入门页面.


这是一个快速演示,使用您的概念与坐/走/跑步循环.请注意,如果没有对转换的持续时间进行硬编码,反应运动是唯一一个处理帧之间转换的方法,这将违背流畅的UI,状态只处理通过不同的步骤.

引用反应动作自述文件:

对于95%的动画组件用例,我们不必使用硬编码的缓动曲线和持续时间.为你的UI元素设置刚度和阻尼,让物理的魔力照顾其余部分.这样,您就不必担心动画行为中断等小情况.它还极大地简化了API.

如果您对默认弹簧不满意,可以更改damplingstiffness参数.有一个应用程序可以帮助您获得最满足您的那个.

演示

Source


Cre*_*ers 2

React 并不完全适合用于动画。我并不是说你不能为React 组件设置动画,但这不是 React 试图解决的问题领域的一部分。它所做的就是为您提供一个很好的框架,使多个 UI 部分能够相互交互。例如,在创建游戏时,您将使用 React 和 Redux 来创建和管理屏幕、按钮等。但是游戏本身将单独包含并且不使用 React。

只是啰嗦地说,如果你想使用动画react是不够的,最好使用像greensock的动画库这样的东西:https://greensock.com/ 他们提供了一个关于如何结合使用它的教程反应: https: //greensock.com/react