kritzel-stencil 0.0.162 → 0.0.164
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/cjs/{default-line-tool.config-D1Ns0NmM.js → default-line-tool.config-DJMYrkSu.js} +340 -9
- package/dist/cjs/default-line-tool.config-DJMYrkSu.js.map +1 -0
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/kritzel-color_22.cjs.entry.js +760 -27
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/core.class.js +19 -3
- package/dist/collection/classes/core/core.class.js.map +1 -1
- package/dist/collection/classes/core/reviver.class.js +16 -0
- package/dist/collection/classes/core/reviver.class.js.map +1 -1
- package/dist/collection/classes/core/store.class.js +5 -0
- package/dist/collection/classes/core/store.class.js.map +1 -1
- package/dist/collection/classes/core/viewport.class.js +8 -0
- package/dist/collection/classes/core/viewport.class.js.map +1 -1
- package/dist/collection/classes/managers/anchor.manager.js +181 -3
- package/dist/collection/classes/managers/anchor.manager.js.map +1 -1
- package/dist/collection/classes/objects/path.class.js +85 -0
- package/dist/collection/classes/objects/path.class.js.map +1 -1
- package/dist/collection/classes/objects/shape.class.js +372 -0
- package/dist/collection/classes/objects/shape.class.js.map +1 -0
- package/dist/collection/classes/registries/icon-registry.class.js +4 -0
- package/dist/collection/classes/registries/icon-registry.class.js.map +1 -1
- package/dist/collection/classes/tools/brush-tool.class.js +2 -2
- package/dist/collection/classes/tools/brush-tool.class.js.map +1 -1
- package/dist/collection/classes/tools/line-tool.class.js +2 -2
- package/dist/collection/classes/tools/line-tool.class.js.map +1 -1
- package/dist/collection/classes/tools/shape-tool.class.js +204 -0
- package/dist/collection/classes/tools/shape-tool.class.js.map +1 -0
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +17 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +44 -8
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -1
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +143 -5
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +76 -12
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js.map +1 -1
- package/dist/collection/configs/default-shape-tool.config.js +26 -0
- package/dist/collection/configs/default-shape-tool.config.js.map +1 -0
- package/dist/collection/enums/shape-type.enum.js +7 -0
- package/dist/collection/enums/shape-type.enum.js.map +1 -0
- package/dist/collection/helpers/geometry.helper.js +55 -0
- package/dist/collection/helpers/geometry.helper.js.map +1 -1
- package/dist/collection/interfaces/toolbar-control.interface.js.map +1 -1
- package/dist/components/index.js +3 -3
- package/dist/components/kritzel-brush-style.js +1 -1
- package/dist/components/kritzel-context-menu.js +1 -1
- package/dist/components/kritzel-control-brush-config.js +1 -1
- package/dist/components/kritzel-control-text-config.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-editor.js +49 -16
- package/dist/components/kritzel-editor.js.map +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-icon.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-utility-panel.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/{p-Cqr0Bah5.js → p-5OECjGHq.js} +3 -3
- package/dist/components/{p-Cqr0Bah5.js.map → p-5OECjGHq.js.map} +1 -1
- package/dist/components/{p-CvLFRlQU.js → p-BSBMBjhq.js} +3 -3
- package/dist/components/{p-CvLFRlQU.js.map → p-BSBMBjhq.js.map} +1 -1
- package/dist/components/{p-7_lwv0zQ.js → p-BuS7MM1j.js} +4 -4
- package/dist/components/{p-7_lwv0zQ.js.map → p-BuS7MM1j.js.map} +1 -1
- package/dist/components/{p-BixlbUD7.js → p-Cv4BGNPb.js} +6 -2
- package/dist/components/p-Cv4BGNPb.js.map +1 -0
- package/dist/components/{p-dMCB4tJA.js → p-D1YAsWrL.js} +3 -3
- package/dist/components/{p-dMCB4tJA.js.map → p-D1YAsWrL.js.map} +1 -1
- package/dist/components/{p-CDteBYm9.js → p-D8L0t-Ro.js} +3 -3
- package/dist/components/{p-CDteBYm9.js.map → p-D8L0t-Ro.js.map} +1 -1
- package/dist/components/{p-DZ7kxJUx.js → p-DguzZn_x.js} +3 -3
- package/dist/components/{p-DZ7kxJUx.js.map → p-DguzZn_x.js.map} +1 -1
- package/dist/components/{p-sokRZ7Vn.js → p-Dz2XHHqa.js} +145 -5
- package/dist/components/p-Dz2XHHqa.js.map +1 -0
- package/dist/components/{p-CuhOrcET.js → p-DzUUppVL.js} +837 -21
- package/dist/components/p-DzUUppVL.js.map +1 -0
- package/dist/components/{p-CkD1PQQX.js → p-I3iPEDpx.js} +5 -5
- package/dist/components/{p-CkD1PQQX.js.map → p-I3iPEDpx.js.map} +1 -1
- package/dist/components/{p-DKwJJuFb.js → p-tp96UZ0l.js} +83 -19
- package/dist/components/p-tp96UZ0l.js.map +1 -0
- package/dist/esm/{default-line-tool.config-C35m-d1Y.js → default-line-tool.config-C35P3XfD.js} +332 -10
- package/dist/esm/default-line-tool.config-C35P3XfD.js.map +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-color_22.entry.js +760 -27
- package/dist/esm/loader.js +1 -1
- package/dist/esm/stencil.js +1 -1
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-3e2b5c42.entry.js +10 -0
- package/dist/stencil/p-3e2b5c42.entry.js.map +1 -0
- package/dist/stencil/p-C35P3XfD.js +2 -0
- package/dist/stencil/p-C35P3XfD.js.map +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/core.class.d.ts +1 -0
- package/dist/types/classes/core/store.class.d.ts +2 -0
- package/dist/types/classes/core/viewport.class.d.ts +6 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +20 -0
- package/dist/types/classes/objects/path.class.d.ts +7 -0
- package/dist/types/classes/objects/shape.class.d.ts +116 -0
- package/dist/types/classes/tools/shape-tool.class.d.ts +37 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -2
- package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +16 -1
- package/dist/types/components.d.ts +5 -5
- package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
- package/dist/types/enums/shape-type.enum.d.ts +5 -0
- package/dist/types/helpers/geometry.helper.d.ts +21 -0
- package/dist/types/interfaces/toolbar-control.interface.d.ts +21 -3
- package/package.json +1 -1
- package/dist/cjs/default-line-tool.config-D1Ns0NmM.js.map +0 -1
- package/dist/components/p-BixlbUD7.js.map +0 -1
- package/dist/components/p-CuhOrcET.js.map +0 -1
- package/dist/components/p-DKwJJuFb.js.map +0 -1
- package/dist/components/p-sokRZ7Vn.js.map +0 -1
- package/dist/esm/default-line-tool.config-C35m-d1Y.js.map +0 -1
- package/dist/stencil/p-C35m-d1Y.js +0 -2
- package/dist/stencil/p-C35m-d1Y.js.map +0 -1
- package/dist/stencil/p-d142ef46.entry.js +0 -10
- package/dist/stencil/p-d142ef46.entry.js.map +0 -1
package/dist/cjs/{default-line-tool.config-D1Ns0NmM.js → default-line-tool.config-DJMYrkSu.js}
RENAMED
|
@@ -123,6 +123,61 @@ class KritzelGeometryHelper {
|
|
|
123
123
|
}
|
|
124
124
|
return closestIntersection;
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Generates a polygon approximation of an ellipse.
|
|
128
|
+
* @param centerX - X coordinate of ellipse center
|
|
129
|
+
* @param centerY - Y coordinate of ellipse center
|
|
130
|
+
* @param rx - Horizontal radius
|
|
131
|
+
* @param ry - Vertical radius
|
|
132
|
+
* @param segments - Number of segments (more = smoother approximation)
|
|
133
|
+
* @param rotation - Optional rotation angle in radians
|
|
134
|
+
*/
|
|
135
|
+
static getEllipsePolygonApproximation(centerX, centerY, rx, ry, segments = 32, rotation = 0) {
|
|
136
|
+
const points = [];
|
|
137
|
+
const cos = Math.cos(rotation);
|
|
138
|
+
const sin = Math.sin(rotation);
|
|
139
|
+
for (let i = 0; i < segments; i++) {
|
|
140
|
+
const angle = (2 * Math.PI * i) / segments;
|
|
141
|
+
// Point on unrotated ellipse
|
|
142
|
+
const px = rx * Math.cos(angle);
|
|
143
|
+
const py = ry * Math.sin(angle);
|
|
144
|
+
// Apply rotation around center
|
|
145
|
+
const rotatedX = centerX + px * cos - py * sin;
|
|
146
|
+
const rotatedY = centerY + px * sin + py * cos;
|
|
147
|
+
points.push({ x: rotatedX, y: rotatedY });
|
|
148
|
+
}
|
|
149
|
+
return points;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Finds the closest intersection point between a line segment and a polygon
|
|
153
|
+
* defined as an array of points. Returns the intersection closest to lineStart,
|
|
154
|
+
* or null if no intersection.
|
|
155
|
+
*/
|
|
156
|
+
static getLinePointsArrayIntersection(lineStart, lineEnd, polygonPoints) {
|
|
157
|
+
let closestIntersection = null;
|
|
158
|
+
let closestDistance = Infinity;
|
|
159
|
+
for (let i = 0; i < polygonPoints.length; i++) {
|
|
160
|
+
const edgeStart = polygonPoints[i];
|
|
161
|
+
const edgeEnd = polygonPoints[(i + 1) % polygonPoints.length];
|
|
162
|
+
const intersection = this.getLineIntersectionPoint(lineStart, lineEnd, edgeStart, edgeEnd);
|
|
163
|
+
if (intersection) {
|
|
164
|
+
const distance = Math.sqrt(Math.pow(intersection.x - lineStart.x, 2) +
|
|
165
|
+
Math.pow(intersection.y - lineStart.y, 2));
|
|
166
|
+
if (distance < closestDistance) {
|
|
167
|
+
closestDistance = distance;
|
|
168
|
+
closestIntersection = intersection;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return closestIntersection;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Checks if a point is inside a polygon defined as an array of points.
|
|
176
|
+
* This is a convenience wrapper that works with arbitrary polygon point arrays.
|
|
177
|
+
*/
|
|
178
|
+
static isPointInPolygonPoints(point, polygonPoints) {
|
|
179
|
+
return this.isPointInPolygon(point, polygonPoints);
|
|
180
|
+
}
|
|
126
181
|
}
|
|
127
182
|
|
|
128
183
|
class KritzelBaseObject {
|
|
@@ -14441,6 +14496,91 @@ class KritzelPath extends KritzelBaseObject {
|
|
|
14441
14496
|
const scaledHeight = this.boundingBox.height * viewportScale;
|
|
14442
14497
|
return (scaledWidth * scaledHeight) < 500;
|
|
14443
14498
|
}
|
|
14499
|
+
/**
|
|
14500
|
+
* Finds the point where a line from outsidePoint to the path's center
|
|
14501
|
+
* intersects the stroke edge. Returns null if no intersection found.
|
|
14502
|
+
* This is used for arrow clipping at the actual stroke edge.
|
|
14503
|
+
*/
|
|
14504
|
+
getClipPoint(outsidePoint) {
|
|
14505
|
+
const centerX = this.centerX;
|
|
14506
|
+
const centerY = this.centerY;
|
|
14507
|
+
const halfStroke = this.strokeWidth / this.scale / 2;
|
|
14508
|
+
// Ensure adjusted points are computed
|
|
14509
|
+
if (this._adjustedPoints === null) {
|
|
14510
|
+
this._adjustedPoints = this.computeAdjustedPoints();
|
|
14511
|
+
}
|
|
14512
|
+
if (this._adjustedPoints.length < 1) {
|
|
14513
|
+
return null;
|
|
14514
|
+
}
|
|
14515
|
+
// Sample along the line from outsidePoint to center to find stroke edge
|
|
14516
|
+
const steps = 32;
|
|
14517
|
+
let prevOutside = true;
|
|
14518
|
+
for (let i = 1; i <= steps; i++) {
|
|
14519
|
+
const t = i / steps;
|
|
14520
|
+
const sampleX = outsidePoint.x + (centerX - outsidePoint.x) * t;
|
|
14521
|
+
const sampleY = outsidePoint.y + (centerY - outsidePoint.y) * t;
|
|
14522
|
+
// Check distance to path stroke
|
|
14523
|
+
let minDistance = Infinity;
|
|
14524
|
+
if (this._adjustedPoints.length === 1) {
|
|
14525
|
+
const p = this._adjustedPoints[0];
|
|
14526
|
+
const dx = sampleX - p[0];
|
|
14527
|
+
const dy = sampleY - p[1];
|
|
14528
|
+
minDistance = Math.sqrt(dx * dx + dy * dy);
|
|
14529
|
+
}
|
|
14530
|
+
else {
|
|
14531
|
+
for (let j = 0; j < this._adjustedPoints.length - 1; j++) {
|
|
14532
|
+
const p1 = this._adjustedPoints[j];
|
|
14533
|
+
const p2 = this._adjustedPoints[j + 1];
|
|
14534
|
+
const dist = this.pointToLineSegmentDistance(sampleX, sampleY, p1[0], p1[1], p2[0], p2[1]);
|
|
14535
|
+
if (dist < minDistance) {
|
|
14536
|
+
minDistance = dist;
|
|
14537
|
+
}
|
|
14538
|
+
}
|
|
14539
|
+
}
|
|
14540
|
+
const isInside = minDistance <= halfStroke;
|
|
14541
|
+
// Found the edge: transition from outside to inside
|
|
14542
|
+
if (prevOutside && isInside) {
|
|
14543
|
+
// Refine the intersection point using binary search
|
|
14544
|
+
let tLow = (i - 1) / steps;
|
|
14545
|
+
let tHigh = t;
|
|
14546
|
+
for (let k = 0; k < 8; k++) {
|
|
14547
|
+
const tMid = (tLow + tHigh) / 2;
|
|
14548
|
+
const midX = outsidePoint.x + (centerX - outsidePoint.x) * tMid;
|
|
14549
|
+
const midY = outsidePoint.y + (centerY - outsidePoint.y) * tMid;
|
|
14550
|
+
let midDist = Infinity;
|
|
14551
|
+
if (this._adjustedPoints.length === 1) {
|
|
14552
|
+
const p = this._adjustedPoints[0];
|
|
14553
|
+
const dx = midX - p[0];
|
|
14554
|
+
const dy = midY - p[1];
|
|
14555
|
+
midDist = Math.sqrt(dx * dx + dy * dy);
|
|
14556
|
+
}
|
|
14557
|
+
else {
|
|
14558
|
+
for (let j = 0; j < this._adjustedPoints.length - 1; j++) {
|
|
14559
|
+
const p1 = this._adjustedPoints[j];
|
|
14560
|
+
const p2 = this._adjustedPoints[j + 1];
|
|
14561
|
+
const dist = this.pointToLineSegmentDistance(midX, midY, p1[0], p1[1], p2[0], p2[1]);
|
|
14562
|
+
if (dist < midDist) {
|
|
14563
|
+
midDist = dist;
|
|
14564
|
+
}
|
|
14565
|
+
}
|
|
14566
|
+
}
|
|
14567
|
+
if (midDist <= halfStroke) {
|
|
14568
|
+
tHigh = tMid;
|
|
14569
|
+
}
|
|
14570
|
+
else {
|
|
14571
|
+
tLow = tMid;
|
|
14572
|
+
}
|
|
14573
|
+
}
|
|
14574
|
+
const finalT = (tLow + tHigh) / 2;
|
|
14575
|
+
return {
|
|
14576
|
+
x: outsidePoint.x + (centerX - outsidePoint.x) * finalT,
|
|
14577
|
+
y: outsidePoint.y + (centerY - outsidePoint.y) * finalT,
|
|
14578
|
+
};
|
|
14579
|
+
}
|
|
14580
|
+
prevOutside = !isInside;
|
|
14581
|
+
}
|
|
14582
|
+
return null;
|
|
14583
|
+
}
|
|
14444
14584
|
}
|
|
14445
14585
|
|
|
14446
14586
|
class KritzelImage extends KritzelBaseObject {
|
|
@@ -15225,6 +15365,7 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
15225
15365
|
});
|
|
15226
15366
|
updatedPath.id = currentPath.id;
|
|
15227
15367
|
updatedPath.workspaceId = currentPath.workspaceId;
|
|
15368
|
+
updatedPath.zIndex = currentPath.zIndex;
|
|
15228
15369
|
updatedPath.isCompleted = false;
|
|
15229
15370
|
this._core.store.state.objects.update(updatedPath);
|
|
15230
15371
|
}
|
|
@@ -15247,6 +15388,7 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
15247
15388
|
});
|
|
15248
15389
|
updatedPath.id = currentPath.id;
|
|
15249
15390
|
updatedPath.workspaceId = currentPath.workspaceId;
|
|
15391
|
+
updatedPath.zIndex = currentPath.zIndex;
|
|
15250
15392
|
updatedPath.isCompleted = false;
|
|
15251
15393
|
this._core.store.state.objects.update(updatedPath);
|
|
15252
15394
|
}
|
|
@@ -15263,7 +15405,6 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
15263
15405
|
const currentPath = this._core.store.currentPath;
|
|
15264
15406
|
if (currentPath) {
|
|
15265
15407
|
currentPath.isCompleted = true;
|
|
15266
|
-
currentPath.zIndex = this._core.store.currentZIndex;
|
|
15267
15408
|
this._core.store.state.objects.update(currentPath);
|
|
15268
15409
|
this._core.engine.emitObjectsChange();
|
|
15269
15410
|
}
|
|
@@ -15275,7 +15416,6 @@ class KritzelBrushTool extends KritzelBaseTool {
|
|
|
15275
15416
|
const currentPath = this._core.store.currentPath;
|
|
15276
15417
|
if (currentPath) {
|
|
15277
15418
|
currentPath.isCompleted = true;
|
|
15278
|
-
currentPath.zIndex = this._core.store.currentZIndex;
|
|
15279
15419
|
this._core.store.state.objects.update(currentPath);
|
|
15280
15420
|
this._core.engine.emitObjectsChange();
|
|
15281
15421
|
}
|
|
@@ -15675,6 +15815,7 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
15675
15815
|
});
|
|
15676
15816
|
updatedLine.id = currentLine.id;
|
|
15677
15817
|
updatedLine.workspaceId = currentLine.workspaceId;
|
|
15818
|
+
updatedLine.zIndex = currentLine.zIndex;
|
|
15678
15819
|
updatedLine.isCompleted = false;
|
|
15679
15820
|
this._core.store.state.objects.update(updatedLine);
|
|
15680
15821
|
}
|
|
@@ -15701,6 +15842,7 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
15701
15842
|
});
|
|
15702
15843
|
updatedLine.id = currentLine.id;
|
|
15703
15844
|
updatedLine.workspaceId = currentLine.workspaceId;
|
|
15845
|
+
updatedLine.zIndex = currentLine.zIndex;
|
|
15704
15846
|
updatedLine.isCompleted = false;
|
|
15705
15847
|
this._core.store.state.objects.update(updatedLine);
|
|
15706
15848
|
}
|
|
@@ -15717,7 +15859,6 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
15717
15859
|
const currentLine = this._core.store.currentLine;
|
|
15718
15860
|
if (currentLine) {
|
|
15719
15861
|
currentLine.isCompleted = true;
|
|
15720
|
-
currentLine.zIndex = this._core.store.currentZIndex;
|
|
15721
15862
|
this._core.store.state.objects.update(currentLine);
|
|
15722
15863
|
this._core.engine.emitObjectsChange();
|
|
15723
15864
|
// Switch to selection tool and select the drawn line
|
|
@@ -15731,7 +15872,6 @@ class KritzelLineTool extends KritzelBaseTool {
|
|
|
15731
15872
|
const currentLine = this._core.store.currentLine;
|
|
15732
15873
|
if (currentLine) {
|
|
15733
15874
|
currentLine.isCompleted = true;
|
|
15734
|
-
currentLine.zIndex = this._core.store.currentZIndex;
|
|
15735
15875
|
this._core.store.state.objects.update(currentLine);
|
|
15736
15876
|
this._core.engine.emitObjectsChange();
|
|
15737
15877
|
// Switch to selection tool and select the drawn line
|
|
@@ -16059,6 +16199,10 @@ KritzelIconRegistry.registerIcons({
|
|
|
16059
16199
|
'highlighter': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-highlighter-icon lucide-highlighter"><path d="m9 11-6 6v3h9l3-3"/><path d="m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4"/></svg>',
|
|
16060
16200
|
'eraser': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21"/><path d="M22 21H7"/><path d="m5 11 9 9"/></svg>',
|
|
16061
16201
|
'type': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 7 4 4 20 4 20 7"/><line x1="9" x2="15" y1="20" y2="20"/><line x1="12" x2="12" y1="4" y2="20"/></svg>',
|
|
16202
|
+
'shapes': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8.3 10a.7.7 0 0 1-.626-1.079L11.4 3a.7.7 0 0 1 1.198-.043L16.3 8.9a.7.7 0 0 1-.572 1.1Z"/><rect x="3" y="14" width="7" height="7" rx="1"/><circle cx="17.5" cy="17.5" r="3.5"/></svg>',
|
|
16203
|
+
'shape-rectangle': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>',
|
|
16204
|
+
'shape-ellipse': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="12" rx="10" ry="8"/></svg>',
|
|
16205
|
+
'shape-triangle': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3L22 21H2L12 3Z"/></svg>',
|
|
16062
16206
|
'image': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>',
|
|
16063
16207
|
'chevron-down': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>',
|
|
16064
16208
|
'chevron-up': '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>',
|
|
@@ -33136,7 +33280,34 @@ class KritzelAnchorManager {
|
|
|
33136
33280
|
const reference = endpoint === 'start'
|
|
33137
33281
|
? this.lineLocalToWorld(line, line.endX, line.endY)
|
|
33138
33282
|
: this.lineLocalToWorld(line, line.startX, line.startY);
|
|
33139
|
-
|
|
33283
|
+
// Check for path object (uses stroke edge detection)
|
|
33284
|
+
const pathClipPoint = this.getPathClipPoint(targetObject, reference);
|
|
33285
|
+
if (pathClipPoint) {
|
|
33286
|
+
const localEdge = this.lineWorldToLocal(line, pathClipPoint.x, pathClipPoint.y);
|
|
33287
|
+
const totalLength = Math.sqrt(Math.pow(line.endX - line.startX, 2) +
|
|
33288
|
+
Math.pow(line.endY - line.startY, 2));
|
|
33289
|
+
const distanceFromStart = Math.sqrt(Math.pow(localEdge.x - line.startX, 2) +
|
|
33290
|
+
Math.pow(localEdge.y - line.startY, 2));
|
|
33291
|
+
const t = totalLength > 0 ? distanceFromStart / totalLength : endpoint === 'start' ? 0 : 1;
|
|
33292
|
+
return {
|
|
33293
|
+
localX: localEdge.x,
|
|
33294
|
+
localY: localEdge.y,
|
|
33295
|
+
worldX: pathClipPoint.x,
|
|
33296
|
+
worldY: pathClipPoint.y,
|
|
33297
|
+
t,
|
|
33298
|
+
};
|
|
33299
|
+
}
|
|
33300
|
+
// Check for custom clip polygon (ellipse, triangle shapes)
|
|
33301
|
+
const customClipPolygon = this.getClipPolygonForObject(targetObject);
|
|
33302
|
+
let edgeIntersection;
|
|
33303
|
+
if (customClipPolygon) {
|
|
33304
|
+
// Use custom polygon for non-rectangular shapes
|
|
33305
|
+
edgeIntersection = KritzelGeometryHelper.getLinePointsArrayIntersection(reference, { x: targetObject.centerX, y: targetObject.centerY }, customClipPolygon);
|
|
33306
|
+
}
|
|
33307
|
+
else {
|
|
33308
|
+
// Fall back to bounding box for rectangles and other objects
|
|
33309
|
+
edgeIntersection = KritzelGeometryHelper.getLinePolygonIntersection(reference, { x: targetObject.centerX, y: targetObject.centerY }, targetObject.rotatedPolygon);
|
|
33310
|
+
}
|
|
33140
33311
|
if (!edgeIntersection) {
|
|
33141
33312
|
return null;
|
|
33142
33313
|
}
|
|
@@ -33155,7 +33326,15 @@ class KritzelAnchorManager {
|
|
|
33155
33326
|
};
|
|
33156
33327
|
}
|
|
33157
33328
|
computeCurvedClipInfo(line, endpoint, targetObject) {
|
|
33158
|
-
|
|
33329
|
+
// Check for path object (uses stroke edge detection via sampling)
|
|
33330
|
+
if (KritzelClassHelper.isInstanceOf(targetObject, 'KritzelPath')) {
|
|
33331
|
+
// For curved lines to paths, sample along the curve to find stroke edge
|
|
33332
|
+
const path = targetObject;
|
|
33333
|
+
return this.findCurveExitPointForPath(line, endpoint, path);
|
|
33334
|
+
}
|
|
33335
|
+
// Check for custom clip polygon (ellipse, triangle shapes)
|
|
33336
|
+
const customClipPolygon = this.getClipPolygonForObject(targetObject);
|
|
33337
|
+
const polygonPoints = customClipPolygon ?? this.getPolygonPoints(targetObject.rotatedPolygon);
|
|
33159
33338
|
const exitPoint = this.findCurveExitPoint(line, endpoint, polygonPoints);
|
|
33160
33339
|
if (exitPoint) {
|
|
33161
33340
|
return exitPoint;
|
|
@@ -33163,7 +33342,13 @@ class KritzelAnchorManager {
|
|
|
33163
33342
|
const reference = endpoint === 'start'
|
|
33164
33343
|
? this.lineLocalToWorld(line, line.endX, line.endY)
|
|
33165
33344
|
: this.lineLocalToWorld(line, line.startX, line.startY);
|
|
33166
|
-
|
|
33345
|
+
let fallbackIntersection;
|
|
33346
|
+
if (customClipPolygon) {
|
|
33347
|
+
fallbackIntersection = KritzelGeometryHelper.getLinePointsArrayIntersection(reference, { x: targetObject.centerX, y: targetObject.centerY }, customClipPolygon);
|
|
33348
|
+
}
|
|
33349
|
+
else {
|
|
33350
|
+
fallbackIntersection = KritzelGeometryHelper.getLinePolygonIntersection(reference, { x: targetObject.centerX, y: targetObject.centerY }, targetObject.rotatedPolygon);
|
|
33351
|
+
}
|
|
33167
33352
|
if (!fallbackIntersection) {
|
|
33168
33353
|
return null;
|
|
33169
33354
|
}
|
|
@@ -33203,6 +33388,119 @@ class KritzelAnchorManager {
|
|
|
33203
33388
|
}
|
|
33204
33389
|
return null;
|
|
33205
33390
|
}
|
|
33391
|
+
/**
|
|
33392
|
+
* Finds the exit point for a curved line going to a Path object.
|
|
33393
|
+
* Uses distance-to-stroke sampling instead of polygon containment.
|
|
33394
|
+
*/
|
|
33395
|
+
findCurveExitPointForPath(line, endpoint, path) {
|
|
33396
|
+
const steps = 64;
|
|
33397
|
+
const initialT = endpoint === 'start' ? 0 : 1;
|
|
33398
|
+
const halfStroke = path.strokeWidth / path.scale / 2;
|
|
33399
|
+
// Ensure path has computed points
|
|
33400
|
+
const pathPoints = this.getPathAdjustedPoints(path);
|
|
33401
|
+
if (pathPoints.length < 1) {
|
|
33402
|
+
return null;
|
|
33403
|
+
}
|
|
33404
|
+
// Check if starting point is inside the stroke
|
|
33405
|
+
const initialSample = this.evaluateLineAtT(line, initialT);
|
|
33406
|
+
let prevInside = this.isPointInPathStroke(initialSample.worldX, initialSample.worldY, pathPoints, halfStroke);
|
|
33407
|
+
let prevT = initialT;
|
|
33408
|
+
for (let i = 1; i <= steps; i++) {
|
|
33409
|
+
const t = endpoint === 'start' ? i / steps : 1 - i / steps;
|
|
33410
|
+
const sample = this.evaluateLineAtT(line, t);
|
|
33411
|
+
const inside = this.isPointInPathStroke(sample.worldX, sample.worldY, pathPoints, halfStroke);
|
|
33412
|
+
if (prevInside && !inside) {
|
|
33413
|
+
// Refine using binary search
|
|
33414
|
+
const refinedT = this.refineCurveExitParameterForPath(line, pathPoints, halfStroke, prevT, t);
|
|
33415
|
+
const refinedPoint = this.evaluateLineAtT(line, refinedT);
|
|
33416
|
+
return {
|
|
33417
|
+
localX: refinedPoint.localX,
|
|
33418
|
+
localY: refinedPoint.localY,
|
|
33419
|
+
worldX: refinedPoint.worldX,
|
|
33420
|
+
worldY: refinedPoint.worldY,
|
|
33421
|
+
t: refinedT,
|
|
33422
|
+
};
|
|
33423
|
+
}
|
|
33424
|
+
prevInside = inside;
|
|
33425
|
+
prevT = t;
|
|
33426
|
+
}
|
|
33427
|
+
return null;
|
|
33428
|
+
}
|
|
33429
|
+
refineCurveExitParameterForPath(line, pathPoints, halfStroke, insideT, outsideT) {
|
|
33430
|
+
let tInside = insideT;
|
|
33431
|
+
let tOutside = outsideT;
|
|
33432
|
+
for (let i = 0; i < 8; i++) {
|
|
33433
|
+
const mid = (tInside + tOutside) / 2;
|
|
33434
|
+
const sample = this.evaluateLineAtT(line, mid);
|
|
33435
|
+
const inside = this.isPointInPathStroke(sample.worldX, sample.worldY, pathPoints, halfStroke);
|
|
33436
|
+
if (inside) {
|
|
33437
|
+
tInside = mid;
|
|
33438
|
+
}
|
|
33439
|
+
else {
|
|
33440
|
+
tOutside = mid;
|
|
33441
|
+
}
|
|
33442
|
+
}
|
|
33443
|
+
return (tInside + tOutside) / 2;
|
|
33444
|
+
}
|
|
33445
|
+
getPathAdjustedPoints(path) {
|
|
33446
|
+
// Access the path's adjusted points through its internal computation
|
|
33447
|
+
// We'll need to manually compute them since they're private
|
|
33448
|
+
return this.computePathAdjustedPoints(path);
|
|
33449
|
+
}
|
|
33450
|
+
computePathAdjustedPoints(path) {
|
|
33451
|
+
if (!path.points?.length) {
|
|
33452
|
+
return [];
|
|
33453
|
+
}
|
|
33454
|
+
const angle = path.rotation;
|
|
33455
|
+
const cos = Math.cos(angle);
|
|
33456
|
+
const sin = Math.sin(angle);
|
|
33457
|
+
const xs = path.points.map(p => p[0]);
|
|
33458
|
+
const ys = path.points.map(p => p[1]);
|
|
33459
|
+
const pivot = {
|
|
33460
|
+
x: (Math.min(...xs) + Math.max(...xs)) / 2,
|
|
33461
|
+
y: (Math.min(...ys) + Math.max(...ys)) / 2,
|
|
33462
|
+
};
|
|
33463
|
+
const { x: cx, y: cy } = pivot;
|
|
33464
|
+
const rotatedPoints = path.points.map(([x, y]) => {
|
|
33465
|
+
const dx = x - cx;
|
|
33466
|
+
const dy = y - cy;
|
|
33467
|
+
return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];
|
|
33468
|
+
});
|
|
33469
|
+
return rotatedPoints.map(([px, py]) => [
|
|
33470
|
+
Math.abs(px - path.x) / path.scale + path.translateX,
|
|
33471
|
+
Math.abs(py - path.y) / path.scale + path.translateY,
|
|
33472
|
+
]);
|
|
33473
|
+
}
|
|
33474
|
+
isPointInPathStroke(x, y, pathPoints, halfStroke) {
|
|
33475
|
+
if (pathPoints.length === 1) {
|
|
33476
|
+
const p = pathPoints[0];
|
|
33477
|
+
const dx = x - p[0];
|
|
33478
|
+
const dy = y - p[1];
|
|
33479
|
+
return Math.sqrt(dx * dx + dy * dy) <= halfStroke;
|
|
33480
|
+
}
|
|
33481
|
+
for (let i = 0; i < pathPoints.length - 1; i++) {
|
|
33482
|
+
const p1 = pathPoints[i];
|
|
33483
|
+
const p2 = pathPoints[i + 1];
|
|
33484
|
+
const dist = this.pointToSegmentDistance(x, y, p1[0], p1[1], p2[0], p2[1]);
|
|
33485
|
+
if (dist <= halfStroke) {
|
|
33486
|
+
return true;
|
|
33487
|
+
}
|
|
33488
|
+
}
|
|
33489
|
+
return false;
|
|
33490
|
+
}
|
|
33491
|
+
pointToSegmentDistance(px, py, x1, y1, x2, y2) {
|
|
33492
|
+
const dx = x2 - x1;
|
|
33493
|
+
const dy = y2 - y1;
|
|
33494
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
33495
|
+
if (lengthSquared === 0) {
|
|
33496
|
+
return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
|
|
33497
|
+
}
|
|
33498
|
+
let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;
|
|
33499
|
+
t = Math.max(0, Math.min(1, t));
|
|
33500
|
+
const nearestX = x1 + t * dx;
|
|
33501
|
+
const nearestY = y1 + t * dy;
|
|
33502
|
+
return Math.sqrt((px - nearestX) * (px - nearestX) + (py - nearestY) * (py - nearestY));
|
|
33503
|
+
}
|
|
33206
33504
|
refineCurveExitParameter(line, polygonPoints, insideT, outsideT) {
|
|
33207
33505
|
let tInside = insideT;
|
|
33208
33506
|
let tOutside = outsideT;
|
|
@@ -33336,6 +33634,30 @@ class KritzelAnchorManager {
|
|
|
33336
33634
|
getPolygonPoints(polygon) {
|
|
33337
33635
|
return [polygon.topLeft, polygon.topRight, polygon.bottomRight, polygon.bottomLeft];
|
|
33338
33636
|
}
|
|
33637
|
+
/**
|
|
33638
|
+
* Gets the custom clip polygon for an object if it has one.
|
|
33639
|
+
* Returns null for objects that should use the default rotatedPolygon.
|
|
33640
|
+
*/
|
|
33641
|
+
getClipPolygonForObject(object) {
|
|
33642
|
+
// Check if the object is a KritzelShape with a custom clip polygon
|
|
33643
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelShape')) {
|
|
33644
|
+
const shape = object;
|
|
33645
|
+
return shape.getClipPolygon();
|
|
33646
|
+
}
|
|
33647
|
+
// Path objects use getPathClipPoint instead of polygon
|
|
33648
|
+
return null;
|
|
33649
|
+
}
|
|
33650
|
+
/**
|
|
33651
|
+
* Gets the clip point for a Path object (stroke edge intersection).
|
|
33652
|
+
* Returns null if the object is not a Path or no intersection found.
|
|
33653
|
+
*/
|
|
33654
|
+
getPathClipPoint(object, outsidePoint) {
|
|
33655
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelPath')) {
|
|
33656
|
+
const path = object;
|
|
33657
|
+
return path.getClipPoint(outsidePoint);
|
|
33658
|
+
}
|
|
33659
|
+
return null;
|
|
33660
|
+
}
|
|
33339
33661
|
/**
|
|
33340
33662
|
* Converts local line coordinates to world coordinates.
|
|
33341
33663
|
*/
|
|
@@ -33518,6 +33840,8 @@ exports.DEFAULT_LINE_TOOL_CONFIG = DEFAULT_LINE_TOOL_CONFIG;
|
|
|
33518
33840
|
exports.DEFAULT_SYNC_CONFIG = DEFAULT_SYNC_CONFIG;
|
|
33519
33841
|
exports.DEFAULT_TEXT_CONFIG = DEFAULT_TEXT_CONFIG;
|
|
33520
33842
|
exports.Doc = Doc;
|
|
33843
|
+
exports.EditorState = EditorState;
|
|
33844
|
+
exports.EditorView = EditorView;
|
|
33521
33845
|
exports.HocuspocusProvider = HocuspocusProvider;
|
|
33522
33846
|
exports.HocuspocusProviderWebsocket = HocuspocusProviderWebsocket;
|
|
33523
33847
|
exports.IndexedDBSyncProvider = IndexedDBSyncProvider;
|
|
@@ -33532,6 +33856,7 @@ exports.KritzelCursorHelper = KritzelCursorHelper;
|
|
|
33532
33856
|
exports.KritzelDevicesHelper = KritzelDevicesHelper;
|
|
33533
33857
|
exports.KritzelEraserTool = KritzelEraserTool;
|
|
33534
33858
|
exports.KritzelEventHelper = KritzelEventHelper;
|
|
33859
|
+
exports.KritzelGeometryHelper = KritzelGeometryHelper;
|
|
33535
33860
|
exports.KritzelIconRegistry = KritzelIconRegistry;
|
|
33536
33861
|
exports.KritzelImage = KritzelImage;
|
|
33537
33862
|
exports.KritzelImageTool = KritzelImageTool;
|
|
@@ -33549,8 +33874,12 @@ exports.KritzelWorkspace = KritzelWorkspace;
|
|
|
33549
33874
|
exports.ObjectHelper = ObjectHelper;
|
|
33550
33875
|
exports.Observable = Observable$1;
|
|
33551
33876
|
exports.ObservableV2 = ObservableV2;
|
|
33877
|
+
exports.Schema = Schema;
|
|
33878
|
+
exports.TextSelection = TextSelection;
|
|
33552
33879
|
exports.UndoManager = UndoManager;
|
|
33880
|
+
exports.addListNodes = addListNodes;
|
|
33553
33881
|
exports.applyUpdate = applyUpdate;
|
|
33882
|
+
exports.baseKeymap = baseKeymap;
|
|
33554
33883
|
exports.create = create$8;
|
|
33555
33884
|
exports.createDecoder = createDecoder$1;
|
|
33556
33885
|
exports.createEncoder = createEncoder$1;
|
|
@@ -33562,6 +33891,7 @@ exports.floor = floor$2;
|
|
|
33562
33891
|
exports.fromBase64 = fromBase64;
|
|
33563
33892
|
exports.getUnixTime = getUnixTime$1;
|
|
33564
33893
|
exports.isNode = isNode;
|
|
33894
|
+
exports.keymap = keymap;
|
|
33565
33895
|
exports.length = length$3;
|
|
33566
33896
|
exports.map = map;
|
|
33567
33897
|
exports.min = min$2;
|
|
@@ -33571,6 +33901,7 @@ exports.pow = pow;
|
|
|
33571
33901
|
exports.readVarString = readVarString$2;
|
|
33572
33902
|
exports.readVarUint = readVarUint$2;
|
|
33573
33903
|
exports.readVarUint8Array = readVarUint8Array$2;
|
|
33904
|
+
exports.schema = schema;
|
|
33574
33905
|
exports.setIfUndefined = setIfUndefined$1;
|
|
33575
33906
|
exports.toBase64 = toBase64;
|
|
33576
33907
|
exports.toUint8Array = toUint8Array$1;
|
|
@@ -33578,6 +33909,6 @@ exports.varStorage = varStorage;
|
|
|
33578
33909
|
exports.writeVarString = writeVarString$2;
|
|
33579
33910
|
exports.writeVarUint = writeVarUint$2;
|
|
33580
33911
|
exports.writeVarUint8Array = writeVarUint8Array$2;
|
|
33581
|
-
//# sourceMappingURL=default-line-tool.config-
|
|
33912
|
+
//# sourceMappingURL=default-line-tool.config-DJMYrkSu.js.map
|
|
33582
33913
|
|
|
33583
|
-
//# sourceMappingURL=default-line-tool.config-
|
|
33914
|
+
//# sourceMappingURL=default-line-tool.config-DJMYrkSu.js.map
|