javascript:那些有趣的案例

前言

今天在codepen上遇到一个有趣的东西,使用WebGL和GLSL的3D图形渲染示例。它创建了一个HTML5画布,并在其上绘制了一个由立方体组成的场景

网址

http://js.yunduanjianzhan.cn/

js代码

const canvas = document.createElement("canvas")
const gl = canvas.getContext("webgl2")

document.body.innerHTML = ""
document.body.appendChild(canvas)
document.body.style = "margin:0;touch-action:none;overflow:hidden"
canvas.style.width = "100%"
canvas.style.height = "auto"
canvas.style.userSelect = "none"

const dpr = Math.max(1, .5*window.devicePixelRatio)

function resize() {
  const {
    innerWidth: width,
    innerHeight: height
  } = window

  canvas.width = width * dpr
  canvas.height = height * dpr

  gl.viewport(0, 0, width * dpr, height * dpr)
}

window.onresize = resize

const vertexSource = `#version 300 es
    #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    #else
    precision mediump float;
    #endif
    
    in vec4 position;
    
    void main(void) {
      gl_Position = position;
    }
`

const fragmentSource = `#version 300 es
    /*********
     * made by Matthias Hurrle (@atzedent) 
     */
    #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    #else
    precision mediump float;
    #endif
    
    out vec4 fragColor;
    
    uniform vec2 resolution;
    uniform float time;
    uniform vec2 touch;
    uniform int pointerCount;
    
    #define mouse (touch/resolution)
    #define P pointerCount
    #define T mod(time+40.,180.)
    #define TICK (fract(T*.025))
    
    mat2 rot(float a) {
        float c=cos(a), s=sin(a);
    
        return mat2(c,-s,s,c);
    }
    
    float rnd(vec2 p) {
        return fract(sin(dot(p,p.yx+vec2(234.78,543.12)))*345678.);
    }
    
    float box(vec3 p, vec3 s, float r) {
        p = abs(p)-s;
    
        return length(max(p,.0))+
            min(.0,max(max(p.x,p.y),p.z))-r;
    }
    
    float map(vec3 p) {
        vec3 q = p;
        const float n = 3.;
        p.xz = (fract(p.xz/n)-.5)*n;
        vec2 id = (floor(q.xz/n)-.5)*n;
        float h = max(.2,rnd(id)*2.5),
        w = max(.5,1.-rnd(id));
    
        q = mod(q*10.,1.125);
        float bld = box((p-vec3(0,h,0))+.05,vec3(w,h,w),.0125),
        wnd = box(q,vec3(1),.005);
    
        return max(bld, -(TICK<.5?max(wnd,-(bld+.05)):min(wnd,bld-.025)));
    }
    
    void cam(inout vec3 p) {
        if (P>0) {
            p.yz *= rot(-mouse.y*3.1415+1.5707);
            p.xz *= rot(3.1415-mouse.x*6.2832);
        } else {
            if (TICK>.5) {
                p.yz *= rot(-.45);
                p.xz *= rot(2.7+sin(T*.05));
            } else {
                p.yz *= rot(-.25);
                p.xz *= rot(3.1415+cos(T*.1)*.75);
            }
        }
    }
    
    void main(void) {
        vec2 uv = (
            gl_FragCoord.xy-.5*resolution
        )/min(resolution.x,resolution.y);
    
        vec3 col = vec3(0),
        p = vec3(0),
        rd = normalize(vec3(uv,1.8));
    
        cam(p);
        cam(rd);
    
        p.z += T*3.;
    
        const float steps = 60., maxd = 200.;
        float diffuse = mix(.5,1.,rnd(uv*10.+vec2(T,1)));
        for (float i=.0; i<steps; i++) {
            float d = map(p)*.5*diffuse;
    
            if (d < 1e-2) {
                col += (steps-i)/steps;
                col *= vec3(3,2,1);
                break;
            }
    
            if (d > maxd) break;
    
            p += rd*d;
        }
      fragColor = vec4(col, 1);
    }
`

function compile(shader, source) {
  gl.shaderSource(shader, source)
  gl.compileShader(shader)

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.error(gl.getShaderInfoLog(shader))
  }
}

let program

function setup() {
  const vs = gl.createShader(gl.VERTEX_SHADER)
  const fs = gl.createShader(gl.FRAGMENT_SHADER)

  compile(vs, vertexSource)
  compile(fs, fragmentSource)

  program = gl.createProgram()

  gl.attachShader(program, vs)
  gl.attachShader(program, fs)
  gl.linkProgram(program)

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error(gl.getProgramInfoLog(program))
  }
}

let vertices, buffer;

function init() {
  vertices = [
    -1,-1, 1,
    -1,-1, 1,
    -1, 1, 1,
    -1, 1, 1
  ]
  buffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)

  const position = gl.getAttribLocation(program, "position")

  gl.enableVertexAttribArray(position)
  gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0)

  program.resolution = gl.getUniformLocation(program, "resolution")
  program.time = gl.getUniformLocation(program, "time")
    program.touch = gl.getUniformLocation(program, "touch")
    program.pointerCount = gl.getUniformLocation(program, "pointerCount")
}

const mouse = {
  x: 0,
  y: 0,
  touches: new Set(),
  update: function(x, y, pointerId) {
    this.x = x * dpr
    this.y = (innerHeight - y) * dpr
    this.touches.add(pointerId)
  },
  remove: function(pointerId) { this.touches.delete(pointerId) }
}

function loop(now) {
  gl.clearColor(0, 0, 0, 1)
  gl.clear(gl.COLOR_BUFFER_BIT)
  gl.useProgram(program)
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.uniform2f(program.resolution, canvas.width, canvas.height)
  gl.uniform1f(program.time, now * 1e-3)
  gl.uniform2f(program.touch, mouse.x, mouse.y)
  gl.uniform1i(program.pointerCount, mouse.touches.size)
  gl.drawArrays(gl.TRIANGLES, 0, vertices.length * .5)
  requestAnimationFrame(loop)
}

setup()
init()
resize()
loop(0)

window.addEventListener("pointerdown", e => mouse.update(e.clientX, e.clientY, e.pointerId))
window.addEventListener("pointerup", e => mouse.remove(e.pointerId))
window.addEventListener("pointermove", e => {
  if (mouse.touches.has(e.pointerId))
    mouse.update(e.clientX, e.clientY, e.pointerId)
})

案例

(一)时间

显示实时时间:
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1; // 月份从0开始,所以需要加1
const day = now.getDate();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
console.log(`当前时间:${year}-${month}-${day} ${hours}:${minutes}:${seconds}`);


const timeElement = document.getElementById('time');

function updateTime() {
	const now = new Date();
	const year = now.getFullYear();
	const month = now.getMonth() + 1;
	const day = now.getDate();
	const hours = now.getHours();
	const minutes = now.getMinutes();
	const seconds = now.getSeconds();

	timeElement.textContent = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

setInterval(updateTime, 1000); // 每秒更新一次时间
根据时间提示问候

const greetingElement = document.getElementById('greeting');

function updateGreeting() {
	const now = new Date();
	const hours = now.getHours();
	let greeting;

	if (hours >= 5 && hours < 7) {
		greeting = '早上好!一天开始了,祝你有个美好的一天!';
	} else if (hours >= 7 && hours < 10) {
		greeting = '上午好!工作顺利,精神抖擞!';
	} else if (hours >= 10 && hours < 12) {
		greeting = '中午好!休息一下,吃顿美味的午餐吧!';
	} else if (hours >= 12 && hours < 14) {
		greeting = '下午好!休息好了,继续努力工作吧!';
	} else if (hours >= 14 && hours < 18) {
		greeting = '傍晚好!累了一天,愿你晚上能好好放松!';
	} else if (hours >= 18 && hours < 20) {
		greeting = '晚上好!享受美食,放松心情,准备迎接新的一天吧!';
	} else if (hours >= 20 && hours < 22) {
		greeting = '晚安!今天过得怎么样?希望你有个美好的夜晚!';
	} else {
		greeting = '夜深了,愿你拥有一个美好的梦乡!';
	}

	greetingElement.textContent = greeting;
}

updateGreeting();
网页栏显示实时时间
  function updateTitle() {
            const now = new Date();
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            const timeString = `${hours}:${minutes}:${seconds}`;

            document.title = timeString;
        }

        setInterval(updateTitle, 100); // 每秒更新一次标题

(二)css样式更换

动态调整元素尺寸
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>动态调整元素尺寸</title>
  <style>
        .box {
            background-color: lightblue;
            width: 100px;
            height: 100px;
            transition: all 0.5s;
        }
    </style>
</head>
<body>
    <div class="box"></div>
  <script>
        function resizeBox() {
            const box = document.querySelector('.box');
            const newSize = Math.min(window.innerWidth, window.innerHeight) * 0.5;
            box.style.width = newSize + 'px';
            box.style.height = newSize + 'px';
        }

        window.addEventListener('resize', resizeBox);
        resizeBox();
    </script>
</body>
</html>
切换主题
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>切换主题</title>
  <style>
        body {
            font-family: Arial, sans-serif;
            transition: background-color 0.5s;
        }
        .dark-theme {
            background-color: #333;
            color: white;
        }
    </style>
</head>
<body>
    <h1>切换主题示例</h1>
   <button id="toggleTheme">切换主题</button>
  <script>
        const toggleThemeButton = document.getElementById('toggleTheme');
        let darkThemeEnabled = false;

        function toggleTheme() {
            darkThemeEnabled = !darkThemeEnabled;
            document.body.classList.toggle('dark-theme', darkThemeEnabled);
        }

        toggleThemeButton.addEventListener('click', toggleTheme);
    </script>
</body>
</html>

(三)鼠标键盘事件

禁止F12和右键
    // 禁止右键菜单
        document.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            alert('右键菜单已禁用');
        });

        // 禁止F12键
        document.addEventListener('keydown', function (e) {
            if (e.key === 'F12') {
                e.preventDefault();
                alert('F12已禁用');
            }
        });
文本或图片跟随鼠标
        const followMouse = document.getElementById('followMouse');

        document.addEventListener('mousemove', function (e) {
            followMouse.style.left = e.clientX + 'px';
            followMouse.style.top = e.clientY + 'px';
        });
 禁止鼠标
        // 禁止鼠标点击
        document.addEventListener('click', function (e) {
            e.preventDefault();
            alert('鼠标点击已禁用');
        });

        // 禁止鼠标移动
        document.addEventListener('mousemove', function (e) {
            e.preventDefault();
            alert('鼠标移动已禁用');
        });

(四)打字效果的文本展示

function typeWriterEffect(element, speed = 50) {
    const text = element.innerText;
    element.innerHTML = '';
    let index = 0;

    function type() {
        if (index< text.length) {
            element.innerHTML += text.charAt(index);
            index++;
            setTimeout(type, speed);
        }
    }

    type();
}

// 选择页面中的typewriter元素并应用打字效果
const typewriterElement = document.querySelector('.typewriter');
typeWriterEffect(typewriterElement);

 作者知识有限

也许与您还差距很远,写这篇文章也是为了巩固javascript的知识

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值