创作灵感
前段时间碰到个用渲染序列桢替代3D的项目需求,然后手写一个基本的控制播放序列的功能。折腾几小时,因为是用vue开发的,所以单独写了个序列桢的播放组件传参调用。 虽然是可以用了但感觉每次这样感觉真麻烦。于是想到Web 组件可以自定义标签的功能,于是网上搜索了下自定义标签的基本用法,捣鼓了一个用来播放序列桢的标签。
呃,当然可能在线使用是个鸡肋功能(网络带宽原因序列图过大时会卡顿),只是工作关系,常用于开发本地互动数字媒体,用于单机版如展览展示等特殊需求上使用挺方便的。做了个粗糙的小样,给需要的人做个参考。
使用方法
1. 把 anim-sequence.js 放在要引用的目录里
2. 在html 文件里引用 anim-sequence.js .
3. 在要展示序列动画的地方,添加自定义的标签,配置好序列桢的路径、速率、总桢数就可运行。
code:
<t-animseq src="你的序列桢路径(不含自动增加的编号及扩展名)" total="250" rate="60" autoplay/>
<t-animseq src="images/seq/xx_" total="250" rate="60" autoplay/>
4. 注意src你的序列桢所在目录,如:images/seq/xx_0.jpg .... images/seq/xx_250.jpg 。 src的值为:images/seq/xx_ 。 扩展名默认为jpg ,如要修改png,添加属性:format="png"
代码
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta name="description" content="自定义标签测试">
<meta name="author" content="mythlong,阿爆野">
<meta name="email" content="myth_long@qq.com">
<title>自定义标签测试-序列桢动画标签</title>
<style>
html,body{
height: 100%;
margin: 0;
overflow: hidden;
}
body{
background-color: #333;
}
.seq-con,.seq-con div{
margin:2px;
}
</style>
</head>
<body>
<!--
example:
<t-animseq src="../images/seq/dieluoji/" total="250" rate="60" manual onclick="toggle()"/>
anual onclick="toggle()" 两个不能同时使用
参数 说明:
total :总序列桢数 必填
src : 序列桢的路径 必填
format: 文件格式(jpg ,png),默认jpg.
rate : 速率(1-60) 默认每少25桢,
autoplay :自动播放
reverse :配合自动播放,反向播放
manual : 手动左右拖动鼠标控制序列切换
可用方法:play(),pause(),toggle(),next(),prev();
-->
<div class="seq-con" style="width: 49%;min-width: 256px;display: inline-block;color:#fff;">自动播放
<t-animseq id="ani_seq1" src="../images/seq/dieluoji/" format="jpg" total="250" autoplay manual />
</div>
<div class="seq-con" style="width: 49%;min-width: 256px;display: inline-block;color:#fff;">点击播放
<t-animseq id="ani_seq2" src="../images/seq/dieluoji/" total="250" rate="60" reverse onclick="toggle()" />
</div>
<div class="seq-con" style="color:#fff;">拖动播放
<t-animseq id="ani_seq3" src="../images/seq/dieluoji/" total="250" manual/>
</div>
<script src="js/anim-sequence.js"></script>
</body>
</html>
anim-sequence.js
//author:mythlong
//email:myth_long@qq.com
//2024-01-06.
class AnimSeq extends HTMLElement {
static get observedAttributes() {
return ["src", "format", "total", "rate" ];
}
constructor() {
super();
this.interv=0;
this.rate=25;
this.fmt='jpg';
this.cid=0;
this.reverse=false;
this.total=0;
this.status='none';
this.img=null;
this.manual=false;
const shadow = this.attachShadow({ mode: "open" });
const div = document.createElement("div");
this.img = document.createElement("img");
if (this.hasAttribute('format')) {
this.fmt = this.getAttribute('format');
}
if (this.hasAttribute('total')) {
this.total = this.getAttribute('total');
}
if (this.hasAttribute('rate')) {
this.rate = this.getAttribute('rate');
}
if (this.hasAttribute('reverse')) {
this.reverse = true;
}
if (this.hasAttribute('manual')) {
this.manual = true;
}
this.img.src = this.getAttribute('src') + this.cid +'.' + this.fmt;
this.img.style.width = '100%';
this.img.style.height = '100%';
this.img.style.userSelect = 'none';
div.style.userSelect = 'none';
div.style.width = '100%';
div.style.height = '100%';
shadow.appendChild(div);
div.appendChild(this.img);
this.dist=20;
this.curX=0;
this.canAct=false;
if(this.manual){
this.fn=this.mouseupHander.bind(this);
this.addEventListener('mousedown',this.mousedownHander,false);
this.addEventListener('mousemove',this.mousemoveHander,false);
document.addEventListener('mouseup',this.fn,false);
this.interv=setInterval(()=>{
if(this.canAct){
this.img.src=this.getAttribute('src') + this.cid +'.' + this.fmt;
}
},20);
}
}
mousedownHander(e){
e.preventDefault();
this.canAct=true;
this.curX=e.clientX;
}
mousemoveHander(e){
e.preventDefault();
if(this.canAct){
this.cid=parseInt(this.cid)+Math.round(e.clientX-this.curX);
if(this.cid>this.total){
this.cid=0;
}
else if(this.cid<0){
this.cid=this.total;
}
this.curX=e.clientX;
}
}
mouseupHander(e){
this.canAct=false;
this.curX=e.clientX;
}
connectedCallback() {
if (this.hasAttribute('autoplay')) {
this.play();
}
}
disconnectedCallback() {
clearInterval(this.interv);
if(this.manual){
this.removeEventListener('mousedown',this.mousedownHander);
this.removeEventListener('mousemove',this.mousemoveHander);
document.removeEventListener('mouseup',this.fn);
}
}
play() {
this.status='play';
clearInterval(this.interv);
this.interv=setInterval(()=>{
if(this.reverse){
this.cid--;
if(this.cid<0){
this.cid=this.total;
}
}
else{
this.cid++;
if(this.cid>this.total){
this.cid=0;
}
}
this.img.src=this.getAttribute('src') + this.cid +'.' + this.fmt;
},1000/this.rate);
}
pause() {
this.status='pause';
clearInterval(this.interv);
}
toggle(){
if(this.status=='play'){
this.pause();
}
else if(this.status!='play'){
this.play();
}
}
next(){
this.cid++;
if(this.cid>this.total){
this.cid=0;
}
this.img.src=this.getAttribute('src') + this.cid +'.' + this.fmt;
}
prev(){
this.cid--;
if(this.cid<0){
this.cid=this.total;
}
this.img.src=this.getAttribute('src') + this.cid +'.' + this.fmt;
}
}
customElements.define("t-animseq", AnimSeq);
在线演示
PS:在线因为服务器带宽有限,展示卡顿。所以自己在本地上用序列测试为佳~