canvas烟花燃放绽放动画效果代码
代码语言:html
所属分类:动画
代码描述:canvas烟花燃放绽放动画效果代码
下面为部分代码预览,完整代码请点击下载或在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;
}
body {
background-color: #050505;
}
</style>
</head>
<body>
<script>
window.canvasOptions = {
autoClear: true,
autoCompensate: false,
autoPushPop: true,
canvas: true,
//- centered: true,
desynchronized: false,
width: null,
height: null
};
</script>
<script>
function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}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 THREE_QUARTER_PI = PI * THREE_QUARTER;
const THIRD_PI = PI * THIRD;
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 THREE_QUARTER_TAU = TAU * THREE_QUARTER;
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 _mouseUpdateTimeThreshold = 12;
let mouseUpdate = -Infinity,mouseIn = false,mouseDown = false,mouseButton = -1,
mouseMove = null,mousePos = null,mousePosPrev = null,
mouseDownTime = -Infinity,mouseDownPos = null,
mouseEnterPos = null,mouseExitPos = null,
mouseUpTime = -Infinity,mouseUpPos = null,
mouseEnterTime = -Infinity,mouseExitTime = -Infinity;
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) {
if (_logMouseEvents) {
console.log('Missing event data');
}
return;
}
const _mouseUpdate = e.timeStamp === undefined ? performance.now() : e.timeStamp;
if (mouseUpdate > 0 && _mouseUpdate - mouseUpdate < _mouseUpdateTimeThreshold) {
if (_logMouseEvents) {
// https://nolanlawson.com/2019/08/11/high-performance-input-handling-on-the-web/
// https://bugs.chromium.org/p/chromium/issues/detail?id=992954
// http://event-timing.glitch.me/
console.log('Skipping mouse event, are the dev tools open?');
}
return;
}
mouseUpdate = _mouseUpdate;
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;
mouseEnterTime = e.timeStamp;
// mouseExitTime = -Infinity;
});
canvas.addEventListener('mouseleave', e => {
updateMouse(e, 'mouseleave');
mouseIn = mouseDown = false;
// mouseEnterTime = -Infinity;
mouseExitTime = e.timeStamp;
});
canvas.addEventListener('mousemove', e => {
updateMouse(e, 'mousemove');
mouseIn = true;
mouseMove = e.timeStamp;
});
canvas.addEventListener('mousedown', e => {
updateMouse(e, 'mousedown');
mouseIn = mouseDown = true;
mouseButton = e.button;
mouseDownTime = e.timeStamp;
mouseDownPos = mousePos.copy();
});
canvas.addEventListener('mouseup', e => {
updateMouse(e, 'mouseup');
mouseDown = false;
mouseButton = e.button;
mouseUpTime = e.timeStamp;
mouseUpPos = mousePos.copy();
});
canvas.addEventListener('touchstart', e => (updateMouse(e, 'touchstart'), mouseIn = true));
canvas.addEventListener('touchend', e => (updateMouse(e, 'touchend'), mouseIn = mouseDown = false));
canvas.addEventListener('touchcancel', e => (updateMouse(e, 'touchcancel'), mouseIn = mouseDown = false));
canvas.addEventListener('touchmove', e => (updateMouse(e, 'touchmove'), mouseIn = true));
window.addEventListener('resize', _resizeCanvas);
window.addEventListener('load', () => {
mousePos = new Vector();
mousePosPrev = new Vector();
mouseUpPos = new Vector();
mouseDownPos = new Vector();
mouseEnterPos = new Vector();
mouseExitPos = 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 isVectorish(n) {
return n instanceof Vector || typeof n === 'object' && 'x' in n && 'y' in n;
}
function _resolveVectorArgs(x, y) {
if (arguments.length === 0 || typeof x === 'undefined') return [];
if (typeof x === 'number') return [x, ..._resolveVectorArgs(y)];else
if (isVectorish(x)) return [x.x, x.y, ..._resolveVectorArgs(y)];else
if (Array.isArray(x)) return [...x, ..._resolveVectorArgs(y)];
throw new Error(`Could not understand arguments with types [ ${typeof x}, ${typeof y} ]`);
}
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;
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);
} else
if (isVectorish(r)) {
({ x: r = 255, y: g = 255, z: b = 255, a = 1 } = r);
}
return `rgba(${[r, g, b, a]})`;
}
function fill(...args) {
let path;
if (args.length) {
if (args[0] instanceof Path2D) {
path = args.shift();
}
fillStyle(...args);
}
// Must branch the fill/stroke call as it
// recognizes the undefined argument
path ? ctx.fill(path) : ctx.fill();
}
function stroke(...args) {
let path;
if (args.length) {
if (args[0] instanceof Path2D) {
path = args.shift();
}
strokeStyle(...args);
}
// Must branch the fill/stroke call as it
// recognizes the undefined argument
path ? ctx.stroke(path) : ctx.stroke();
}
function clip(...args) {
ctx.clip(...args);
}
function createLinearGradient(x1 = -100, y1 = -100, x2 = 100, y2 = 100, stops = []) {
// Vector, Vector [stops]
if (typeof x1 !== 'number' && typeof y1 !== 'number') {
stops = x2;
({ x: x2, y: y2 } = y1);
({ x: x1, y: y1 } = x1);
}
// Vector, number, number, [stops]
else if (typeof x1 !== 'number' && typeof y1 === 'number' && typeof x2 === 'number') {
stops = y2;
[x2, y2] = [y1, x2];
({ x: x1, y: y1 } = x1);
}
// Number, number, Vector, [stops]
else if (typeof x1 === 'number' && typeof y1 === 'number' && typeof x2 !== 'number') {
stops = y2;
({ x: x2, y: y2 } = x2);
}
const grad = ctx.createLinearGradient(x1, y1, x2, y2);
if (stops && Array.isArray(stops) && stops.length) {
stops.forEach(stop => {
// offset: number, color: string
try {
if (Array.isArray(stop)) {
grad.addColorStop(stop[0], stop[1]);
}
// { offset: number, color: string }
else if (stop.offset && stop.color) {
grad.addColorStop(stop.offset, stop.color);
}
} catch (err) {
console.error(err);
console.error(stop);
}
});
}
return grad;
}
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);
}
/*
void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
*/
function drawImage(img, ...inputArgs) {
const finalArgs = [];
if (inputArgs.length === 0) {
finalArgs.push(0, 0);
} else
{
for (let i = 0; i < inputArgs.length; i += 2) {
const result = _resolveVectorArgs(...inputArgs.slice(i, i + 2));
finalArgs.push(...result);
}
}
if (img) {
if (img instanceof AlcaImage) {
img = img.image;
}
}
if (img) {
ctx.drawImage(img, ...finalArgs);
}
}
// function getImageAlphaBounds(img, opts) {
// if(!img) return new Vector();
// const alphaMin = opts.alphaMin === undefined ? 10 : opts.alphaMin;
// const { data, width, height, canvas, ctx } = getImageData(img);
// const bound = new Vector();
// for(let i = 0; i < imgData.data.length; i += 4) {
// if(imgData.data[i + 3] > alphaMin) {
// const { x, y } = iToXY(i * 0.25, sizeHalf, sizeHalf);
// if(x < bound.h) {
// bound.h = x;
// }
// if(y < bound.v) {
// bound.v = y;
// }
// }
// }
// }
function strokeText(str = 'Hello world', ...pos) {
const [x = 0, y = 0] = _resolveVectorArgs(...pos);
ctx.strokeText(str, x, y);
}
function fillText(str = 'Hello world', ...pos) {
const [x = 0, y = 0] = _resolveVectorArgs(...pos);
ctx.fillText(str, x, y);
}
function strokeFillText(str = 'Hello world', ...pos) {
const [x = 0, y = 0] = _resolveVectorArgs(...pos);
strokeText(str, x, y);
fillText(str, x, y);
}
function fillStrokeText(str = 'Hello world', ...pos) {
const [x = 0, y = 0] = _resolveVectorArgs(...pos);
fillText(str, x, y);
strokeText(str, x, y);
}
function measureText(text, fontSettings, backupFontSettings) {
const hasFontSettings = fontSettings !== undefined;
if (hasFontSettings) {
push();
font(fontSettings, backupFontSettings);
}
const measure = ctx.measureText(text);
if (hasFontSettings) {
pop();
}
return measure;
}
// 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') {
ctx.translate(offsetX, offsetY);
ctx.rotate(rot);
ctx.translate(-offsetX, -offsetY);
} else
if (isVectorish(offsetX)) {
ctx.translate(offsetX.x, offsetX.y);
ctx.rotate(rot);
ctx.translate(-offsetX.x, -offsetX.y);
}
}
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