diff --git a/package-lock.json b/package-lock.json index 85c4442..eb3e992 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.1", "license": "MPL2.0", "dependencies": { - "@figma-plugin/helpers": "^0.15", "react": "^18.2", "react-dom": "^18.2", "slugify": "^1.6" @@ -1164,15 +1163,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@figma-plugin/helpers": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@figma-plugin/helpers/-/helpers-0.15.2.tgz", - "integrity": "sha512-ggFxoefZKc0D/HJXFHqliLWCLQG3QTbByHqgiSpTK0D76qTDv2fpcF9bytjSMVnc4flD7Rq17tLNP/WmaJt3dA==", - "dependencies": { - "lodash": "^4.17.15", - "matrix-inverse": "^1.0.1" - } - }, "node_modules/@figma/eslint-plugin-figma-plugins": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@figma/eslint-plugin-figma-plugins/-/eslint-plugin-figma-plugins-0.15.0.tgz", @@ -5098,7 +5088,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -5154,11 +5145,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/matrix-inverse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/matrix-inverse/-/matrix-inverse-1.0.1.tgz", - "integrity": "sha512-ubaJ6vEJfpsRpOLYLJN3bCW3VbO2t0OtZIfausKiizsPNCvCXsWsLMR8jm4zmi8bSnodp3ht25iqdpSe0wIbxg==" - }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", diff --git a/package.json b/package.json index 1ca1bda..560c3d0 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "author": "Kaleidos", "license": "MPL2.0", "dependencies": { - "@figma-plugin/helpers": "^0.15", "react": "^18.2", "react-dom": "^18.2", "slugify": "^1.6" diff --git a/plugin-src/translators/index.ts b/plugin-src/translators/index.ts index 70254a2..c238869 100644 --- a/plugin-src/translators/index.ts +++ b/plugin-src/translators/index.ts @@ -1,5 +1,5 @@ export * from './translateFills'; -// export * from './translateGradientLinearFill'; +export * from './translateGradientLinearFill'; export * from './translateSolidFill'; export * from './translateTextDecoration'; export * from './translateTextTransform'; diff --git a/plugin-src/translators/translateFills.ts b/plugin-src/translators/translateFills.ts index 8be07be..0abe2e9 100644 --- a/plugin-src/translators/translateFills.ts +++ b/plugin-src/translators/translateFills.ts @@ -3,17 +3,10 @@ import { Fill } from '@ui/lib/types/utils/fill'; // import { translateGradientLinearFill } from './translateGradientLinearFill'; import { translateSolidFill } from './translateSolidFill'; -const translateFill = ( - fill: Paint, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - width: number, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - height: number -): Fill | undefined => { +const translateFill = (fill: Paint /*, width: number, height: number*/): Fill | undefined => { switch (fill.type) { case 'SOLID': return translateSolidFill(fill); - // @TODO: fix this // case 'GRADIENT_LINEAR': // return translateGradientLinearFill(fill, width, height); } @@ -22,9 +15,9 @@ const translateFill = ( }; export const translateFills = ( - fills: readonly Paint[] | typeof figma.mixed, - width: number, - height: number + fills: readonly Paint[] | typeof figma.mixed + // width: number, + // height: number ): Fill[] => { // @TODO: think better variable name // @TODO: make it work with figma.mixed @@ -33,7 +26,7 @@ export const translateFills = ( const penpotFills = []; for (const fill of fills2) { - const penpotFill = translateFill(fill, width, height); + const penpotFill = translateFill(fill /*, width, height*/); if (penpotFill) { penpotFills.unshift(penpotFill); diff --git a/plugin-src/translators/translateGradientLinearFill.ts b/plugin-src/translators/translateGradientLinearFill.ts index db2028d..0079c7b 100644 --- a/plugin-src/translators/translateGradientLinearFill.ts +++ b/plugin-src/translators/translateGradientLinearFill.ts @@ -1,6 +1,5 @@ -import { extractLinearGradientParamsFromTransform } from '@figma-plugin/helpers'; - import { rgbToHex } from '@plugin/utils'; +import { calculateLinearGradient } from '@plugin/utils/calculateLinearGradient'; import { Fill } from '@ui/lib/types/utils/fill'; @@ -9,7 +8,7 @@ export const translateGradientLinearFill = ( width: number, height: number ): Fill => { - const points = extractLinearGradientParamsFromTransform(width, height, fill.gradientTransform); + const points = calculateLinearGradient(width, height, fill.gradientTransform); return { fillColorGradient: { diff --git a/plugin-src/utils/applyMatrixToPoint.ts b/plugin-src/utils/applyMatrixToPoint.ts new file mode 100644 index 0000000..d1b2287 --- /dev/null +++ b/plugin-src/utils/applyMatrixToPoint.ts @@ -0,0 +1,6 @@ +export const applyMatrixToPoint = (matrix: number[][], point: number[]) => { + return [ + point[0] * matrix[0][0] + point[1] * matrix[0][1] + matrix[0][2], + point[0] * matrix[1][0] + point[1] * matrix[1][1] + matrix[1][2] + ]; +}; diff --git a/plugin-src/utils/calculateLinearGradient.ts b/plugin-src/utils/calculateLinearGradient.ts new file mode 100644 index 0000000..ecf818e --- /dev/null +++ b/plugin-src/utils/calculateLinearGradient.ts @@ -0,0 +1,23 @@ +import { applyMatrixToPoint } from '@plugin/utils/applyMatrixToPoint'; +import { matrixInvert } from '@plugin/utils/matrixInvert'; + +export const calculateLinearGradient = (shapeWidth: number, shapeHeight: number, t: Transform) => { + const transform = t.length === 2 ? [...t, [0, 0, 1]] : [...t]; + const mxInv = matrixInvert(transform); + + if (!mxInv) { + return { + start: [0, 0], + end: [0, 0] + }; + } + + const startEnd = [ + [0, 0.5], + [1, 0.5] + ].map(p => applyMatrixToPoint(mxInv, p)); + return { + start: [startEnd[0][0] * shapeWidth, startEnd[0][1] * shapeHeight], + end: [startEnd[1][0] * shapeWidth, startEnd[1][1] * shapeHeight] + }; +}; diff --git a/plugin-src/utils/matrixInvert.ts b/plugin-src/utils/matrixInvert.ts new file mode 100644 index 0000000..731220c --- /dev/null +++ b/plugin-src/utils/matrixInvert.ts @@ -0,0 +1,96 @@ +export const matrixInvert = (M: number[][]): number[][] | undefined => { + // if the matrix isn't square: exit (error) + if (M.length !== M[0].length) { + return; + } + + // create the identity matrix (I), and a copy (C) of the original + const dim = M.length; + let i = 0, + ii = 0, + j = 0, + e = 0; + const I: number[][] = [], + C: number[][] = []; + for (i = 0; i < dim; i += 1) { + // Create the row + I[i] = []; + C[i] = []; + for (j = 0; j < dim; j += 1) { + // if we're on the diagonal, put a 1 (for identity) + if (i === j) { + I[i][j] = 1; + } else { + I[i][j] = 0; + } + + // Also, make the copy of the original + C[i][j] = M[i][j]; + } + } + + // Perform elementary row operations + for (i = 0; i < dim; i += 1) { + // get the element e on the diagonal + e = C[i][i]; + + // if we have a 0 on the diagonal (we'll need to swap with a lower row) + if (e === 0) { + // look through every row below the i'th row + for (ii = i + 1; ii < dim; ii += 1) { + // if the ii'th row has a non-0 in the i'th col + if (C[ii][i] !== 0) { + // it would make the diagonal have a non-0 so swap it + for (j = 0; j < dim; j++) { + e = C[i][j]; // temp store i'th row + C[i][j] = C[ii][j]; // replace i'th row by ii'th + C[ii][j] = e; // replace ii'th by temp + e = I[i][j]; // temp store i'th row + I[i][j] = I[ii][j]; // replace i'th row by ii'th + I[ii][j] = e; // replace ii'th by temp + } + // don't bother checking other rows since we've swapped + break; + } + } + // get the new diagonal + e = C[i][i]; + // if it's still 0, not invertable (error) + if (e === 0) { + return; + } + } + + // Scale this row down by e (so we have a 1 on the diagonal) + for (j = 0; j < dim; j++) { + C[i][j] = C[i][j] / e; // apply to original matrix + I[i][j] = I[i][j] / e; // apply to identity + } + + // Subtract this row (scaled appropriately for each row) from ALL of + // the other rows so that there will be 0's in this column in the + // rows above and below this one + for (ii = 0; ii < dim; ii++) { + // Only apply to other rows (we want a 1 on the diagonal) + if (ii === i) { + continue; + } + + // We want to change this element to 0 + e = C[ii][i]; + + // Subtract (the row above(or below) scaled by e) from (the + // current row) but start at the i'th column and assume all the + // stuff left of diagonal is 0 (which it should be if we made this + // algorithm correctly) + for (j = 0; j < dim; j++) { + C[ii][j] -= e * C[i][j]; // apply to original matrix + I[ii][j] -= e * I[i][j]; // apply to identity + } + } + } + + // we've done all operations, C should be the identity + // matrix I should be the inverse: + return I; +};