@effing/canvas 0.22.0 → 0.22.2
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.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +90 -52
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -764,8 +764,7 @@ function acquireOffscreen(w, h) {
|
|
|
764
764
|
const canvas2 = ref.deref();
|
|
765
765
|
if (canvas2) {
|
|
766
766
|
const ctx = canvas2.getContext("2d");
|
|
767
|
-
ctx.
|
|
768
|
-
ctx.clearRect(0, 0, w, h);
|
|
767
|
+
ctx.reset();
|
|
769
768
|
return [canvas2, ctx];
|
|
770
769
|
}
|
|
771
770
|
}
|
|
@@ -1041,6 +1040,7 @@ function drawBoxShadow(ctx, x, y, width, height, boxShadow, borderRadius) {
|
|
|
1041
1040
|
|
|
1042
1041
|
// src/jsx/draw/svg.ts
|
|
1043
1042
|
import { Path2D } from "@napi-rs/canvas";
|
|
1043
|
+
import parseCssColor from "parse-css-color";
|
|
1044
1044
|
function resolveCurrentColor(value, color) {
|
|
1045
1045
|
if (value?.toLowerCase() === "currentcolor") return color;
|
|
1046
1046
|
return value;
|
|
@@ -1098,10 +1098,10 @@ function parseFrac(value, fallback) {
|
|
|
1098
1098
|
}
|
|
1099
1099
|
function applyOpacity(color, opacity) {
|
|
1100
1100
|
if (opacity >= 1) return color;
|
|
1101
|
-
const
|
|
1102
|
-
if (
|
|
1103
|
-
|
|
1104
|
-
return
|
|
1101
|
+
const parsed = parseCssColor(color);
|
|
1102
|
+
if (!parsed) return color;
|
|
1103
|
+
const [r, g, b] = parsed.values;
|
|
1104
|
+
return `rgba(${r}, ${g}, ${b}, ${parsed.alpha * opacity})`;
|
|
1105
1105
|
}
|
|
1106
1106
|
function addGradientStops(gradient, def) {
|
|
1107
1107
|
for (const stop of normalizeChildren(def)) {
|
|
@@ -1438,7 +1438,14 @@ function drawSvgContainer(ctx, node, x, y, width, height) {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
const color = node.style.color ?? "black";
|
|
1440
1440
|
const merged = mergeStyleIntoProps(node.props);
|
|
1441
|
-
const
|
|
1441
|
+
const inherited = {
|
|
1442
|
+
fill: resolveCurrentColor(merged.fill, color) ?? "black",
|
|
1443
|
+
stroke: resolveCurrentColor(merged.stroke, color),
|
|
1444
|
+
strokeWidth: merged.strokeWidth ?? merged["stroke-width"],
|
|
1445
|
+
strokeLinecap: merged.strokeLinecap ?? merged["stroke-linecap"],
|
|
1446
|
+
strokeLinejoin: merged.strokeLinejoin ?? merged["stroke-linejoin"],
|
|
1447
|
+
strokeOpacity: merged.strokeOpacity ?? merged["stroke-opacity"]
|
|
1448
|
+
};
|
|
1442
1449
|
const children = node.props.children;
|
|
1443
1450
|
if (children != null) {
|
|
1444
1451
|
const childArray = Array.isArray(children) ? children : [children];
|
|
@@ -1447,7 +1454,7 @@ function drawSvgContainer(ctx, node, x, y, width, height) {
|
|
|
1447
1454
|
);
|
|
1448
1455
|
const defs = collectDefs(svgChildren);
|
|
1449
1456
|
for (const child of svgChildren) {
|
|
1450
|
-
drawSvgChild(ctx, child,
|
|
1457
|
+
drawSvgChild(ctx, child, inherited, color, defs, vbW, vbH);
|
|
1451
1458
|
}
|
|
1452
1459
|
}
|
|
1453
1460
|
ctx.restore();
|
|
@@ -1604,15 +1611,17 @@ function applyFilter(filterDef, sourceGraphic, w, h) {
|
|
|
1604
1611
|
}
|
|
1605
1612
|
return lastResult;
|
|
1606
1613
|
}
|
|
1607
|
-
function drawSvgChild(ctx, child,
|
|
1614
|
+
function drawSvgChild(ctx, child, inherited, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
|
|
1608
1615
|
const { type } = child;
|
|
1609
1616
|
const props = mergeStyleIntoProps(child.props);
|
|
1610
1617
|
if (type === "defs" || type === "clipPath" || type === "mask" || type === "filter")
|
|
1611
1618
|
return;
|
|
1612
1619
|
const transform = type !== "g" ? props.transform : void 0;
|
|
1613
|
-
|
|
1620
|
+
const opacity = type !== "g" ? Number(props.opacity ?? 1) : 1;
|
|
1621
|
+
if (transform || opacity < 1) {
|
|
1614
1622
|
ctx.save();
|
|
1615
|
-
applySvgTransform(ctx, transform);
|
|
1623
|
+
if (transform) applySvgTransform(ctx, transform);
|
|
1624
|
+
if (opacity < 1) ctx.globalAlpha *= opacity;
|
|
1616
1625
|
}
|
|
1617
1626
|
const clipRef = parseUrlRef(props.clipPath ?? props["clip-path"]);
|
|
1618
1627
|
const clipShapes = clipRef ? defs.clips.get(clipRef) : void 0;
|
|
@@ -1632,28 +1641,28 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
|
|
|
1632
1641
|
})() : ctx;
|
|
1633
1642
|
switch (type) {
|
|
1634
1643
|
case "path":
|
|
1635
|
-
drawPath(targetCtx, props,
|
|
1644
|
+
drawPath(targetCtx, props, inherited, color, defs);
|
|
1636
1645
|
break;
|
|
1637
1646
|
case "circle":
|
|
1638
|
-
drawCircle(targetCtx, props,
|
|
1647
|
+
drawCircle(targetCtx, props, inherited, color, defs, vbW, vbH);
|
|
1639
1648
|
break;
|
|
1640
1649
|
case "rect":
|
|
1641
|
-
drawSvgRect(targetCtx, props,
|
|
1650
|
+
drawSvgRect(targetCtx, props, inherited, color, defs, vbW, vbH);
|
|
1642
1651
|
break;
|
|
1643
1652
|
case "line":
|
|
1644
|
-
drawLine(targetCtx, props, color, defs, vbW, vbH);
|
|
1653
|
+
drawLine(targetCtx, props, inherited, color, defs, vbW, vbH);
|
|
1645
1654
|
break;
|
|
1646
1655
|
case "ellipse":
|
|
1647
|
-
drawEllipse(targetCtx, props,
|
|
1656
|
+
drawEllipse(targetCtx, props, inherited, color, defs, vbW, vbH);
|
|
1648
1657
|
break;
|
|
1649
1658
|
case "polygon":
|
|
1650
|
-
drawPolygon(targetCtx, props,
|
|
1659
|
+
drawPolygon(targetCtx, props, inherited, color, defs);
|
|
1651
1660
|
break;
|
|
1652
1661
|
case "polyline":
|
|
1653
|
-
drawPolyline(targetCtx, props,
|
|
1662
|
+
drawPolyline(targetCtx, props, inherited, color, defs);
|
|
1654
1663
|
break;
|
|
1655
1664
|
case "g":
|
|
1656
|
-
drawGroup(targetCtx, child,
|
|
1665
|
+
drawGroup(targetCtx, child, inherited, color, defs, vbW, vbH);
|
|
1657
1666
|
break;
|
|
1658
1667
|
}
|
|
1659
1668
|
if (needsOffscreen && elemCanvas) {
|
|
@@ -1663,7 +1672,15 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
|
|
|
1663
1672
|
Math.ceil(vbH)
|
|
1664
1673
|
);
|
|
1665
1674
|
for (const shape of maskShapes) {
|
|
1666
|
-
drawSvgChild(
|
|
1675
|
+
drawSvgChild(
|
|
1676
|
+
maskCtx,
|
|
1677
|
+
shape,
|
|
1678
|
+
{ fill: "white" },
|
|
1679
|
+
"white",
|
|
1680
|
+
defs,
|
|
1681
|
+
vbW,
|
|
1682
|
+
vbH
|
|
1683
|
+
);
|
|
1667
1684
|
}
|
|
1668
1685
|
targetCtx.globalCompositeOperation = "destination-in";
|
|
1669
1686
|
targetCtx.drawImage(maskCanvas, 0, 0);
|
|
@@ -1685,16 +1702,16 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
|
|
|
1685
1702
|
releaseOffscreen(elemCanvas);
|
|
1686
1703
|
}
|
|
1687
1704
|
if (clipPath) ctx.restore();
|
|
1688
|
-
if (transform) ctx.restore();
|
|
1705
|
+
if (transform || opacity < 1) ctx.restore();
|
|
1689
1706
|
}
|
|
1690
|
-
function drawPath(ctx, props,
|
|
1707
|
+
function drawPath(ctx, props, inherited, color, defs) {
|
|
1691
1708
|
const d = props.d;
|
|
1692
1709
|
if (!d) return;
|
|
1693
1710
|
const path = new Path2D(d);
|
|
1694
1711
|
const bbox = pathBBox(d);
|
|
1695
|
-
applyFillAndStroke(ctx, props, path,
|
|
1712
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1696
1713
|
}
|
|
1697
|
-
function drawCircle(ctx, props,
|
|
1714
|
+
function drawCircle(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
|
|
1698
1715
|
const cx = svgLength(props.cx, vbW);
|
|
1699
1716
|
const cy = svgLength(props.cy, vbH);
|
|
1700
1717
|
const r = svgLength(props.r, Math.min(vbW, vbH));
|
|
@@ -1702,9 +1719,9 @@ function drawCircle(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
|
|
|
1702
1719
|
const path = new Path2D();
|
|
1703
1720
|
path.arc(cx, cy, r, 0, Math.PI * 2);
|
|
1704
1721
|
const bbox = { x: cx - r, y: cy - r, width: 2 * r, height: 2 * r };
|
|
1705
|
-
applyFillAndStroke(ctx, props, path,
|
|
1722
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1706
1723
|
}
|
|
1707
|
-
function drawSvgRect(ctx, props,
|
|
1724
|
+
function drawSvgRect(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
|
|
1708
1725
|
const x = svgLength(props.x, vbW);
|
|
1709
1726
|
const y = svgLength(props.y, vbH);
|
|
1710
1727
|
const w = svgLength(props.width, vbW);
|
|
@@ -1723,9 +1740,9 @@ function drawSvgRect(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
|
|
|
1723
1740
|
path.rect(x, y, w, h);
|
|
1724
1741
|
}
|
|
1725
1742
|
const bbox = { x, y, width: w, height: h };
|
|
1726
|
-
applyFillAndStroke(ctx, props, path,
|
|
1743
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1727
1744
|
}
|
|
1728
|
-
function drawLine(ctx, props, color, defs, vbW = 0, vbH = 0) {
|
|
1745
|
+
function drawLine(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
|
|
1729
1746
|
const x1 = svgLength(props.x1, vbW);
|
|
1730
1747
|
const y1 = svgLength(props.y1, vbH);
|
|
1731
1748
|
const x2 = svgLength(props.x2, vbW);
|
|
@@ -1739,9 +1756,9 @@ function drawLine(ctx, props, color, defs, vbW = 0, vbH = 0) {
|
|
|
1739
1756
|
width: Math.abs(x2 - x1),
|
|
1740
1757
|
height: Math.abs(y2 - y1)
|
|
1741
1758
|
};
|
|
1742
|
-
applyStroke(ctx, props, path, color, defs, bbox);
|
|
1759
|
+
applyStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1743
1760
|
}
|
|
1744
|
-
function drawEllipse(ctx, props,
|
|
1761
|
+
function drawEllipse(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
|
|
1745
1762
|
const cx = svgLength(props.cx, vbW);
|
|
1746
1763
|
const cy = svgLength(props.cy, vbH);
|
|
1747
1764
|
const rx = svgLength(props.rx, vbW);
|
|
@@ -1755,9 +1772,9 @@ function drawEllipse(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
|
|
|
1755
1772
|
width: 2 * rx,
|
|
1756
1773
|
height: 2 * ry
|
|
1757
1774
|
};
|
|
1758
|
-
applyFillAndStroke(ctx, props, path,
|
|
1775
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1759
1776
|
}
|
|
1760
|
-
function drawPolygon(ctx, props,
|
|
1777
|
+
function drawPolygon(ctx, props, inherited, color, defs) {
|
|
1761
1778
|
const points = parsePoints(props.points);
|
|
1762
1779
|
if (points.length < 2) return;
|
|
1763
1780
|
const path = new Path2D();
|
|
@@ -1767,9 +1784,9 @@ function drawPolygon(ctx, props, inheritedFill, color, defs) {
|
|
|
1767
1784
|
}
|
|
1768
1785
|
path.closePath();
|
|
1769
1786
|
const bbox = pointsBBox(points);
|
|
1770
|
-
applyFillAndStroke(ctx, props, path,
|
|
1787
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1771
1788
|
}
|
|
1772
|
-
function drawPolyline(ctx, props,
|
|
1789
|
+
function drawPolyline(ctx, props, inherited, color, defs) {
|
|
1773
1790
|
const points = parsePoints(props.points);
|
|
1774
1791
|
if (points.length < 2) return;
|
|
1775
1792
|
const path = new Path2D();
|
|
@@ -1778,7 +1795,7 @@ function drawPolyline(ctx, props, inheritedFill, color, defs) {
|
|
|
1778
1795
|
path.lineTo(points[i][0], points[i][1]);
|
|
1779
1796
|
}
|
|
1780
1797
|
const bbox = pointsBBox(points);
|
|
1781
|
-
applyFillAndStroke(ctx, props, path,
|
|
1798
|
+
applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1782
1799
|
}
|
|
1783
1800
|
function applySvgTransform(ctx, transform) {
|
|
1784
1801
|
const re = /\b(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)/g;
|
|
@@ -1841,22 +1858,31 @@ function applySvgTransform(ctx, transform) {
|
|
|
1841
1858
|
}
|
|
1842
1859
|
}
|
|
1843
1860
|
}
|
|
1844
|
-
function drawGroup(ctx, node,
|
|
1861
|
+
function drawGroup(ctx, node, inherited, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
|
|
1845
1862
|
const children = normalizeChildren(node);
|
|
1846
1863
|
if (children.length === 0) return;
|
|
1847
1864
|
const merged = mergeStyleIntoProps(node.props);
|
|
1848
|
-
const
|
|
1865
|
+
const groupInherited = {
|
|
1866
|
+
fill: resolveCurrentColor(merged.fill, color) ?? inherited.fill,
|
|
1867
|
+
stroke: resolveCurrentColor(merged.stroke, color) ?? inherited.stroke,
|
|
1868
|
+
strokeWidth: merged.strokeWidth ?? merged["stroke-width"] ?? inherited.strokeWidth,
|
|
1869
|
+
strokeLinecap: merged.strokeLinecap ?? merged["stroke-linecap"] ?? inherited.strokeLinecap,
|
|
1870
|
+
strokeLinejoin: merged.strokeLinejoin ?? merged["stroke-linejoin"] ?? inherited.strokeLinejoin,
|
|
1871
|
+
strokeOpacity: merged.strokeOpacity ?? merged["stroke-opacity"] ?? inherited.strokeOpacity
|
|
1872
|
+
};
|
|
1873
|
+
const opacity = Number(merged.opacity ?? 1);
|
|
1849
1874
|
const transform = merged.transform;
|
|
1850
|
-
if (transform) {
|
|
1875
|
+
if (transform || opacity < 1) {
|
|
1851
1876
|
ctx.save();
|
|
1852
|
-
applySvgTransform(ctx, transform);
|
|
1877
|
+
if (transform) applySvgTransform(ctx, transform);
|
|
1878
|
+
if (opacity < 1) ctx.globalAlpha *= opacity;
|
|
1853
1879
|
}
|
|
1854
1880
|
for (const child of children) {
|
|
1855
1881
|
if (child != null && typeof child === "object") {
|
|
1856
|
-
drawSvgChild(ctx, child,
|
|
1882
|
+
drawSvgChild(ctx, child, groupInherited, color, defs, vbW, vbH);
|
|
1857
1883
|
}
|
|
1858
1884
|
}
|
|
1859
|
-
if (transform) {
|
|
1885
|
+
if (transform || opacity < 1) {
|
|
1860
1886
|
ctx.restore();
|
|
1861
1887
|
}
|
|
1862
1888
|
}
|
|
@@ -1869,8 +1895,8 @@ function parsePoints(value) {
|
|
|
1869
1895
|
}
|
|
1870
1896
|
return result;
|
|
1871
1897
|
}
|
|
1872
|
-
function applyFillAndStroke(ctx, props, path,
|
|
1873
|
-
const fill = resolveCurrentColor(props.fill, color) ??
|
|
1898
|
+
function applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox) {
|
|
1899
|
+
const fill = resolveCurrentColor(props.fill, color) ?? inherited.fill;
|
|
1874
1900
|
const fillRule = props.fillRule ?? props["fill-rule"];
|
|
1875
1901
|
const fillOpacity = Number(props.fillOpacity ?? props["fill-opacity"] ?? 1);
|
|
1876
1902
|
const fillRef = parseUrlRef(fill);
|
|
@@ -1902,17 +1928,19 @@ function applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox)
|
|
|
1902
1928
|
ctx.fillStyle = applyOpacity(fill, fillOpacity);
|
|
1903
1929
|
ctx.fill(path, fillRule ?? "nonzero");
|
|
1904
1930
|
}
|
|
1905
|
-
applyStroke(ctx, props, path, color, defs, bbox);
|
|
1931
|
+
applyStroke(ctx, props, path, inherited, color, defs, bbox);
|
|
1906
1932
|
}
|
|
1907
|
-
function applyStroke(ctx, props, path, color, defs, bbox) {
|
|
1908
|
-
const stroke = resolveCurrentColor(props.stroke, color);
|
|
1933
|
+
function applyStroke(ctx, props, path, inherited, color, defs, bbox) {
|
|
1934
|
+
const stroke = resolveCurrentColor(props.stroke, color) ?? inherited.stroke;
|
|
1909
1935
|
if (!stroke || stroke === "none") return;
|
|
1910
1936
|
const strokeOpacity = Number(
|
|
1911
|
-
props.strokeOpacity ?? props["stroke-opacity"] ?? 1
|
|
1937
|
+
props.strokeOpacity ?? props["stroke-opacity"] ?? inherited.strokeOpacity ?? 1
|
|
1912
1938
|
);
|
|
1913
|
-
ctx.lineWidth = Number(
|
|
1914
|
-
|
|
1915
|
-
|
|
1939
|
+
ctx.lineWidth = Number(
|
|
1940
|
+
props.strokeWidth ?? props["stroke-width"] ?? inherited.strokeWidth ?? 1
|
|
1941
|
+
);
|
|
1942
|
+
ctx.lineCap = props.strokeLinecap ?? props["stroke-linecap"] ?? inherited.strokeLinecap ?? "butt";
|
|
1943
|
+
ctx.lineJoin = props.strokeLinejoin ?? props["stroke-linejoin"] ?? inherited.strokeLinejoin ?? "miter";
|
|
1916
1944
|
const strokeRef = parseUrlRef(stroke);
|
|
1917
1945
|
if (strokeRef) {
|
|
1918
1946
|
const gradientDef = defs.gradients.get(strokeRef);
|
|
@@ -3194,11 +3222,21 @@ async function buildNode(element, parentStyle, yogaNode, viewportWidth, viewport
|
|
|
3194
3222
|
if (tagName === "svg") {
|
|
3195
3223
|
if (props.width != null && style.width === void 0) {
|
|
3196
3224
|
const v = props.width;
|
|
3197
|
-
|
|
3225
|
+
if (typeof v === "string") {
|
|
3226
|
+
const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);
|
|
3227
|
+
style.width = typeof resolved === "string" && resolved.endsWith("%") ? resolved : Number(resolved);
|
|
3228
|
+
} else {
|
|
3229
|
+
style.width = Number(v);
|
|
3230
|
+
}
|
|
3198
3231
|
}
|
|
3199
3232
|
if (props.height != null && style.height === void 0) {
|
|
3200
3233
|
const v = props.height;
|
|
3201
|
-
|
|
3234
|
+
if (typeof v === "string") {
|
|
3235
|
+
const resolved = resolveUnit(v, viewportWidth, viewportHeight, 16, 16);
|
|
3236
|
+
style.height = typeof resolved === "string" && resolved.endsWith("%") ? resolved : Number(resolved);
|
|
3237
|
+
} else {
|
|
3238
|
+
style.height = Number(v);
|
|
3239
|
+
}
|
|
3202
3240
|
}
|
|
3203
3241
|
const viewBox = props.viewBox;
|
|
3204
3242
|
if (viewBox) {
|