整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

p5.js 视频播放指南

文简介

在刚接触 p5.js 时我以为这只是一个艺术方向的 canvas 库,没想到它还支持视频文件和视频流的播放。

本文简单讲讲如何使用 P5.js 播放视频。



播放视频文件

p5.js 除了可以使用 video 元素播放视频外,还支持使用 image 控件播放视频。


方式1:video元素播放视频

基础用法

p5.js 的 createVideo() 方法可以创建一个 <video> 元素。

createVideo(src, [callback]) 可以传入2个参数:

  • src: 视频路径(必传)。可以传一个字符串类型的视频路径;也可以传入字符串数组类型,指定多个路径支持不同浏览器。
  • callback: 回调函数(非必传)。在视频加载完成时触发。


录制 GIF 后比较卡,将就看着吧~

// 加载本地视频
let playing = false // 播放状态
let video = null // 视频
let button = null // 按钮

// 视频加载完成的回调函数
function afterLoad() {
  console.log('加载完成')
}

// 加载资源的生命周期
function preload() {
  video = createVideo('assets/02.mp4', afterLoad)
}

// 初始化的生命周期
function setup() {
  noCanvas()
  button = createButton('播放')
  button.mousePressed(toggleVid)
}

// 点击按钮的事件
function toggleVid() {
  if (playing) {
    video.pause()
    button.html('播放')
  } else {
    video.loop()
    button.html('暂停')
  }
  playing = !playing;
}

粗略讲讲上面这段代码。

  • preload() 是 p5.js 提供的一个生命周期,我们通常会将“加载静态资源”这个步骤放在 preload() 里执行。在 《p5.js光速入门》的图片 章节里介绍过。
  • setup() 是一个初始化的生命周期。
  • createVideo() 方法加载视频。第二个参数传入回调函数 afterLoad,在加载完视频资源后会执行回调函数。
  • video.loop() 方法可以播放视频。
  • video.pause() 方法可以暂停视频。
  • noCanvas() 方法用来隐藏 <canvas> 元素,因为我们使用 createVideo() 会在页面创建一个 <video> 元素,所以我们就不需要 <canvas> 元素了。


播放方法

除了 video.loop() 方法,还可以使用 video.play() 播放视频。loop 是循环播放;play 只播放一次,播完就暂停。


传入多个视频地址

createVideo() 方法的第一个参数除了传入一个字符串类型的视频地址外,还可以传入字符串数组,作用就是兼容处理。

比如你的视频资源只有 2.mp4,你希望可以先播放 1.mp4,没有这个视频再播放 2.mp4,就可以这样写:

createVideo(['1.mp4', '2.mp4'])

但通常我们不会这样写,通常我们会给同一个视频提供不同的视频格式,然后用这种方法传入多个视频地址。

因为有些浏览器不一定支持你想播放的地址,此时就可以做个保底处理。


设置视频窗口尺寸

使用 createVideo() 方法创建完视频后,可以通过 size(width, height) 设置视频的宽高。

let video = null

function preload() {
  video = createVideo('assets/02.mp4')
  video.size(300, 600)
}


设置音量

使用 createVideo() 创建的视频控件可以使用 volume() 设置视频的音量,该方法接受1个参数,参数值在 0~1 之间。

let video = null

function preload() {
  video = createVideo('assets/02.mp4', videoLoaded)
}

function videoLoaded() {
  video.volume(0.5) // 将视频音量设置为50%
}



方式2:用image控件播放视频

一开始我也没想到 image 控件可以播放视频,误打误撞试出来的。

这次我就不录屏了,工友们自己运行试试看吧。

let playing = false
let video = null
let button = null

function preload() {
  video = createVideo('assets/02.mp4')
}

function setup() {
  video.hide()
  createCanvas(568, 320)
  button = createButton('播放')
  button.mousePressed(toggleVid)
}

function draw() {
  image(video, 0, 0)
}

function toggleVid() {
  if (playing) {
    video.pause();
    button.html('播放');
  } else {
    video.loop();
    button.html('暂停');
  }
  playing = !playing;
}

上面的代码中,我在 setup() 里使用了 video.hide() 方法将 createVideo() 创建出来的 <video> 元素隐藏起来,因为这次我们需要将视频渲染到画布中,所以不再需要 <video> 了。

接着我们在 draw() 里用 image 不断刷新视频,所以上面这样写是对的。

其他地方没变化。



接入摄像头

如果你的设备有摄像头,p5.js 是支持调用摄像头并将内容展示在画布上的。

let capture

function setup() {
  createCanvas(480, 360)
  capture = createCapture(VIDEO)
  capture.hide()
}

function draw() {
  image(capture, 0, 0, capture.width, capture.height)
}

通过 createCapture() 方法创建一个包含摄像头的音频/视频源 <video> 元素,把这个元素的内容放在 p5.js 的 image 控件里。

这个默认是显示的,而且它是一个独立的元素,默认和画布分离。所以使用 capture.hide() 方法把 <video> 元素隐藏起来,不然页面中会出现两个视频窗口。


其他做法和前面的【方式2】差不多,这里就不再啰嗦了。



推荐阅读

《p5.js 光速入门》

《p5.js 使用npm安装p5.js后如何使用?》

《p5.js 变换操作》

《p5.js 3D图形-立方体》

《p5.js 开发点彩画派的绘画工具》

《p5.js画布操作实战:创建,绑定指定元素,动态调整大小,隐藏滚动条,删除画布》


点赞 + 关注 + 收藏 = 学会了


页动画图像、Flash 动画和 JavaScript 实现的效果图片,我们用最基础的CSS也能实现。制作一个简单的gif动画图,上图就是效果图。

用CSS3制作动画图,你需要了解两个css属性。

其一是 @keyframes

因为它限定了CSS 样式和动画逐步从目前的样式更改为新的样式的变化过程。浏览器兼容的时候需要在keyframes上加前缀,-webkit-, -ms- 或 -moz- 。

keyframes中有两个属性,from和to,from里面的内容定义动画开始的状态,to记录动画结束的状态。@keyframes后面紧跟的是动画的名字,这个可以自定义取名字,比如我取 gifname,页面某个标签元素使用这个动画时候,就需要用到这个名字。

@keyframes gifname
{
    from {background: red;}
    to {background: yellow;}
}
 
@-webkit-keyframes gifname /* Safari 与 Chrome */
{
    from {background: red;}
    to {background: yellow;}
}

from和to也可以用百分比来表示动画的过程,可以用百分比的话,就可以把动画的内容定义得更加丰富了。

@keyframes gifname
{
    0%   {background: red;}
    25%  {background: yellow;}
    50%  {background: blue;}
    100% {background: green;}
}
 
@-webkit-keyframes gifname /* Safari 与 Chrome */
{
    0%   {background: red;}
    25%  {background: yellow;}
    50%  {background: blue;}
    100% {background: green;}
}

比如我在一个div元素上用到这个动画

div
{
    animation: gifname 5s;
    -webkit-animation: gifname 5s; /* Safari 与 Chrome */
}

其二是 animation

刚刚我们在div元素中看到的animation就是我们要认识的第二个属性。animation其实是一堆属性的简写。比如看下面一句代码:

 animation:gifname 2s step-start 1s infinite alternate;

这一句其实可以写成

    animation-name: gifname;
    animation-duration: 2s;
    animation-timing-function: step-start;
    animation-delay: 1s;
    animation-iteration-count: infinite;
    animation-direction: alternate;

animation-name:动画名称

这里是 引入 @keyframes 动画的名称。

animation-duration:动画的持续时间

单位可以是秒(s),也可以是毫秒(ms)

animation-timing-function:动画的过度类型

属性值 :默认是 "ease"

linear:线性过渡。等同于贝塞尔曲线(0.0, 0.0, 1.0, 1.0)

ease:平滑过渡。等同于贝塞尔曲线(0.25, 0.1, 0.25, 1.0)

ease-in:由慢到快。等同于贝塞尔曲线(0.42, 0, 1.0, 1.0)

ease-out:由快到慢。等同于贝塞尔曲线(0, 0, 0.58, 1.0)

ease-in-out:由慢到快再到慢。等同于贝塞尔曲线(0.42, 0, 0.58, 1.0)

cubic-bezier(n,n,n,n):在 cubic-bezier 函数中自己的值。可能的值是从 0 到 1 的数值。

step-start:马上跳到动画每一结束帧的状态

animation-delay:动画延迟时间

默认是 0。

animation-iteration-count:动画循环次数

默认是 1。属性值infinite 代表无数次。

animation-direction:动画是否在下一周期逆向地播放

属性值

normal:正常方向

reverse:反方向运行

alternate:动画先正常运行再反方向运行,并持续交替运行

alternate-reverse:动画先反运行再正方向运行,并持续交替运行

另外还有两项属性:

animation-fill-mode:设置动画播放后的效果

取值:

none:初始样式,不改变默认行为.(默认行为)

forwards:动画播放结束后保持最后一个状态;

backwards:结束后保持第一个状态;


animation-play-state :检索或设置对象动画的状态

属性值

animation-play-state:running | paused;

running:运动

paused: 暂停

animation-play-state:paused; 当鼠标经过时动画停止,鼠标移开动画继续执行

到此为止,属性我们都学习完了,开始实践部分:

首先准备好我们需要的图片,这里我使用了九张图片。


我把九张图片放在九个<li></li>标签里。所有li标签用ul标签包含起来。然后把ul放在一个div标签里,div设置成一张图片的大小,然后通过逐帧移动ul元素实现动画。

最后的处理,把超出div元素的部分隐藏即可。然后就得到了文章开始时候的图片了。

最关键的,上代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>css动画</title>
<style>
    *{
        margin: 0;
        padding: 0;
    }
    li{
        list-style: none;
        margin-right: 0;
    }
#div{
    width:100px;
	height:100px;
    border: 1px solid #fff;
    overflow: hidden;
	margin: 100px 0 0 100px;
    }
    #box{
     width:900px;
     height:100px;   
    border: 1px solid #fff;
    overflow:visible;
    position:relative;
    animation:myfirst 2s step-start 1s infinite ;
    /* Firefox: */
	-moz-animation:myfirst 2s step-start 1s infinite ;
	/* Safari and Chrome: */
	-webkit-animation:myfirst 2s step-start 1s infinite ;
	/* Opera: */
	-o-animation:myfirst 2s step-start 1s infinite ;
    }
    #box li{
        float: left;
        width:98px;
        height:100px; 
        border:1px solid #fff;
    }
    li img{
        width:100%;
        height:100%;
    }
    @keyframes myfirst
{
	0%   { left:0px; top:0;}
	11.1%  { left:-100px; top:0;}
	22.2%  { left:-200px; top:0;}
	33.3%  { left:-300px; top:0;}
	44.4%  { left:-400px; top:0;}
    55.5%  { left:-500px; top:0;}
	66.6%  { left:-600px; top:0;}
	77.7%  { left:-700px; top:0;}
	88.8%  { left:-800px; top:0;}
  100% {left:0px; top:0;}
}
@-moz-keyframes myfirst /* Firefox */
{
	0%   { left:0px; top:0;}
	11.1%  { left:-100px; top:0;}
	22.2%  { left:-200px; top:0;}
	33.3%  { left:-300px; top:0;}
	44.4%  { left:-400px; top:0;}
  55.5%  { left:-500px; top:0;}
	66.6%  { left:-600px; top:0;}
	77.7%  { left:-700px; top:0;}
	88.8%  { left:-800px; top:0;}
  100% {left:0px; top:0;}
}

@-webkit-keyframes myfirst /* Safari and Chrome */
{
	0%   { left:0px; top:0;}
	11.1%  { left:-100px; top:0;}
	22.2%  { left:-200px; top:0;}
	33.3%  { left:-300px; top:0;}
	44.4%  { left:-400px; top:0;}
  55.5%  { left:-500px; top:0;}
	66.6%  { left:-600px; top:0;}
	77.7%  { left:-700px; top:0;}
	88.8%  { left:-800px; top:0;}
  100% {left:0px; top:0;}
}

@-o-keyframes myfirst /* Opera */
{
	0%   { left:0px; top:0;}
	11.1%  { left:-100px; top:0;}
	22.2%  { left:-200px; top:0;}
	33.3%  { left:-300px; top:0;}
	44.4%  { left:-400px; top:0;}
  55.5%  { left:-500px; top:0;}
	66.6%  { left:-600px; top:0;}
	77.7%  { left:-700px; top:0;}
	88.8%  { left:-800px; top:0;}
   100% {left:0px; top:0;}
}

    </style>
</head>
<body>
    <div id="div">
        <ul id="box">
            <li><img src="./img/o1.jpg"/></li>
            <li><img src="./img/o2.jpg"/></li>
            <li><img src="./img/o3.jpg"/></li>
            <li><img src="./img/o4.jpg"/></li>
            <li><img src="./img/o5.jpg"/></li>
            <li><img src="./img/o6.jpg"/></li>
            <li><img src="./img/o7.jpg"/></li>
            <li><img src="./img/o8.jpg"/></li>
            <li><img src="./img/o9.jpg"/></li>
        </ul>
    </div>
</body>
</html>

最后唠叨一句,该动画不支持IE9及更早版本的IE浏览器


喜欢的话,就点赞支持一下吧!

、变形

CSS3变形是一些效果的集合

如平移、旋转、缩放、倾斜效果

每个效果都可以称为变形(transform),它们可以分别操控元素发生平移、旋转、缩放、倾斜等变化

语法:transform:[transform-function] *;

变形函数

translate():平移函数,基于X、Y坐标重新定位元素的位置

transform:translate(100px,0) x轴移动

transform:translate(0,100px) y轴移动


scale():缩放函数,可以使任意元素对象尺寸发生变化

transform:scale(2,0) 设置X轴的缩放

transform:scale(0,2) 设置Y轴的缩放


rotate():旋转函数,取值是一个度数值

transform:rotate(30deg);


skew():倾斜函数,取值是一个度数值

transform:skewX(ax):表示只设置X轴的倾斜

transform:skewY(ay):表示只设置Y轴的倾斜


注:rotate( )函数只是旋转,而不会改变元素的形状

skew( )函数是倾斜,元素不会旋转,会改变元素的形状



二、过度

transition呈现的是一种过渡,是一种动画转换的过程,如渐现、渐弱、动画快慢等

CSS3 transition的过渡功能更像是一种“黄油”,通过一些CSS的简单动作触发样式平滑过渡

语法:transition:[transition-property transition-duration transition-timing-function transition-delay ]


过渡属性( transition-property )

定义转换动画的CSS属性名称

IDENT:指定的CSS属性(width、height、background-color属性等)

all:指定所有元素支持transition-property属性的样式,一般为了方便都会使用all


过渡所需的时间( transition-duration )

定义转换动画的时间长度,即从设置旧属性到换新属性所花费的时间,单位为秒(s)


过渡动画函数( transition-timing-function )

指定浏览器的过渡速度,以及过渡期间的操作进展情况,通过给过渡添加一个函数来指定动画的快慢方式

ease:速度由快到慢(默认值)

linear:速度恒速(匀速运动)

ease-in:速度越来越快(渐显效果)

ease-out:速度越来越慢(渐隐效果)

ease-in-out:速度先加速再减速(渐显渐隐效果)


过渡延迟时间( transition-delay )

指定一个动画开始执行的时间,当改变元素属性值后多长时间去执行过渡效果

正值:元素过渡效果不会立即触发,当过了设置的时间值后才会被触发

负值:元素过渡效果会从该时间点开始显示,之前的动作被截断

0:默认值,元素过渡效果立即执行


三、animation动画简介

animation实现动画主要由两个部分组成

通过类似Flash动画的关键帧来声明一个动画

在animation属性中调用关键帧声明的动画实现一个更为复杂的动画效果

设置关键贞:

@keyframes spread {

0% {width:0;}

33% {width:23px;}

66% {width:46px;}

100% {width:69px;}

}

调用关键贞:

animation:animation-name animation–duration animation-timing-function

animation-delay animation-iteration-count animation-direction

animation-play-state animation-fill-mode;


动画的使用过程:

动画的播放次数(animation-iteration-count)

值通常为整数,默认值为1

特殊值infinite,表示动画无限次播放

动画的播放方向(animation-direction)

normal,动画每次都是循环向前播放

alternate,动画播放为偶数次则向前播放

动画的播放状态(animation-play-state)

running将暂停的动画重新播放

paused将正在播放的元素动画停下来



代码展示:


<html>

<head>

<title>照片墙</title>

</head>

<link rel="stylesheet" href="duocaiqiang.css">

<body>

<div class="content">

<div class="box">

<img src="img/1.jpg">

<img src="img/2.jpg">

<img src="img/3.jpg">

<img src="img/4.jpg">

<img src="img/5.jpg">

<img src="img/6.jpg">

<img src="img/7.jpg">

<img src="img/8.jpg">

<img src="img/9.jpg">

<img src="img/10.jpg">

</div>

</div>

</body>

</html>

*{

margin: 0;

padding: 0;

}


/* 父div设置宽高 */

.box{

width: 80%;

height: 600px;

margin: 0px auto;

margin-top: 10px;

position: relative;

}

/* 所有的图片设置 */

.box>img{

width: 300px;

height: 250px;

position: absolute;

border: 1px solid white;

box-shadow:5px 5px 5px rgba(0,0,0,.6);

border-radius: 20px;

}

/* 第一张图片设置 */

.box>img:nth-of-type(1) {

right: 2;

top: 0px;

transform: rotate(48deg);

}


.box>img:nth-of-type(2){

left: 2px;

top: 10px;

transform: rotate(319deg);

}

.box>img:nth-of-type(3){

left: 500px;

top: 40px;

transform: rotate(278deg);

}

.box>img:nth-of-type(4){

left:250px;

top:40px;

transform: rotate(-50deg);

}

.box>img:nth-of-type(5){

top:300px;

transform: rotate(-80deg);

}

.box>img:nth-of-type(6){

left:700px;

top:300px;

transform: rotate(-260deg);

}

.box>img:nth-of-type(7){

left: 310px;

top: 300px;

transform: rotate(94deg);

}

.box>img:nth-of-type(8){

left: 460px;

top: 300px;

transform: rotate(205deg);

}

.box>img:nth-of-type(9){

left: 100px;

top: 210px;

transform: rotate(38deg);

}

.box>img:nth-of-type(10){

right:100px;

top:300px;

transform: rotate(-210deg);

}

.box>img:hover{

/* 图片前置 */

z-index: 1;

/* 还原放大1.5倍 */

transform: rotate(360deg) scale(2);

transition:all 1s ease-in-out;

}




<!DOCTYPE html>

<html lang="en">


<head>

<meta charset="UTF-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>QQ彩贝导航条</title>

</head>

<link rel="stylesheet" href="QQcaibeidaohang.css">


<body>

<div class="container">

<nav>

<section>

<div class="topleft">

<h1>

<a href="#">

<img src="img/logo_170x46.png">

</a>

</h1>

</div>

<div class="topMiddle">

<ul>

<li><a href="#"><span class="iconOne"></span>返回商场&nbsp;|&nbsp;</a></li>

<li><a href="#">商旅频道&nbsp;|&nbsp;</a></li>

<li><a href="#"><span class="iconTwo"></span>积分商场&nbsp;|&nbsp;</a></li>

<li><a href="#">商旅地方&nbsp;|&nbsp;</a></li>

<li><a href="#">了解彩贝&nbsp;|&nbsp;</a></li>

<li><a href="#">彩贝活动&nbsp;|&nbsp;</a></li>

<li><a href="#">个人中心</a></li>

</ul>

</div>

<div class="topRight">

<ul>

<li><a href="#"></a></li>

<li><a href="#"></a></li>

<li><a href="#"></a></li>

</ul>

</div>

</section>

</nav>

</div>

</body>


</html>

*{

margin: 0;

padding:0;


}

li{

list-style: none;

}

a{

text-decoration: none;

color: #787690;

}

/* 整个导航 */

nav{

height: 100px;

width: 100%;

margin: 0 auto;

position: relative;

background: linear-gradient(to bottom, #FFFFFF, rgba(204, 204, 204, 0.4));

}

/* 导航Logo部分 */

.topleft{

padding-top: 30px;

padding-left: 110px;

}

/* 中间整体部分 */

.topMiddle{

position: absolute;

left: 400px;

bottom: 20px;

height: 50px;

}

/* 导航中间文字 */

.topMiddle>ul>li{

float: left;

margin-right: 20px;

padding-top: 20px;

}

.topMiddle>ul>li>a:hover{

color:yellow;

}


/* 导航中间文字部分第一个li */

.iconOne{

display: inline-block;

position: absolute;

width: 46px;

height: 100px;

left: 0;

top:0;

background: url('../htmlNine/img/header_03.png') 2px 1px no-repeat;


}/* 导航中间文字部分第三个li */


.iconTwo{

display: inline-block;

position: absolute;

width: 46px;

height: 100px;

top:0;

background: url('../htmlNine/img/header_07.png') 2px 1px no-repeat;

}



/* 调用关键贞 */

.topMiddle>ul>li:nth-child(1)>a:hover .iconOne{

background: url('../htmlNine/img/header_05.png') 2px 1px no-repeat;

animation: identifier 1s ease-out both;

}



/* 调用关键贞 */

.topMiddle>ul>li:nth-child(3)>a:hover .iconTwo{

background: url('../htmlNine/img/header_09.png') 2px 1px no-repeat;

animation: identifier 1s ease-out both;

}

/* topRight */

/* 登录部分所有li */

.topRight{

position: absolute;

left: 1380px;

bottom: 55px;

height: 40px;

}

.topRight>ul>li{

height: 25px;

width: 30px;

}


/* 登录部分三个图标 */

.topRight>ul>li:nth-child(1){

position: absolute;

right: 100px;

top:45px;

background: url('../htmlNine/img/iconsB_13.png') 2px 1px no-repeat;

}

.topRight>ul>li:nth-child(2){

position: absolute;

right: 150px;

top:45px;

background: url('../htmlNine/img/iconsB_12.gif') 2px 1px no-repeat;

}

.topRight>ul>li:nth-child(3){

position: absolute;

right:200px;

top:45px;

background: url('../htmlNine/img/iconsB_11.gif') 2px 1px no-repeat;

}


.topRight>ul>li:hover{

/* 变形 */

transform: rotate(720deg) scale(2);

/* 过度 */

transition:all 0.6s ease-in-out ;

}


/* 动画设置关键帧名称identifier */

@keyframes identifier {

0%{width: 0;}

33%{width:23px;}

66%{width: 46px;}

100%{width: 69px;}

}


效果链接:file:///D:/ruanjian/VS/wenjianxiangmu/htmlNine/duocaiqiang.html

file:///D:/ruanjian/VS/wenjianxiangmu/htmlNine/QQcaibeidaohang.html