@inditextech/weave-sdk 5.3.0 → 5.4.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/sdk.js +441 -82
- package/dist/sdk.node.js +442 -83
- package/dist/sdk.node.stats.html +1 -1
- package/dist/sdk.stats.html +1 -1
- package/dist/types.d.ts +159 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +441 -82
- package/dist/types.js.map +1 -1
- package/dist/types.stats.html +1 -1
- package/package.json +2 -2
package/dist/sdk.node.js
CHANGED
|
@@ -4679,7 +4679,15 @@ function handleClickOrTap(ctx, e) {
|
|
|
4679
4679
|
nodeTargeted.dblClick();
|
|
4680
4680
|
return;
|
|
4681
4681
|
}
|
|
4682
|
-
|
|
4682
|
+
const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
|
|
4683
|
+
if (!e.evt.shiftKey) {
|
|
4684
|
+
const wasSelectedBeforeThisClick = tr.nodes().findIndex((node) => node.getAttrs().id === nodeTargeted.getAttrs().id) !== -1;
|
|
4685
|
+
nodeTargeted.click({
|
|
4686
|
+
wasSelected: wasSelectedBeforeThisClick,
|
|
4687
|
+
ctrlOrMetaPressed: isCtrlOrCmdPressed
|
|
4688
|
+
});
|
|
4689
|
+
}
|
|
4690
|
+
if (isCtrlOrCmdPressed) return;
|
|
4683
4691
|
if (!metaPressed) {
|
|
4684
4692
|
tr.nodes([nodeTargeted]);
|
|
4685
4693
|
tr.show();
|
|
@@ -5948,6 +5956,7 @@ const augmentKonvaNodeClass = (config) => {
|
|
|
5948
5956
|
Konva.Node.prototype.closeCrop = function() {};
|
|
5949
5957
|
Konva.Node.prototype.resetCrop = function() {};
|
|
5950
5958
|
Konva.Node.prototype.dblClick = function() {};
|
|
5959
|
+
Konva.Node.prototype.click = function() {};
|
|
5951
5960
|
Konva.Node.prototype.allowedAnchors = function() {
|
|
5952
5961
|
return [];
|
|
5953
5962
|
};
|
|
@@ -9460,7 +9469,7 @@ var WeaveRegisterManager = class {
|
|
|
9460
9469
|
};
|
|
9461
9470
|
//#endregion
|
|
9462
9471
|
//#region package.json
|
|
9463
|
-
var version = "5.
|
|
9472
|
+
var version = "5.4.1";
|
|
9464
9473
|
//#endregion
|
|
9465
9474
|
//#region src/managers/setup.ts
|
|
9466
9475
|
var WeaveSetupManager = class {
|
|
@@ -13390,8 +13399,13 @@ const WEAVE_TEXT_NODE_DEFAULT_CONFIG = {
|
|
|
13390
13399
|
transform: { ...WEAVE_NODES_SELECTION_DEFAULT_CONFIG.selection },
|
|
13391
13400
|
outline: { enabled: false },
|
|
13392
13401
|
cursor: { color: "#000000" },
|
|
13393
|
-
edition: { borderSize: 2 }
|
|
13402
|
+
edition: { borderSize: 2 },
|
|
13403
|
+
link: {
|
|
13404
|
+
defaultColor: "#1155ccff",
|
|
13405
|
+
hoverColor: "#3d7be0ff"
|
|
13406
|
+
}
|
|
13394
13407
|
};
|
|
13408
|
+
const WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS = ["http:", "https:"];
|
|
13395
13409
|
const TEXT_LAYOUT = {
|
|
13396
13410
|
["SMART"]: "smart",
|
|
13397
13411
|
["AUTO_ALL"]: "auto-all",
|
|
@@ -13400,6 +13414,21 @@ const TEXT_LAYOUT = {
|
|
|
13400
13414
|
};
|
|
13401
13415
|
//#endregion
|
|
13402
13416
|
//#region src/nodes/text/text.ts
|
|
13417
|
+
/**
|
|
13418
|
+
* Validates that a link is an absolute http(s) URL. Used both by the zod
|
|
13419
|
+
* schema (getSchema()) and defensively again at click-time (setLink() and
|
|
13420
|
+
* the pointerclick handler), since the value is user-authored content
|
|
13421
|
+
* rendered and clicked on by other collaborators — schemes like
|
|
13422
|
+
* `javascript:` or `data:` must never reach `window.open`.
|
|
13423
|
+
*/
|
|
13424
|
+
function isValidTextLink(value) {
|
|
13425
|
+
try {
|
|
13426
|
+
const url = new URL(value);
|
|
13427
|
+
return WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS.includes(url.protocol);
|
|
13428
|
+
} catch {
|
|
13429
|
+
return false;
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13403
13432
|
var WeaveTextNode = class extends WeaveNode {
|
|
13404
13433
|
config;
|
|
13405
13434
|
nodeType = WEAVE_TEXT_NODE_TYPE;
|
|
@@ -13463,6 +13492,8 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13463
13492
|
}
|
|
13464
13493
|
}
|
|
13465
13494
|
onRender(props) {
|
|
13495
|
+
const linkPreviousFill = props.link ? props.linkPreviousFill ?? props.fill : props.linkPreviousFill;
|
|
13496
|
+
const linkPreviousTextDecoration = props.link ? props.linkPreviousTextDecoration ?? props.textDecoration : props.linkPreviousTextDecoration;
|
|
13466
13497
|
const text = new Konva.Text({
|
|
13467
13498
|
...props,
|
|
13468
13499
|
name: "node",
|
|
@@ -13472,6 +13503,12 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13472
13503
|
stroke: this.config.outline.color,
|
|
13473
13504
|
strokeWidth: this.config.outline.width,
|
|
13474
13505
|
fillAfterStrokeEnabled: true
|
|
13506
|
+
},
|
|
13507
|
+
...props.link && {
|
|
13508
|
+
textDecoration: "underline",
|
|
13509
|
+
fill: this.config.link.defaultColor,
|
|
13510
|
+
linkPreviousFill,
|
|
13511
|
+
linkPreviousTextDecoration
|
|
13475
13512
|
}
|
|
13476
13513
|
});
|
|
13477
13514
|
this.setupDefaultNodeAugmentation(text);
|
|
@@ -13530,6 +13567,7 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13530
13567
|
this.triggerEditMode(text);
|
|
13531
13568
|
};
|
|
13532
13569
|
text.setAttr("triggerEditMode", this.triggerEditMode.bind(this));
|
|
13570
|
+
this.setupLinkBehavior(text);
|
|
13533
13571
|
let actualAnchor = void 0;
|
|
13534
13572
|
text.on("transformstart", (e) => {
|
|
13535
13573
|
const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
|
|
@@ -13626,6 +13664,9 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13626
13664
|
return text;
|
|
13627
13665
|
}
|
|
13628
13666
|
onUpdate(nodeInstance, nextProps) {
|
|
13667
|
+
const isLinked = Boolean(nextProps.link);
|
|
13668
|
+
const linkPreviousFill = nextProps.link ? nextProps.linkPreviousFill ?? nextProps.fill : nextProps.linkPreviousFill;
|
|
13669
|
+
const linkPreviousTextDecoration = nextProps.link ? nextProps.linkPreviousTextDecoration ?? nextProps.textDecoration : nextProps.linkPreviousTextDecoration;
|
|
13629
13670
|
nodeInstance.setAttrs({
|
|
13630
13671
|
...nextProps,
|
|
13631
13672
|
...!this.config.outline.enabled && { strokeEnabled: false },
|
|
@@ -13634,6 +13675,13 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13634
13675
|
stroke: this.config.outline.color,
|
|
13635
13676
|
strokeWidth: this.config.outline.width,
|
|
13636
13677
|
fillAfterStrokeEnabled: true
|
|
13678
|
+
},
|
|
13679
|
+
link: nextProps.link,
|
|
13680
|
+
linkPreviousFill: isLinked ? linkPreviousFill : void 0,
|
|
13681
|
+
linkPreviousTextDecoration: isLinked ? linkPreviousTextDecoration : void 0,
|
|
13682
|
+
...isLinked && {
|
|
13683
|
+
textDecoration: "underline",
|
|
13684
|
+
fill: this.config.link.defaultColor
|
|
13637
13685
|
}
|
|
13638
13686
|
});
|
|
13639
13687
|
let width = nextProps.width;
|
|
@@ -13675,6 +13723,10 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
13675
13723
|
delete cleanedAttrs.overridesMouseControl;
|
|
13676
13724
|
delete cleanedAttrs.shouldUpdateOnTransform;
|
|
13677
13725
|
delete cleanedAttrs.dragBoundFunc;
|
|
13726
|
+
if (cleanedAttrs.link) {
|
|
13727
|
+
if (typeof cleanedAttrs.linkPreviousFill === "string") cleanedAttrs.fill = cleanedAttrs.linkPreviousFill;
|
|
13728
|
+
if (typeof cleanedAttrs.linkPreviousTextDecoration === "string") cleanedAttrs.textDecoration = cleanedAttrs.linkPreviousTextDecoration;
|
|
13729
|
+
}
|
|
13678
13730
|
return {
|
|
13679
13731
|
key: attrs.id ?? "",
|
|
13680
13732
|
type: attrs.nodeType,
|
|
@@ -14080,6 +14132,94 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
14080
14132
|
this.createTextAreaDOM(textNode, areaPosition);
|
|
14081
14133
|
this.instance.emitEvent("onEnterTextNodeEditMode", { node: textNode });
|
|
14082
14134
|
}
|
|
14135
|
+
/**
|
|
14136
|
+
* Wires the hover colour swap, link cursor and click-to-open behaviour for
|
|
14137
|
+
* a rendered text node. Runs on top of (not instead of) the generic
|
|
14138
|
+
* selection-hover-halo handling in setupDefaultNodeEvents()/node.ts, the
|
|
14139
|
+
* same way connector.ts layers its own handleMouseover/handleMouseout.
|
|
14140
|
+
*/
|
|
14141
|
+
setupLinkBehavior(text) {
|
|
14142
|
+
text.handleMouseover = () => {
|
|
14143
|
+
if (!text.getAttrs().link) return;
|
|
14144
|
+
text.fill(this.config.link.hoverColor);
|
|
14145
|
+
text.getLayer()?.batchDraw();
|
|
14146
|
+
};
|
|
14147
|
+
text.handleMouseout = () => {
|
|
14148
|
+
if (!text.getAttrs().link) return;
|
|
14149
|
+
text.fill(this.config.link.defaultColor);
|
|
14150
|
+
text.getLayer()?.batchDraw();
|
|
14151
|
+
};
|
|
14152
|
+
text.defineMousePointer = () => {
|
|
14153
|
+
return text.getAttrs().link ? "pointer" : "default";
|
|
14154
|
+
};
|
|
14155
|
+
let linkClickTimeout;
|
|
14156
|
+
const clearLinkClickTimeout = () => {
|
|
14157
|
+
if (linkClickTimeout) {
|
|
14158
|
+
clearTimeout(linkClickTimeout);
|
|
14159
|
+
linkClickTimeout = void 0;
|
|
14160
|
+
}
|
|
14161
|
+
};
|
|
14162
|
+
const previousDblClick = text.dblClick.bind(text);
|
|
14163
|
+
text.dblClick = () => {
|
|
14164
|
+
clearLinkClickTimeout();
|
|
14165
|
+
previousDblClick();
|
|
14166
|
+
};
|
|
14167
|
+
text.click = ({ wasSelected, ctrlOrMetaPressed }) => {
|
|
14168
|
+
if (!text.getAttrs().link) return;
|
|
14169
|
+
if (ctrlOrMetaPressed) {
|
|
14170
|
+
clearLinkClickTimeout();
|
|
14171
|
+
this.openTextLink(text);
|
|
14172
|
+
return;
|
|
14173
|
+
}
|
|
14174
|
+
if (wasSelected) {
|
|
14175
|
+
clearLinkClickTimeout();
|
|
14176
|
+
linkClickTimeout = setTimeout(() => {
|
|
14177
|
+
linkClickTimeout = void 0;
|
|
14178
|
+
if (!this.editing) this.openTextLink(text);
|
|
14179
|
+
}, Konva.dblClickWindow);
|
|
14180
|
+
}
|
|
14181
|
+
};
|
|
14182
|
+
}
|
|
14183
|
+
openTextLink(textNode) {
|
|
14184
|
+
if (this.instance.isServerSide()) return;
|
|
14185
|
+
const link = textNode.getAttrs().link;
|
|
14186
|
+
if (typeof link !== "string" || !isValidTextLink(link)) return;
|
|
14187
|
+
window.open(link, "_blank", "noopener,noreferrer");
|
|
14188
|
+
}
|
|
14189
|
+
/**
|
|
14190
|
+
* Public API to read/set/remove the URL a text node links to. Setting an
|
|
14191
|
+
* invalid or non-http(s) URL is a no-op (see isValidTextLink()).
|
|
14192
|
+
*
|
|
14193
|
+
* The node's real fill/textDecoration are captured once into
|
|
14194
|
+
* `linkPreviousFill`/`linkPreviousTextDecoration` the first time a link is
|
|
14195
|
+
* rendered (see onRender()/onUpdate()) and restored by serialize()
|
|
14196
|
+
* whenever the node is re-serialized while linked — so they survive any
|
|
14197
|
+
* number of resizes/drags/edits while the link is active. removeLink()
|
|
14198
|
+
* relies on that: it omits `link` *and* those two bookkeeping props from
|
|
14199
|
+
* the serialized props entirely, so all three are deleted from shared
|
|
14200
|
+
* state (see updateYjsMapFromObject in managers/state.ts) rather than
|
|
14201
|
+
* persisted as `undefined`, and the node's original fill/text decoration
|
|
14202
|
+
* reappear immediately.
|
|
14203
|
+
*/
|
|
14204
|
+
getLink(nodeInstance) {
|
|
14205
|
+
const link = nodeInstance.getAttrs().link;
|
|
14206
|
+
return typeof link === "string" ? link : void 0;
|
|
14207
|
+
}
|
|
14208
|
+
setLink(nodeInstance, url) {
|
|
14209
|
+
if (!isValidTextLink(url)) return;
|
|
14210
|
+
const serialized = this.serialize(nodeInstance);
|
|
14211
|
+
serialized.props.linkPreviousFill = serialized.props.fill;
|
|
14212
|
+
serialized.props.linkPreviousTextDecoration = serialized.props.textDecoration;
|
|
14213
|
+
serialized.props.link = url;
|
|
14214
|
+
this.instance.updateNode(serialized);
|
|
14215
|
+
}
|
|
14216
|
+
removeLink(nodeInstance) {
|
|
14217
|
+
const serialized = this.serialize(nodeInstance);
|
|
14218
|
+
delete serialized.props.link;
|
|
14219
|
+
delete serialized.props.linkPreviousFill;
|
|
14220
|
+
delete serialized.props.linkPreviousTextDecoration;
|
|
14221
|
+
this.instance.updateNode(serialized);
|
|
14222
|
+
}
|
|
14083
14223
|
onDestroyInstance() {
|
|
14084
14224
|
super.onDestroyInstance();
|
|
14085
14225
|
if (!this.instance.isServerSide() && this.keyPressHandler) {
|
|
@@ -14145,7 +14285,8 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
14145
14285
|
...props.strokeEnabled && { strokeEnabled: props.strokeEnabled },
|
|
14146
14286
|
...props.stroke && { stroke: props.stroke },
|
|
14147
14287
|
...props.strokeWidth && { strokeWidth: props.strokeWidth },
|
|
14148
|
-
...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled }
|
|
14288
|
+
...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled },
|
|
14289
|
+
...props.link && { link: props.link }
|
|
14149
14290
|
} });
|
|
14150
14291
|
}
|
|
14151
14292
|
static updateNodeState(prevNodeState, nextProps) {
|
|
@@ -14170,7 +14311,8 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
14170
14311
|
...nextProps.strokeEnabled && { strokeEnabled: nextProps.strokeEnabled },
|
|
14171
14312
|
...nextProps.stroke && { stroke: nextProps.stroke },
|
|
14172
14313
|
...nextProps.strokeWidth && { strokeWidth: nextProps.strokeWidth },
|
|
14173
|
-
...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled }
|
|
14314
|
+
...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled },
|
|
14315
|
+
...nextProps.link && { link: nextProps.link }
|
|
14174
14316
|
} });
|
|
14175
14317
|
}
|
|
14176
14318
|
static getSchema() {
|
|
@@ -14204,6 +14346,9 @@ var WeaveTextNode = class extends WeaveNode {
|
|
|
14204
14346
|
]).default("top").describe("Vertical alignment of the text, can be 'top', 'middle' or 'bottom'."),
|
|
14205
14347
|
fill: z.string().default("#000000ff").describe("Fill color of the text in hex format with alpha channel (e.g. #RRGGBBAA)."),
|
|
14206
14348
|
text: z.string().default("text").describe("The actual text content of the node."),
|
|
14349
|
+
link: z.string().url().refine((value) => isValidTextLink(value), { message: "Link must be an absolute http:// or https:// URL." }).optional().describe("External URL the whole text of the node links to. When set, the text is forced underlined and coloured with the configured link colours regardless of fill/textDecoration, is clickable, and opens the URL in a new tab. Only http(s) URLs are accepted. Omit/remove to make the node plain text again."),
|
|
14350
|
+
linkPreviousFill: z.string().optional().describe("Internal bookkeeping: the fill colour the node had right before a link was set, captured automatically so it can be restored when the link is removed. Managed automatically — do not set directly."),
|
|
14351
|
+
linkPreviousTextDecoration: z.string().optional().describe("Internal bookkeeping: the textDecoration the node had right before a link was set, captured automatically so it can be restored when the link is removed. Managed automatically — do not set directly."),
|
|
14207
14352
|
strokeEnabled: z.boolean().default(false).describe("Whether the text outline is enabled."),
|
|
14208
14353
|
stroke: z.string().optional().default("#d6d6d6").describe("Color of the text outline in hex format with alpha channel (e.g. #RRGGBBAA)."),
|
|
14209
14354
|
strokeWidth: z.number().optional().default(2).describe("Width of the text outline in pixels."),
|
|
@@ -17873,21 +18018,29 @@ var WeaveFrameNode = class extends WeaveNode {
|
|
|
17873
18018
|
const WEAVE_STROKE_NODE_TYPE = "stroke";
|
|
17874
18019
|
const WEAVE_STROKE_NODE_DEFAULT_CONFIG = {
|
|
17875
18020
|
splineResolution: 8,
|
|
18021
|
+
splineTargetEdge: 1,
|
|
18022
|
+
splineMaxSteps: 48,
|
|
17876
18023
|
resamplingSpacing: 2,
|
|
17877
18024
|
isEraser: false
|
|
17878
18025
|
};
|
|
17879
18026
|
//#endregion
|
|
17880
18027
|
//#region src/nodes/stroke/stroke.ts
|
|
17881
|
-
var WeaveStrokeNode = class extends WeaveNode {
|
|
18028
|
+
var WeaveStrokeNode = class WeaveStrokeNode extends WeaveNode {
|
|
17882
18029
|
config;
|
|
17883
18030
|
nodeType = WEAVE_STROKE_NODE_TYPE;
|
|
17884
18031
|
initialize = void 0;
|
|
18032
|
+
/**
|
|
18033
|
+
* Below this chord deviation (in canvas units) a spline span is treated as
|
|
18034
|
+
* straight and emitted as a single edge. Subdividing a straight span costs
|
|
18035
|
+
* vertices without changing any pixel.
|
|
18036
|
+
*/
|
|
18037
|
+
static SPLINE_FLATNESS_EPSILON = .08;
|
|
17885
18038
|
constructor(params) {
|
|
17886
18039
|
super();
|
|
17887
18040
|
const { config } = params ?? {};
|
|
17888
18041
|
this.config = mergeExceptArrays(WEAVE_STROKE_NODE_DEFAULT_CONFIG, config);
|
|
17889
18042
|
}
|
|
17890
|
-
resamplePoints(pts, minDist =
|
|
18043
|
+
resamplePoints(pts, minDist = this.config.resamplingSpacing) {
|
|
17891
18044
|
if (pts.length < 2) return pts;
|
|
17892
18045
|
const result = [pts[0]];
|
|
17893
18046
|
let last = pts[0];
|
|
@@ -17901,29 +18054,73 @@ var WeaveStrokeNode = class extends WeaveNode {
|
|
|
17901
18054
|
}
|
|
17902
18055
|
return result;
|
|
17903
18056
|
}
|
|
17904
|
-
|
|
18057
|
+
/** Perpendicular distance from `p` to the segment `a`-`b`. */
|
|
18058
|
+
distanceToSegment(p, a, b) {
|
|
18059
|
+
const dx = b.x - a.x;
|
|
18060
|
+
const dy = b.y - a.y;
|
|
18061
|
+
const lengthSq = dx * dx + dy * dy;
|
|
18062
|
+
let t = lengthSq ? ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq : 0;
|
|
18063
|
+
t = Math.max(0, Math.min(1, t));
|
|
18064
|
+
return Math.hypot(p.x - (a.x + dx * t), p.y - (a.y + dy * t));
|
|
18065
|
+
}
|
|
18066
|
+
/**
|
|
18067
|
+
* Evaluates the uniform Catmull-Rom basis for one 4-point window at `t`.
|
|
18068
|
+
*/
|
|
18069
|
+
catmullRomAt(p0, p1, p2, p3, t) {
|
|
18070
|
+
const tt = t * t;
|
|
18071
|
+
const ttt = tt * t;
|
|
18072
|
+
const q1 = -ttt + 2 * tt - t;
|
|
18073
|
+
const q2 = 3 * ttt - 5 * tt + 2;
|
|
18074
|
+
const q3 = -3 * ttt + 4 * tt + t;
|
|
18075
|
+
const q4 = ttt - tt;
|
|
18076
|
+
return {
|
|
18077
|
+
x: (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2,
|
|
18078
|
+
y: (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2,
|
|
18079
|
+
pressure: (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2
|
|
18080
|
+
};
|
|
18081
|
+
}
|
|
18082
|
+
/**
|
|
18083
|
+
* Samples a Catmull-Rom spline through `pts`, subdividing each span by its
|
|
18084
|
+
* ARC LENGTH rather than by a fixed step count.
|
|
18085
|
+
*
|
|
18086
|
+
* A fixed count is the reason a finished stroke looks faceted while the
|
|
18087
|
+
* one being drawn looks smooth: both render with the same number of
|
|
18088
|
+
* subdivisions per span, but a live stroke's control points sit ~1-2px
|
|
18089
|
+
* apart while a finalized stroke's - after Douglas-Peucker simplification
|
|
18090
|
+
* - sit a median 9-28px apart. The same 8 subdivisions therefore produce
|
|
18091
|
+
* sub-pixel edges live and edges up to ~15px long once finalized, with
|
|
18092
|
+
* visible turns between them.
|
|
18093
|
+
*
|
|
18094
|
+
* `resolution` is now the MINIMUM number of subdivisions for a curved
|
|
18095
|
+
* span (so dense, live-drawn spans behave exactly as before); long spans
|
|
18096
|
+
* get proportionally more, capped so pathological input cannot explode
|
|
18097
|
+
* the vertex count. Spans whose midpoint deviates from their chord by
|
|
18098
|
+
* less than `SPLINE_FLATNESS_EPSILON` are effectively straight and are
|
|
18099
|
+
* emitted as a single edge - subdividing a straight line adds vertices
|
|
18100
|
+
* without changing a pixel.
|
|
18101
|
+
*/
|
|
18102
|
+
getSplinePoints(pts, resolution = this.config.splineResolution) {
|
|
18103
|
+
if (pts.length < 2) return [...pts];
|
|
18104
|
+
const targetEdge = this.config.splineTargetEdge;
|
|
18105
|
+
const maxSteps = this.config.splineMaxSteps;
|
|
17905
18106
|
const result = [];
|
|
17906
18107
|
for (let i = -1; i < pts.length - 2; i++) {
|
|
17907
18108
|
const p0 = pts[Math.max(i, 0)];
|
|
17908
18109
|
const p1 = pts[i + 1];
|
|
17909
18110
|
const p2 = pts[i + 2];
|
|
17910
18111
|
const p3 = pts[Math.min(i + 3, pts.length - 1)];
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
17914
|
-
|
|
17915
|
-
|
|
17916
|
-
|
|
17917
|
-
|
|
17918
|
-
const
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
|
|
17923
|
-
y,
|
|
17924
|
-
pressure
|
|
17925
|
-
});
|
|
17926
|
-
}
|
|
18112
|
+
const chord = Math.hypot(p2.x - p1.x, p2.y - p1.y);
|
|
18113
|
+
let deviation = 0;
|
|
18114
|
+
for (const probe of [
|
|
18115
|
+
.25,
|
|
18116
|
+
.5,
|
|
18117
|
+
.75
|
|
18118
|
+
]) {
|
|
18119
|
+
const at = this.catmullRomAt(p0, p1, p2, p3, probe);
|
|
18120
|
+
deviation = Math.max(deviation, this.distanceToSegment(at, p1, p2));
|
|
18121
|
+
}
|
|
18122
|
+
const steps = deviation < WeaveStrokeNode.SPLINE_FLATNESS_EPSILON ? 1 : Math.min(Math.max(Math.ceil(chord / targetEdge), resolution), maxSteps);
|
|
18123
|
+
for (let s = 0; s < steps; s++) result.push(this.catmullRomAt(p0, p1, p2, p3, s / steps));
|
|
17927
18124
|
}
|
|
17928
18125
|
result.push(pts[pts.length - 1]);
|
|
17929
18126
|
return result;
|
|
@@ -17941,19 +18138,26 @@ var WeaveStrokeNode = class extends WeaveNode {
|
|
|
17941
18138
|
* Draws a filled polygon from the accumulated left/right outline points of a
|
|
17942
18139
|
* dash segment and adds round caps at both ends.
|
|
17943
18140
|
* NOTE: mutates `rightSide` via Array.reverse() — callers must not reuse it after this call.
|
|
18141
|
+
*
|
|
18142
|
+
* The outline is NOT re-smoothed here. It used to be, back when the
|
|
18143
|
+
* centerline was sampled at a fixed subdivision count and could be coarse;
|
|
18144
|
+
* now that the centerline is subdivided by arc length, its offset curves
|
|
18145
|
+
* are already smooth, and measurement showed the extra spline pass cost
|
|
18146
|
+
* roughly half of the node's total render time while changing the drawn
|
|
18147
|
+
* result by well under a pixel (95th-percentile outline edge 1.72px vs
|
|
18148
|
+
* 1.76px; byte-identical on long, gently-curved strokes).
|
|
17944
18149
|
*/
|
|
17945
18150
|
drawDashPolygon(ctx, leftSide, rightSide, color) {
|
|
17946
18151
|
const capStartL = leftSide[0];
|
|
17947
18152
|
const capStartR = rightSide[0];
|
|
17948
18153
|
const capEndL = leftSide.at(-1);
|
|
17949
18154
|
const capEndR = rightSide.at(-1);
|
|
17950
|
-
const
|
|
17951
|
-
const smoothRight = this.getSplinePoints(rightSide.reverse(), 4);
|
|
18155
|
+
const outlineRight = rightSide.reverse();
|
|
17952
18156
|
ctx.beginPath();
|
|
17953
18157
|
ctx.fillStyle = color;
|
|
17954
|
-
ctx.moveTo(
|
|
17955
|
-
for (const p of
|
|
17956
|
-
for (const p of
|
|
18158
|
+
ctx.moveTo(leftSide[0].x, leftSide[0].y);
|
|
18159
|
+
for (const p of leftSide) ctx.lineTo(p.x, p.y);
|
|
18160
|
+
for (const p of outlineRight) ctx.lineTo(p.x, p.y);
|
|
17957
18161
|
ctx.closePath();
|
|
17958
18162
|
ctx.fill();
|
|
17959
18163
|
this.drawRoundCap(ctx, capStartL, capStartR, color);
|
|
@@ -17970,13 +18174,23 @@ var WeaveStrokeNode = class extends WeaveNode {
|
|
|
17970
18174
|
ctx.fill();
|
|
17971
18175
|
return;
|
|
17972
18176
|
}
|
|
17973
|
-
const filtered = this.resamplePoints(pts,
|
|
17974
|
-
const centerline = this.getSplinePoints(filtered,
|
|
18177
|
+
const filtered = this.resamplePoints(pts, this.config.resamplingSpacing);
|
|
18178
|
+
const centerline = this.getSplinePoints(filtered, this.config.splineResolution);
|
|
17975
18179
|
let dashIndex = 0;
|
|
17976
18180
|
let dashOn = true;
|
|
17977
18181
|
let dashRemaining = dash.length ? dash[0] : Infinity;
|
|
17978
18182
|
let leftSide = [];
|
|
17979
18183
|
let rightSide = [];
|
|
18184
|
+
let pendingEndLeft = null;
|
|
18185
|
+
let pendingEndRight = null;
|
|
18186
|
+
const flushRun = () => {
|
|
18187
|
+
if (!dashOn || !leftSide.length || !rightSide.length) return;
|
|
18188
|
+
if (pendingEndLeft && pendingEndRight) {
|
|
18189
|
+
leftSide.push(pendingEndLeft);
|
|
18190
|
+
rightSide.push(pendingEndRight);
|
|
18191
|
+
}
|
|
18192
|
+
this.drawDashPolygon(ctx, leftSide, rightSide, color);
|
|
18193
|
+
};
|
|
17980
18194
|
for (let i = 0; i < centerline.length - 1; i++) {
|
|
17981
18195
|
const p0 = centerline[i];
|
|
17982
18196
|
const p1 = centerline[i + 1];
|
|
@@ -18009,22 +18223,24 @@ var WeaveStrokeNode = class extends WeaveNode {
|
|
|
18009
18223
|
y: y0 - ny * pw0,
|
|
18010
18224
|
pressure: 1
|
|
18011
18225
|
});
|
|
18012
|
-
|
|
18226
|
+
pendingEndLeft = {
|
|
18013
18227
|
x: x1 + nx * pw1,
|
|
18014
18228
|
y: y1 + ny * pw1,
|
|
18015
18229
|
pressure: 1
|
|
18016
|
-
}
|
|
18017
|
-
|
|
18230
|
+
};
|
|
18231
|
+
pendingEndRight = {
|
|
18018
18232
|
x: x1 - nx * pw1,
|
|
18019
18233
|
y: y1 - ny * pw1,
|
|
18020
18234
|
pressure: 1
|
|
18021
|
-
}
|
|
18235
|
+
};
|
|
18022
18236
|
}
|
|
18023
18237
|
dashRemaining -= step;
|
|
18024
18238
|
if (dashRemaining <= 0) {
|
|
18025
|
-
|
|
18239
|
+
flushRun();
|
|
18026
18240
|
leftSide = [];
|
|
18027
18241
|
rightSide = [];
|
|
18242
|
+
pendingEndLeft = null;
|
|
18243
|
+
pendingEndRight = null;
|
|
18028
18244
|
dashOn = !dashOn;
|
|
18029
18245
|
dashIndex = (dashIndex + 1) % dash.length;
|
|
18030
18246
|
dashRemaining = dash[dashIndex];
|
|
@@ -18032,7 +18248,7 @@ var WeaveStrokeNode = class extends WeaveNode {
|
|
|
18032
18248
|
traveled += step;
|
|
18033
18249
|
}
|
|
18034
18250
|
}
|
|
18035
|
-
|
|
18251
|
+
flushRun();
|
|
18036
18252
|
}
|
|
18037
18253
|
drawShape(ctx, shape) {
|
|
18038
18254
|
const strokeElements = shape.getAttrs().strokeElements;
|
|
@@ -24036,7 +24252,22 @@ const BRUSH_TOOL_STATE = {
|
|
|
24036
24252
|
["IDLE"]: "idle",
|
|
24037
24253
|
["DEFINE_STROKE"]: "defineStroke"
|
|
24038
24254
|
};
|
|
24039
|
-
|
|
24255
|
+
/**
|
|
24256
|
+
* Suffix applied to a finished stroke's preview node while it is briefly
|
|
24257
|
+
* kept on screen alongside the persisted node, so the two cannot collide on
|
|
24258
|
+
* the same id.
|
|
24259
|
+
*/
|
|
24260
|
+
const PREVIEW_ID_SUFFIX = "--preview";
|
|
24261
|
+
/**
|
|
24262
|
+
* How many frames the preview of a finished stroke may wait for its
|
|
24263
|
+
* persisted counterpart to be rendered before it is removed regardless.
|
|
24264
|
+
* Bounds the handover so a preview can never be orphaned on screen.
|
|
24265
|
+
*/
|
|
24266
|
+
const PREVIEW_HANDOVER_MAX_FRAMES = 30;
|
|
24267
|
+
const BRUSH_TOOL_DEFAULT_CONFIG = {
|
|
24268
|
+
interpolationSteps: 10,
|
|
24269
|
+
simplifyTolerance: .5
|
|
24270
|
+
};
|
|
24040
24271
|
//#endregion
|
|
24041
24272
|
//#region src/actions/brush-tool/brush-tool.ts
|
|
24042
24273
|
var WeaveBrushToolAction = class extends WeaveAction {
|
|
@@ -24053,6 +24284,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24053
24284
|
prevTouchAction;
|
|
24054
24285
|
penActive = false;
|
|
24055
24286
|
lastSmoothedPressure = .5;
|
|
24287
|
+
hasPressureSample = false;
|
|
24056
24288
|
lastPointerPos = null;
|
|
24057
24289
|
lastPointerTime = 0;
|
|
24058
24290
|
predictedCount = 0;
|
|
@@ -24084,26 +24316,84 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24084
24316
|
opacity: 1
|
|
24085
24317
|
};
|
|
24086
24318
|
}
|
|
24087
|
-
|
|
24319
|
+
/**
|
|
24320
|
+
* Velocity-adaptive exponential smoothing of a single raw pressure sample.
|
|
24321
|
+
*
|
|
24322
|
+
* This is the one place pressure smoothing happens. Every sample that
|
|
24323
|
+
* becomes a stroke point must go through it - including the
|
|
24324
|
+
* high-frequency coalesced samples a stylus reports (see
|
|
24325
|
+
* `handlePointerMove`), which previously bypassed it entirely and so
|
|
24326
|
+
* landed in the stroke with their raw value, no pressure floor, and
|
|
24327
|
+
* without advancing the smoothing state for later samples.
|
|
24328
|
+
*
|
|
24329
|
+
* Timing intentionally uses `performance.now()` (not the event's own
|
|
24330
|
+
* `timeStamp`), matching the original behaviour: the two are not
|
|
24331
|
+
* guaranteed to share a time origin, and mixing them corrupts the
|
|
24332
|
+
* velocity term that drives `alpha`.
|
|
24333
|
+
*
|
|
24334
|
+
* The first sample of a stroke SEEDS the filter with its own value
|
|
24335
|
+
* rather than being blended toward the neutral 0.5 baseline. Blending
|
|
24336
|
+
* from a constant gives every stroke a warm-up transient: the filter
|
|
24337
|
+
* starts at 0.5 and converges toward the pressure actually being
|
|
24338
|
+
* applied, so a stroke drawn lighter than 0.5 renders visibly fatter at
|
|
24339
|
+
* its start (and heavier than 0.5, thinner) until the filter catches
|
|
24340
|
+
* up. Seeding removes that transient entirely - smoothing then only
|
|
24341
|
+
* ever acts between real samples, which is its actual purpose.
|
|
24342
|
+
*/
|
|
24343
|
+
smoothPressureSample(raw, clientX, clientY) {
|
|
24088
24344
|
const now = performance.now();
|
|
24089
24345
|
let velocity = 0;
|
|
24090
|
-
|
|
24091
|
-
|
|
24092
|
-
const
|
|
24346
|
+
const hasPosition = Number.isFinite(clientX) && Number.isFinite(clientY);
|
|
24347
|
+
if (hasPosition && this.lastPointerPos && now - this.lastPointerTime > 0) {
|
|
24348
|
+
const dx = clientX - this.lastPointerPos.x;
|
|
24349
|
+
const dy = clientY - this.lastPointerPos.y;
|
|
24093
24350
|
velocity = Math.hypot(dx, dy) / (now - this.lastPointerTime) * 1e3;
|
|
24094
24351
|
}
|
|
24095
|
-
this.lastPointerPos = {
|
|
24096
|
-
x:
|
|
24097
|
-
y:
|
|
24352
|
+
if (hasPosition) this.lastPointerPos = {
|
|
24353
|
+
x: clientX,
|
|
24354
|
+
y: clientY
|
|
24098
24355
|
};
|
|
24099
24356
|
this.lastPointerTime = now;
|
|
24357
|
+
const safeRaw = Number.isFinite(raw) ? raw : .5;
|
|
24358
|
+
if (!this.hasPressureSample) {
|
|
24359
|
+
this.hasPressureSample = true;
|
|
24360
|
+
this.lastSmoothedPressure = safeRaw;
|
|
24361
|
+
return Math.max(this.lastSmoothedPressure, .15);
|
|
24362
|
+
}
|
|
24100
24363
|
const alpha = Math.min(Math.max(velocity / 1500, .15), .6);
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
else raw = .5;
|
|
24104
|
-
this.lastSmoothedPressure = alpha * raw + (1 - alpha) * this.lastSmoothedPressure;
|
|
24364
|
+
const smoothed = alpha * safeRaw + (1 - alpha) * this.lastSmoothedPressure;
|
|
24365
|
+
this.lastSmoothedPressure = Number.isFinite(smoothed) ? smoothed : safeRaw;
|
|
24105
24366
|
return Math.max(this.lastSmoothedPressure, .15);
|
|
24106
24367
|
}
|
|
24368
|
+
/**
|
|
24369
|
+
* Raw pressure a pointer sample reports: the device's own reading for a
|
|
24370
|
+
* pen, a neutral constant for devices that do not sense pressure.
|
|
24371
|
+
*/
|
|
24372
|
+
getRawPressure(pointerType, pressure) {
|
|
24373
|
+
if (pointerType === "pen") return (typeof pressure === "number" ? pressure : 0) || .5;
|
|
24374
|
+
return .5;
|
|
24375
|
+
}
|
|
24376
|
+
getEventPressure(e) {
|
|
24377
|
+
return this.smoothPressureSample(this.getRawPressure(e.evt.pointerType, e.evt.pressure), e.evt.clientX, e.evt.clientY);
|
|
24378
|
+
}
|
|
24379
|
+
/**
|
|
24380
|
+
* Resets the pressure-smoothing state (smoothed pressure, last known pointer
|
|
24381
|
+
* position/time, and predicted-point bookkeeping) to a neutral baseline.
|
|
24382
|
+
*
|
|
24383
|
+
* This state is scoped to a single stroke: it must be reset before the
|
|
24384
|
+
* first pressure sample of a new stroke is computed (in `handlePointerDown`,
|
|
24385
|
+
* ahead of the `getEventPressure` call for point 0), not only afterwards -
|
|
24386
|
+
* otherwise that first sample can inherit smoothing state left behind by
|
|
24387
|
+
* the previous stroke (its ending pressure, pointer position and time),
|
|
24388
|
+
* inflating the very first point's pressure.
|
|
24389
|
+
*/
|
|
24390
|
+
resetPressureSmoothingState() {
|
|
24391
|
+
this.lastSmoothedPressure = .5;
|
|
24392
|
+
this.hasPressureSample = false;
|
|
24393
|
+
this.lastPointerPos = null;
|
|
24394
|
+
this.lastPointerTime = 0;
|
|
24395
|
+
this.predictedCount = 0;
|
|
24396
|
+
}
|
|
24107
24397
|
setupEvents() {
|
|
24108
24398
|
const stage = this.instance.getStage();
|
|
24109
24399
|
this.prevTouchAction = stage.container().style.touchAction;
|
|
@@ -24135,6 +24425,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24135
24425
|
if (e?.evt?.button !== 0) return;
|
|
24136
24426
|
if (e.evt.pointerType === "touch" && this.penActive) return;
|
|
24137
24427
|
if (e.evt.pointerType === "pen") this.penActive = true;
|
|
24428
|
+
this.resetPressureSmoothingState();
|
|
24138
24429
|
const pointPressure = this.getEventPressure(e);
|
|
24139
24430
|
this.handleStartStroke(pointPressure);
|
|
24140
24431
|
e.evt.stopPropagation();
|
|
@@ -24147,16 +24438,21 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24147
24438
|
if (this.getZoomPlugin()?.isPinching()) return;
|
|
24148
24439
|
const coalescedEvents = e.evt.getCoalescedEvents ? e.evt.getCoalescedEvents() : [];
|
|
24149
24440
|
if (coalescedEvents.length > 1) {
|
|
24150
|
-
|
|
24151
|
-
|
|
24152
|
-
|
|
24153
|
-
}
|
|
24441
|
+
const samples = coalescedEvents.map((ce) => ({
|
|
24442
|
+
pressure: this.smoothPressureSample(this.getRawPressure(ce.pointerType, ce.pressure), ce.clientX, ce.clientY),
|
|
24443
|
+
isPredicted: false
|
|
24444
|
+
}));
|
|
24154
24445
|
const predictedEvents = e.evt.getPredictedEvents ? e.evt.getPredictedEvents() : [];
|
|
24155
24446
|
if (predictedEvents.length > 0) {
|
|
24156
24447
|
const last = predictedEvents[predictedEvents.length - 1];
|
|
24157
|
-
const predPressure = last.pointerType
|
|
24158
|
-
|
|
24448
|
+
const predPressure = Math.max(.15 * this.getRawPressure(last.pointerType, last.pressure) + .85 * this.lastSmoothedPressure, .15);
|
|
24449
|
+
samples.push({
|
|
24450
|
+
pressure: predPressure,
|
|
24451
|
+
sourceEvent: last,
|
|
24452
|
+
isPredicted: true
|
|
24453
|
+
});
|
|
24159
24454
|
}
|
|
24455
|
+
this.applyMovementSamples(samples);
|
|
24160
24456
|
} else {
|
|
24161
24457
|
const pointPressure = this.getEventPressure(e);
|
|
24162
24458
|
this.handleMovement(pointPressure, void 0, false);
|
|
@@ -24202,10 +24498,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24202
24498
|
};
|
|
24203
24499
|
}
|
|
24204
24500
|
handleStartStroke(pressure) {
|
|
24205
|
-
this.
|
|
24206
|
-
this.lastPointerPos = null;
|
|
24207
|
-
this.lastPointerTime = 0;
|
|
24208
|
-
this.predictedCount = 0;
|
|
24501
|
+
this.resetPressureSmoothingState();
|
|
24209
24502
|
const { mousePoint, container, measureContainer } = this.instance.getMousePointer();
|
|
24210
24503
|
this.clickPoint = mousePoint;
|
|
24211
24504
|
this.container = container;
|
|
@@ -24234,36 +24527,60 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24234
24527
|
}
|
|
24235
24528
|
this.setState(BRUSH_TOOL_STATE.DEFINE_STROKE);
|
|
24236
24529
|
}
|
|
24237
|
-
|
|
24530
|
+
/**
|
|
24531
|
+
* Appends one or more pointer samples to the stroke in a single
|
|
24532
|
+
* read-modify-write, then renders once.
|
|
24533
|
+
*
|
|
24534
|
+
* Batching matters: a stylus reports a burst of coalesced samples per
|
|
24535
|
+
* frame, and applying them one at a time meant copying the whole point
|
|
24536
|
+
* array, recomputing the whole bounding box and issuing a full redraw
|
|
24537
|
+
* once PER SAMPLE. That is O(n) work repeated ~10x a frame, i.e.
|
|
24538
|
+
* quadratic in stroke length - which is why drawing fast could stall for
|
|
24539
|
+
* seconds. Here that O(n) work happens once per event instead.
|
|
24540
|
+
*/
|
|
24541
|
+
applyMovementSamples(samples) {
|
|
24238
24542
|
if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
|
|
24543
|
+
if (samples.length === 0) return;
|
|
24239
24544
|
const stage = this.instance.getStage();
|
|
24240
|
-
const tempStroke =
|
|
24241
|
-
if (this.measureContainer
|
|
24242
|
-
|
|
24545
|
+
const tempStroke = stage.findOne(`#${this.strokeId}`);
|
|
24546
|
+
if (!this.measureContainer || !tempStroke) return;
|
|
24547
|
+
let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
|
|
24548
|
+
for (const sample of samples) {
|
|
24549
|
+
if (sample.sourceEvent) stage.setPointersPositions(sample.sourceEvent);
|
|
24243
24550
|
const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.measureContainer);
|
|
24244
24551
|
const currentPoint = {
|
|
24245
24552
|
x: mousePoint.x - tempStroke.x(),
|
|
24246
24553
|
y: mousePoint.y - tempStroke.y(),
|
|
24247
|
-
pressure
|
|
24554
|
+
pressure: sample.pressure
|
|
24248
24555
|
};
|
|
24249
|
-
|
|
24250
|
-
if (!isPredicted && this.predictedCount > 0) {
|
|
24556
|
+
if (!sample.isPredicted && this.predictedCount > 0) {
|
|
24251
24557
|
newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
|
|
24252
24558
|
this.predictedCount = 0;
|
|
24253
24559
|
}
|
|
24560
|
+
if (!sample.isPredicted && newStrokeElements.length === 1) newStrokeElements[0] = {
|
|
24561
|
+
...newStrokeElements[0],
|
|
24562
|
+
pressure: currentPoint.pressure
|
|
24563
|
+
};
|
|
24254
24564
|
newStrokeElements.push(currentPoint);
|
|
24255
|
-
if (isPredicted) this.predictedCount++;
|
|
24256
|
-
const box = this.getBoundingBox(newStrokeElements);
|
|
24257
|
-
tempStroke.setAttrs({
|
|
24258
|
-
width: box.width,
|
|
24259
|
-
height: box.height,
|
|
24260
|
-
x: 0,
|
|
24261
|
-
y: 0,
|
|
24262
|
-
strokeElements: newStrokeElements
|
|
24263
|
-
});
|
|
24264
|
-
const nodeHandler = this.instance.getNodeHandler("stroke");
|
|
24265
|
-
if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
|
|
24565
|
+
if (sample.isPredicted) this.predictedCount++;
|
|
24266
24566
|
}
|
|
24567
|
+
const box = this.getBoundingBox(newStrokeElements);
|
|
24568
|
+
tempStroke.setAttrs({
|
|
24569
|
+
width: box.width,
|
|
24570
|
+
height: box.height,
|
|
24571
|
+
x: 0,
|
|
24572
|
+
y: 0,
|
|
24573
|
+
strokeElements: newStrokeElements
|
|
24574
|
+
});
|
|
24575
|
+
const nodeHandler = this.instance.getNodeHandler("stroke");
|
|
24576
|
+
if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
|
|
24577
|
+
}
|
|
24578
|
+
handleMovement(pressure, predictedEvent, isPredicted = false) {
|
|
24579
|
+
this.applyMovementSamples([{
|
|
24580
|
+
pressure,
|
|
24581
|
+
sourceEvent: predictedEvent,
|
|
24582
|
+
isPredicted
|
|
24583
|
+
}]);
|
|
24267
24584
|
}
|
|
24268
24585
|
finalizeStroke(tempStroke, nodeHandler) {
|
|
24269
24586
|
const box = this.getBoundingBox(tempStroke.getAttrs().strokeElements);
|
|
@@ -24272,12 +24589,19 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24272
24589
|
newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
|
|
24273
24590
|
this.predictedCount = 0;
|
|
24274
24591
|
}
|
|
24592
|
+
if (newStrokeElements.length >= 2) {
|
|
24593
|
+
const lastIndex = newStrokeElements.length - 1;
|
|
24594
|
+
newStrokeElements[lastIndex] = {
|
|
24595
|
+
...newStrokeElements[lastIndex],
|
|
24596
|
+
pressure: newStrokeElements[lastIndex - 1].pressure
|
|
24597
|
+
};
|
|
24598
|
+
}
|
|
24275
24599
|
newStrokeElements = newStrokeElements.map((point) => ({
|
|
24276
24600
|
...point,
|
|
24277
24601
|
x: point.x - box.x,
|
|
24278
24602
|
y: point.y - box.y
|
|
24279
24603
|
}));
|
|
24280
|
-
const compressedPoints = simplify(newStrokeElements,
|
|
24604
|
+
const compressedPoints = simplify(newStrokeElements, this.config.simplifyTolerance, true);
|
|
24281
24605
|
const sw = tempStroke.getAttrs().strokeWidth ?? 1;
|
|
24282
24606
|
const finalWidth = Math.max(box.width, sw);
|
|
24283
24607
|
const finalHeight = Math.max(box.height, sw);
|
|
@@ -24290,9 +24614,44 @@ var WeaveBrushToolAction = class extends WeaveAction {
|
|
|
24290
24614
|
y: finalY,
|
|
24291
24615
|
strokeElements: compressedPoints
|
|
24292
24616
|
});
|
|
24293
|
-
const
|
|
24294
|
-
|
|
24295
|
-
|
|
24617
|
+
const strokeNodeId = tempStroke.getAttrs().id ?? "";
|
|
24618
|
+
const serializedNode = nodeHandler.serialize(tempStroke);
|
|
24619
|
+
const hasPoints = tempStroke.getAttrs().strokeElements.length >= 1;
|
|
24620
|
+
const preview = this.instance.getStage().findOne(`#${strokeNodeId}`);
|
|
24621
|
+
if (!hasPoints) {
|
|
24622
|
+
preview?.destroy();
|
|
24623
|
+
return;
|
|
24624
|
+
}
|
|
24625
|
+
if (preview) preview.setAttrs({ id: `${strokeNodeId}${PREVIEW_ID_SUFFIX}` });
|
|
24626
|
+
this.instance.addNode(serializedNode, this.container?.getAttrs().id);
|
|
24627
|
+
this.removePreviewWhenRendered(preview, strokeNodeId);
|
|
24628
|
+
}
|
|
24629
|
+
/**
|
|
24630
|
+
* Destroys the finished stroke's preview node once its persisted
|
|
24631
|
+
* counterpart has actually been rendered onto the stage, so the stroke is
|
|
24632
|
+
* never absent from the canvas between the two.
|
|
24633
|
+
*
|
|
24634
|
+
* Falls back to destroying immediately where no frame scheduler exists
|
|
24635
|
+
* (non-browser hosts), and gives up waiting after a bounded number of
|
|
24636
|
+
* frames so a preview can never be orphaned if the node never arrives.
|
|
24637
|
+
*/
|
|
24638
|
+
removePreviewWhenRendered(preview, realNodeId) {
|
|
24639
|
+
if (!preview) return;
|
|
24640
|
+
const scheduleFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : void 0;
|
|
24641
|
+
if (!scheduleFrame) {
|
|
24642
|
+
preview.destroy();
|
|
24643
|
+
return;
|
|
24644
|
+
}
|
|
24645
|
+
let framesWaited = 0;
|
|
24646
|
+
const check = () => {
|
|
24647
|
+
if (this.instance.getStage().findOne(`#${realNodeId}`) || framesWaited >= 30) {
|
|
24648
|
+
preview.destroy();
|
|
24649
|
+
return;
|
|
24650
|
+
}
|
|
24651
|
+
framesWaited++;
|
|
24652
|
+
scheduleFrame(check);
|
|
24653
|
+
};
|
|
24654
|
+
check();
|
|
24296
24655
|
}
|
|
24297
24656
|
handleEndStroke() {
|
|
24298
24657
|
const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
|
|
@@ -28154,7 +28513,7 @@ const POOL_SIZE_MULTIPLIER = 128;
|
|
|
28154
28513
|
let pool;
|
|
28155
28514
|
let poolOffset;
|
|
28156
28515
|
let fillPool = (bytes) => {
|
|
28157
|
-
if (bytes < 0) throw new RangeError("Wrong ID size");
|
|
28516
|
+
if (bytes < 0 || bytes > 1024) throw new RangeError("Wrong ID size");
|
|
28158
28517
|
try {
|
|
28159
28518
|
if (!pool || pool.length < bytes) {
|
|
28160
28519
|
pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
|
|
@@ -32935,4 +33294,4 @@ const setupCanvasBackend = async () => {
|
|
|
32935
33294
|
await import("konva/canvas-backend");
|
|
32936
33295
|
};
|
|
32937
33296
|
//#endregion
|
|
32938
|
-
export { ALIGN_NODES_ALIGN_TO, ALIGN_NODES_TOOL_ACTION_NAME, ALIGN_NODES_TOOL_STATE, BRUSH_TOOL_ACTION_NAME, BRUSH_TOOL_DEFAULT_CONFIG, BRUSH_TOOL_STATE, CONNECTOR_TOOL_ACTION_NAME, CONNECTOR_TOOL_DEFAULT_CONFIG, CONNECTOR_TOOL_STATE, COPY_PASTE_NODES_PLUGIN_STATE, DEFAULT_GUIDE_TOOL_ACTION_CONFIG, DEFAULT_SNAPPING_MANAGER_CONFIG, ELLIPSE_TOOL_ACTION_NAME, ELLIPSE_TOOL_STATE, ERASER_TOOL_ACTION_NAME, ERASER_TOOL_STATE, FRAME_TOOL_ACTION_NAME, FRAME_TOOL_STATE, GUIDE_DISTANCE_NAME, GUIDE_DISTANCE_ORIGIN, GUIDE_KIND, GUIDE_NAME, GUIDE_ORIENTATION, GUIDE_STATE, GUIDE_TOOL_ACTION_NAME, GUIDE_TOOL_STATE, LINE_TOOL_ACTION_NAME, LINE_TOOL_DEFAULT_CONFIG, LINE_TOOL_STATE, MEASURE_TOOL_ACTION_NAME, MEASURE_TOOL_STATE, MOVE_ORIENTATION, MOVE_TOOL_ACTION_NAME, MOVE_TOOL_STATE, PEN_TOOL_ACTION_NAME, PEN_TOOL_STATE, POLYGON_TOOL_ACTION_NAME, POLYGON_TOOL_STATE, RECTANGLE_TOOL_ACTION_NAME, RECTANGLE_TOOL_STATE, REGULAR_POLYGON_TOOL_ACTION_NAME, REGULAR_POLYGON_TOOL_STATE, SELECTION_TOOL_ACTION_NAME, SELECTION_TOOL_STATE, STAGE_MINIMAP_DEFAULT_CONFIG, STAR_TOOL_ACTION_NAME, STAR_TOOL_STATE, TEXT_LAYOUT, TEXT_TOOL_ACTION_NAME, TEXT_TOOL_STATE, VIDEO_TOOL_ACTION_NAME, VIDEO_TOOL_STATE, WEAVE_ARROW_NODE_TYPE, WEAVE_ARROW_TOOL_ACTION_NAME, WEAVE_ARROW_TOOL_STATE, WEAVE_COMMENTS_RENDERER_KEY, WEAVE_COMMENTS_TOOL_LAYER_ID, WEAVE_COMMENT_CREATE_ACTION, WEAVE_COMMENT_NODE_ACTION, WEAVE_COMMENT_NODE_DEFAULTS, WEAVE_COMMENT_NODE_TYPE, WEAVE_COMMENT_STATUS, WEAVE_COMMENT_TOOL_ACTION_NAME, WEAVE_COMMENT_TOOL_DEFAULT_CONFIG, WEAVE_COMMENT_TOOL_STATE, WEAVE_COMMENT_VIEW_ACTION, WEAVE_CONNECTOR_NODE_ANCHOR_ORIGIN, WEAVE_CONNECTOR_NODE_DECORATOR_TYPE, WEAVE_CONNECTOR_NODE_DEFAULT_CONFIG, WEAVE_CONNECTOR_NODE_LINE_ORIGIN, WEAVE_CONNECTOR_NODE_LINE_TYPE, WEAVE_CONNECTOR_NODE_TYPE, WEAVE_COPY_PASTE_CONFIG_DEFAULT, WEAVE_COPY_PASTE_NODES_KEY, WEAVE_COPY_PASTE_PASTE_CATCHER_ID, WEAVE_COPY_PASTE_PASTE_MODES, WEAVE_DEFAULT_USER_INFO_FUNCTION, WEAVE_ELLIPSE_NODE_TYPE, WEAVE_FRAME_DEFAULT_BACKGROUND_COLOR, WEAVE_FRAME_NODE_DEFAULT_CONFIG, WEAVE_FRAME_NODE_DEFAULT_PROPS, WEAVE_FRAME_NODE_TYPE, WEAVE_GRID_DEFAULT_CONFIG, WEAVE_GRID_DOT_TYPES, WEAVE_GRID_LAYER_ID, WEAVE_GRID_TYPES, WEAVE_GROUP_NODE_TYPE, WEAVE_IMAGES_TOOL_ACTION_NAME, WEAVE_IMAGES_TOOL_DEFAULT_CONFIG, WEAVE_IMAGES_TOOL_STATE, WEAVE_IMAGES_TOOL_UPLOAD_TYPE, WEAVE_IMAGE_CROP_ANCHOR_POSITION, WEAVE_IMAGE_CROP_END_TYPE, WEAVE_IMAGE_DEFAULT_CONFIG, WEAVE_IMAGE_NODE_TYPE, WEAVE_IMAGE_TOOL_ACTION_NAME, WEAVE_IMAGE_TOOL_CONFIG_DEFAULT, WEAVE_IMAGE_TOOL_STATE, WEAVE_IMAGE_TOOL_UPLOAD_TYPE, WEAVE_LAYER_NODE_TYPE, WEAVE_LINE_NODE_DEFAULT_CONFIG, WEAVE_LINE_NODE_TYPE, WEAVE_MEASURE_NODE_DEFAULT_CONFIG, WEAVE_MEASURE_NODE_TYPE, WEAVE_MEASURE_TOOL_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID, WEAVE_NODES_SELECTION_DEFAULT_CONFIG, WEAVE_NODES_SELECTION_KEY, WEAVE_NODES_SELECTION_LAYER_ID, WEAVE_NODES_SNAPPING_PLUGIN_KEY, WEAVE_POLYGON_NODE_TYPE, WEAVE_POLYGON_PRESETS, WEAVE_RECTANGLE_NODE_TYPE, WEAVE_REGULAR_POLYGON_NODE_TYPE, WEAVE_SHAPE_LABEL_DEFAULTS, WEAVE_STAGE_DEFAULT_MODE, WEAVE_STAGE_DROP_AREA_KEY, WEAVE_STAGE_GRID_PLUGIN_KEY, WEAVE_STAGE_IMAGE_CROPPING_MODE, WEAVE_STAGE_KEYBOARD_MOVE_DEFAULT_CONFIG, WEAVE_STAGE_KEYBOARD_MOVE_KEY, WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION, WEAVE_STAGE_MINIMAP_KEY, WEAVE_STAGE_NODE_TYPE, WEAVE_STAGE_PANNING_DEFAULT_CONFIG, WEAVE_STAGE_PANNING_KEY, WEAVE_STAGE_PANNING_THROTTLE_MS, WEAVE_STAGE_SHAPE_LABEL_EDITION_MODE, WEAVE_STAGE_TEXT_EDITION_MODE, WEAVE_STAGE_ZOOM_DEFAULT_CONFIG, WEAVE_STAGE_ZOOM_KEY, WEAVE_STAGE_ZOOM_TYPE, WEAVE_STAR_NODE_TYPE, WEAVE_STROKE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_NODE_TYPE, WEAVE_STROKE_SINGLE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_SINGLE_NODE_TIP_SIDE, WEAVE_STROKE_SINGLE_NODE_TIP_TYPE, WEAVE_STROKE_SINGLE_NODE_TYPE, WEAVE_STROKE_TOOL_ACTION_NAME, WEAVE_STROKE_TOOL_ACTION_NAME_ALIASES, WEAVE_STROKE_TOOL_DEFAULT_CONFIG, WEAVE_STROKE_TOOL_STATE, WEAVE_TEXT_NODE_DEFAULT_CONFIG, WEAVE_TEXT_NODE_TYPE, WEAVE_USERS_POINTERS_CONFIG_DEFAULT_PROPS, WEAVE_USERS_POINTERS_KEY, WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS, WEAVE_USERS_PRESENCE_PLUGIN_KEY, WEAVE_USERS_SELECTION_KEY, WEAVE_USER_POINTER_KEY, WEAVE_USER_PRESENCE_KEY, WEAVE_USER_SELECTION_KEY, WEAVE_VIDEO_DEFAULT_CONFIG, WEAVE_VIDEO_NODE_TYPE, Weave, WeaveAction, WeaveAlignNodesToolAction, WeaveArrowNode, WeaveArrowToolAction, WeaveBrushToolAction, WeaveCommentNode, WeaveCommentToolAction, WeaveCommentsRendererPlugin, WeaveConnectedUsersPlugin, WeaveConnectorNode, WeaveConnectorToolAction, WeaveContextMenuPlugin, WeaveCopyPasteNodesPlugin, WeaveEllipseNode, WeaveEllipseToolAction, WeaveEraserToolAction, WeaveExportNodesToolAction, WeaveExportStageToolAction, WeaveFitToScreenToolAction, WeaveFitToSelectionToolAction, WeaveFrameNode, WeaveFrameToolAction, WeaveGroupNode, WeaveGuideToolAction, WeaveImageNode, WeaveImageToolAction, WeaveImagesToolAction, WeaveLayerNode, WeaveLineNode, WeaveLineToolAction, WeaveMeasureNode, WeaveMeasureToolAction, WeaveMoveToolAction, WeaveNode, WeaveNodesMultiSelectionFeedbackPlugin, WeaveNodesSelectionPlugin, WeaveNodesSnappingPlugin, WeavePenToolAction, WeavePlugin, WeavePolygonNode, WeavePolygonToolAction, WeaveRectangleNode, WeaveRectangleToolAction, WeaveRegularPolygonNode, WeaveRegularPolygonToolAction, WeaveRenderer, WeaveSelectionToolAction, WeaveStageDropAreaPlugin, WeaveStageGridPlugin, WeaveStageKeyboardMovePlugin, WeaveStageMinimapPlugin, WeaveStageNode, WeaveStagePanningPlugin, WeaveStageResizePlugin, WeaveStageZoomPlugin, WeaveStarNode, WeaveStarToolAction, WeaveStateManipulation, WeaveStore, WeaveStrokeNode, WeaveStrokeSingleNode, WeaveStrokeToolAction, WeaveTextNode, WeaveTextToolAction, WeaveUsersPointersPlugin, WeaveUsersPresencePlugin, WeaveUsersSelectionPlugin, WeaveVideoNode, WeaveVideoToolAction, WeaveZoomInToolAction, WeaveZoomOutToolAction, buildAncestorGroupIds, canComposite, clearContainerTargets, computeEllipseLabelMinSize, computePolygonLabelMinSize, computeRectangleLabelMinSize, containerOverCursor, containsNodeDeep, defaultInitialState, downscaleImageFile, downscaleImageFromURL, getBoundingBox, getDownscaleRatio, getExportBoundingBox, getImageSizeFromFile, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isServer, labelId, loadImageSource, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps };
|
|
33297
|
+
export { ALIGN_NODES_ALIGN_TO, ALIGN_NODES_TOOL_ACTION_NAME, ALIGN_NODES_TOOL_STATE, BRUSH_TOOL_ACTION_NAME, BRUSH_TOOL_DEFAULT_CONFIG, BRUSH_TOOL_STATE, CONNECTOR_TOOL_ACTION_NAME, CONNECTOR_TOOL_DEFAULT_CONFIG, CONNECTOR_TOOL_STATE, COPY_PASTE_NODES_PLUGIN_STATE, DEFAULT_GUIDE_TOOL_ACTION_CONFIG, DEFAULT_SNAPPING_MANAGER_CONFIG, ELLIPSE_TOOL_ACTION_NAME, ELLIPSE_TOOL_STATE, ERASER_TOOL_ACTION_NAME, ERASER_TOOL_STATE, FRAME_TOOL_ACTION_NAME, FRAME_TOOL_STATE, GUIDE_DISTANCE_NAME, GUIDE_DISTANCE_ORIGIN, GUIDE_KIND, GUIDE_NAME, GUIDE_ORIENTATION, GUIDE_STATE, GUIDE_TOOL_ACTION_NAME, GUIDE_TOOL_STATE, LINE_TOOL_ACTION_NAME, LINE_TOOL_DEFAULT_CONFIG, LINE_TOOL_STATE, MEASURE_TOOL_ACTION_NAME, MEASURE_TOOL_STATE, MOVE_ORIENTATION, MOVE_TOOL_ACTION_NAME, MOVE_TOOL_STATE, PEN_TOOL_ACTION_NAME, PEN_TOOL_STATE, POLYGON_TOOL_ACTION_NAME, POLYGON_TOOL_STATE, PREVIEW_HANDOVER_MAX_FRAMES, PREVIEW_ID_SUFFIX, RECTANGLE_TOOL_ACTION_NAME, RECTANGLE_TOOL_STATE, REGULAR_POLYGON_TOOL_ACTION_NAME, REGULAR_POLYGON_TOOL_STATE, SELECTION_TOOL_ACTION_NAME, SELECTION_TOOL_STATE, STAGE_MINIMAP_DEFAULT_CONFIG, STAR_TOOL_ACTION_NAME, STAR_TOOL_STATE, TEXT_LAYOUT, TEXT_TOOL_ACTION_NAME, TEXT_TOOL_STATE, VIDEO_TOOL_ACTION_NAME, VIDEO_TOOL_STATE, WEAVE_ARROW_NODE_TYPE, WEAVE_ARROW_TOOL_ACTION_NAME, WEAVE_ARROW_TOOL_STATE, WEAVE_COMMENTS_RENDERER_KEY, WEAVE_COMMENTS_TOOL_LAYER_ID, WEAVE_COMMENT_CREATE_ACTION, WEAVE_COMMENT_NODE_ACTION, WEAVE_COMMENT_NODE_DEFAULTS, WEAVE_COMMENT_NODE_TYPE, WEAVE_COMMENT_STATUS, WEAVE_COMMENT_TOOL_ACTION_NAME, WEAVE_COMMENT_TOOL_DEFAULT_CONFIG, WEAVE_COMMENT_TOOL_STATE, WEAVE_COMMENT_VIEW_ACTION, WEAVE_CONNECTOR_NODE_ANCHOR_ORIGIN, WEAVE_CONNECTOR_NODE_DECORATOR_TYPE, WEAVE_CONNECTOR_NODE_DEFAULT_CONFIG, WEAVE_CONNECTOR_NODE_LINE_ORIGIN, WEAVE_CONNECTOR_NODE_LINE_TYPE, WEAVE_CONNECTOR_NODE_TYPE, WEAVE_COPY_PASTE_CONFIG_DEFAULT, WEAVE_COPY_PASTE_NODES_KEY, WEAVE_COPY_PASTE_PASTE_CATCHER_ID, WEAVE_COPY_PASTE_PASTE_MODES, WEAVE_DEFAULT_USER_INFO_FUNCTION, WEAVE_ELLIPSE_NODE_TYPE, WEAVE_FRAME_DEFAULT_BACKGROUND_COLOR, WEAVE_FRAME_NODE_DEFAULT_CONFIG, WEAVE_FRAME_NODE_DEFAULT_PROPS, WEAVE_FRAME_NODE_TYPE, WEAVE_GRID_DEFAULT_CONFIG, WEAVE_GRID_DOT_TYPES, WEAVE_GRID_LAYER_ID, WEAVE_GRID_TYPES, WEAVE_GROUP_NODE_TYPE, WEAVE_IMAGES_TOOL_ACTION_NAME, WEAVE_IMAGES_TOOL_DEFAULT_CONFIG, WEAVE_IMAGES_TOOL_STATE, WEAVE_IMAGES_TOOL_UPLOAD_TYPE, WEAVE_IMAGE_CROP_ANCHOR_POSITION, WEAVE_IMAGE_CROP_END_TYPE, WEAVE_IMAGE_DEFAULT_CONFIG, WEAVE_IMAGE_NODE_TYPE, WEAVE_IMAGE_TOOL_ACTION_NAME, WEAVE_IMAGE_TOOL_CONFIG_DEFAULT, WEAVE_IMAGE_TOOL_STATE, WEAVE_IMAGE_TOOL_UPLOAD_TYPE, WEAVE_LAYER_NODE_TYPE, WEAVE_LINE_NODE_DEFAULT_CONFIG, WEAVE_LINE_NODE_TYPE, WEAVE_MEASURE_NODE_DEFAULT_CONFIG, WEAVE_MEASURE_NODE_TYPE, WEAVE_MEASURE_TOOL_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID, WEAVE_NODES_SELECTION_DEFAULT_CONFIG, WEAVE_NODES_SELECTION_KEY, WEAVE_NODES_SELECTION_LAYER_ID, WEAVE_NODES_SNAPPING_PLUGIN_KEY, WEAVE_POLYGON_NODE_TYPE, WEAVE_POLYGON_PRESETS, WEAVE_RECTANGLE_NODE_TYPE, WEAVE_REGULAR_POLYGON_NODE_TYPE, WEAVE_SHAPE_LABEL_DEFAULTS, WEAVE_STAGE_DEFAULT_MODE, WEAVE_STAGE_DROP_AREA_KEY, WEAVE_STAGE_GRID_PLUGIN_KEY, WEAVE_STAGE_IMAGE_CROPPING_MODE, WEAVE_STAGE_KEYBOARD_MOVE_DEFAULT_CONFIG, WEAVE_STAGE_KEYBOARD_MOVE_KEY, WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION, WEAVE_STAGE_MINIMAP_KEY, WEAVE_STAGE_NODE_TYPE, WEAVE_STAGE_PANNING_DEFAULT_CONFIG, WEAVE_STAGE_PANNING_KEY, WEAVE_STAGE_PANNING_THROTTLE_MS, WEAVE_STAGE_SHAPE_LABEL_EDITION_MODE, WEAVE_STAGE_TEXT_EDITION_MODE, WEAVE_STAGE_ZOOM_DEFAULT_CONFIG, WEAVE_STAGE_ZOOM_KEY, WEAVE_STAGE_ZOOM_TYPE, WEAVE_STAR_NODE_TYPE, WEAVE_STROKE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_NODE_TYPE, WEAVE_STROKE_SINGLE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_SINGLE_NODE_TIP_SIDE, WEAVE_STROKE_SINGLE_NODE_TIP_TYPE, WEAVE_STROKE_SINGLE_NODE_TYPE, WEAVE_STROKE_TOOL_ACTION_NAME, WEAVE_STROKE_TOOL_ACTION_NAME_ALIASES, WEAVE_STROKE_TOOL_DEFAULT_CONFIG, WEAVE_STROKE_TOOL_STATE, WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS, WEAVE_TEXT_NODE_DEFAULT_CONFIG, WEAVE_TEXT_NODE_TYPE, WEAVE_USERS_POINTERS_CONFIG_DEFAULT_PROPS, WEAVE_USERS_POINTERS_KEY, WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS, WEAVE_USERS_PRESENCE_PLUGIN_KEY, WEAVE_USERS_SELECTION_KEY, WEAVE_USER_POINTER_KEY, WEAVE_USER_PRESENCE_KEY, WEAVE_USER_SELECTION_KEY, WEAVE_VIDEO_DEFAULT_CONFIG, WEAVE_VIDEO_NODE_TYPE, Weave, WeaveAction, WeaveAlignNodesToolAction, WeaveArrowNode, WeaveArrowToolAction, WeaveBrushToolAction, WeaveCommentNode, WeaveCommentToolAction, WeaveCommentsRendererPlugin, WeaveConnectedUsersPlugin, WeaveConnectorNode, WeaveConnectorToolAction, WeaveContextMenuPlugin, WeaveCopyPasteNodesPlugin, WeaveEllipseNode, WeaveEllipseToolAction, WeaveEraserToolAction, WeaveExportNodesToolAction, WeaveExportStageToolAction, WeaveFitToScreenToolAction, WeaveFitToSelectionToolAction, WeaveFrameNode, WeaveFrameToolAction, WeaveGroupNode, WeaveGuideToolAction, WeaveImageNode, WeaveImageToolAction, WeaveImagesToolAction, WeaveLayerNode, WeaveLineNode, WeaveLineToolAction, WeaveMeasureNode, WeaveMeasureToolAction, WeaveMoveToolAction, WeaveNode, WeaveNodesMultiSelectionFeedbackPlugin, WeaveNodesSelectionPlugin, WeaveNodesSnappingPlugin, WeavePenToolAction, WeavePlugin, WeavePolygonNode, WeavePolygonToolAction, WeaveRectangleNode, WeaveRectangleToolAction, WeaveRegularPolygonNode, WeaveRegularPolygonToolAction, WeaveRenderer, WeaveSelectionToolAction, WeaveStageDropAreaPlugin, WeaveStageGridPlugin, WeaveStageKeyboardMovePlugin, WeaveStageMinimapPlugin, WeaveStageNode, WeaveStagePanningPlugin, WeaveStageResizePlugin, WeaveStageZoomPlugin, WeaveStarNode, WeaveStarToolAction, WeaveStateManipulation, WeaveStore, WeaveStrokeNode, WeaveStrokeSingleNode, WeaveStrokeToolAction, WeaveTextNode, WeaveTextToolAction, WeaveUsersPointersPlugin, WeaveUsersPresencePlugin, WeaveUsersSelectionPlugin, WeaveVideoNode, WeaveVideoToolAction, WeaveZoomInToolAction, WeaveZoomOutToolAction, buildAncestorGroupIds, canComposite, clearContainerTargets, computeEllipseLabelMinSize, computePolygonLabelMinSize, computeRectangleLabelMinSize, containerOverCursor, containsNodeDeep, defaultInitialState, downscaleImageFile, downscaleImageFromURL, getBoundingBox, getDownscaleRatio, getExportBoundingBox, getImageSizeFromFile, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isServer, labelId, loadImageSource, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps };
|