UNPKG

css-transform-matrix-plugin

Version:

A webpack plugin that automatically converts CSS transform properties to matrix3d for GPU acceleration

402 lines (395 loc) 13.1 kB
'use strict'; var valueParser = require('postcss-value-parser'); class TransformParser { // 解析 transform 属性值 static parseTransformValue(value) { const parsed = valueParser(value); const functions = []; parsed.walk((node) => { if (node.type === 'function') { const functionNode = node; const args = this.extractFunctionArgs(functionNode); functions.push({ name: functionNode.value, args, }); } }); return functions; } // 提取函数参数并转换为数值 static extractFunctionArgs(node) { const args = []; if (node.nodes) { node.nodes.forEach((arg) => { if (arg.type === 'word') { const numValue = this.parseNumericValue(arg.value); if (numValue !== null) { args.push(numValue); } } }); } return args; } // 解析数值(支持 px, deg, % 等单位) static parseNumericValue(value) { // 移除单位,只保留数值 const match = value.match(/^(-?\d*\.?\d+)(px|deg|%|em|rem)?$/); if (match) { const num = parseFloat(match[1]); const unit = match[2]; // 角度转弧度 if (unit === 'deg') { return (num * Math.PI) / 180; } return num; } return null; } } // 角度转换函数 // 创建单位矩阵 function createIdentityMatrix() { return { m11: 1, m12: 0, m13: 0, m14: 0, m21: 0, m22: 1, m23: 0, m24: 0, m31: 0, m32: 0, m33: 1, m34: 0, m41: 0, m42: 0, m43: 0, m44: 1, }; } // 矩阵乘法 - 将两个 4x4 矩阵相乘 function multiplyMatrices(a, b) { return { // 第一行 m11: a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 + a.m14 * b.m41, m12: a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 + a.m14 * b.m42, m13: a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 + a.m14 * b.m43, m14: a.m11 * b.m14 + a.m12 * b.m24 + a.m13 * b.m34 + a.m14 * b.m44, // 第二行 m21: a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 + a.m24 * b.m41, m22: a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 + a.m24 * b.m42, m23: a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 + a.m24 * b.m43, m24: a.m21 * b.m14 + a.m22 * b.m24 + a.m23 * b.m34 + a.m24 * b.m44, // 第三行 m31: a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 + a.m34 * b.m41, m32: a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 + a.m34 * b.m42, m33: a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 + a.m34 * b.m43, m34: a.m31 * b.m14 + a.m32 * b.m24 + a.m33 * b.m34 + a.m34 * b.m44, // 第四行 m41: a.m41 * b.m11 + a.m42 * b.m21 + a.m43 * b.m31 + a.m44 * b.m41, m42: a.m41 * b.m12 + a.m42 * b.m22 + a.m43 * b.m32 + a.m44 * b.m42, m43: a.m41 * b.m13 + a.m42 * b.m23 + a.m43 * b.m33 + a.m44 * b.m43, m44: a.m41 * b.m14 + a.m42 * b.m24 + a.m43 * b.m34 + a.m44 * b.m44, }; } // CSS Transform 矩阵转换器 class MatrixTransformer { // 将transform函数数组抓暖胃3D矩阵 static transformsToMatrix3D(functions) { let result = createIdentityMatrix(); for (const func of functions) { const matrix = this.createMatrixFromFunction(func); result = multiplyMatrices(result, matrix); } return result; } // 根据单个transform函数创建矩阵 static createMatrixFromFunction(func) { const { name, args } = func; switch (name) { case 'translateX': return this.createTranslateXMatrix(args[0] || 0); case 'translateY': return this.createTranslateYMatrix(args[0] || 0); case 'translateZ': return this.createTranslateZMatrix(args[0] || 0); case 'translate': return this.createTranslateMatrix(args[0] || 0, args[1] || 0); case 'translate3d': return this.createTranslate3DMatrix(args[0] || 0, args[1] || 0, args[2] || 0); case 'scaleX': return this.createScaleXMatrix(args[0] || 1); case 'scaleY': return this.createScaleYMatrix(args[0] || 1); case 'scaleZ': return this.createScaleZMatrix(args[0] || 1); case 'scale': return this.createScaleMatrix(args[0] || 1, args[1] || args[0] || 1); case 'scale3d': return this.createScale3DMatrix(args[0] || 1, args[1] || 1, args[2] || 1); case 'rotate': case 'rotateZ': return this.createRotateZMatrix(args[0] || 0); case 'rotateX': return this.createRotateXMatrix(args[0] || 0); case 'rotateY': return this.createRotateYMatrix(args[0] || 0); case 'skewX': return this.createSkewXMatrix(args[0] || 0); case 'skewY': return this.createSkewYMatrix(args[0] || 0); case 'skew': return this.createSkewMatrix(args[0] || 0, args[1] || 0); case 'matrix3d': if (args.length >= 16) { return this.createMatrix3DFromArray(args); } else { console.warn(`matrix3d requires 16 arguments, got ${args.length}`); return createIdentityMatrix(); } case 'matrix': if (args.length >= 6) { return this.createMatrixFrom2D(args); } else { console.warn(`matrix requires 6 arguments, got ${args.length}`); return createIdentityMatrix(); } default: console.warn(`Unsupported transform function: ${name}`); return createIdentityMatrix(); } } // 位移矩阵 static createTranslateXMatrix(x) { const matrix = createIdentityMatrix(); matrix.m41 = x; return matrix; } static createTranslateYMatrix(y) { const matrix = createIdentityMatrix(); matrix.m42 = y; return matrix; } static createTranslateZMatrix(z) { const matrix = createIdentityMatrix(); matrix.m43 = z; return matrix; } static createTranslateMatrix(x, y) { const matrix = createIdentityMatrix(); matrix.m41 = x; matrix.m42 = y; return matrix; } static createTranslate3DMatrix(x, y, z) { const matrix = createIdentityMatrix(); matrix.m41 = x; matrix.m42 = y; matrix.m43 = z; return matrix; } // 缩放矩阵 static createScaleXMatrix(sx) { const matrix = createIdentityMatrix(); matrix.m11 = sx; return matrix; } static createScaleYMatrix(sy) { const matrix = createIdentityMatrix(); matrix.m22 = sy; return matrix; } static createScaleZMatrix(sz) { const matrix = createIdentityMatrix(); matrix.m33 = sz; return matrix; } static createScaleMatrix(sx, sy) { const matrix = createIdentityMatrix(); matrix.m11 = sx; matrix.m22 = sy; return matrix; } static createScale3DMatrix(sx, sy, sz) { const matrix = createIdentityMatrix(); matrix.m11 = sx; matrix.m22 = sy; matrix.m33 = sz; return matrix; } // 旋转矩阵 static createRotateXMatrix(angle) { const matrix = createIdentityMatrix(); const cos = Math.cos(angle); const sin = Math.sin(angle); matrix.m22 = cos; matrix.m23 = -sin; matrix.m32 = sin; matrix.m33 = cos; return matrix; } static createRotateYMatrix(angle) { const matrix = createIdentityMatrix(); const cos = Math.cos(angle); const sin = Math.sin(angle); matrix.m11 = cos; matrix.m13 = sin; matrix.m31 = -sin; matrix.m33 = cos; return matrix; } static createRotateZMatrix(angle) { const matrix = createIdentityMatrix(); const cos = Math.cos(angle); const sin = Math.sin(angle); matrix.m11 = cos; matrix.m12 = -sin; matrix.m21 = sin; matrix.m22 = cos; return matrix; } // 倾斜矩阵 static createSkewXMatrix(angle) { const matrix = createIdentityMatrix(); matrix.m21 = Math.tan(angle); return matrix; } static createSkewYMatrix(angle) { const matrix = createIdentityMatrix(); matrix.m12 = Math.tan(angle); return matrix; } static createSkewMatrix(angleX, angleY) { const matrix = createIdentityMatrix(); matrix.m12 = Math.tan(angleY); matrix.m21 = Math.tan(angleX); return matrix; } /** * 将矩阵转换为 CSS matrix3d 字符串 */ static matrixToCSS(matrix) { const values = [ matrix.m11, matrix.m12, matrix.m13, matrix.m14, matrix.m21, matrix.m22, matrix.m23, matrix.m24, matrix.m31, matrix.m32, matrix.m33, matrix.m34, matrix.m41, matrix.m42, matrix.m43, matrix.m44, ]; // 保留6位小数,移除尾随零 const formattedValues = values.map((v) => parseFloat(v.toFixed(6)).toString()); return `matrix3d(${formattedValues.join(', ')})`; } // 从 matrix3d 的 16 个参数创建矩阵 static createMatrix3DFromArray(args) { return { m11: args[0], m12: args[1], m13: args[2], m14: args[3], m21: args[4], m22: args[5], m23: args[6], m24: args[7], m31: args[8], m32: args[9], m33: args[10], m34: args[11], m41: args[12], m42: args[13], m43: args[14], m44: args[15], }; } // 从 2D matrix 的 6 个参数创建 3D 矩阵 static createMatrixFrom2D(args) { return { m11: args[0], m12: args[1], m13: 0, m14: 0, m21: args[2], m22: args[3], m23: 0, m24: 0, m31: 0, m32: 0, m33: 1, m34: 0, m41: args[4], m42: args[5], m43: 0, m44: 1, }; } } function createPostCSSPlugin(options = {}) { const config = { enabled: true, keepOriginal: false, verbose: false, ...options, }; return { postcssPlugin: 'css-transform-matrix', Declaration: (decl) => { if (!config.enabled || decl.prop !== 'transform' || decl.value === 'none') { return; } try { const originalValue = decl.value; // 跳过已经处理的 matrix3d if (originalValue.includes('matrix3d(')) { if (config.verbose) { console.log(`[CSS Transform Matrix] Skipping: ${originalValue}`); } return; } const functions = TransformParser.parseTransformValue(originalValue); if (functions.length === 0) { return; } const matrix = MatrixTransformer.transformsToMatrix3D(functions); const matrixCSS = MatrixTransformer.matrixToCSS(matrix); if (config.keepOriginal) { decl.cloneBefore({ prop: `/* original-transform */`, value: originalValue, }); } decl.value = matrixCSS; if (config.verbose) { console.log(`[CSS Transform Matrix] ${originalValue} -> ${matrixCSS}`); } } catch (error) { if (config.verbose) { const errorMessage = error instanceof Error ? error.message : String(error); console.warn(`[CSS Transform Matrix] Failed: ${decl.value}`, errorMessage); } } }, }; } // PostCSS 插件标识 createPostCSSPlugin.postcss = true; exports.createPostCSSPlugin = createPostCSSPlugin; //# sourceMappingURL=postcss.js.map