@spectratools/graphic-designer-cli 0.6.0 → 0.7.1
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/cli.js +242 -31
- package/dist/index.d.ts +15 -5
- package/dist/index.js +242 -31
- package/dist/qa.d.ts +1 -1
- package/dist/qa.js +48 -10
- package/dist/renderer.d.ts +1 -1
- package/dist/renderer.js +242 -31
- package/dist/{spec.schema-Dm_wOLTd.d.ts → spec.schema-BDvtn_mJ.d.ts} +1456 -21
- package/dist/spec.schema.d.ts +1 -1
- package/dist/spec.schema.js +48 -10
- package/package.json +1 -1
package/dist/renderer.js
CHANGED
|
@@ -1151,12 +1151,12 @@ function withAlpha2(color, alpha) {
|
|
|
1151
1151
|
}
|
|
1152
1152
|
function drawGradientRect(ctx, rect, gradient, borderRadius = 0) {
|
|
1153
1153
|
const fill = gradient.type === "linear" ? createLinearRectGradient(ctx, rect, gradient.angle ?? 180) : ctx.createRadialGradient(
|
|
1154
|
-
rect.x + rect.width / 2,
|
|
1155
|
-
rect.y + rect.height / 2,
|
|
1156
|
-
0,
|
|
1157
|
-
rect.x + rect.width / 2,
|
|
1158
|
-
rect.y + rect.height / 2,
|
|
1159
|
-
Math.max(rect.width, rect.height) / 2
|
|
1154
|
+
gradient.cx ?? rect.x + rect.width / 2,
|
|
1155
|
+
gradient.cy ?? rect.y + rect.height / 2,
|
|
1156
|
+
gradient.innerRadius ?? 0,
|
|
1157
|
+
gradient.cx ?? rect.x + rect.width / 2,
|
|
1158
|
+
gradient.cy ?? rect.y + rect.height / 2,
|
|
1159
|
+
gradient.outerRadius ?? Math.max(rect.width, rect.height) / 2
|
|
1160
1160
|
);
|
|
1161
1161
|
addGradientStops(fill, gradient.stops);
|
|
1162
1162
|
ctx.save();
|
|
@@ -2009,21 +2009,61 @@ function edgeAnchor(bounds, target) {
|
|
|
2009
2009
|
const t = absDx * hh > absDy * hw ? hw / absDx : hh / absDy;
|
|
2010
2010
|
return { x: c.x + dx * t, y: c.y + dy * t };
|
|
2011
2011
|
}
|
|
2012
|
+
function resolveAnchor(bounds, anchor, fallbackTarget) {
|
|
2013
|
+
if (!anchor) return edgeAnchor(bounds, fallbackTarget);
|
|
2014
|
+
if (typeof anchor === "string") {
|
|
2015
|
+
const c2 = rectCenter(bounds);
|
|
2016
|
+
switch (anchor) {
|
|
2017
|
+
case "top":
|
|
2018
|
+
return { x: c2.x, y: bounds.y };
|
|
2019
|
+
case "bottom":
|
|
2020
|
+
return { x: c2.x, y: bounds.y + bounds.height };
|
|
2021
|
+
case "left":
|
|
2022
|
+
return { x: bounds.x, y: c2.y };
|
|
2023
|
+
case "right":
|
|
2024
|
+
return { x: bounds.x + bounds.width, y: c2.y };
|
|
2025
|
+
case "center":
|
|
2026
|
+
return c2;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
const c = rectCenter(bounds);
|
|
2030
|
+
return {
|
|
2031
|
+
x: c.x + anchor.x * (bounds.width / 2),
|
|
2032
|
+
y: c.y + anchor.y * (bounds.height / 2)
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
function anchorNormal(anchor, point, diagramCenter) {
|
|
2036
|
+
if (typeof anchor === "string") {
|
|
2037
|
+
switch (anchor) {
|
|
2038
|
+
case "top":
|
|
2039
|
+
return { x: 0, y: -1 };
|
|
2040
|
+
case "bottom":
|
|
2041
|
+
return { x: 0, y: 1 };
|
|
2042
|
+
case "left":
|
|
2043
|
+
return { x: -1, y: 0 };
|
|
2044
|
+
case "right":
|
|
2045
|
+
return { x: 1, y: 0 };
|
|
2046
|
+
case "center":
|
|
2047
|
+
return outwardNormal(point, diagramCenter);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
return outwardNormal(point, diagramCenter);
|
|
2051
|
+
}
|
|
2012
2052
|
function outwardNormal(point, diagramCenter) {
|
|
2013
2053
|
const dx = point.x - diagramCenter.x;
|
|
2014
2054
|
const dy = point.y - diagramCenter.y;
|
|
2015
2055
|
const len = Math.hypot(dx, dy) || 1;
|
|
2016
2056
|
return { x: dx / len, y: dy / len };
|
|
2017
2057
|
}
|
|
2018
|
-
function curveRoute(fromBounds, toBounds, diagramCenter, tension) {
|
|
2058
|
+
function curveRoute(fromBounds, toBounds, diagramCenter, tension, fromAnchor, toAnchor) {
|
|
2019
2059
|
const fromCenter = rectCenter(fromBounds);
|
|
2020
2060
|
const toCenter = rectCenter(toBounds);
|
|
2021
|
-
const p0 =
|
|
2022
|
-
const p3 =
|
|
2061
|
+
const p0 = resolveAnchor(fromBounds, fromAnchor, toCenter);
|
|
2062
|
+
const p3 = resolveAnchor(toBounds, toAnchor, fromCenter);
|
|
2023
2063
|
const dist = Math.hypot(p3.x - p0.x, p3.y - p0.y);
|
|
2024
2064
|
const offset = dist * tension;
|
|
2025
|
-
const n0 =
|
|
2026
|
-
const n3 =
|
|
2065
|
+
const n0 = anchorNormal(fromAnchor, p0, diagramCenter);
|
|
2066
|
+
const n3 = anchorNormal(toAnchor, p3, diagramCenter);
|
|
2027
2067
|
const cp1 = { x: p0.x + n0.x * offset, y: p0.y + n0.y * offset };
|
|
2028
2068
|
const cp2 = { x: p3.x + n3.x * offset, y: p3.y + n3.y * offset };
|
|
2029
2069
|
return [p0, cp1, cp2, p3];
|
|
@@ -2037,11 +2077,11 @@ function localToWorld(origin, axisX, axisY, local) {
|
|
|
2037
2077
|
y: origin.y + axisX.y * local.x + axisY.y * local.y
|
|
2038
2078
|
};
|
|
2039
2079
|
}
|
|
2040
|
-
function arcRoute(fromBounds, toBounds, diagramCenter, tension) {
|
|
2080
|
+
function arcRoute(fromBounds, toBounds, diagramCenter, tension, fromAnchor, toAnchor) {
|
|
2041
2081
|
const fromCenter = rectCenter(fromBounds);
|
|
2042
2082
|
const toCenter = rectCenter(toBounds);
|
|
2043
|
-
const start =
|
|
2044
|
-
const end =
|
|
2083
|
+
const start = resolveAnchor(fromBounds, fromAnchor, toCenter);
|
|
2084
|
+
const end = resolveAnchor(toBounds, toAnchor, fromCenter);
|
|
2045
2085
|
const chord = { x: end.x - start.x, y: end.y - start.y };
|
|
2046
2086
|
const chordLength = Math.hypot(chord.x, chord.y);
|
|
2047
2087
|
if (chordLength < 1e-6) {
|
|
@@ -2079,11 +2119,11 @@ function arcRoute(fromBounds, toBounds, diagramCenter, tension) {
|
|
|
2079
2119
|
[pMid, cp3, cp4, p3]
|
|
2080
2120
|
];
|
|
2081
2121
|
}
|
|
2082
|
-
function orthogonalRoute(fromBounds, toBounds) {
|
|
2122
|
+
function orthogonalRoute(fromBounds, toBounds, fromAnchor, toAnchor) {
|
|
2083
2123
|
const fromC = rectCenter(fromBounds);
|
|
2084
2124
|
const toC = rectCenter(toBounds);
|
|
2085
|
-
const p0 =
|
|
2086
|
-
const p3 =
|
|
2125
|
+
const p0 = resolveAnchor(fromBounds, fromAnchor, toC);
|
|
2126
|
+
const p3 = resolveAnchor(toBounds, toAnchor, fromC);
|
|
2087
2127
|
const midX = (p0.x + p3.x) / 2;
|
|
2088
2128
|
return [p0, { x: midX, y: p0.y }, { x: midX, y: p3.y }, p3];
|
|
2089
2129
|
}
|
|
@@ -2094,6 +2134,35 @@ function bezierPointAt(p0, cp1, cp2, p3, t) {
|
|
|
2094
2134
|
y: mt * mt * mt * p0.y + 3 * mt * mt * t * cp1.y + 3 * mt * t * t * cp2.y + t * t * t * p3.y
|
|
2095
2135
|
};
|
|
2096
2136
|
}
|
|
2137
|
+
function bezierTangentAt(p0, cp1, cp2, p3, t) {
|
|
2138
|
+
const mt = 1 - t;
|
|
2139
|
+
return {
|
|
2140
|
+
x: 3 * mt * mt * (cp1.x - p0.x) + 6 * mt * t * (cp2.x - cp1.x) + 3 * t * t * (p3.x - cp2.x),
|
|
2141
|
+
y: 3 * mt * mt * (cp1.y - p0.y) + 6 * mt * t * (cp2.y - cp1.y) + 3 * t * t * (p3.y - cp2.y)
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
function isInsideRect(point, rect) {
|
|
2145
|
+
return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height;
|
|
2146
|
+
}
|
|
2147
|
+
function findBoundaryIntersection(p0, cp1, cp2, p3, targetRect, searchFromEnd) {
|
|
2148
|
+
const step = 5e-3;
|
|
2149
|
+
if (searchFromEnd) {
|
|
2150
|
+
for (let t = 0.95; t >= 0.5; t -= step) {
|
|
2151
|
+
const pt = bezierPointAt(p0, cp1, cp2, p3, t);
|
|
2152
|
+
if (!isInsideRect(pt, targetRect)) {
|
|
2153
|
+
return t;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
} else {
|
|
2157
|
+
for (let t = 0.05; t <= 0.5; t += step) {
|
|
2158
|
+
const pt = bezierPointAt(p0, cp1, cp2, p3, t);
|
|
2159
|
+
if (!isInsideRect(pt, targetRect)) {
|
|
2160
|
+
return t;
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
return void 0;
|
|
2165
|
+
}
|
|
2097
2166
|
function pointAlongArc(route, t) {
|
|
2098
2167
|
const [first, second] = route;
|
|
2099
2168
|
if (t <= 0.5) {
|
|
@@ -2221,8 +2290,16 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
2221
2290
|
let labelPoint;
|
|
2222
2291
|
ctx.save();
|
|
2223
2292
|
ctx.globalAlpha = conn.opacity;
|
|
2293
|
+
const arrowPlacement = conn.arrowPlacement ?? "endpoint";
|
|
2224
2294
|
if (routing === "curve") {
|
|
2225
|
-
const [p0, cp1, cp2, p3] = curveRoute(
|
|
2295
|
+
const [p0, cp1, cp2, p3] = curveRoute(
|
|
2296
|
+
fromBounds,
|
|
2297
|
+
toBounds,
|
|
2298
|
+
diagramCenter,
|
|
2299
|
+
tension,
|
|
2300
|
+
conn.fromAnchor,
|
|
2301
|
+
conn.toAnchor
|
|
2302
|
+
);
|
|
2226
2303
|
ctx.strokeStyle = style.color;
|
|
2227
2304
|
ctx.lineWidth = style.width;
|
|
2228
2305
|
ctx.setLineDash(style.dash ?? []);
|
|
@@ -2236,8 +2313,33 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
2236
2313
|
startAngle = Math.atan2(p0.y - cp1.y, p0.x - cp1.x);
|
|
2237
2314
|
endAngle = Math.atan2(p3.y - cp2.y, p3.x - cp2.x);
|
|
2238
2315
|
labelPoint = bezierPointAt(p0, cp1, cp2, p3, labelT);
|
|
2316
|
+
if (arrowPlacement === "boundary") {
|
|
2317
|
+
if (conn.arrow === "end" || conn.arrow === "both") {
|
|
2318
|
+
const tEnd = findBoundaryIntersection(p0, cp1, cp2, p3, toBounds, true);
|
|
2319
|
+
if (tEnd !== void 0) {
|
|
2320
|
+
endPoint = bezierPointAt(p0, cp1, cp2, p3, tEnd);
|
|
2321
|
+
const tangent = bezierTangentAt(p0, cp1, cp2, p3, tEnd);
|
|
2322
|
+
endAngle = Math.atan2(tangent.y, tangent.x);
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
if (conn.arrow === "start" || conn.arrow === "both") {
|
|
2326
|
+
const tStart = findBoundaryIntersection(p0, cp1, cp2, p3, fromBounds, false);
|
|
2327
|
+
if (tStart !== void 0) {
|
|
2328
|
+
startPoint = bezierPointAt(p0, cp1, cp2, p3, tStart);
|
|
2329
|
+
const tangent = bezierTangentAt(p0, cp1, cp2, p3, tStart);
|
|
2330
|
+
startAngle = Math.atan2(tangent.y, tangent.x) + Math.PI;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2239
2334
|
} else if (routing === "arc") {
|
|
2240
|
-
const [first, second] = arcRoute(
|
|
2335
|
+
const [first, second] = arcRoute(
|
|
2336
|
+
fromBounds,
|
|
2337
|
+
toBounds,
|
|
2338
|
+
diagramCenter,
|
|
2339
|
+
tension,
|
|
2340
|
+
conn.fromAnchor,
|
|
2341
|
+
conn.toAnchor
|
|
2342
|
+
);
|
|
2241
2343
|
const [p0, cp1, cp2, pMid] = first;
|
|
2242
2344
|
const [, cp3, cp4, p3] = second;
|
|
2243
2345
|
ctx.strokeStyle = style.color;
|
|
@@ -2254,9 +2356,29 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
2254
2356
|
startAngle = Math.atan2(p0.y - cp1.y, p0.x - cp1.x);
|
|
2255
2357
|
endAngle = Math.atan2(p3.y - cp4.y, p3.x - cp4.x);
|
|
2256
2358
|
labelPoint = pointAlongArc([first, second], labelT);
|
|
2359
|
+
if (arrowPlacement === "boundary") {
|
|
2360
|
+
if (conn.arrow === "end" || conn.arrow === "both") {
|
|
2361
|
+
const [, s_cp3, s_cp4, s_p3] = second;
|
|
2362
|
+
const tEnd = findBoundaryIntersection(pMid, s_cp3, s_cp4, s_p3, toBounds, true);
|
|
2363
|
+
if (tEnd !== void 0) {
|
|
2364
|
+
endPoint = bezierPointAt(pMid, s_cp3, s_cp4, s_p3, tEnd);
|
|
2365
|
+
const tangent = bezierTangentAt(pMid, s_cp3, s_cp4, s_p3, tEnd);
|
|
2366
|
+
endAngle = Math.atan2(tangent.y, tangent.x);
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
if (conn.arrow === "start" || conn.arrow === "both") {
|
|
2370
|
+
const tStart = findBoundaryIntersection(p0, cp1, cp2, pMid, fromBounds, false);
|
|
2371
|
+
if (tStart !== void 0) {
|
|
2372
|
+
startPoint = bezierPointAt(p0, cp1, cp2, pMid, tStart);
|
|
2373
|
+
const tangent = bezierTangentAt(p0, cp1, cp2, pMid, tStart);
|
|
2374
|
+
startAngle = Math.atan2(tangent.y, tangent.x) + Math.PI;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2257
2378
|
} else {
|
|
2258
|
-
const
|
|
2259
|
-
|
|
2379
|
+
const hasAnchorHints = conn.fromAnchor !== void 0 || conn.toAnchor !== void 0;
|
|
2380
|
+
const useElkRoute = routing === "auto" && !hasAnchorHints && (edgeRoute?.points.length ?? 0) >= 2;
|
|
2381
|
+
linePoints = useElkRoute ? edgeRoute?.points ?? orthogonalRoute(fromBounds, toBounds, conn.fromAnchor, conn.toAnchor) : orthogonalRoute(fromBounds, toBounds, conn.fromAnchor, conn.toAnchor);
|
|
2260
2382
|
startPoint = linePoints[0];
|
|
2261
2383
|
const startSegment = linePoints[1] ?? linePoints[0];
|
|
2262
2384
|
const endStart = linePoints[linePoints.length - 2] ?? linePoints[0];
|
|
@@ -2488,6 +2610,13 @@ function expandRect(rect, amount) {
|
|
|
2488
2610
|
height: rect.height + amount * 2
|
|
2489
2611
|
};
|
|
2490
2612
|
}
|
|
2613
|
+
function applyDrawShadow(ctx, shadow) {
|
|
2614
|
+
if (!shadow) return;
|
|
2615
|
+
ctx.shadowColor = shadow.color;
|
|
2616
|
+
ctx.shadowBlur = shadow.blur;
|
|
2617
|
+
ctx.shadowOffsetX = shadow.offsetX;
|
|
2618
|
+
ctx.shadowOffsetY = shadow.offsetY;
|
|
2619
|
+
}
|
|
2491
2620
|
function fromPoints(points) {
|
|
2492
2621
|
const minX = Math.min(...points.map((point) => point.x));
|
|
2493
2622
|
const minY = Math.min(...points.map((point) => point.y));
|
|
@@ -2669,6 +2798,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2669
2798
|
height: command.height
|
|
2670
2799
|
};
|
|
2671
2800
|
withOpacity(ctx, command.opacity, () => {
|
|
2801
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2672
2802
|
roundRectPath(ctx, rect, command.radius);
|
|
2673
2803
|
if (command.fill) {
|
|
2674
2804
|
ctx.fillStyle = command.fill;
|
|
@@ -2692,6 +2822,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2692
2822
|
}
|
|
2693
2823
|
case "circle": {
|
|
2694
2824
|
withOpacity(ctx, command.opacity, () => {
|
|
2825
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2695
2826
|
ctx.beginPath();
|
|
2696
2827
|
ctx.arc(command.cx, command.cy, command.radius, 0, Math.PI * 2);
|
|
2697
2828
|
ctx.closePath();
|
|
@@ -2726,6 +2857,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2726
2857
|
case "text": {
|
|
2727
2858
|
const fontFamily = resolveDrawFont(theme, command.fontFamily);
|
|
2728
2859
|
withOpacity(ctx, command.opacity, () => {
|
|
2860
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2729
2861
|
applyFont(ctx, {
|
|
2730
2862
|
size: command.fontSize,
|
|
2731
2863
|
weight: command.fontWeight,
|
|
@@ -2776,6 +2908,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2776
2908
|
const to = { x: command.x2, y: command.y2 };
|
|
2777
2909
|
const lineAngle = angleBetween(from, to);
|
|
2778
2910
|
withOpacity(ctx, command.opacity, () => {
|
|
2911
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2779
2912
|
drawLine(ctx, from, to, {
|
|
2780
2913
|
color: command.color,
|
|
2781
2914
|
width: command.width,
|
|
@@ -2800,6 +2933,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2800
2933
|
case "bezier": {
|
|
2801
2934
|
const points = command.points;
|
|
2802
2935
|
withOpacity(ctx, command.opacity, () => {
|
|
2936
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2803
2937
|
drawBezier(ctx, points, {
|
|
2804
2938
|
color: command.color,
|
|
2805
2939
|
width: command.width,
|
|
@@ -2833,6 +2967,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2833
2967
|
const operations = parseSvgPath(command.d);
|
|
2834
2968
|
const baseBounds = pathBounds(operations);
|
|
2835
2969
|
withOpacity(ctx, command.opacity, () => {
|
|
2970
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2836
2971
|
applySvgOperations(ctx, operations);
|
|
2837
2972
|
if (command.fill) {
|
|
2838
2973
|
ctx.fillStyle = command.fill;
|
|
@@ -2873,9 +3008,16 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2873
3008
|
height: textHeight + command.paddingY * 2
|
|
2874
3009
|
};
|
|
2875
3010
|
withOpacity(ctx, command.opacity, () => {
|
|
3011
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2876
3012
|
roundRectPath(ctx, rect, command.borderRadius);
|
|
2877
3013
|
ctx.fillStyle = command.background;
|
|
2878
3014
|
ctx.fill();
|
|
3015
|
+
if (command.shadow) {
|
|
3016
|
+
ctx.shadowColor = "transparent";
|
|
3017
|
+
ctx.shadowBlur = 0;
|
|
3018
|
+
ctx.shadowOffsetX = 0;
|
|
3019
|
+
ctx.shadowOffsetY = 0;
|
|
3020
|
+
}
|
|
2879
3021
|
applyFont(ctx, {
|
|
2880
3022
|
size: command.fontSize,
|
|
2881
3023
|
weight: 600,
|
|
@@ -2903,6 +3045,7 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2903
3045
|
height: command.height
|
|
2904
3046
|
};
|
|
2905
3047
|
withOpacity(ctx, command.opacity, () => {
|
|
3048
|
+
applyDrawShadow(ctx, command.shadow);
|
|
2906
3049
|
drawGradientRect(ctx, rect, command.gradient, command.radius);
|
|
2907
3050
|
});
|
|
2908
3051
|
rendered.push({
|
|
@@ -2913,6 +3056,36 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
2913
3056
|
});
|
|
2914
3057
|
break;
|
|
2915
3058
|
}
|
|
3059
|
+
case "grid": {
|
|
3060
|
+
const canvasWidth = ctx.canvas.width;
|
|
3061
|
+
const canvasHeight = ctx.canvas.height;
|
|
3062
|
+
withOpacity(ctx, command.opacity, () => {
|
|
3063
|
+
ctx.strokeStyle = command.color;
|
|
3064
|
+
ctx.lineWidth = command.width;
|
|
3065
|
+
const startX = command.offsetX % command.spacing;
|
|
3066
|
+
for (let x = startX; x <= canvasWidth; x += command.spacing) {
|
|
3067
|
+
ctx.beginPath();
|
|
3068
|
+
ctx.moveTo(x, 0);
|
|
3069
|
+
ctx.lineTo(x, canvasHeight);
|
|
3070
|
+
ctx.stroke();
|
|
3071
|
+
}
|
|
3072
|
+
const startY = command.offsetY % command.spacing;
|
|
3073
|
+
for (let y = startY; y <= canvasHeight; y += command.spacing) {
|
|
3074
|
+
ctx.beginPath();
|
|
3075
|
+
ctx.moveTo(0, y);
|
|
3076
|
+
ctx.lineTo(canvasWidth, y);
|
|
3077
|
+
ctx.stroke();
|
|
3078
|
+
}
|
|
3079
|
+
});
|
|
3080
|
+
rendered.push({
|
|
3081
|
+
id,
|
|
3082
|
+
kind: "draw",
|
|
3083
|
+
bounds: { x: 0, y: 0, width: canvasWidth, height: canvasHeight },
|
|
3084
|
+
foregroundColor: command.color,
|
|
3085
|
+
allowOverlap: true
|
|
3086
|
+
});
|
|
3087
|
+
break;
|
|
3088
|
+
}
|
|
2916
3089
|
}
|
|
2917
3090
|
}
|
|
2918
3091
|
return rendered;
|
|
@@ -3194,9 +3367,19 @@ var linearGradientSchema = z2.object({
|
|
|
3194
3367
|
}).strict();
|
|
3195
3368
|
var radialGradientSchema = z2.object({
|
|
3196
3369
|
type: z2.literal("radial"),
|
|
3370
|
+
cx: z2.number().optional(),
|
|
3371
|
+
cy: z2.number().optional(),
|
|
3372
|
+
innerRadius: z2.number().min(0).optional(),
|
|
3373
|
+
outerRadius: z2.number().min(0).optional(),
|
|
3197
3374
|
stops: z2.array(gradientStopSchema).min(2)
|
|
3198
3375
|
}).strict();
|
|
3199
3376
|
var gradientSchema = z2.discriminatedUnion("type", [linearGradientSchema, radialGradientSchema]);
|
|
3377
|
+
var drawShadowSchema = z2.object({
|
|
3378
|
+
color: colorHexSchema2.default("rgba(0,0,0,0.5)"),
|
|
3379
|
+
blur: z2.number().min(0).max(64).default(10),
|
|
3380
|
+
offsetX: z2.number().default(0),
|
|
3381
|
+
offsetY: z2.number().default(4)
|
|
3382
|
+
}).strict();
|
|
3200
3383
|
var drawFontFamilySchema = z2.enum(["heading", "body", "mono"]);
|
|
3201
3384
|
var drawRectSchema = z2.object({
|
|
3202
3385
|
type: z2.literal("rect"),
|
|
@@ -3208,7 +3391,8 @@ var drawRectSchema = z2.object({
|
|
|
3208
3391
|
stroke: colorHexSchema2.optional(),
|
|
3209
3392
|
strokeWidth: z2.number().min(0).max(32).default(0),
|
|
3210
3393
|
radius: z2.number().min(0).max(256).default(0),
|
|
3211
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3394
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3395
|
+
shadow: drawShadowSchema.optional()
|
|
3212
3396
|
}).strict();
|
|
3213
3397
|
var drawCircleSchema = z2.object({
|
|
3214
3398
|
type: z2.literal("circle"),
|
|
@@ -3218,7 +3402,8 @@ var drawCircleSchema = z2.object({
|
|
|
3218
3402
|
fill: colorHexSchema2.optional(),
|
|
3219
3403
|
stroke: colorHexSchema2.optional(),
|
|
3220
3404
|
strokeWidth: z2.number().min(0).max(32).default(0),
|
|
3221
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3405
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3406
|
+
shadow: drawShadowSchema.optional()
|
|
3222
3407
|
}).strict();
|
|
3223
3408
|
var drawTextSchema = z2.object({
|
|
3224
3409
|
type: z2.literal("text"),
|
|
@@ -3233,7 +3418,8 @@ var drawTextSchema = z2.object({
|
|
|
3233
3418
|
baseline: z2.enum(["top", "middle", "alphabetic", "bottom"]).default("alphabetic"),
|
|
3234
3419
|
letterSpacing: z2.number().min(-10).max(50).default(0),
|
|
3235
3420
|
maxWidth: z2.number().positive().optional(),
|
|
3236
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3421
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3422
|
+
shadow: drawShadowSchema.optional()
|
|
3237
3423
|
}).strict();
|
|
3238
3424
|
var drawLineSchema = z2.object({
|
|
3239
3425
|
type: z2.literal("line"),
|
|
@@ -3246,7 +3432,8 @@ var drawLineSchema = z2.object({
|
|
|
3246
3432
|
dash: z2.array(z2.number()).max(6).optional(),
|
|
3247
3433
|
arrow: z2.enum(["none", "end", "start", "both"]).default("none"),
|
|
3248
3434
|
arrowSize: z2.number().min(4).max(32).default(10),
|
|
3249
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3435
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3436
|
+
shadow: drawShadowSchema.optional()
|
|
3250
3437
|
}).strict();
|
|
3251
3438
|
var drawPointSchema = z2.object({
|
|
3252
3439
|
x: z2.number(),
|
|
@@ -3260,7 +3447,8 @@ var drawBezierSchema = z2.object({
|
|
|
3260
3447
|
dash: z2.array(z2.number()).max(6).optional(),
|
|
3261
3448
|
arrow: z2.enum(["none", "end", "start", "both"]).default("none"),
|
|
3262
3449
|
arrowSize: z2.number().min(4).max(32).default(10),
|
|
3263
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3450
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3451
|
+
shadow: drawShadowSchema.optional()
|
|
3264
3452
|
}).strict();
|
|
3265
3453
|
var drawPathSchema = z2.object({
|
|
3266
3454
|
type: z2.literal("path"),
|
|
@@ -3268,7 +3456,8 @@ var drawPathSchema = z2.object({
|
|
|
3268
3456
|
fill: colorHexSchema2.optional(),
|
|
3269
3457
|
stroke: colorHexSchema2.optional(),
|
|
3270
3458
|
strokeWidth: z2.number().min(0).max(32).default(0),
|
|
3271
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3459
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3460
|
+
shadow: drawShadowSchema.optional()
|
|
3272
3461
|
}).strict();
|
|
3273
3462
|
var drawBadgeSchema = z2.object({
|
|
3274
3463
|
type: z2.literal("badge"),
|
|
@@ -3282,7 +3471,8 @@ var drawBadgeSchema = z2.object({
|
|
|
3282
3471
|
paddingX: z2.number().min(0).max(64).default(10),
|
|
3283
3472
|
paddingY: z2.number().min(0).max(32).default(4),
|
|
3284
3473
|
borderRadius: z2.number().min(0).max(64).default(12),
|
|
3285
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3474
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3475
|
+
shadow: drawShadowSchema.optional()
|
|
3286
3476
|
}).strict();
|
|
3287
3477
|
var drawGradientRectSchema = z2.object({
|
|
3288
3478
|
type: z2.literal("gradient-rect"),
|
|
@@ -3292,7 +3482,17 @@ var drawGradientRectSchema = z2.object({
|
|
|
3292
3482
|
height: z2.number().positive(),
|
|
3293
3483
|
gradient: gradientSchema,
|
|
3294
3484
|
radius: z2.number().min(0).max(256).default(0),
|
|
3295
|
-
opacity: z2.number().min(0).max(1).default(1)
|
|
3485
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
3486
|
+
shadow: drawShadowSchema.optional()
|
|
3487
|
+
}).strict();
|
|
3488
|
+
var drawGridSchema = z2.object({
|
|
3489
|
+
type: z2.literal("grid"),
|
|
3490
|
+
spacing: z2.number().min(5).max(200).default(40),
|
|
3491
|
+
color: colorHexSchema2.default("#1E2D4A"),
|
|
3492
|
+
width: z2.number().min(0.1).max(4).default(0.5),
|
|
3493
|
+
opacity: z2.number().min(0).max(1).default(0.2),
|
|
3494
|
+
offsetX: z2.number().default(0),
|
|
3495
|
+
offsetY: z2.number().default(0)
|
|
3296
3496
|
}).strict();
|
|
3297
3497
|
var drawCommandSchema = z2.discriminatedUnion("type", [
|
|
3298
3498
|
drawRectSchema,
|
|
@@ -3302,7 +3502,8 @@ var drawCommandSchema = z2.discriminatedUnion("type", [
|
|
|
3302
3502
|
drawBezierSchema,
|
|
3303
3503
|
drawPathSchema,
|
|
3304
3504
|
drawBadgeSchema,
|
|
3305
|
-
drawGradientRectSchema
|
|
3505
|
+
drawGradientRectSchema,
|
|
3506
|
+
drawGridSchema
|
|
3306
3507
|
]);
|
|
3307
3508
|
var defaultCanvas = {
|
|
3308
3509
|
width: 1200,
|
|
@@ -3408,6 +3609,13 @@ var flowNodeElementSchema = z2.object({
|
|
|
3408
3609
|
badgePosition: z2.enum(["top", "inside-top"]).default("inside-top"),
|
|
3409
3610
|
shadow: flowNodeShadowSchema.optional()
|
|
3410
3611
|
}).strict();
|
|
3612
|
+
var anchorHintSchema = z2.union([
|
|
3613
|
+
z2.enum(["top", "bottom", "left", "right", "center"]),
|
|
3614
|
+
z2.object({
|
|
3615
|
+
x: z2.number().min(-1).max(1),
|
|
3616
|
+
y: z2.number().min(-1).max(1)
|
|
3617
|
+
}).strict()
|
|
3618
|
+
]);
|
|
3411
3619
|
var connectionElementSchema = z2.object({
|
|
3412
3620
|
type: z2.literal("connection"),
|
|
3413
3621
|
from: z2.string().min(1).max(120),
|
|
@@ -3421,9 +3629,12 @@ var connectionElementSchema = z2.object({
|
|
|
3421
3629
|
width: z2.number().min(0.5).max(10).optional(),
|
|
3422
3630
|
strokeWidth: z2.number().min(0.5).max(10).default(2),
|
|
3423
3631
|
arrowSize: z2.number().min(4).max(32).optional(),
|
|
3632
|
+
arrowPlacement: z2.enum(["endpoint", "boundary"]).default("endpoint"),
|
|
3424
3633
|
opacity: z2.number().min(0).max(1).default(1),
|
|
3425
3634
|
routing: z2.enum(["auto", "orthogonal", "curve", "arc"]).default("auto"),
|
|
3426
|
-
tension: z2.number().min(0.1).max(0.8).default(0.35)
|
|
3635
|
+
tension: z2.number().min(0.1).max(0.8).default(0.35),
|
|
3636
|
+
fromAnchor: anchorHintSchema.optional(),
|
|
3637
|
+
toAnchor: anchorHintSchema.optional()
|
|
3427
3638
|
}).strict();
|
|
3428
3639
|
var codeBlockStyleSchema = z2.object({
|
|
3429
3640
|
paddingVertical: z2.number().min(0).max(128).default(56),
|