大屏看板学习

大屏自适应

核心是使用css的transform中的scale进行缩放以自适应,而缩放比例的计算需要确定一个基准,例如1920*1080:

const getScale = useCallback(() => {
    const ww = document.documentElement.clientWidth / 1920;
    const wh = document.documentElement.clientHeight / 1080;
    return ww < wh ? ww : wh;
 }, []);

然后设置好resize的监听事件,以及对应样式就好:

const demoKanBan = () => {
  const [scale, setScale] = useState();

  // 页面初始化执行
  useEffect(() => {
    changeSize();
    window.addEventListener('resize', changeSize);
  }, []);

  // 大屏缩放比例
  const getScale = useCallback(() => {
    const ww = document.documentElement.clientWidth / 1920;
    const wh = document.documentElement.clientHeight / 1080;
    return ww < wh ? ww : wh;
  }, []);

  // 防抖动
  const changeSize = debounce(() => {
    const s = getScale();
    setScale(s);
  }, 500);

  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        position: 'relative',
        backgroundColor: 'black',
      }}
    >
      <div
        style={{
          transform: `scale(${scale}) translate(-50%, -50%)`,
          WebkitTransform: `scale(${scale}) translate(-50%, -50%)`,
          width: `1920px`,
          height: `1080px`,
          transformOrigin: '0 0',
          position: 'absolute',
          left: '50%',
          top: '50%',
          transition: '0.3s',
        }}
      >
        {/* 看板内容 */}
      </div>
    </div>
  );
};

截图如下:


3D旋转

让物体旋转起来,本质就是让它在进行x轴运动的同时,y轴也在运动,我们假定一个运动周期是20s,由于我们可以设置成交替的模式,所以动画的时长就是一半,10s。
我们先来介绍下css的animation这一属性,它是由六个子属性组成的,即:

  • animation-name(动画名称、一般我们设置关键帧即可)
  • animation-duration(定义动画完成一个周期所需要的时间)
  • animation-timing-function(规定动画的速度曲线)
  • animation-delay(定义动画何时开始,定义为负值的话可以使动画跳过指定时间)
  • animation-iteration-count(定义动画的播放次数)
  • animation-direction(定义是否应该轮流反向播放动画)
    所以我们先定义相关的关键帧:
// x轴
@keyframes animX {
    0% {left: 0%;}
    100% {left: 90%;}
}
// y轴
@keyframes animY {
    0% {top: 0%;}
    100% {top: 80%;}
}

然后定义动画即可(多个动画可以','分隔)

.element1 {
    animation: animX 10s cubic-bezier(0.36, 0, 0.64, 1) -5s infinite alternate,
    animY 10s cubic-bezier(0.36, 0, 0.64, 1) 0s infinite alternate,
}

当然,要实现多个动画元素一起运动的效果,在这个例子里我们主要是控制animation-delay这一属性,比如上面的x轴动画是直接从第5s开始,y轴动画则是从0开始,我们可以依次类推接下来所要出现的动画元素初始的位置,如果我们想要n个球一起旋转,那么后一个球只需要在前一个球的基础上分别跳过 动画总时长/n 秒即可;
比如说上面我们定义的动画总时长是20s,10个元素一起旋转,那么从第一个元素往后开始,每个元素的延迟时间都要增加2s,element2的延时时间为-7s、-2s,element3的延迟时间为-9s,-4s,以此类推。
最后的效果如下图:


Three.js

three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。
在react中进行three.js的开发,通过查找相关资料,@react-three/fiber这一个包使用可重用、自包含的组件以声明方式构建场景,这些组件可以对状态做出反应,易于交互,并可以进入react的生态系统。而@react-three/drei则是three.js的一些预先制作好的功能的集合。
我们可以先添加这两个包和three.js:

yarn add three @react-three/fiber @react-three/drei

下面是一些概念:
Canvas标签
这个Canvas是定义 React Three Fiber 场景的地方,有点像Three.js中的:

const scene = new THREE.Scene();

注意,Canvas标签首字母大写,且需要从@react-three/fiber中引入,而其它的大部分标签都已经被注入,可以直接使用。

import { Canvas } from '@react-three/fiber';

<Canvas>
{/* content */}
</Canvas>

mesh标签
相当于Three.js中的网格:

new THREE.Mesh( geometry, material );

只是其相关属性的定义可以写在标签体内,比如缩放和旋转就可以这样子定义:

<mesh
  scale={3}
  rotation={[0, Math.PI / 2, 0]}
>
</mesh>

ambientLight标签
相当于Three.js中的环境光:

const light = new THREE.AmbientLight( color : Integer, intensity : Float);

同样的,现在传入的参数可以作为相关属性定义在标签体内:

<ambientLight intensity={intensity} color={color} />

directionalLight标签
相当于Three.js中的平行光:

const directionalLight = new THREE.DirectionalLight( color : Integer, intensity : Float );

同样的,现在传入的参数可以作为相关属性定义在标签体内:

<directionalLight intensity={intensity} color={color} position={position} />

OrbitControls标签
相当于Three.js中的轨道控制器:

const controls = new OrbitControls( camera, renderer.domElement );

需要从@react-three/drei中引入,使用时直接:

import { OrbitControls } from "@react-three/drei";

<OrbitControls />

导入3d模型
可以去网站https://sketchfab.com/下载相关3d模型,使用原始的Three.js加载3d模型,方法是:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
loader.load( 'path/to/model.glb', function ( gltf ) {
  scene.add( gltf.scene ); 
}, undefined, function ( error ) {
  console.error( error ); 
});

现在我们使用另一种方式来引入GLTF文件,使用一种工具:gltf-pipeline

gltf-pipeline由Richard Lee和Cesium团队用来优化glTF的工具。

    将glTF转换为glb(并反向)
    将缓冲区/纹理保存为嵌入文件或单独文件
    将glTF 1.0模型转换为glTF 2.0
    应用Draco网格压缩

1.安装:

yarn add global gltf-pipeline

2.将 glTF 转换为 Draco glTF。通过终端进入到3d模型的目录下,在终端输入以下命令:

gltf-pipeline -i scene.gltf -o yourName.gltf -d

然后就会在当前目录下生成 yourName.gltf 这一文件

3.生成js文件

npx gltfjsx yourName.gltf

就会在当前目录下生成yourName.js这一文件,这便是通过这个工具进行操作后生成的可嵌入的一个3D模型;

然后我们把这两个文件放入项目中,注意,由于生成的yourName.js中引入gltf默认是

const { nodes, materials } = useGLTF('/xxx.gltf')

所以我们需要把gltf文件放到项目根目录下的publi文件夹下面,然后在需要使用到模型的地方引入这个js文件即可:

import Car from "./Car.js";
import { Suspense } from "react";

<Suspense fallback={null}>
  <Car />
</Suspense>

完整的一个通过@react-three/fiber辅助创建的Three.js示例代码如下:

import { Canvas } from '@react-three/fiber';
import { OrbitControls } from "@react-three/drei";
import React, { Suspense } from "react";
import Car from "./Car.js";

const ThreeTest = () => {
  return (
    <div style={{ width: '100%', height: '100%' }}>
      <Canvas style={{ width: '100%', height: '100%' }}>
        <ambientLight intensity={0.5} />
        <directionalLight position={[-2, 5, 2]} intensity={1} />
        <mesh
          scale={3}
          rotation={[0, Math.PI / 2, 0]}
        >
          <OrbitControls />
          <Suspense fallback={null}>
            <Car />
          </Suspense>
        </mesh>
      </Canvas>
    </div>
  );
};

export default ThreeTest;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容