年底了,接个大活儿,做一个回顾公司五年发展的总结ppt,要求做成H5网页

年底了,接个大活儿,做一个回顾公司五年发展的总结ppt,要求做成H5网页公司想做一个交互性良好、内容表达形式多样、章节清晰、条理分明、易于传播的“ppt”,问了一圈大家伙,只有我选择接下这个任务。

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

公司想做个五年总结

这不快年底了么,公司高层打算把这五年的发展历程做一次回顾巡礼,一方面宣扬一下公司文化,另一方面歌颂一下公司这五年来取得的辉煌成就,单纯的做个海报,写个公众号文章,或整个传统ppt在内部宣讲,再剪个视频啥的已经无法满足公司想众乐乐的强烈情感了。

于是想做一个交互性良好、内容表达形式多样、章节清晰、条理分明、易于传播的“ppt”,于是在公司千人大群里号召,有没有谁能做的,问了好几次,最后只有我应下了这个大活儿。

最后我与一位主要负责这件事的领导(我称为带头大哥)和一位UI小姐姐临时组成了一个小队,来完成这项任务。

在线观看地址,可以先看看效果。记得手指或者鼠标,向上滑动来播放)

很快就确定了中心思想,并设计了一套。。。。对联?

带头大哥没过几日就发我一个文档,上面写了对仗工整,思想明确的“对联”

  1. 重返这五年,重温那岁月
  2. 成长多措举,管理提格局
  3. 工作造氛围,企学见雏形
  4. 发展聚人才,规模逐壮大
  5. 搜索寻突破,拓展创业务
  6. 那年启征程,改变从此始
  7. 种得梧桐树,凤凰自然来
  8. 全方位服务,码农心无骛
  9. 创新谋发展,突破新技术
  10. 环境不断好,员工感幸福
  11. 乘势迎挑战,赋能于行业
  12. 磨砺积能力,自研得硕果
  13. 逆境砥砺行,收入节节高
  • 我:哇撒~,领导,这写的很好嘛~,这每一页不做个动画都说不过去啊。
  • 领导:对,就打算这么做。
  • 我:哈哈哈哈,收到,那么具体做成什么样呢?
  • 领导:em~,我已经安排UI小姐姐开始设计了,过一阵就能出图。
  • 我:哦哦哦,好的~

领会精神的设计小姐姐就开始陆续出图了~~~

image.png

  • 领导:阿强,图做好了,你看一下。
  • 我:ok,哇偶这图可以啊。
  • UI小姐姐:有什么问题,需要切图啥的尽管跟我说。
  • 我:好的好的。
  • 领导:阿强,那么我们开始研究如何做吧,要求是要做成H5,这样可以方便分享传阅,而且时间我们只有五天,我们要尽快了。
  • 我:五天???做不完咋办
  • 领导:你知道的,deedline不是我定的,而且这是👆面看中的亲儿子项目,献礼用的,所以。。。
  • 我:懂了,我搏一把,目前来看用游戏引擎最合适,毕竟画面表现这块,用引擎更好一点。
  • 领导:可以,具体设计方面到时我们再一起商量怎么做,开发这块需要的话,我也可以参与进来,毕竟我也接触过白鹭引擎,对了,你打算用啥写?
  • 我:cocos creater
  • 领导:嗯嗯,没问题,有什么我能帮忙的尽管跟我说,最后能做出来就行
  • 我:好的,收到。

于是我做了一个工具

so,时间这么紧,而且做不完可能会有不小的后果,em~~~~,并且这件事也不是着急干就能干完的,我需要冷静的想一个办法,我忽然想到《代码整洁之道》中好像说过,具体记不清,大体意思是:“越是想快,就要写好代码”。

em~~~,好的,那么我拿出几天设计一个工具吧,不需要多么成熟,只要能够满足容易上手,可以批量制作就行,这样就能够实现人手的增加,效率也会提高的局面,到时完成就变得很有戏了,就这么办。

于是我用了两三天的时间做出了这个工具,并做了一个demo给到了带头大哥,他表示ok,还可以,能接受,而且经过我的指导,他也可以参与进来了,于是我们就开始“愉快地”批量的制作了。

工具的开发思路

我总希望用最简单的话语,描述一件事,我比较喜欢简单,那么我们就用简单的方式把我的设计讲讲。

通过鼠标或触摸滑动,推进动画进程

视频可以快进,倒退,仅仅通过拨动进度条或者滑动屏幕即可,我喜欢这种交互,那就做成这样,舒服。 首先我不想做成静态资源那种的,比如视频,gif之类的,这种是没有“生命”的,只能称之为“物质”,我简单用“阴”代指,我所需要是基于物质所焕发同时也可以创造物质的的“生命,心灵”,我称他为阳。说ta是“活”的有点过,就是说可以交互,可以整合再利用,随时可以通过ta创建视频,gif之类的静态资源,岂不妙哉。

设计好个体,非常关键

我希望设计出一系列独立个体,可以很好的串联起整个逻辑,它具备了基本的功能,同时又具备了扩展的能力,可互相联结,又彼此独立,目前有两个主要的个体,一个是单位个体entity,另一个是动作个体recation

entity大体应该具备以下行为:

  • 描述自身运行的周期: lenPercentstartPercent
  • 生命周期函数
    • 开始:live
    • 渲染:process
    • 结束:end
  • 可以装载其他个体的能力:entityArr
    • 组成单位为:entity
  • 执行动作的集合:recationArr
    • 组成单位为:recation,

recation大体应该具备以下行为:

  • 描述自身运行的周期:startend
  • 执行的动作:action()

那么个体设计好了,围绕个体所展开的逻辑,就顺理成章了。

代码如下:

export default cc.Class({
    extends: cc.Component,

    properties: {

        lenPercent: cc.Float,
        startPercent: cc.Float,
        isAutoStart: cc.Boolean,
        entityArr: {
            default: [],
            type: cc.Node
        }
    },

    //externalDuration:外部时间(父节点传过来的时间),由父节点决定
    //internalDuration:自己内部定的时间,有自己决定,
    //为什么要区分两个呢?由于外部应该只能确定我的播放时间,不应该决定我的播放速率,而后者应该有个体自身决定,
    //startTime和endTime:由父节点指定的开始和结束时间,(根据父节点的世界定的‘外部时间’!!!)
    //timeLine-表示时间到哪了,(根据父节点的世界定的‘外部时间’!!!)
    //totaTime-表示我在父节点应该播放的总时长,(根据父节点的世界定的‘外部时间’!!!)
    //progressValue就是通过父节点传过来的timeLine,totaTime,timeLine得出我处于的播放进度百分比
    //相应的往自己的子节点传的就得参照自己的
    ctor() {
        this.isLive = false;
        this.startTime = undefined;
        this.endTime = undefined;
        this.internalDuration = 0;//个体内部的时长
        this.externalDuration = 0;//个体相对父级的时长
        this.progressValue = 0;
        this.entryData = [];
        this.recationArr = [];
        this.startPosition = cc.v2();
        this.entityArrEx = [];
    },

    // LIFE-CYCLE CALLBACKS:
    start() {
        this.startPosition = this.node.position;
    },
    onLoad() {
        this.node.comName = this.__classname__;
        this.internalDuration = this.node.getContentSize().height;
        //防止设置的时间太长,强制设置为剩余的时长
        if (this.lenPercent + this.startPercent > 1) {
            this.lenPercent = 1 - this.startPercent;
        }
        if (this.isAutoStart) {
            this.startPercent += Math.abs((this.node.position.y / this.node.parent.getContentSize().height));
        }

    },

    onEnable() {
        let self = this;
        if (this.entityArr.length) {
            this.entityArrEx = this.entityArr.map((item, index) => {
                let entity = item.getComponent(item._name);
                if (entity.isAutoStart) {

                }
                this.entryData.push(entity.initData({
                    startTime: this.getStarTime(entity.startPercent),
                    totaTime: self.internalDuration,
                }));
                return entity;
            });
        }
    },

    //业务接口
    getStarTime(value) {
        if (value <= 1) {
            return value * this.internalDuration
        } else {
            return value
        }
    },

    initData({ totaTime, startTime }) {
        this.startTime = startTime;
        this.externalDuration = this.lenPercent <= 1 ? totaTime * this.lenPercent : this.lenPercent;
        //结束时间最大只能是父类节点结束时间
        //因为父节点结束,子节点也必须结束
        this.endTime = Math.min(totaTime, this.startTime + this.externalDuration);
        return {
            startTime: this.startTime,
            internalDuration: this.internalDuration,
            endTime: this.endTime
        }
    },

    getCurrentTime(percent) {
        return (
            this.startTime + (percent <= 1 ? this.externalDuration * percent : percent)
        );
    },

    live() {
        this.isLive = true;
    },

    calcProgress() {
        this.progressValue = (this.timeLine - this.startTime) / this.externalDuration;
    },

    calcReactionProgress({ start, end }) {
        start = (start <= 1) ? this.internalDuration * start : start;
        end = (end <= 1) ? this.internalDuration * end : end;
        return Math.min((this.progressValue * this.internalDuration - start) / (end - start), 1);
    },

    process({ timeLine }) {
        this.timeLine = timeLine;
        this.calcProgress();
        this.internalTimeLine = this.progressValue * this.internalDuration;
        let actionArr = this.recationArr.filter((item) => {
            if (item) {
                let isOk = (timeLine > this.getCurrentTime(item.start) &&
                    timeLine <= this.getCurrentTime(item.end)) ||
                    (!item.start && !item.end)
                if (isOk) {
                    item.isAction = true
                } else {
                    if (item.isAction) {
                        item.action(this.calcActionData(item, true))
                    }
                    item.isAction = false
                }
                return isOk;
            }
        });
        actionArr.forEach((item) => {
            item.action(this.calcActionData(item));
        });
    },

    update() {
        let self = this;
        this.actionEntityArr = this.entityArrEx.filter((entity) => {
            if ((self.internalTimeLine) > entity.startTime && self.internalTimeLine <= entity.endTime) {
                if (!entity.isLive) {
                    entity.live();
                }
                entity.process({
                    timeLine: self.progressValue * self.internalDuration,
                });
                return true;
            } else {
                if (entity.isLive) {
                    entity.end();
                }
            }
            return false;
        });
    },

    calcActionData(item, isEnd) {
        let params = {};
        let actionLen = (item.end - item.start) || 1;
        let progress;
        progress = Math.min((this.progressValue - item.start) / actionLen, 1);
        if (isEnd) {
            let isEndForce = window.GLOBAL.dir > 0;
            let isEndForceStart = window.GLOBAL.dir < 0;
            if (isEndForce) {
                progress = 1
            } else if (isEndForceStart) {
                progress = 0
            }
            params = {
                isEndForce: isEndForce,
                isEndForceStart: isEndForceStart
            }
        }
        params = {
            actionLen,
            progress,
            ...params,
            ...item
        }

        return params;
    },
    end() {
        this.isLive = false;
        //如果滑动非常快,并且是快进而非后退,那么就要直接强行设置反馈为结束
        // if (window.GLOBAL.dir > 0) {

        // }
        this.recationArr.forEach(item => {
            if (item.isAction) {
                item.isAction = false
                item.action(this.calcActionData(item, true))
            }
        });
    },
});

整体思路简单说

  • 就是设置一个进度条,通过触摸屏幕进行前进和后退。
  • 设置每一part的时间占比,然后串联起来。
  • 每一个part内部,也设置内部节点的运动的事件占比,以及具体做什么运动。
  • 然后根据定时循环,判断当前时刻应该执行节点的是哪个,执行的节点该执行的运动是哪个

就这么简单。

这个思路完全可以使用在dom上,完全可以用react和vue实现,我会陆续重构完毕。

我跟领导就开始设计怎么做了

开场

image.png

  • 领导:阿强,这个就是我们项目的开场。

    • 第一张就是首页图,然后过一会自动转场。
    • 第二张就是过场之后显示的。
  • 我:哦哦,懂了,话说,怎么转场呢?

  • 领导:看到小飞机没有~

    • 就这个。

      image.png

    • 还有第二页的这个。

      image.png

    • (A):第一页上来,左下角一个人坐着飞机向上飞,然后小飞机往右上角飞,飞离出去之后,开始转场到二张。

    • (B)然后第二页左下飞入这个小飞机,飞到中心处,也就是图片上的位置,那么开场part就ok了。)

  • 我:ok,明白了,开整。

实现方式:

A实现:

image.png

目标就是让这个节点移动一段距离停下来,那么写一个脚本plane0_1,上来就执行一个移动一段距离的动作。

import entity from '../../base/entity';
cc.Class({
    extends: entity,

    properties: {
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        this._super();
        let self = this;
        // 就是上来,就执行一个运动,moveBy就是一段时间,移动移动距离的动画api
        var action = cc.moveBy(1, cc.v2(this.node.getContentSize().width + 100, 200))
        // 执行动作
        this.node.runAction(action);
    },
});


挂载到节点上就可以了。

image.png

这里简单介绍一下,我设置了几个参数:

  • lenPercent:就是节点运动的总时长
  • startPercent:就是运动的开始时刻
  • isAutoStart:就是自动启动,无视startPercent的设置
  • entityArr:就是复制管理的节点,这样自己的运动周期内就能操作其关联的节点的运动。

B实现:主要就是实现这个节点移动飞行

image.png

那么根据上面描述的思路,我们不难实现这个小飞机的移动,无非就是设置这个小飞机在这个part里的开始时刻是多少,运动多久,运动到哪,只要把这些定好,动画自动产生。

那么开发脚本

import entity from '../../base/entity';
cc.Class({
    extends: entity,

    properties: {
        plane: cc.Node
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        this._super();
        let self = this;

        // 向右上角移动一段距离
        var action = cc.moveBy(1, cc.v2(this.node.getContentSize().width + 500, 500))
        // spawn是同时执行运动的函数,目的是让moveBy运动结合一个缩小的运动,这样,有种越发越远,又越小的视觉感。
        let action2 = cc.spawn(action, cc.scaleTo(1, 2))
        // 执行动作
        this.node.runAction(cc.sequence(cc.delayTime(1), action2, cc.callFunc(() => {
            self.node.active = false;
            self.node.parent.active = false;
            self.plane.runAction(cc.moveTo(1, cc.v2(0, 0)))
        })));
    },
});

那么下面整体实现,基本都是依靠上面这些思路,实现的,单纯的开始套就能实现下面的动画了。 是不是很神奇,这套思路,完全可以套用到react和vue上。

  • 整好了,领导~,看下效果

    ezgif.com-gif-maker (16).gif

  • 领导:行,可以,就这样。

part1

  • 重返这五年,重温那岁月

    image.png

  • 领导:这张呢~

  • 我:坐飞机的小女孩往上飞出去,做小角的男人飞入画面

  • 领导:差不多,不过坐小飞机的小女孩这块,应该再丰富一点。

    • 记得我们刚才说的那个小飞机没,这个小女孩飞的时候,渐渐的变小,有种往远飞的感觉,然后变成小飞机飞走~
  • 我:哦哦哦,懂了,开整

    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (17).gif

  • 领导:行,可以,就这样。

part2

  • 成长多措举,管理提格局
  • 工作造氛围,企学见雏形

image.png

  • 我:这个要做成啥样?

  • 领导:入场就是从右边缓缓进来,还有看到这个没

    image.png

    • 这些圆片一点一点的滑入屏幕,然后屏幕出现内容

    • 这张图

      image.png

      • 就是屏幕上一点一点出现内容,然后人物一点一点入画。
  • 我:懂了,开整

    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (18).gif

  • 领导:对,是这样。

part3

  • 发展聚人才,规模逐壮大
  • 搜索寻突破,拓展创业务

image.png

  • 领导:这个主要想表达的就是公司不断的壮大,业务上不断的突破,所以要有种过程感,你看着发挥吧
  • 我:收到,我试试
    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (19).gif

  • 领导:嗯,很不错,可以可以,有过程的画面感。
    • 日历还能动啊,而且日历动的同时,后面的背景一点一点的显示,也寓示了我们的办公楼越来越大,可以,有细节,不错。
    • 过场加入了云彩变大,切换很自然嘛。

part4

  • 那年启征程,改变从此始

    image.png

  • 领导:这个该咋设计呢?你看飞机这么多,我们能让这些飞机各飞各的么?

  • 我:可以啊,我试试

    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (23).gif

  • 领导:可以的,就这样吧。

part5

  • 种得梧桐树,凤凰自然来

image.png

  • 领导:这个柱状图能不能表现出一点一点增长的效果,还有向上箭头能不能也可以有个升的过程
    • 还有这个拿笔的人物

      image.png

      • 可不可以有种书写感,就是表现出在写字
  • 我:哦哦哦,我试试,应该可以,针对这些情况,我再丰富几种表现手段
    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (20).gif

  • 领导:嗯,可以,就是这效果。

part6

  • 全方位服务,码农心无骛
  • 创新谋发展,突破新技术

image.png

  • 领导:这就可以自由发挥了,用一个合理的方式一点一点介绍就好。
  • 我:懂,开整
    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (21).gif

  • 领导:嗯,很不错嘛,有ppt的感觉,挺好的
  • 我:哈哈哈,确实有点。

part7

  • 环境不断好,员工感幸福
  • 乘势迎挑战,赋能于行业

image.png

  • 领导:第一张就是简单的显隐就可以,主要是第二张的这个

    image.png

    • 这个,我跟UI小姐姐说了,希望做成一个列表,但小姐姐做成了这种,那么就需要滚动了。
  • 我:就像滚动页面那样,哦哦哦,我明白了,开整。

    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (22).gif

  • 领导:行,可以的,就这样。

part8

  • 磨砺积能力,自研得硕果

image.png

  • 领导:阿强,这个主要是表现我们去的成就,我们仅仅把文字凸显出来就好,其他就不要求了

    • 但,我觉得第一幅图,还是可以做点文章的,他表示我们获得的证书,你看看能不能实现,物理下落,然后一本本摞起来的效果
  • 我:哈哈哈,好的,我试试,效果我尽量做,可能物理效果没那么像,但摞起来的效果肯定是有的。

  • 领导:可以,你试试

  • 我:好的,开整。

    • 整好了,领导~,看下效果

      ezgif.com-gif-maker (24).gif

  • 领导:辛苦了,阿强,再加把劲,我们要成功了。

  • 我:好的~~~下一个就是结尾了吧,加油~

尾声

  • 逆境砥砺行,收入节节高

image.png

  • 领导:阿强这个结尾,我们收好,我们要有种意境,这样就有感觉,你能懂么
  • 我:我懂你
  • 领导:你看奥第一幅和第二幅区别,是一个没有河水,一个有河水,还有就是一个有没破晓,一个有日出
    • 你看你能衔接好,这可是一个艰巨的任务,干完这个我们就胜利了
  • 我:好的领导,我一定完成任务
    • many hours later

    • 可算整好了,我的大哥~,效果我是尽力了。

      ezgif.com-gif-maker (25).gif

  • 领导:干的漂亮,阿强,有意境了,非常不错,辛苦了。
  • 我:嘿嘿,马马虎虎,我尽力了,我打包好就上线吧。
  • 领导:好的好的,辛苦了。

这就是在线预览地址,可以看看效果。

结尾

目前项目仅仅用了5天时间就出来了个雏形,还很粗糙,很多地方可以进一步的优化。

image.png

这仅仅是一个开始,未来,我会使用react或者vue3,整一个lowcode制作工具,这样就可以更加的方便制作了。

然后开源,敬请期待。

有问题随时交流,我建立一个小清晰qq群,叫“闲D岛”,技术问答群,有问必答,有兴趣可以加群号:551406017

题外话

有一说一,我比较低调,一般出风头的事儿,我是没啥想法的,主要是我觉得争名逐利的画面太尴尬,我来不了这个,但也不知我那天是怎么了,当群里问了好几次都没人回应,我就来了点脾气,即然没谁上,那我试试吧。就这样我接下了这个任务,现在再想,可能就是因为这点脾气,我才敢去做的,也许有点莽了,如果没做成呢?哈哈哈,那就不能想了,还好我实现了,我让这个脾气变得更像勇气了,有时候真不妨大胆一点,觉得自己可以,那就试一试,真没准行呢,别怕输,输丢什么人,怕才丢人呢。

今天的文章年底了,接个大活儿,做一个回顾公司五年发展的总结ppt,要求做成H5网页分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/17305.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注