HTML5人物关节拉伸模拟动画特效

所属分类: 网页特效-动画效果    2024-03-22 10:23:37

HTML5人物关节拉伸模拟动画特效 ie兼容6
 查看演示  登录后下载 温馨提示
登录会员即可享受免费下载
 我要建站

HTML5人物关节拉伸模拟动画特效(共3个文件)

    • index.html

使用方法

// 为何使用大括号包裹所有代码:就是一个语句块,去掉也行。用这个的好处是里面使用let,const定义的变量或常量,外面不可用,限制最小作用域。
{
	const Human = class {
		constructor(size, gravity, x, y, struct) {
			this.points = [];
			this.constraints = [];
			this.shapes = [];
			for (const point of struct.points) {
				this.points.push(
					new Human.Point(x, y, point, size, gravity)
				);
			}
			for (const shape of struct.shapes) {
				this.shapes.push(
					new Human.Shape(
						this.points[shape.p0],
						this.points[shape.p1],
						shape,
						struct.svg[shape.svg],
						size
					)
				);
			}
			for (const constraint of struct.constraints) {
				if (constraint.angle) {
					this.constraints.push(
						new Human.Angle(
							this.points[constraint.p0],
							this.points[constraint.p1],
							this.points[constraint.p2],
							constraint
						)
					);
				} else {
					this.constraints.push(
						new Human.Constraint(
							this.points[constraint.p0],
							this.points[constraint.p1],
							constraint
						)
					);
				}
			}
		}
		anim() {
			for (const point of this.points) point.integrate();
			for (const constraint of this.constraints) constraint.update();
			for (const shape of this.shapes) shape.draw();
		}
	};
	Human.Point = class {
		constructor(x, y, p, s, g) {
			this.x = x + p.x * s;
			this.y = y + p.y * s;
			this.px = this.x;
			this.py = this.y;
			this.vx = 0.0;
			this.vy = 0.0;
			this.m = p.m || 1.0;
			this.g = g;
		}
		join(p1, distance, force) {
			const dx = p1.x - this.x;
			const dy = p1.y - this.y;
			const dist = Math.sqrt(dx * dx + dy * dy);
			const tw = this.m + p1.m;
			const r1 = p1.m / tw;
			const r0 = this.m / tw;
			const dz = (distance - dist) * force;
			const sx = dx / dist * dz;
			const sy = dy / dist * dz;
			p1.x += sx * r0;
			p1.y += sy * r0;
			this.x -= sx * r1;
			this.y -= sy * r1;
		}
		dist(p1) {
			const dx = this.x - p1.x;
			const dy = this.y - p1.y;
			return Math.sqrt(dx * dx + dy * dy);
		}
		integrate() {
			this.vx = this.x - this.px;
			this.vy = this.y - this.py;
			this.px = this.x;
			this.py = this.y;
			this.x += this.vx + this.g * dir;
			this.y += this.vy + 1.0 * (Math.random() - 0.5);
		}
	};
	Human.Shape = class {
		constructor(p0, p1, shape, svg, size) {
			this.p0 = p0;
			this.p1 = p1;
			this.width = shape.w * size;
			this.height = shape.h * size;
			this.offset = shape.offset;
			this.shape = document.createElement("canvas");
			this.shape.width = this.height + this.width * this.offset;
			this.shape.height = this.width;
			const image = new Image();
			image.onload = e => {
				const ctx = this.shape.getContext("2d");
				ctx.drawImage(image, 0, 0, this.height + this.width * this.offset, this.width);
			};
			image.src = "data:image/svg+xml;base64," + window.btoa(svg);
		}
		draw() {
			const a = Math.atan2(this.p1.y - this.p0.y, this.p1.x - this.p0.x);
			ctx.translate(this.p0.x, this.p0.y);
			ctx.rotate(a);
			ctx.drawImage(
				this.shape,
				-this.height * this.offset,
				-this.width * 0.5
			);
			ctx.rotate(-a);
			ctx.translate(-this.p0.x, -this.p0.y);
		}
	};
	Human.Constraint = class {
		constructor(p0, p1, constraint) {
			this.p0 = p0;
			this.p1 = p1;
			this.distance = p0.dist(p1);
			this.force = constraint.force || 1.0;
		}
		update() {
			this.p0.join(this.p1, this.distance, this.force);
		}
	};
	Human.Angle = class {
		constructor(p0, p1, p2, constraint) {
			this.p0 = p0;
			this.p1 = p1;
			this.p2 = p2;
			this.len1 = p0.dist(p1);
			this.len2 = p1.dist(p2);
			this.angle = constraint.angle.value;
			this.range = constraint.angle.range;
			this.force = constraint.force || 0.1;
		}
		a12(p0, p1, p2) {
			const a = Math.atan2(p1.y - p0.y, p1.x - p0.x);
			const b = Math.atan2(p2.y - p1.y, p2.x - p1.x);
			const c = this.angle - (b - a);
			const d = c > Math.PI ? c - 2 * Math.PI : c < -Math.PI ? c + 2 * Math.PI : c;
			const e = Math.abs(d) > this.range
				? (-Math.sign(d) * this.range + d) * this.force
				: 0;
			const m = p0.m + p1.m;
			const m1 = p0.m / m;
			const m2 = p1.m / m;
			const cos = Math.cos(a - e);
			const sin = Math.sin(a - e);
			const x1 = p0.x + (p1.x - p0.x) * m2;
			const y1 = p0.y + (p1.y - p0.y) * m2;
			p0.x = x1 - cos * this.len1 * m2;
			p0.y = y1 - sin * this.len1 * m2;
			p1.x = x1 + cos * this.len1 * m1;
			p1.y = y1 + sin * this.len1 * m1;
			return e;
		}
		a23(e, p1, p2) {
			const a = Math.atan2(p1.y - p2.y, p1.x - p2.x) + e;
			const m = p1.m + p2.m;
			const m2 = p1.m / m;
			const m3 = p2.m / m;
			const cos = Math.cos(a);
			const sin = Math.sin(a);
			const x1 = p2.x + (p1.x - p2.x) * m2;
			const y1 = p2.y + (p1.y - p2.y) * m2;
			p2.x = x1 - cos * this.len2 * m2;
			p2.y = y1 - sin * this.len2 * m2;
			p1.x = x1 + cos * this.len2 * m3;
			p1.y = y1 + sin * this.len2 * m3;
		}
		update() {
			const e = this.a12(this.p0, this.p1, this.p2);
			this.a23(e, this.p1, this.p2);
		}
	};
	const canvas = {
		init() {
			this.elem = document.createElement("canvas");
			document.body.appendChild(this.elem);
			this.resize();
			window.addEventListener("resize", () => canvas.resize(), false);
			const ctx = this.elem.getContext("2d");
			if (!ctx.setLineDash)	{
				ctx.setLineDash = function () {}
			}
			return ctx;
		},
		resize() {
			this.width = this.elem.width = this.elem.offsetWidth;
			this.height = this.elem.height = this.elem.offsetHeight;
			this.max = Math.max(canvas.width, canvas.height);
			this.x = this.width * 0.5;
			this.y = this.height * 0.5;
			this.m = 100000;
			this.background = document.createElement("canvas");
			this.background.width = this.width;
			this.background.height = this.height;
			const ctx = this.background.getContext("2d");
			let c = -50;
			for (let i = canvas.max; i >= canvas.max / 10 - 1; i -= canvas.max / 5) {
				ctx.beginPath();
				ctx.arc(canvas.x, canvas.y, i, 0, 2 * Math.PI);
				c += 30;
				ctx.fillStyle = "hsl(208, 30%, " + c + "%)";
				ctx.fill();
			}
		}
	};
	const pointer = {
		init(canvas) {
			this.x = 0;
			this.y = 0;
			this.pointDrag = null;
			this.m = 10000;
			this.msd = 0;
			window.addEventListener("mousemove", e => this.move(e), false);
			canvas.elem.addEventListener("touchmove", e => this.move(e), false);
			window.addEventListener("mousedown", e => this.down(e), false);
			window.addEventListener("touchstart", e => this.down(e), false);
			window.addEventListener("mouseup", e => this.up(e), false);
			window.addEventListener("touchend", e => this.up(e), false);
		},
		down(e) {
			this.move(e);
			this.msd = 1000000;
			this.findPoint(human1);
			this.findPoint(human2);
		},
		findPoint(human) {
			for (const point of human.points) {
				const dx = point.x - this.x;
				const dy = point.y - this.y;
				const sd = dx * dx + dy * dy;
				if (sd < 5000 && sd < this.msd) {
					this.msd = sd;
					this.pointDrag = point;
				}
			}
		},
		drag() {
			this.pointDrag.join(this, 0, 0.02);
			ctx.beginPath();
			ctx.lineWidth = 2;
			ctx.setLineDash([2,2]);
			ctx.moveTo(this.x, this.y);
			ctx.lineTo(this.pointDrag.x, this.pointDrag.y);
			ctx.stroke();
			ctx.beginPath();
			ctx.arc(this.x, this.y, 10, 0, 2 * Math.PI);
			ctx.fill();
		},
		up(e) {
			this.pointDrag = null;
		},
		move(e) {
			let touchMode = e.targetTouches,
				pointer;
			if (touchMode) {
				e.preventDefault();
				pointer = touchMode[0];
			} else pointer = e;
			this.x = pointer.clientX;
			this.y = pointer.clientY;
		}
	};
	// ---- init ----
	const ctx = canvas.init();
	pointer.init(canvas);
	let dir = 1;
	// ---- main loop ----
	const run = () => {
		requestAnimationFrame(run);
		ctx.drawImage(canvas.background, 0, 0);
		if (Math.random() > 0.997) dir = -dir;
		human1.points[16].join(human2.points[16], 0, 1);
		human1.points[16].join(canvas, 0, 0.02);
		human2.points[16].join(canvas, 0, 0.02);
		human1.anim();
		human2.anim();
		if (pointer.pointDrag) pointer.drag();
	};
	const human = {
		points: [
			{ x: 0, y: 0 },
			{ x: 0, y: -2.8 },
			{ x: 0, y: -4 },
			{ x: -1.1, y: -2.2},
			{ x: 1.1, y: -2.2 },
			{ x: -0.5, y: 1.2 },
			{ x: 0.5, y: 1.2 },
			{ x: 0, y: 1.5 },
			{ x: -0.5, y: 3.5 },
			{ x: 0.5, y: 3.5 },
			{ x: -0.5, y: 6.5 },
			{ x: 0.5, y: 6.5 },
			{ x: -0.5, y: 7 },
			{ x: 0.5, y: 7 },
			{ x: 3, y: -2.2 },
			{ x: -3, y: -2.2 },
			{ x: 4.7, y: -2.2 },
			{ x: -4.7, y: -2.2 }
		],
		constraints: [
			{ p0: 0, p1: 3 },
			{ p0: 0, p1: 4 },
			{ p0: 1, p1: 3 },
			{ p0: 1, p1: 4 },
			{ p0: 3, p1: 4 },
			{ p0: 0, p1: 5 },
			{ p0: 0, p1: 6 },
			{ p0: 7, p1: 5 },
			{ p0: 7, p1: 6 },
			{ p0: 5, p1: 6 },
			{
				p0: 2,
				p1: 1,
				p2: 0,
				angle: { value: 0, range: 1 }
			},
			{
				p0: 3,
				p1: 15,
				p2: 17,
				angle: { value: Math.PI / 2, range: Math.PI / 3 }
			},
			{
				p0: 4,
				p1: 14,
				p2: 16,
				angle: { value: -Math.PI / 2, range: Math.PI / 3 }
			},
			{
				p0: 1,
				p1: 0,
				p2: 7,
				angle: { value: 0, range: 0.3 }
			},
			{
				p0: 0,
				p1: 5,
				p2: 8,
				angle: { value: 0, range: Math.PI / 3 }
			},
			{
				p0: 0,
				p1: 6,
				p2: 9,
				angle: { value: 0, range: Math.PI / 3 }
			},
			{
				p0: 5,
				p1: 8,
				p2: 10,
				angle: { value: Math.PI / 2, range: Math.PI / 3 }
			},
			{
				p0: 6,
				p1: 9,
				p2: 11,
				angle: { value: Math.PI / 2, range: Math.PI / 3 }
			},
			{
				p0: 8,
				p1: 10,
				p2: 12,
				angle: { value: 0, range: 0.2 }
			},
			{
				p0: 9,
				p1: 11,
				p2: 13,
				angle: { value: 0, range: 0.2 }
			}
		],
		shapes: [
			{ p0: 0, p1: 1, h: 3, w: 3.2, svg: "tors", offset: 0.35 },
			{ p0: 1, p1: 2, h: 2, w: 1.8, svg: "head", offset: 0.15 },
			{ p0: 7, p1: 0, h: 2, w: 2.8, svg: "stomach", offset: 0.1 },
			{ p0: 5, p1: 8, h: 3, w: 1.2, svg: "leg1", offset: 0.15 },
			{ p0: 6, p1: 9, h: 3, w: 1.2, svg: "leg1", offset: 0.15 },
			{ p0: 8, p1: 10, h: 4, w: 1.1, svg: "leg2", offset: 0.15 },
			{ p0: 9, p1: 11, h: 4, w: 1.1, svg: "leg2", offset: 0.15 },
			{ p0: 10, p1: 12, h: 0.5, w: 2.5, svg: "foo

站长提示:
1. 苦力吧素材官方QQ群:950875342
2. 平台上所有素材资源,需注册登录会员方能正常下载。
3. 会员用户积极反馈网站、素材资源BUG或错误问题,每次奖励2K币
4. PHP源码类素材,如需协助安装调试,或你有二次开发需求,可联系苦力吧客服。
5. 付费素材资源,需充值后方能下载,如有任何疑问可直接联系苦力吧客服
相关资源 / 动画效果

CSS3带雪花飘落的旋转圣诞树动画特效

一款圣诞树3D旋转特效,旋转的圣诞树,雪花缓缓飘落动画。
  动画效果
 931  0

jquery鼠标点击DIV触发波纹动画特效插件

一款轻量级波纹动画插件,当鼠标点击按钮或指定的任何DIV元素时,将会触发Material Design波纹效果。
  动画效果
 2308  0

纯CSS3打字机文本动画特效代码

一款文本打字动画效果,支持中文英文字体,逼真平滑的打字机动画。
  动画效果
 145  0

CSS创建的鼠标悬停动画效果

一款鼠标悬停触发动画特效,鼠标在悬停导航菜单上时突出边框和过渡阴影特效。
  动画效果
 6425  0

评论数(0) 回复有机会获得K币 用户协议

^_^ 还没有人评论,快来抢个沙发!
😀
  • 😀
  • 😊
  • 😂
  • 😍
  • 😑
  • 😷
  • 😵
  • 😛
  • 😣
  • 😱
  • 😋
  • 😎
  • 😵
  • 😕
  • 😶
  • 😚
  • 😜
  • 😭
发表评论