动态立体线条动画效果

代码语言:html

所属分类:视觉差异

代码描述:动态立体线条动画效果

代码标签: 动画 效果

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

<style>
body {
  margin: 0;
  overflow: hidden;
  background-color: #141414;
}

.overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 100;
}
</style>

</head>
<body translate="no">
<script>
  window.canvasOptions = {
  	//- autoClear: true,
  	autoCompensate: false,
  	autoPushPop: true,
  	canvas: true,
  	centered: true,
  	desynchronized: false,
  	width: null,
  	height: null
  };
  /* requestAnimationFrame */
</script>

<script>
    const {
	E, LN10, LN2, LOG10E, LOG2E, PI, SQRT1_2, SQRT2,
	abs, acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, ceil, clz32,
	cosh, exp, expm1, floor, fround, hypot, imul, log, log10, log1p, log2, max,
	min, pow, /* random, */ round, sign, sinh, sqrt, tan, tanh, trunc
} = Math;

let _codepenIDRegex = /codepen\.io\/[^/]+\/(?:pen|debug|fullpage|fullembedgrid)\/([^?#]+)/;

// Why not?
const ZERO       = 0.0;
const ONE        = 1.0;
const TWO        = 2.0;
const THREE      = 3.0;
const FOUR       = 4.0;
const FIVE       = 5.0;
const SIX        = 6.0;
const SEVEN      = 7.0;
const EIGHT      = 8.0;
const NINE       = 9.0;
const TEN        = 10.0;
const ELEVEN     = 11.0;
const TWELVE     = 12.0;
const SIXTEEN    = 16.0;
const THIRTY     = 30.0;
const THIRTY_TWO = 32.0;
const SIXTY      = 60.0;
const HUNDRED    = 100.0;
const THOUSAND   = 1000.0;

const HALF            = ONE / TWO;
const THIRD           = ONE / THREE;
const TWO_THIRDS      = THIRD * TWO;
const QUARTER         = ONE / FOUR;
const THREE_QUARTER   = QUARTER * THREE;
const FIFTH           = ONE / FIVE;
const SIXTH           = ONE / SIX;
const SEVENTH         = ONE / SEVEN;
const EIGHTH          = ONE / EIGHT;
const TWELFTH         = ONE / TWELVE;
const SIXTEENTH       = ONE / SIXTEEN;
const ONE_THIRTIETH   = ONE / THIRTY;
const THIRTY_SECONDTH = ONE / THIRTY_TWO;
const SIXTIETH        = ONE / SIXTY;

const TENTH              = 1e-1;
const HUNDREDTH          = 1e-2;
const THOUSANDTH         = 1e-3;
const TEN_THOUSANDTH     = 1e-4;
const HUNDRED_THOUSANDTH = 1e-5;
const MILLIONTH          = 1e-6;
const TEN_MILLIONTH      = 1e-7;
const HUNDRED_MILLIONTH  = 1e-8;
const BILLIONTH          = 1e-9;
const TEN_BILLIONTH      = 1e-10;
const HUNDRED_BILLIONTH  = 1e-11;

const HALF_PI             = PI * HALF;
const THIRD_PI            = PI * THIRD;
const THREE_QUARTER_PI    = PI * THREE_QUARTER;
const QUARTER_PI          = PI * QUARTER;
const FIFTH_PI            = PI * FIFTH;
const SIXTH_PI            = PI * SIXTH;
const SEVENTH_PI          = PI * SEVENTH;
const EIGHTH_PI           = PI * EIGHTH;
const TWELFTH_PI          = PI * TWELFTH;
const SIXTEENTH_PI        = PI * SIXTEENTH;
const THIRTY_SECONDTH_PI  = PI * THIRTY_SECONDTH;
const TAU                 = PI * TWO;
const TWO_TAU             = TAU * TWO;
const HALF_TAU            = PI;
const THIRD_TAU           = TAU * THIRD;
const QUARTER_TAU         = HALF_PI;
const FIFTH_TAU           = TAU * FIFTH;
const SIXTH_TAU           = THIRD_PI;
const EIGHTH_TAU          = QUARTER_PI;
const TWELFTH_TAU         = SIXTH_PI;
const SIXTEENTH_TAU       = EIGHTH_PI;
const THIRTY_SECONDTH_TAU = SIXTEENTH_PI;

const SQRT_3              = sqrt(THREE);
const SQRT_4              = sqrt(FOUR);
const SQRT_5              = sqrt(FIVE);

const PHI                 = (1 + sqrt(5)) * 0.5;
const GOLDEN_ANGLE        = 1 / (PHI * PHI);

const COLOR_BLACK         = hsl(0, 0, 0);
const COLOR_WHITE         = hsl(0, 0, 100);
const COLOR_RED           = hsl(0, 100, 50);
const COLOR_ORANGE        = hsl(30, 100, 50);
const COLOR_YELLOW        = hsl(60, 100, 50);
const COLOR_GREEN         = hsl(120, 100, 50);
const COLOR_CYAN          = hsl(180, 100, 50);
const COLOR_BLUE          = hsl(240, 100, 50);
const COLOR_PURPLE        = hsl(280, 100, 50);
const COLOR_MAGENTA       = hsl(300, 100, 50);

const TEXTALIGN_LEFT      = 'left';
const TEXTALIGN_CENTER    = 'center';
const TEXTALIGN_RIGHT     = 'right';
const TEXTBASELINE_TOP    = 'top';
const TEXTBASELINE_MIDDLE = 'middle';
const TEXTBASELINE_BOTTOM = 'bottom';

let _defaulCanvasOptions = {
		autoClear: false,
		autoCompensate: true,
		autoPushPop: false,
		canvas: true,
		centered: false,
		desynchronized: false,
		drawAndStop: false,
		width: null,
		height: null
	};
let _canvasOptions = {};
let canvas = document.getElementById('canvas');
if(canvas === null) {
	canvas = document.createElement('canvas');
	canvas.id = 'canvas';
	document.body.appendChild(canvas);
}
let ctx = canvas.getContext('2d', {
	desynchronized: window.canvasOptions && window.canvasOptions.desynchronized !== undefined ?
		window.canvasOptions.desynchronized : _defaulCanvasOptions.desynchronized
	// preserveDrawingBuffer: true // WebGL
});
const _originalCtx = ctx;
let _anim, _lastCanvasTime, canvasFrameRate, frameCount, width, height, width_half, height_half, width_quarter, height_quarter;
let _canvasCurrentlyCentered = false;
let _logMouseEvents = false;
let mouseUpdate = -Infinity, mouseIn = false, mouseDown = false, mouseMove = null, mousePos = null, mousePosPrev = null;

function updateMouse(e, eventName) { // Modified from p5.js
	if(_logMouseEvents) {
		console.log('Mouse event', eventName, e);
	}
	if(e && !e.clientX) {
		e = e.touches && e.touches.length ? e.touches[0] : (e.changedTouches ? e.changedTouches[0] : e);
	}
	if(!e) {
		return 'Missing event data';
	}
	mouseUpdate = e.timeStamp === undefined ? performance.now() : e.timeStamp;
	let rect = canvas.getBoundingClientRect();
	let sx   = canvas.scrollWidth / width;
	let sy   = canvas.scrollHeight / height;
	let x = (e.clientX - rect.left) / sx;
	let y = (e.clientY - rect.top) / sy;
	if(x < 0) x = 0;
	else if(x > width) x = width;
	if(y < 0) y = 0;
	else if(y > height) y = height;
	if(mousePos) {
		mousePosPrev.set(mousePos);
		mousePos.set(x, y);
	}
	// return { x, y, winX: e.clientX, winY: e.clientY, id: e.identifier };
}

// let mouseIn = false, mouseDown = false, mouseMove = null, mousePos = { x: 0, y: 0 };
// function updateMouse(e) {
// 	if(e && !e.clientX) {
// 		e = e.touches ? e.touches[0] : (e.changedTouches ? e.changedTouches[0] : e);
// 	}
// 	const { innerWidth: width, innerHeight: height } = window;
// 	uniforms.mouse.value.set(e.clientX / width, 1 - e.clientY / height);
// }

// [
// 	[ 'mouseenter', e => mouseIn = true ],
// 	[ 'mouseleave', e => (mouseIn = false, mouseDown = false) ],
// 	[ 'mousemove', e => (mouseIn = true, mouseMove = e.timeStamp) ],
// 	[ 'mousedown', e => (mouseIn = true, mouseDown = true) ],
// 	[ 'mouseup', e => mouseDown = false ],
// 	[ 'touchstart', e => mouseIn = true ],
// 	[ 'touchend', e => (mouseIn = false, mouseDown = false) ],
// 	[ 'touchcancel', e => (mouseIn = false, mouseDown = false) ],
// 	[ 'touchmove', e => (mouseIn = true, mouseMove = e.timeStamp) ]
// ].forEach(([ eventName, cb ]) => document.body.addEventListener(eventName, e => {
// 	updateMouse(e);
// 	cb(e);
// }));

canvas.addEventListener('mouseenter',  e => (updateMouse(e, 'mouseenter'), mouseIn = true));
canvas.addEventListener('mouseleave',  e => (updateMouse(e, 'mouseleave'), mouseIn = false, mouseDown = false));
canvas.addEventListener('mousemove',   e => (updateMouse(e, 'mousemove'), mouseIn = true, mouseMove = e.timeStamp));
canvas.addEventListener('mousedown',   e => (updateMouse(e, 'mousedown'), mouseIn = true, mouseDown = true));
canvas.addEventListener('mouseup',     e => (updateMouse(e, 'mouseup'), mouseDown = false));
canvas.addEventListener('touchstart',  e => (updateMouse(e, 'touchstart'), mouseIn = true));
canvas.addEventListener('touchend',    e => (updateMouse(e, 'touchend'), mouseIn = false, mouseDown = false));
canvas.addEventListener('touchcancel', e => (updateMouse(e, 'touchcancel'), mouseIn = false, mouseDown = false));
canvas.addEventListener('touchmove',   e => (updateMouse(e, 'touchmove'), mouseIn = true));
window.addEventListener('resize', _resizeCanvas);
window.addEventListener('load', () => {
	mousePos = new Vector();
	mousePosPrev = new Vector();
	Object.assign(
		_canvasOptions,
		_defaulCanvasOptions,
		'canvasOptions' in window ? window.canvasOptions : {}
	);
	if(_canvasOptions.canvas === false) {
		document.body.removeChild(canvas);
	}
	_resizeCanvas();
	if('setup' in window) {
		window.setup();
	}
	frameCount = 0;
	_anim = requestAnimationFrame(_draw);
});

function _draw(timestamp) {
	frameCount++;
	canvasFrameRate = 1000.0 / (timestamp - _lastCanvasTime);
	if(!_lastCanvasTime) {
		_lastCanvasTime = timestamp;
	}
	// _lastCanvasTime = timestamp;
	ctx = _originalCtx;
	_canvasOptions.autoClear && clear(null);
	if(_canvasOptions.autoPushPop) {
		push();
		_canvasOptions.centered && (_canvasCurrentlyCentered = true) && translateCenter();
		_canvasOptions.autoCompensate && compensateCanvas();
	}
	'draw' in window && window.draw(timestamp);
	_canvasOptions.autoPushPop && pop();
	_canvasCurrentlyCentered = false;
	_lastCanvasTime = timestamp;
	if(_canvasOptions.drawAndStop) {
		return;
	}
	// beginPath();
	// rect(width_half - 20, height_half - 20, 120, 30);
	// fill(hsl(0, 0, 0));
	// fillStyle(hsl(0, 0, 100));
	// font('24px monospace');
	// fillText(canvasFrameRate.toFixed(2), width_half, height_half);
	_anim = requestAnimationFrame(_draw);
}

function _resizeCanvas(specificCanvas) {
	width = canvas.width = _canvasOptions.width !== null ? _canvasOptions.width : window.innerWidth;
	height = canvas.height = _canvasOptions.height !== null ? _canvasOptions.height : window.innerHeight;
	width_quarter = (width_half = width * HALF) * HALF;
	height_quarter = (height_half = height * HALF) * HALF;
	ctx.fillStyle = 'hsl(0, 0%, 100%)';
	ctx.strokeStyle = 'hsl(0, 0%, 100%)';
	if('onResize' in window) {
		window.onResize();
	}
}

function clear(x, y, w, h) {
	if(x !== undefined && typeof x === 'number') {
		ctx.clearRect(x, y, w, h);
	}
	else if(_canvasOptions.centered && _canvasCurrentlyCentered/*  && x !== null */) {
		ctx.clearRect(-width_half, -height_half, width, height);
	}
	else {
		ctx.clearRect(0, 0, width, height);
	}
}

function background(a) {
	push();
	if(typeof a !== 'number') {
		fillStyle(a);
	}
	if(_canvasOptions.centered && _canvasCurrentlyCentered) {
		ctx.fillRect(-width_half, -height_half, width, height);
	}
	else {
		ctx.fillRect(0, 0, width, height);
	}
	pop();
}

function globalAlpha(alpha = ctx.globalAlpha) {
	return ctx.globalAlpha = alpha;
}

function fillStyle(...args) {
	if(args.length === 1) {
		let a = args[0];
		if(typeof a === 'string' || a instanceof CanvasGradient || a instanceof CanvasPattern) {
			ctx.fillStyle = args[0];
		}
	}
	return ctx.fillStyle;
}

function lineWidth(w) {
	if(typeof w === 'number') {
		ctx.lineWidth = w;
	}
	return ctx.lineWidth;
}

// "butt" || "round" || "square";
function lineCap(style = 'butt') {
	ctx.lineCap = style;
}

// "bevel" || "round" || "miter"
function lineJoin(style) {
	ctx.lineJoin = style;
}

function miterLimit(value = 10) {
	ctx.miterLimit = value;
}

function strokeStyle(...args) {
	if(args.length === 1) {
		let a = args[0];
		if(typeof a === 'string' || a instanceof CanvasGradient) {
			ctx.strokeStyle = a;
		}
	}
	else if(args.length === 2) {
		strokeStyle(args[0]);
		lineWidth(args[1]);
	}
	return ctx.strokeStyle;
}

function lerpRGB(...args) {
	let r1 = 255;
	let b1 = 255;
	let g1 = 255;
	let a1 = 1;
	let r2 = 0;
	let g2 = 0;
	let b2 = 0;
	let a2 = 1;
	let t = 0.5;
	if(args.length === 3) {
		if(Array.isArray(args[0]) && Array.isArray(args[1])) {
			return lerpRGB(...args[0], ...args[1], args[2]);
		}
		[
			{ r: r1 = 255, b: b1 = 255, g: g1 = 255, a: a1 = 1 },
			{ r: r2 = 0, b: b2 = 0, g: g2 = 0, a: a2 = 1 },
			t
		] = args;
	}
	else if(args.length === 7) {
		[
			r1, g1, b1,
			r2, g2, b2,
			t
		] = args;
	}
	else if(args.length === 9) {
		[
			r1, g1, b1, a1,
			r2, g2, b2, a2,
			t
		] = args;
	}
	else if(args.length === 2 && Array.isArray(args[0])) {
		if(args[0].length === 2) {
			return lerpRGB(...args[0], args[1]);
		}
		// TODO: Allow (possibly weighted) lerping between n-count RGBs at specified positions
	}
	else {
		return { r: 127.5, g: 127.5, b: 127.5, a: 1 };
	}
	let r = lerp(r1, r2, t);
	let g = lerp(g1, g2, t);
	let b = lerp(b1, b2, t);
	let a = lerp(a1, a2, t);
	return { r, g, b, a };
}

function hsl(hue, sat, light, alpha = 1) {
	if(typeof hue !== 'number') {
		if(Array.isArray(hue)) {
			[ hue, sat, light, alpha = alpha ] = hue;
		}
		else if('h' in hue) {
			({ h: hue, s: sat, l: light, a: alpha = alpha } = hue);
		}
	}
	hue = hue % 360;
	if(hue < 0) {
		hue += 360;
	}
	return `hsl(${hue} ${sat}% ${light}% / ${alpha})`;
}

function parseHSL(input) {
	if(typeof input !== 'string') {
		return input;
	}
	let result = input.match(/hsla?\(([\d.]+)\s*,?\s*([\d.]+)%\s*,?\s*([\d.]+)%\s*[/,]?\s*([\d.]*)?\)/);
	if(result) {
		let [ i, h, s, l, a ] = result;
		return { input, h, s, l, a };
	}
	return null;
}

function setHueHSL(input, val) {
	if(val === undefined) return input;
	let p = parseHSL(input);
	p.h = val;
	return hsl(p);
}

function rotateHSL(input, amt = 90) {
	if(amt === 0) return input;
	let p = parseHSL(input);
	p.h += amt;
	return hsl(p);
}

function saturateHSL(input, amt = 0.1) {
	if(amt === 0) return input;
	let p = parseHSL(input);
	p.s *= 1 + amt;
	return hsl(p);
}

function lightenHSL(input, amt = 0.1) {
	if(amt === 0) return input;
	let p = parseHSL(input);
	p.l *= 1 + amt;
	return hsl(p);
}

function rgb(r = 255, g = 255, b = 255, a = 1) {
	if(typeof r !== 'number' && 'r' in r) {
		({ r = 255, g = 255, b = 255, a = 1 } = r);
	}
	return `rgba(${r}, ${g}, ${b}, ${a})`;
}

function fill(...args) {
	if(args.length) {
		fillStyle(...args);
	}
	ctx.fill();
}

function stroke(...args) {
	if(args.length) {
		strokeStyle(...args);
	}
	ctx.stroke();
}

function clip() {
	ctx.clip();
}

function createLinearGradient(x1 = -100, y1 = -100, x2 = 100, y2 = 100) {
	if(typeof x1 !== 'number' && typeof y1 !== 'number') {
		({ x: x2, y: y2 } = y1);
		({ x: x1, y: y1 } = x1);
	}
	else if(typeof x1 !== 'number' && typeof y1 === 'number' && typeof x2 === 'number') {
		[ x2, y2 ] = [ y1, x2 ];
		({ x: x1, y: y1 } = x1);
	}
	else if(typeof x1 === 'number' && typeof y1 === 'number' && typeof x2 !== 'number') {
		({ x: x2, y: y2 } = x2);
	}
	return ctx.createLinearGradient(x1, y1, x2, y2);
}

function createRadialGradient(x1 = 0, y1 = 0, r1 = 0, x2 = 0, y2 = 0, r2 = 200) {
	return ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
}

function createPattern(image, repetition = null) {
	return ctx.createPattern(image, repetition);
}

function drawImage(img, x = 0, y = 0, ...args) {
	ctx.drawImage(img, x, y, ...args);
}

function strokeText(str = 'Hello world', x = 0, y = 0) {
	ctx.strokeText(str, x, y);
}

function fillText(str = 'Hello world', x = 0, y = 0) {
	ctx.fillText(str, x, y);
}

function strokeFillText(str = 'Hello world', x = 0, y = 0) {
	strokeText(str, x, y);
	fillText(str, x, y);
}

function fillStrokeText(str = 'Hello world', x = 0, y = 0) {
	fillText(str, x, y);
	strokeText(str, x, y);
}

function measureText(...args) {
	return ctx.measureText(...args);
}

// ctx.textAlign = "left" || "right" || "center" || "start" || "end";
function textAlign(str = 'left') {
	ctx.textAlign = str;
}

// ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";
function textBaseline(str = 'left') {
	if(str === 'center') str = 'middle';
	ctx.textBaseline = str;
}

function push() {
	ctx.save();
}

function pop() {
	ctx.restore();
}

function resetTransform() {
	ctx.resetTransform();
}

function translate(x = 0, y = 0) {
	if(typeof x === 'number') {
		ctx.translate(x, y);
	}
	else if('x' in x) {
		ctx.translate(x.x, x.y);
	}
}

function translateCenter(x = 0, y = 0) {
	ctx.translate(width_half + x, height_half + y);
}

function rotate(rot, offsetX, offsetY) {
	rot = rot % TAU;
	if(offsetX === undefined) {
		ctx.rotate(rot);
	}
	else if(typeof offsetX !== 'number') {
		if('x' in offsetX) {
			ctx.translate(offsetX.x, offsetX.y);
			ctx.rotate(rot);
			ctx.translate(-offsetX.x, -offsetX.y);
		}
	}
	else {
		ctx.translate(offsetX, offsetY);
		ctx.rotate(rot);
		ctx.translate(-offsetX, -offsetY);
	}
}

function scale(x = 1, y = x) {
	ctx.scale(x, y);
}

function shearX(rad) {
	ctx.transform(1, 0, tan(rad), 1, 0, 0);
}

function shearY(rad) {
	ctx.transform(1, tan(rad), 0, 1, 0, 0);
}

function compensateCanvas() {
	let offX = 0;
	let offY = 0;
	if(width % 2) offX += 0.5;
	if(height % 2) offY += 0.5;
	if(offX || offY) {
		translate(offX, offY);
	}
}

const compOper = {
		default:		'source-over',		sourceOver:		'source-over',		sourceIn:			'source-in',
		sourceOut:		'source-out',		sourceAtop:		'source-atop',		destinationOver:	'destination-over',
		destinationIn:	'destination-in',	destinationOut:	'destination-out',	destinationAtop:	'destination-atop',
		lighter:		'lighter',			copy:			'copy',				xor: 				'xor',
		multiply:		'multiply',			screen:			'screen',			overlay:			'overlay',
		darken:			'darken',			lighten:		'lighten',			colorDodge:			'color-dodge',
		colorBurn:		'color-burn',		hardLight:		'hard-light',		softLight:			'soft-light',
		difference:		'difference',		exclusion:		'exclusion',		hue:				'hue',
		saturation:		'saturation',		color:			'color',			luminosity:			'luminosity',
		source: {
			over:		'source-over',		in:				'source-in',		out:				'source-out',
			atop:		'source-atop'
		},
		destination: {
			over:		'destination-over',	in:				'destination-in',	out:				'destination-out',
			atop:		'destination-atop'
		},
		light: {
			hard:		'hard-light',		soft:			'soft-light'
		}
	};


function compositeOperation(type = compOper.default) { // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
	ctx.globalCompositeOperation = type;
}

// const filters = [
// 		[ 'url', [ 'url' ] ],
// 		[ 'blur', [ 'length' ] ],
// 		[ 'brightness', [ 'percentage' ] ],
// 		[ 'contrast', [ 'percentage' ] ]
// 	];

function filter(filterFuncs = 'none') {
	ctx.filter = filterFuncs;
}

function beginPath() {
	ctx.beginPath();
}

function isVectorish(n) {
	return n instanceof Vector || (typeof n === 'object' && 'x' in n && 'y' in n);
}

function moveTo(x, y) {
	if(typeof x === 'number') {
		ctx.moveTo(x, y);
	}
	else if(isVectorish(x)) {
		ctx.moveTo(x.x, x.y);
	}
}

function lineTo(x, y) {
	if(typeof x === 'number') {
		ctx.lineTo(x, y);
	}
	else if(isVectorish(x)) {
		ctx.lineTo(x.x, x.y);
	}
}

function quadraticCurveTo(cpX, cpY, x, y) {
	// ctx.quadraticCurveTo(cpX, cpY, x, y);
	let a = [];
	let b = [];
	if(typeof cpX === 'number') {
		a = [ cpX, cpY ];
		if(typeof x === 'number') {
			b = [ x, y ];
		}
		else if('x' in x) {
			b = x.xy;
		}
	}
	else if('x' in cpX) {
		a = cpX.xy;
		if(typeof cpY === 'number') {
			b = [ cpY, x ];
		}
		else if('x' in cpY) {
			b = cpY.xy;
		}
	}
	ctx.quadraticCurveTo(a[0], a[1], b[0], b[1]);
}

function bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y) {
	let a = [];
	let b = [];
	let c = [];
	if(typeof cp1X === 'number') {
		a = [ cp1X, cp1Y ];
		if(typeof cp2X === 'number') {
			b = [ cp2X, cp2Y ];
			if(typeof x === 'number') {
				c = [ x, y ];
			}
			else if('x' in x) {
				c = x.xy;
			}
		}
		else if('x' in cp2X) {
			b = cp2X.xy;
			if(typeof cp2Y === 'number') {
				c = [ cp2Y, x ];
			}
			else if('x' in cp2Y) {
				c = cp2Y.xy;
			}
		}
	}
	else if('x' in cp1X) {
		a = cp1X.xy;
		if(typeof cp1Y === 'number') {
			b = [ cp1Y, cp2X ];
			if(typeof cp2Y === 'number') {
				c = [ cp2Y, x ];
			}
			else if('x' in cp2Y) {
				c = cp2Y.xy;
			}
		}
		else if('x' in cp1Y) {
			b = cp1Y.xy;
			if(typeof cp2X === 'number') {
				c = [ cp2X, cp2Y ];
			}
			else if('x' in cp2X) {
				c = cp2X.xy;
			}
		}
	}
	ctx.bezierCurveTo(a[0], a[1], b[0], b[1], c[0], c[1]);
}

function closePath() {
	ctx.closePath();
}

function point(x = 0, y = 0, r = 0, g = 0, b = 0, a = 255, doPut_ = true) {
	// let imgData = ctx.createImageData(1, 1);
	// imgData.data[0] = r;
	// imgData.data[1] = g;
	// imgData.data[2] = b;
	// imgData.data[3] = a;
	// if(doPut_) {
	// 	ctx.putImageData(imgData, x, y);
	// }
	// return imgData;
}

function line(x = 0, y = 0, x_ = 0, y_ = 0) {
	if(typeof x === 'number') {
		moveTo(x, y);
		lineTo(x_, y_);
	}
	else if(isVectorish(x)) {
		moveTo(x);
		lineTo(y, x_);
	}
}

function vertices(...verts) {
	if(verts.length === 0) return;
	else if(verts.length === 1 && Array.isArray(verts[0])) {
		verts = verts[0];
	}
	for(let i = 0; i < verts.length; i++) {
		let n = verts[i];
		let x = 0;
		let y = 0;
		if(Array.isArray(n)) {
			([ x, y ] = n);
		}
		else if(isVectorish(n)) {
			({ x, y } = n);
		}
		lineTo(x, y);
	}
}

function arcTo(x1 = 0, y1 = 0, x2 = 0, y2 = 0, radius = 50) {
	ctx.arcTo(x1, y1, x2, y2, radius);
}

function rect(x, y, w, h, r) {
	if(isVectorish(x)) {
		// Shift args down 1
		[ w, h, r ] = [ y, w, h ];
		({ x, y } = x);
	}
	// x = 0, y = 0, w = 10, h = w, r = 0
	x = x ?? 0;
	y = y ?? 0;
	w = w ?? 10;
	h = h ?? w;
	r = r ?? 0;
	if(r > 0) {
		moveTo(x + r, y);
		arcTo(x + w, y,     x + w, y + h, r);
		arcTo(x + w, y + h, x,     y + h, r);
		arcTo(x,     y + h, x,     y,     r);
		arcTo(x,     y,     x + w, y,     r);
		closePath();
	}
	else {
		ctx.rect(x, y, w, h);
	}
}

function arc(x, y, radius, startAngle, endAngle, anticlockwise) {
	if(isVectorish(x)) {
		// Shift args down 1
		[ radius, startAngle, endAngle, anticlockwise ] = [ y, radius, startAngle, endAngle ];
		({ x, y } = x);
	}
	// x = 0, y = 0, radius = 50, startAngle = 0, endAngle = Math.PI * 2, anticlockwise = false
	x = x ?? 0;
	y = y ?? 0;
	radius = radius ?? 50;
	startAngle = startAngle ?? 0;
	endAngle = endAngle ?? TAU;
	anticlockwise = anticlockwise ?? false;
	if(radius < 0) radius = 0;
	ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
}

// function circle(x = 0, y = undefined, rX = 20, rY = undefined) {
function circle(x, y, rX, rY) {
	// if(typeof x !== 'number' && 'x' in x) {
	// 	if(y !== undefined) {
	// 		rX = y;
	// 	}
	// 	y = x.y;
	// 	x = x.x;
	// }
	// else if(y === undefined) {
	// 	y = 0;
	// }
	// if(typeof rX !== 'number' && 'x' in rX) {
	// 	rY = rX.y;
	// 	rX = rX.x;
	// }
	if(isVectorish(x)) {
		[ rX, rY ] = [ y, rX ];
		({ x, y } = x);
	}
	if(isVectorish(rX)) {
		({ x: rX, y: rY } = rX);
	}
	x = x ?? 0;
	y = y ?? 0;
	rX = rX ?? 20;
	ctx.moveTo(x + rX, y);
	if(rY !== undefined) {
		ellipse(x, y, rX, rY);
	}
	else {
		if(rX < 0) rX = 0;
		ctx.arc(x, y, rX, 0, TAU);
	}
}

// function ellipse(x = 0, y = 0, rX = 50, rY = 50, rot = 0, angStart = 0, angEnd = Math.PI * 2, antiCw = false) {
function ellipse(x, y, rX, rY, rot, angStart, angEnd, antiCw) {
	if(isVectorish(x)) {
		[ rX, rY, rot, angStart, angEnd, antiCw ] = [ y, rX, rY, rot, angS.........完整代码请登录后点击上方下载按钮下载查看

网友评论0