Skip to content

Commit

Permalink
Merge pull request #322 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: add @idraw/figma
  • Loading branch information
chenshenhai authored Jun 8, 2024
2 parents 466043b + 6786f97 commit b167d07
Show file tree
Hide file tree
Showing 90 changed files with 2,386 additions and 3,692 deletions.
File renamed without changes.
Binary file not shown.
36 changes: 36 additions & 0 deletions packages/figma/dev/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>canvas</title>
<style>
html,
body {
margin: 0;
height: 0;
background: #ffffff;
}
.full-screen {
/* position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0; */
/* background: #000000; */
/* background: #eaeaea; */
}
canvas {
/* background-image: linear-gradient(#aaaaaa30 1px, transparent 0), linear-gradient(90deg, #aaaaaa30 1px, transparent 0),
linear-gradient(#aaaaaa30 1px, transparent 0), linear-gradient(90deg, #aaaaaa30 1px, transparent 0);
background-size: 10px 10px, 10px 10px, 50px 50px, 50px 50px;
border-right: 1px solid #aaaaaa30;
border-bottom: 1px solid #aaaaaa30; */
}
</style>
</head>
<body>
<div id="canvas-preview"></div>

<script type="module" src="./main.ts"></script>
</body>
</html>
90 changes: 90 additions & 0 deletions packages/figma/dev/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { Data, ElementAssets, Element } from '@idraw/types';
import { deepClone, getElemenetsAssetIds } from '@idraw/util';
import { figmaBytesToMap, figmaMapToIDrawData, figmaBytesToIDrawData } from '../src';
import { iDraw } from '../../idraw';
// import data from './data';

const url = new URLSearchParams(window.location.search);

async function action(params: { data: Data }) {
const previewDOM = document.querySelector('#canvas-preview') as HTMLDivElement;

const { data } = params;
const devicePixelRatio = window.devicePixelRatio;
const width = window.innerWidth;
const height = 600;

const data1 = deepClone(data);

const idraw = new iDraw(previewDOM, {
devicePixelRatio,
width,
height
});
idraw.setData(data1);
idraw.centerContent();
}

// async function main() {
// if (targetFile) {
// const filePath = `/demo/lab-figma-to-elements/figma/${targetFile}`;
// const figma = await fetch(filePath).then((res) => res.blob());
// const buffer = await figma.arrayBuffer();

// {
// const filePath = `/demo/lab-figma-to-elements/figma/${targetFile}`;
// const figma = await fetch(filePath).then((res) => res.blob());
// const buff = await figma.arrayBuffer();
// const bytes = new Uint8Array(buff);
// const figmaMap = await figmaBytesToMap(bytes);
// console.log('figmaMap ===== ', figmaMap);
// const data = await figmaMapToIDrawData(figmaMap);
// console.log('object ===== ', data);
// }

// let data = await figmaBufferToIDrawData(buffer);
// // console.log('object ====== ', object);

// // const map = figmaObjectToMap(object);
// // console.log('map ==== ', map);

// // const tree = figmaObjectToTree(object);
// // console.log('tree ==== ', tree);

// // let data = figmaObjectToIDrawData(object);
// // TODO
// data = {
// elements: (data.elements[0] as Element<'group'>).detail.children
// };
// // console.log('data ===== ', data);
// await action({ data });
// } else {
// list();
// }
// }

async function main() {
const filePath = `/dev/figma/iOS-Native-Wireframes-Community.fig`;
console.log('filePath ------ ', filePath);
const figma = await fetch(filePath).then((res) => res.blob());
const arrayBuffer = await figma.arrayBuffer();
const buffer = new Uint8Array(arrayBuffer);

let data: Data = await figmaBytesToIDrawData(buffer);
// // TODO
data = {
elements: (data.elements[0] as Element<'group'>).detail.children,
global: data.elements[0].global
};

console.log('data ===== ', data);
await action({ data });
}

main()
.then(() => {
console.log('Ok');
})
.catch((err) => {
console.log(err);
});
17 changes: 17 additions & 0 deletions packages/figma/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@idraw/figma",
"version": "0.4.0-beta.25",
"dependencies": {
"@ant-design/icons": "^5.1.3",
"@idraw/types": "workspace:^0.4.0-beta.25",
"@idraw/util": "workspace:^0.4.0-beta.25",
"kiwi-schema": "^0.5.0",
"matrix-inverse": "^2.0.0",
"pako": "^2.1.0",
"uzip": "^0.20201231.0"
},
"devDependencies": {
"@types/pako": "^2.0.3",
"@idraw/types": "workspace:^0.4.0-beta.25"
}
}
88 changes: 88 additions & 0 deletions packages/figma/src/common/calc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { Element, ElementSize } from '@idraw/types';
import { rotateElementVertexes } from '@idraw/util';

export function calcGroupSize(group: Element<'group'>): ElementSize {
const area: ElementSize = { x: 0, y: 0, w: 0, h: 0 };
group.detail.children.forEach((elem) => {
const elemSize: ElementSize = {
x: elem.x,
y: elem.y,
w: elem.w,
h: elem.h,
angle: elem.angle
};
if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) {
const ves = rotateElementVertexes(elemSize);
if (ves.length === 4) {
const xList = [ves[0].x, ves[1].x, ves[2].x, ves[3].x];
const yList = [ves[0].y, ves[1].y, ves[2].y, ves[3].y];
elemSize.x = Math.min(...xList);
elemSize.y = Math.min(...yList);
elemSize.w = Math.abs(Math.max(...xList) - Math.min(...xList));
elemSize.h = Math.abs(Math.max(...yList) - Math.min(...yList));
}
}
const areaStartX = Math.min(elemSize.x, area.x);
const areaStartY = Math.min(elemSize.y, area.y);

const areaEndX = Math.max(elemSize.x + elemSize.w, area.x + area.w);
const areaEndY = Math.max(elemSize.y + elemSize.h, area.y + area.h);

area.x = areaStartX;
area.y = areaStartY;
area.w = Math.abs(areaEndX - areaStartX);
area.h = Math.abs(areaEndY - areaStartY);
});
return area;
}

export function resetGroupSize(group: Element<'group'>): Element<'group'> {
const area = { x: 0, y: 0, w: 0, h: 0 };
if (group.detail.children.length > 0) {
const firstElem = group.detail.children[0];
area.x = firstElem.x;
area.y = firstElem.y;
area.w = firstElem.w;
area.h = firstElem.h;
}
group.detail.children.forEach((elem) => {
const elemSize: ElementSize = {
x: elem.x,
y: elem.y,
w: elem.w,
h: elem.h,
angle: elem.angle
};
if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) {
const ves = rotateElementVertexes(elemSize);
if (ves.length === 4) {
const xList = [ves[0].x, ves[1].x, ves[2].x, ves[3].x];
const yList = [ves[0].y, ves[1].y, ves[2].y, ves[3].y];
elemSize.x = Math.min(...xList);
elemSize.y = Math.min(...yList);
elemSize.w = Math.abs(Math.max(...xList) - Math.min(...xList));
elemSize.h = Math.abs(Math.max(...yList) - Math.min(...yList));
}
}
const areaStartX = Math.min(elemSize.x, area.x);
const areaStartY = Math.min(elemSize.y, area.y);

const areaEndX = Math.max(elemSize.x + elemSize.w, area.x + area.w);
const areaEndY = Math.max(elemSize.y + elemSize.h, area.y + area.h);

area.x = areaStartX;
area.y = areaStartY;
area.w = Math.abs(areaEndX - areaStartX);
area.h = Math.abs(areaEndY - areaStartY);
});

group.detail.children.forEach((elem) => {
elem.x -= area.x;
elem.y -= area.y;
});

group.w = area.w;
group.h = area.h;

return group;
}
77 changes: 77 additions & 0 deletions packages/figma/src/common/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { FigmaGUID, FigmaNode, FigmaNodeType, FigmaParseOptions, FigmaSymbolOverrideItem } from '../types';

export function figmaGUIDToID(guid: FigmaGUID): string {
return `${guid.sessionID}:${guid.localID}`;
}

export function getOverrideNodeMap(node: FigmaNode<'INSTANCE'>): Record<string, Partial<FigmaNode>> {
const overrideNodeMap: Record<string, Partial<FigmaNode>> = {};
const { symbolData, derivedSymbolData } = node;
const { symbolOverrides } = symbolData;
if (Array.isArray(symbolOverrides) && symbolOverrides.length > 0) {
symbolOverrides.forEach((item) => {
const { guidPath, ...restData } = item;
guidPath.guids.forEach((guid) => {
const id = figmaGUIDToID(guid);
if (overrideNodeMap[id]) {
overrideNodeMap[id] = { ...overrideNodeMap[id], ...restData };
} else {
overrideNodeMap[id] = restData;
}
});
});
}

if (Array.isArray(derivedSymbolData) && derivedSymbolData.length > 0) {
derivedSymbolData.forEach((item) => {
const { guidPath, ...restData } = item;
guidPath.guids.forEach((guid) => {
const id = figmaGUIDToID(guid);
if (overrideNodeMap[id]) {
overrideNodeMap[id] = { ...overrideNodeMap[id], ...restData };
} else {
overrideNodeMap[id] = restData;
}
});
});
}

return overrideNodeMap;
}

export function mergeNodeOverrideData<T extends FigmaNodeType = 'CANVAS'>(
node: FigmaNode<T>,
opts: FigmaParseOptions<T>
): Partial<FigmaNode<T>> | FigmaSymbolOverrideItem {
let overrideData: Partial<FigmaNode<T>> = {};

const { overrideNodeMap = {}, overrideProperties } = opts;
const { overrideKey } = node;

if (overrideKey) {
const overrideId = figmaGUIDToID(overrideKey);
if (overrideNodeMap[overrideId]) {
overrideData = { ...overrideData, ...overrideNodeMap[overrideId] } as Partial<FigmaNode<T>>;
}
}
if (overrideProperties) {
overrideData = { ...overrideData, ...overrideProperties };
}

return overrideData;
}

export async function uint8ArrayToBase64(u8: Uint8Array, opts: { type: string }): Promise<string> {
const { type } = opts;
return new Promise((resolve, reject) => {
var blob = new Blob([u8], { type });
var fileReader = new FileReader();
fileReader.addEventListener('load', () => {
resolve(fileReader.result as string);
});
fileReader.addEventListener('error', (err) => {
reject(err);
});
fileReader.readAsDataURL(blob);
});
}
1 change: 1 addition & 0 deletions packages/figma/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const figmaImageDir = 'images/';
Loading

0 comments on commit b167d07

Please sign in to comment.