@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
class GifPlayer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} template 图片模板路径:变量,{i}
|
||||||
|
* @param {*} num 图片的总数{i}=0~(num-1), 默认34
|
||||||
|
* @param {*} canvas 画布
|
||||||
|
* @param {*} radioRate 播放速率比,0=不播放 默认1
|
||||||
|
*/
|
||||||
|
constructor(template, num, canvas, radioRate) {
|
||||||
|
this.load = false;
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.radioRate = radioRate;
|
||||||
|
this.ctx = this.canvas.getContext('2d');
|
||||||
|
// this.ctx.save();
|
||||||
|
this.#init(template, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #init(template, num) {
|
||||||
|
this.imgs = await this.loadImgs(template, num);
|
||||||
|
this.canvas.dispatchEvent(new CustomEvent('loadend', { bubbles: false }))
|
||||||
|
this.load = true;
|
||||||
|
this.canvas.width = this.imgs[0].naturalWidth * window.devicePixelRatio;
|
||||||
|
this.canvas.height = this.imgs[0].naturalHeight * window.devicePixelRatio;
|
||||||
|
this.i = 0;
|
||||||
|
this.time = Date.now();
|
||||||
|
this.playing = true;
|
||||||
|
this.ctx.drawImage(this.imgs[0], 0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
this.#backgroudPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载图片
|
||||||
|
* @param {*} template 图片模板路径:变量,{i}
|
||||||
|
* @param {*} num 图片的总数{i}=0~(num-1), 默认34
|
||||||
|
*/
|
||||||
|
loadImgs(template, num = 34) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const imgs = [];
|
||||||
|
const ps = [];
|
||||||
|
for (let i = 0; i < num; i++) {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = template.replace('{i}', i);
|
||||||
|
imgs[i] = img;
|
||||||
|
ps.push(new Promise((resolve1, reject1) => {
|
||||||
|
img.onload = resolve1;
|
||||||
|
img.onerror = reject1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Promise.all(ps).then(() => {
|
||||||
|
resolve(imgs);
|
||||||
|
}).catch(err => {
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#backgroudPlay() {
|
||||||
|
if (this.radioRate === 0 || !this.playing) {
|
||||||
|
requestAnimationFrame(() => { this.#backgroudPlay() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Date.now();
|
||||||
|
if (now - this.time >= 50 / this.radioRate) {
|
||||||
|
this.time = now;
|
||||||
|
this.i++;
|
||||||
|
if (this.i >= this.imgs.length) {
|
||||||
|
this.i = 0;
|
||||||
|
this.canvas.dispatchEvent(new CustomEvent('loopend', { bubbles: false }))
|
||||||
|
}
|
||||||
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
// this.ctx.restore();
|
||||||
|
this.ctx.drawImage(this.imgs[this.i], 0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => { this.#backgroudPlay() });
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.playing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export { GifPlayer };
|
||||||
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 366 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 127 KiB |
@ -0,0 +1,271 @@
|
|||||||
|
.login {
|
||||||
|
position: relative;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
--w-bg: #c9dcf6;
|
||||||
|
--w-bg-1: #00000004;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
background-color: #0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-bg {
|
||||||
|
background-color: var(--w-bg);
|
||||||
|
background-image: repeating-linear-gradient(45deg, #0000 0, #0000 .3em, var(--w-bg-1) .6em, #0000 1em, #0000 1.2em),
|
||||||
|
repeating-linear-gradient(-45deg, #0000 0, #0000 .3em, var(--w-bg-1) .6em, #0000 1em, #0000 1.2em);
|
||||||
|
|
||||||
|
filter: url(#bgFilter);
|
||||||
|
transform: scale(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-layout {
|
||||||
|
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
width: 50em;
|
||||||
|
height: 50em;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.energy-base {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image: url(./energy-base.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 1em 20em;
|
||||||
|
background-size: calc(713em / 20) auto;
|
||||||
|
/* filter: brightness(190%); */
|
||||||
|
animation: am-login-doing 1.7s infinite alternate-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.energy-body {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image: url(./energy-body.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 7em 5em;
|
||||||
|
background-size: calc(495em / 20) auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-frame {
|
||||||
|
width: 30em;
|
||||||
|
/* min-height: 30em; */
|
||||||
|
background-color: #FFF;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 0 0 1em rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 3em;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1.7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
width: 10em;
|
||||||
|
position: absolute;
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-input {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: solid 1px #0002;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2em .5em .3em;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
margin-right: 1em;
|
||||||
|
|
||||||
|
|
||||||
|
path {
|
||||||
|
fill: #0003;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
font-size: 1.1em;
|
||||||
|
padding: .5em 0em;
|
||||||
|
color: #0005;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #0005;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 5em;
|
||||||
|
height: 2em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:focus) {
|
||||||
|
border-bottom: solid 1px #0004;
|
||||||
|
|
||||||
|
input{
|
||||||
|
color: #0009;
|
||||||
|
}
|
||||||
|
|
||||||
|
path {
|
||||||
|
fill: #0007;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reme {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: .6em 1em;
|
||||||
|
color: #0008;
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin-right: .5em;
|
||||||
|
transform: translateY(.11em) scale(1.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
user-select: none;
|
||||||
|
margin-top: 2em;
|
||||||
|
height: 2.3em;
|
||||||
|
position: relative;
|
||||||
|
background-color: #1163fd;
|
||||||
|
color: #FFF;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: normal;
|
||||||
|
letter-spacing: 2em;
|
||||||
|
text-indent: 2em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: .3em;
|
||||||
|
width: 100%;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:not(.loading) {
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(120%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
filter: brightness(80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: #0003;
|
||||||
|
backdrop-filter: blur(.1em);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
border: solid .2em #fff;
|
||||||
|
mask-image: conic-gradient(from 0deg,#0000 0%,#000 75%,#000 83%,#0000 85%);
|
||||||
|
animation: am-login-loading 1s ease infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-login-loading {
|
||||||
|
0% {
|
||||||
|
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@keyframes am-login-doing {
|
||||||
|
0% {
|
||||||
|
|
||||||
|
filter: brightness(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
|
||||||
|
filter: brightness(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --noise-base {
|
||||||
|
syntax: '<number>';
|
||||||
|
inherits: true;
|
||||||
|
initial-value: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noise {
|
||||||
|
filter: url(#noiseFilter);
|
||||||
|
--noise-base: 0;
|
||||||
|
animation: am-noise 5.1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-noise {
|
||||||
|
0% {
|
||||||
|
--noise-base: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
--noise-base: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
--noise-base: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,189 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" style="font-size: .85vw;">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="assets/login/login.css">
|
||||||
|
<script type="module" src="login.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="margin: 0; padding: 0;">
|
||||||
|
<div class="login">
|
||||||
|
<label style="position: absolute; right: 1em; bottom: 1em; z-index: 10;"><input type="checkbox" onchange="if(this.checked){document.body.style.setProperty('--dyn','flex');document.body.style.setProperty('--sta','none'); }else{document.body.style.setProperty('--sta','flex');document.body.style.setProperty('--dyn','none'); }">转动风车</label>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="login-bg">
|
||||||
|
<svg style="display: none;">
|
||||||
|
<defs>
|
||||||
|
<filter id="bgFilter" color-interpolation-filters="linearRGB" filterUnits="objectBoundingBox"
|
||||||
|
primitiveUnits="userSpaceOnUse">
|
||||||
|
<feTurbulence type="turbulence" baseFrequency=".5 .5" numOctaves="100" seed="100" stitchTiles="stitch"
|
||||||
|
x="-20%" y="-20%" width="140%" height="140%" result="turbulence" />
|
||||||
|
<feDisplacementMap in="SourceGraphic" in2="turbulence" scale="200" xChannelSelector="R" yChannelSelector="A"
|
||||||
|
x="-20%" y="-20%" width="140%" height="140%" result="displacementMap" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="login-layout">
|
||||||
|
<div>
|
||||||
|
<svg viewBox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="width: 200em; height: 200em; position: absolute; top:0; left: -5em; --line-light:#60b17c;">
|
||||||
|
<!-- 定义阴影滤镜 -->
|
||||||
|
<defs>
|
||||||
|
<filter id="shadow" x="-200%" y="-200%" width="500%" height="500%">
|
||||||
|
<feDropShadow dx="0" dy="0" stdDeviation="2" flood-color="var(--line-light,red)" flood-opacity="1" />
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
<!-- 定义线性渐变 -->
|
||||||
|
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color: black; stop-opacity: 1" />
|
||||||
|
<stop offset="100%" style="stop-color: white; stop-opacity: 1" />
|
||||||
|
</linearGradient>
|
||||||
|
|
||||||
|
<!-- 定义mask -->
|
||||||
|
<mask id="mask">
|
||||||
|
<rect x="-20" y="-1" width="20" height="3" fill="url(#gradient)">
|
||||||
|
<animateMotion dur="2.3s" repeatCount="indefinite" rotate="auto">
|
||||||
|
<mpath href="#bezierPath" />
|
||||||
|
</animateMotion>
|
||||||
|
</rect>
|
||||||
|
</mask>
|
||||||
|
|
||||||
|
<mask id="mask2">
|
||||||
|
<rect x="-20" y="-1" width="20" height="3" fill="url(#gradient)">
|
||||||
|
<animateMotion dur="1.7s" repeatCount="indefinite" rotate="auto">
|
||||||
|
<mpath href="#bezierPath2" />
|
||||||
|
</animateMotion>
|
||||||
|
</rect>
|
||||||
|
</mask>
|
||||||
|
|
||||||
|
|
||||||
|
<mask id="mask3">
|
||||||
|
<rect x="-20" y="-1" width="20" height="3" fill="url(#gradient)">
|
||||||
|
<animateMotion dur="2.1s" repeatCount="indefinite" rotate="auto">
|
||||||
|
<mpath href="#bezierPath3" />
|
||||||
|
</animateMotion>
|
||||||
|
</rect>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<path id="bezierPath" d="
|
||||||
|
M 40,518
|
||||||
|
Q 180,500,200,435
|
||||||
|
" stroke-width="1" stroke="#0001" fill="none" />
|
||||||
|
<path d="
|
||||||
|
M 40,518
|
||||||
|
Q 180,500,200,435
|
||||||
|
" stroke-width="1" stroke="var(--line-light,red)" fill="none" mask="url(#mask)" />
|
||||||
|
<circle cx="0" cy="0" r="1" fill="var(--line-light,red)" filter="url(#shadow)">
|
||||||
|
<animateMotion dur="2.3s" repeatCount="indefinite" calcMode="linear">
|
||||||
|
<mpath href="#bezierPath" rotate="reverse" />
|
||||||
|
</animateMotion>
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<path id="bezierPath2" d="
|
||||||
|
M 560,200
|
||||||
|
Q 500,400,400,390
|
||||||
|
" stroke-width="1" stroke="#0001" fill="none" />
|
||||||
|
<path d="
|
||||||
|
M 560,200
|
||||||
|
Q 500,400,400,390
|
||||||
|
" stroke-width="1" stroke="var(--line-light,red)" fill="none" mask="url(#mask2)" />
|
||||||
|
<circle cx="0" cy="0" r="1" fill="var(--line-light,red)" filter="url(#shadow)">
|
||||||
|
<animateMotion dur="1.7s" repeatCount="indefinite" calcMode="linear">
|
||||||
|
<mpath href="#bezierPath2" rotate="reverse" />
|
||||||
|
</animateMotion>
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<path id="bezierPath3" d="
|
||||||
|
M 995,528
|
||||||
|
Q 400,500,300,431
|
||||||
|
" stroke-width="1" stroke="#0001" fill="none" />
|
||||||
|
<path d="
|
||||||
|
M 995,528
|
||||||
|
Q 400,500,300,431
|
||||||
|
" stroke-width="1" stroke="var(--line-light,red)" fill="none" mask="url(#mask3)" />
|
||||||
|
<circle cx="0" cy="0" r="1" fill="var(--line-light,red)" filter="url(#shadow)">
|
||||||
|
<animateMotion dur="2.1s" repeatCount="indefinite" calcMode="linear">
|
||||||
|
<mpath href="#bezierPath3" rotate="reverse" />
|
||||||
|
</animateMotion>
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
<div class="energy-base"></div>
|
||||||
|
<div class="energy-body noise">
|
||||||
|
<svg style="display: none;">
|
||||||
|
<defs>
|
||||||
|
<filter id="noiseFilter" color-interpolation-filters="linearRGB" filterUnits="objectBoundingBox"
|
||||||
|
primitiveUnits="userSpaceOnUse">
|
||||||
|
<feTurbulence type="turbulence" baseFrequency="0 0.21" numOctaves="2" seed="2" stitchTiles="stitch"
|
||||||
|
x="0%" y="0%" width="100%" height="100%" result="turbulence" />
|
||||||
|
<feDisplacementMap in="SourceGraphic" in2="turbulence" scale="10" xChannelSelector="R"
|
||||||
|
yChannelSelector="B" x="0%" y="0%" width="100%" height="100%" result="displacementMap" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<canvas class="canvas" style="width: 30em; left: 80em; top: 14em; display: var(--dyn,none); "></canvas>
|
||||||
|
<canvas class="canvas" style="width: 15em; left: 44em; top: 1em; display: var(--dyn,none);"></canvas>
|
||||||
|
<canvas class="canvas" style="width: 9em; left: -6em; top: 40.2em; transform: none; display: var(--dyn,none);"></canvas>
|
||||||
|
<img class="canvas" src="./assets/login/energy-input.png"
|
||||||
|
style="width: 18em; left: 86em; top: 15em; transform: none; display: var(--sta,flex);" />
|
||||||
|
<img class="canvas" src="./assets/login/energy-input.png"
|
||||||
|
style="width: 12em; left: 45em; top: -5em; transform: none; display: var(--sta,flex);" />
|
||||||
|
<img class="canvas" src="./assets/login/energy-input.png" style="width: 8em; left: -5em; top: 35em; display: var(--sta,flex);" />
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="login-frame">
|
||||||
|
<h1>欢迎登录</h1>
|
||||||
|
<h1>园区智慧能源综合管控平台</h1>
|
||||||
|
<div class="login-input" style="margin-top: 2em;">
|
||||||
|
<svg t="1739438726965" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="3160">
|
||||||
|
<path
|
||||||
|
d="M164.655 68.977v0 0zM866.321 769.149q0 59.804-36.377 94.437t-96.684 34.632h-435.544q-60.293 0-96.684-34.632t-36.377-94.437q0-26.414 1.744-51.573t6.977-54.321 13.2-54.069 21.432-48.586 30.892-40.367 42.614-26.665 55.563-9.963q4.479 0 20.931 10.717t37.131 23.916 53.819 23.916 66.531 10.717 66.531-10.717 53.819-23.916 37.131-23.916 20.931-10.717q30.405 0 55.563 9.963t42.614 26.665 30.893 40.367 21.432 48.586 13.2 54.069 6.977 54.321 1.744 51.573zM706.846 324.131q0 79.242-56.065 135.292t-135.293 56.065-135.293-56.065-56.065-135.292 56.065-135.293 135.293-56.065 135.293 56.065 56.065 135.293z"
|
||||||
|
p-id="3161"></path>
|
||||||
|
</svg>
|
||||||
|
<input type="text" autocomplete="off" placeholder="请输入用户名" autofocus />
|
||||||
|
</div>
|
||||||
|
<div class="login-input">
|
||||||
|
<svg t="1739438853067" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="4166" width="200" height="200">
|
||||||
|
<path
|
||||||
|
d="M807.049 391.258c0.946-9.62 1.45-19.37 1.45-29.239 0-163.7-132.706-296.406-296.406-296.406S215.687 198.318 215.687 362.02c0 9.802 0.498 19.486 1.432 29.043-43.925 18.95-74.675 62.638-74.675 113.516v330.363c0 68.25 55.328 123.58 123.58 123.58h491.672c68.25 0 123.578-55.328 123.578-123.58V504.578c0-50.704-30.54-94.267-74.225-113.32zM510.917 165.905c109.134 0 197.604 88.47 197.604 197.603 0 5.895-0.275 11.726-0.782 17.49H314.094a200.097 200.097 0 0 1-0.782-17.49c0.002-109.132 88.472-197.603 197.605-197.603z"
|
||||||
|
p-id="4167"></path>
|
||||||
|
</svg>
|
||||||
|
<input type="password" autocomplete="off" placeholder="请输入登录密码" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-input">
|
||||||
|
<svg t="1739438995410" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="5146" width="200" height="200">
|
||||||
|
<path
|
||||||
|
d="M908.65 256.38c-2.81-27.59-23.15-50.2-50.29-55.9a1187.653 1187.653 0 0 1-162.65-37.44A604.025 604.025 0 0 1 550.39 78.1c-23.19-16.7-54.47-16.7-77.67 0a381.187 381.187 0 0 1-146.42 84.39 545.725 545.725 0 0 1-158.17 39.09c-27.74 4.48-48.52 27.83-49.74 55.9s-1.69 140.29-1.69 263.77c0 223.54 263.77 439.86 395.7 439.86 131.88 0 355.46-152.59 391.22-436.48 8.95-167.68 5.03-268.29 5.03-268.29v0.04zM765.02 429.05L489.47 688.93c-12.4 11.82-31.35 13.68-45.81 4.48l-7.23-6.17-152.04-158.12c-14.2-15.43-13.21-39.45 2.22-53.65 15.43-14.2 39.45-13.2 53.65 2.22l125.2 131.34L713.6 374.29c15.44-14.2 39.47-13.2 53.67 2.24 14.2 15.44 13.2 39.47-2.24 53.67v-1.15h-0.01z"
|
||||||
|
p-id="5147"></path>
|
||||||
|
</svg>
|
||||||
|
<input type="input" autocomplete="off" placeholder="请输入验证码" />
|
||||||
|
<img title="点击更换验证码" src="http://dummyimage.com/110x40/6aadfb/FFF&text=123456"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="reme"><input type="checkbox" /> 记住密码</label>
|
||||||
|
|
||||||
|
<div class="login-btn" onclick="this.classList.toggle('loading');" style="pointer-events: all;">登录</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { GifPlayer } from './GifPlayer.js';
|
||||||
|
window.onload = () => {
|
||||||
|
|
||||||
|
const noise = document.querySelector('.noise');
|
||||||
|
const noiseStyle = getComputedStyle(noise);
|
||||||
|
const noiseFilter = document.querySelector('#noiseFilter').firstElementChild;
|
||||||
|
|
||||||
|
const noisePlayer = () => {
|
||||||
|
let base = noiseStyle.getPropertyValue('--noise-base');
|
||||||
|
noiseFilter.setAttribute('baseFrequency', `0 ${base}`);
|
||||||
|
requestAnimationFrame(noisePlayer)
|
||||||
|
}
|
||||||
|
noisePlayer();
|
||||||
|
|
||||||
|
let speed = [.75,.5,.35]
|
||||||
|
|
||||||
|
document.querySelectorAll("canvas.canvas").forEach((canvas,i) => {
|
||||||
|
console.debug(i)
|
||||||
|
new GifPlayer('./assets/login/gif/{i}.png', 19, canvas, speed[i]);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,116 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<canvas id="gifCanvas"></canvas>
|
||||||
|
<div>
|
||||||
|
<button onclick="window.gifPlayer.start()">start</button>
|
||||||
|
<button onclick="window.gifPlayer.stop()">stop</button>
|
||||||
|
|
||||||
|
<input type="number" max="10" min="0" step="0.1" value="1"><button onclick="window.gifPlayer.radioRate=Number(this.previousElementSibling.value)">播放速率比</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const gifCanvas = document.querySelector('#gifCanvas');
|
||||||
|
|
||||||
|
|
||||||
|
class GifPlayer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} template 图片模板路径:变量,{i}
|
||||||
|
* @param {*} num 图片的总数{i}=0~(num-1), 默认34
|
||||||
|
* @param {*} canvas 画布
|
||||||
|
* @param {*} radioRate 播放速率比,0=不播放 默认1
|
||||||
|
*/
|
||||||
|
constructor(template, num, canvas, radioRate) {
|
||||||
|
this.load = false;
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.radioRate = radioRate;
|
||||||
|
this.ctx = this.canvas.getContext('2d');
|
||||||
|
// this.ctx.save();
|
||||||
|
this.#init(template, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #init(template, num) {
|
||||||
|
this.imgs = await this.loadImgs(template, num);
|
||||||
|
this.canvas.dispatchEvent(new CustomEvent('loadend',{bubbles:false}))
|
||||||
|
this.load = true;
|
||||||
|
this.canvas.width = this.imgs[0].naturalWidth * window.devicePixelRatio;
|
||||||
|
this.canvas.height = this.imgs[0].naturalHeight * window.devicePixelRatio;
|
||||||
|
this.i = 0;
|
||||||
|
this.time = Date.now();
|
||||||
|
this.playing = true;
|
||||||
|
this.ctx.drawImage(this.imgs[0], 0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
this.#backgroudPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载图片
|
||||||
|
* @param {*} template 图片模板路径:变量,{i}
|
||||||
|
* @param {*} num 图片的总数{i}=0~(num-1), 默认34
|
||||||
|
*/
|
||||||
|
loadImgs(template, num = 34) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const imgs = [];
|
||||||
|
const ps = [];
|
||||||
|
for (let i = 0; i < num; i++) {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = template.replace('{i}', i);
|
||||||
|
imgs[i] = img;
|
||||||
|
ps.push(new Promise((resolve1, reject1) => {
|
||||||
|
img.onload = resolve1;
|
||||||
|
img.onerror = reject1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Promise.all(ps).then(() => {
|
||||||
|
resolve(imgs);
|
||||||
|
}).catch(err => {
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#backgroudPlay() {
|
||||||
|
if (this.radioRate === 0 || !this.playing) {
|
||||||
|
requestAnimationFrame(()=>{this.#backgroudPlay()});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Date.now();
|
||||||
|
if (now - this.time >= 50 / this.radioRate) {
|
||||||
|
this.time = now;
|
||||||
|
this.i++;
|
||||||
|
if (this.i >= this.imgs.length) {
|
||||||
|
this.i = 0;
|
||||||
|
}
|
||||||
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
// this.ctx.restore();
|
||||||
|
this.ctx.drawImage(this.imgs[this.i], 0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
}
|
||||||
|
requestAnimationFrame(()=>{this.#backgroudPlay()});
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.playing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
window.gifPlayer = new GifPlayer('./gif/{i}.png', 34, gifCanvas, 1);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<img class="noise" src="https://evoai.cn/assets/img/team.png" alt="">
|
||||||
|
<svg style="display: none;">
|
||||||
|
<defs>
|
||||||
|
<filter id="noiseFilter" color-interpolation-filters="linearRGB" filterUnits="objectBoundingBox"
|
||||||
|
primitiveUnits="userSpaceOnUse">
|
||||||
|
<feTurbulence type="turbulence" baseFrequency="0 0.21" numOctaves="2" seed="2" stitchTiles="stitch" x="0%" y="0%"
|
||||||
|
width="100%" height="100%" result="turbulence" />
|
||||||
|
<feDisplacementMap in="SourceGraphic" in2="turbulence" scale="10" xChannelSelector="R" yChannelSelector="B"
|
||||||
|
x="0%" y="0%" width="100%" height="100%" result="displacementMap" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
<style>
|
||||||
|
@property --noise-base {
|
||||||
|
syntax: '<number>';
|
||||||
|
inherits: true;
|
||||||
|
initial-value: 0;
|
||||||
|
}
|
||||||
|
.noise {
|
||||||
|
width: 50vmin;
|
||||||
|
margin: 1em auto;
|
||||||
|
filter: url(#noiseFilter);
|
||||||
|
--noise-base: 0;
|
||||||
|
animation: am-noise 3s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes am-noise {
|
||||||
|
0% {--noise-base: 0;}
|
||||||
|
10% {--noise-base: 0.1;}
|
||||||
|
20% {--noise-base: 0;}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
const noise = document.querySelector('.noise');
|
||||||
|
const noiseStyle = getComputedStyle(noise);
|
||||||
|
const noiseFilter = document.querySelector('#noiseFilter').firstElementChild;
|
||||||
|
console.info(noiseFilter);
|
||||||
|
const noisePlayer = ()=>{
|
||||||
|
let base = noiseStyle.getPropertyValue('--noise-base');
|
||||||
|
noiseFilter.setAttribute('baseFrequency', `0 ${base}`);
|
||||||
|
requestAnimationFrame(noisePlayer)
|
||||||
|
}
|
||||||
|
noisePlayer();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||