figmatk 0.3.8 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -500,6 +500,100 @@ function renderLine(deck, node) {
|
|
|
500
500
|
return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${sw}"/>`;
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
/**
|
|
504
|
+
* VECTOR — decode fillGeometry/strokeGeometry commandsBlob binary to SVG paths.
|
|
505
|
+
*
|
|
506
|
+
* Blob format: [cmdByte][float32LE params...]
|
|
507
|
+
* 0x01 = moveTo (x, y)
|
|
508
|
+
* 0x02 = lineTo (x, y)
|
|
509
|
+
* 0x04 = cubicTo (c1x, c1y, c2x, c2y, x, y)
|
|
510
|
+
* 0x00 = close
|
|
511
|
+
*
|
|
512
|
+
* Coordinates are in node-size space. The full affine transform matrix is used
|
|
513
|
+
* to position, scale, and rotate the vector in the slide.
|
|
514
|
+
*/
|
|
515
|
+
function renderVector(deck, node) {
|
|
516
|
+
const t = node.transform ?? {};
|
|
517
|
+
const m00 = t.m00 ?? 1, m01 = t.m01 ?? 0, m02 = t.m02 ?? 0;
|
|
518
|
+
const m10 = t.m10 ?? 0, m11 = t.m11 ?? 1, m12 = t.m12 ?? 0;
|
|
519
|
+
const blobs = deck.message?.blobs;
|
|
520
|
+
const parts = [];
|
|
521
|
+
|
|
522
|
+
// Fill paths
|
|
523
|
+
const fillColor = resolveFill(getFillPaints(node));
|
|
524
|
+
if (fillColor && node.fillGeometry?.length && blobs) {
|
|
525
|
+
for (const geo of node.fillGeometry) {
|
|
526
|
+
const d = decodeCmdBlob(blobs, geo.commandsBlob);
|
|
527
|
+
if (!d) continue;
|
|
528
|
+
const rule = geo.windingRule === 'EVENODD' ? ' fill-rule="evenodd"' : '';
|
|
529
|
+
parts.push(`<path d="${d}" fill="${fillColor}"${rule}/>`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Stroke paths
|
|
534
|
+
const strokeColor = resolveFill(node.strokePaints);
|
|
535
|
+
const sw = node.strokeWeight ?? 0;
|
|
536
|
+
if (strokeColor && sw > 0 && node.strokeGeometry?.length && blobs) {
|
|
537
|
+
for (const geo of node.strokeGeometry) {
|
|
538
|
+
const d = decodeCmdBlob(blobs, geo.commandsBlob);
|
|
539
|
+
if (!d) continue;
|
|
540
|
+
// strokeGeometry encodes the stroke outline as a fill shape
|
|
541
|
+
const rule = geo.windingRule === 'EVENODD' ? ' fill-rule="evenodd"' : '';
|
|
542
|
+
parts.push(`<path d="${d}" fill="${strokeColor}"${rule}/>`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (!parts.length) return renderPlaceholder(deck, node);
|
|
547
|
+
return `<g transform="matrix(${m00},${m10},${m01},${m11},${m02},${m12})">\n${parts.join('\n')}\n</g>`;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/** Decode a commandsBlob index into an SVG path d-string. */
|
|
551
|
+
function decodeCmdBlob(blobs, blobIdx) {
|
|
552
|
+
if (blobIdx == null || !blobs?.[blobIdx]) return null;
|
|
553
|
+
const raw = blobs[blobIdx].bytes ?? blobs[blobIdx];
|
|
554
|
+
if (!raw) return null;
|
|
555
|
+
|
|
556
|
+
// Convert indexed object to Buffer if needed
|
|
557
|
+
let buf;
|
|
558
|
+
if (Buffer.isBuffer(raw) || raw instanceof Uint8Array) {
|
|
559
|
+
buf = Buffer.from(raw);
|
|
560
|
+
} else {
|
|
561
|
+
const len = Object.keys(raw).length;
|
|
562
|
+
buf = Buffer.alloc(len);
|
|
563
|
+
for (let i = 0; i < len; i++) buf[i] = raw[i];
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const cmds = [];
|
|
567
|
+
let off = 0;
|
|
568
|
+
while (off < buf.length) {
|
|
569
|
+
const cmd = buf[off++];
|
|
570
|
+
if (cmd === 0x01) { // moveTo
|
|
571
|
+
const x = buf.readFloatLE(off); off += 4;
|
|
572
|
+
const y = buf.readFloatLE(off); off += 4;
|
|
573
|
+
cmds.push(`M${f(x)},${f(y)}`);
|
|
574
|
+
} else if (cmd === 0x02) { // lineTo
|
|
575
|
+
const x = buf.readFloatLE(off); off += 4;
|
|
576
|
+
const y = buf.readFloatLE(off); off += 4;
|
|
577
|
+
cmds.push(`L${f(x)},${f(y)}`);
|
|
578
|
+
} else if (cmd === 0x04) { // cubicTo
|
|
579
|
+
const c1x = buf.readFloatLE(off); off += 4;
|
|
580
|
+
const c1y = buf.readFloatLE(off); off += 4;
|
|
581
|
+
const c2x = buf.readFloatLE(off); off += 4;
|
|
582
|
+
const c2y = buf.readFloatLE(off); off += 4;
|
|
583
|
+
const x = buf.readFloatLE(off); off += 4;
|
|
584
|
+
const y = buf.readFloatLE(off); off += 4;
|
|
585
|
+
cmds.push(`C${f(c1x)},${f(c1y)} ${f(c2x)},${f(c2y)} ${f(x)},${f(y)}`);
|
|
586
|
+
} else if (cmd === 0x00) { // close
|
|
587
|
+
cmds.push('Z');
|
|
588
|
+
} else {
|
|
589
|
+
break; // unknown command — stop
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return cmds.length ? cmds.join('') : null;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function f(v) { return +v.toFixed(2); }
|
|
596
|
+
|
|
503
597
|
function renderPlaceholder(deck, node) {
|
|
504
598
|
const { x, y } = pos(node);
|
|
505
599
|
const { w, h } = size(node);
|
|
@@ -580,7 +674,7 @@ const RENDERERS = {
|
|
|
580
674
|
GROUP: renderGroup,
|
|
581
675
|
SECTION: renderGroup,
|
|
582
676
|
BOOLEAN_OPERATION: renderGroup,
|
|
583
|
-
VECTOR:
|
|
677
|
+
VECTOR: renderVector,
|
|
584
678
|
LINE: renderLine,
|
|
585
679
|
STAR: renderPlaceholder,
|
|
586
680
|
POLYGON: renderPlaceholder,
|
package/manifest.json
CHANGED
package/package.json
CHANGED