@twick/canvas 0.15.13 → 0.15.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +24 -0
- package/dist/index.js +804 -245
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +805 -246
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2
5
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
6
|
const fabric = require("fabric");
|
|
4
7
|
const react = require("react");
|
|
@@ -48,7 +51,13 @@ const CANVAS_OPERATIONS = {
|
|
|
48
51
|
/** Items have been ungrouped */
|
|
49
52
|
ITEM_UNGROUPED: "ITEM_UNGROUPED",
|
|
50
53
|
/** Caption properties have been updated */
|
|
51
|
-
CAPTION_PROPS_UPDATED: "CAPTION_PROPS_UPDATED"
|
|
54
|
+
CAPTION_PROPS_UPDATED: "CAPTION_PROPS_UPDATED",
|
|
55
|
+
/** Watermark has been updated */
|
|
56
|
+
WATERMARK_UPDATED: "WATERMARK_UPDATED",
|
|
57
|
+
/** A new element was added via drop on canvas; payload is { element } */
|
|
58
|
+
ADDED_NEW_ELEMENT: "ADDED_NEW_ELEMENT",
|
|
59
|
+
/** Z-order changed (bring to front / send to back). Payload is { elementId, direction }. Timeline should reorder tracks. */
|
|
60
|
+
Z_ORDER_CHANGED: "Z_ORDER_CHANGED"
|
|
52
61
|
};
|
|
53
62
|
const ELEMENT_TYPES = {
|
|
54
63
|
/** Text element type */
|
|
@@ -62,7 +71,11 @@ const ELEMENT_TYPES = {
|
|
|
62
71
|
/** Rectangle element type */
|
|
63
72
|
RECT: "rect",
|
|
64
73
|
/** Circle element type */
|
|
65
|
-
CIRCLE: "circle"
|
|
74
|
+
CIRCLE: "circle",
|
|
75
|
+
/** Icon element type */
|
|
76
|
+
ICON: "icon",
|
|
77
|
+
/** Background color element type */
|
|
78
|
+
BACKGROUND_COLOR: "backgroundColor"
|
|
66
79
|
};
|
|
67
80
|
const isBrowser = typeof window !== "undefined";
|
|
68
81
|
const isCanvasSupported = isBrowser && !!window.HTMLCanvasElement;
|
|
@@ -124,6 +137,26 @@ const createCanvas = ({
|
|
|
124
137
|
canvasMetadata
|
|
125
138
|
};
|
|
126
139
|
};
|
|
140
|
+
function measureTextWidth(text, options) {
|
|
141
|
+
if (typeof document === "undefined" || !text) return 0;
|
|
142
|
+
const canvas = document.createElement("canvas");
|
|
143
|
+
const ctx = canvas.getContext("2d");
|
|
144
|
+
if (!ctx) return 0;
|
|
145
|
+
const {
|
|
146
|
+
fontSize,
|
|
147
|
+
fontFamily,
|
|
148
|
+
fontStyle = "normal",
|
|
149
|
+
fontWeight = "normal"
|
|
150
|
+
} = options;
|
|
151
|
+
ctx.font = `${fontStyle} ${String(fontWeight)} ${fontSize}px ${fontFamily}`;
|
|
152
|
+
const lines = text.split("\n");
|
|
153
|
+
let maxWidth = 0;
|
|
154
|
+
for (const line of lines) {
|
|
155
|
+
const { width } = ctx.measureText(line);
|
|
156
|
+
if (width > maxWidth) maxWidth = width;
|
|
157
|
+
}
|
|
158
|
+
return Math.ceil(maxWidth);
|
|
159
|
+
}
|
|
127
160
|
const reorderElementsByZIndex = (canvas) => {
|
|
128
161
|
if (!canvas) return;
|
|
129
162
|
const backgroundColor = canvas.backgroundColor;
|
|
@@ -134,6 +167,49 @@ const reorderElementsByZIndex = (canvas) => {
|
|
|
134
167
|
objects.forEach((obj) => canvas.add(obj));
|
|
135
168
|
canvas.renderAll();
|
|
136
169
|
};
|
|
170
|
+
const changeZOrder = (canvas, elementId, direction) => {
|
|
171
|
+
var _a, _b;
|
|
172
|
+
if (!canvas) return null;
|
|
173
|
+
const objects = canvas.getObjects();
|
|
174
|
+
const sorted = [...objects].sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));
|
|
175
|
+
const idx = sorted.findIndex((obj2) => {
|
|
176
|
+
var _a2;
|
|
177
|
+
return ((_a2 = obj2.get) == null ? void 0 : _a2.call(obj2, "id")) === elementId;
|
|
178
|
+
});
|
|
179
|
+
if (idx < 0) return null;
|
|
180
|
+
const minZ = ((_a = sorted[0]) == null ? void 0 : _a.zIndex) ?? 0;
|
|
181
|
+
const maxZ = ((_b = sorted[sorted.length - 1]) == null ? void 0 : _b.zIndex) ?? 0;
|
|
182
|
+
const obj = sorted[idx];
|
|
183
|
+
if (direction === "front") {
|
|
184
|
+
obj.set("zIndex", maxZ + 1);
|
|
185
|
+
reorderElementsByZIndex(canvas);
|
|
186
|
+
return maxZ + 1;
|
|
187
|
+
}
|
|
188
|
+
if (direction === "back") {
|
|
189
|
+
obj.set("zIndex", minZ - 1);
|
|
190
|
+
reorderElementsByZIndex(canvas);
|
|
191
|
+
return minZ - 1;
|
|
192
|
+
}
|
|
193
|
+
if (direction === "forward" && idx < sorted.length - 1) {
|
|
194
|
+
const next = sorted[idx + 1];
|
|
195
|
+
const myZ = obj.zIndex ?? idx;
|
|
196
|
+
const nextZ = next.zIndex ?? idx + 1;
|
|
197
|
+
obj.set("zIndex", nextZ);
|
|
198
|
+
next.set("zIndex", myZ);
|
|
199
|
+
reorderElementsByZIndex(canvas);
|
|
200
|
+
return nextZ;
|
|
201
|
+
}
|
|
202
|
+
if (direction === "backward" && idx > 0) {
|
|
203
|
+
const prev = sorted[idx - 1];
|
|
204
|
+
const myZ = obj.zIndex ?? idx;
|
|
205
|
+
const prevZ = prev.zIndex ?? idx - 1;
|
|
206
|
+
obj.set("zIndex", prevZ);
|
|
207
|
+
prev.set("zIndex", myZ);
|
|
208
|
+
reorderElementsByZIndex(canvas);
|
|
209
|
+
return prevZ;
|
|
210
|
+
}
|
|
211
|
+
return obj.zIndex ?? idx;
|
|
212
|
+
};
|
|
137
213
|
const getCanvasContext = (canvas) => {
|
|
138
214
|
var _a, _b, _c, _d;
|
|
139
215
|
if (!canvas || !((_b = (_a = canvas.elements) == null ? void 0 : _a.lower) == null ? void 0 : _b.ctx)) return;
|
|
@@ -154,12 +230,31 @@ const convertToCanvasPosition = (x, y, canvasMetadata) => {
|
|
|
154
230
|
y: y * canvasMetadata.scaleY + canvasMetadata.height / 2
|
|
155
231
|
};
|
|
156
232
|
};
|
|
233
|
+
const getObjectCanvasCenter = (obj) => {
|
|
234
|
+
if (obj.getCenterPoint) {
|
|
235
|
+
const p = obj.getCenterPoint();
|
|
236
|
+
return { x: p.x, y: p.y };
|
|
237
|
+
}
|
|
238
|
+
return { x: obj.left ?? 0, y: obj.top ?? 0 };
|
|
239
|
+
};
|
|
240
|
+
const getObjectCanvasAngle = (obj) => {
|
|
241
|
+
if (typeof obj.getTotalAngle === "function") {
|
|
242
|
+
return obj.getTotalAngle();
|
|
243
|
+
}
|
|
244
|
+
return obj.angle ?? 0;
|
|
245
|
+
};
|
|
157
246
|
const convertToVideoPosition = (x, y, canvasMetadata, videoSize) => {
|
|
158
247
|
return {
|
|
159
248
|
x: Number((x / canvasMetadata.scaleX - videoSize.width / 2).toFixed(2)),
|
|
160
249
|
y: Number((y / canvasMetadata.scaleY - videoSize.height / 2).toFixed(2))
|
|
161
250
|
};
|
|
162
251
|
};
|
|
252
|
+
const convertToVideoDimensions = (widthCanvas, heightCanvas, canvasMetadata) => {
|
|
253
|
+
return {
|
|
254
|
+
width: Number((widthCanvas / canvasMetadata.scaleX).toFixed(2)),
|
|
255
|
+
height: Number((heightCanvas / canvasMetadata.scaleY).toFixed(2))
|
|
256
|
+
};
|
|
257
|
+
};
|
|
163
258
|
const getCurrentFrameEffect = (item, seekTime) => {
|
|
164
259
|
var _a;
|
|
165
260
|
let currentFrameEffect;
|
|
@@ -171,6 +266,17 @@ const getCurrentFrameEffect = (item, seekTime) => {
|
|
|
171
266
|
}
|
|
172
267
|
return currentFrameEffect;
|
|
173
268
|
};
|
|
269
|
+
const hexToRgba = (hex, alpha) => {
|
|
270
|
+
const color = hex.replace(/^#/, "");
|
|
271
|
+
const fullHex = color.length === 3 ? color.split("").map((c) => c + c).join("") : color;
|
|
272
|
+
if (fullHex.length !== 6) {
|
|
273
|
+
return hex;
|
|
274
|
+
}
|
|
275
|
+
const r = parseInt(fullHex.slice(0, 2), 16);
|
|
276
|
+
const g = parseInt(fullHex.slice(2, 4), 16);
|
|
277
|
+
const b = parseInt(fullHex.slice(4, 6), 16);
|
|
278
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
279
|
+
};
|
|
174
280
|
const disabledControl = new fabric.Control({
|
|
175
281
|
/** X position offset */
|
|
176
282
|
x: 0,
|
|
@@ -602,40 +708,66 @@ const addTextElement = ({
|
|
|
602
708
|
canvas,
|
|
603
709
|
canvasMetadata
|
|
604
710
|
}) => {
|
|
605
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
711
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
|
|
606
712
|
const { x, y } = convertToCanvasPosition(
|
|
607
713
|
((_a = element.props) == null ? void 0 : _a.x) || 0,
|
|
608
714
|
((_b = element.props) == null ? void 0 : _b.y) || 0,
|
|
609
715
|
canvasMetadata
|
|
610
716
|
);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
717
|
+
const fontSize = Math.floor(
|
|
718
|
+
(((_c = element.props) == null ? void 0 : _c.fontSize) || DEFAULT_TEXT_PROPS.size) * canvasMetadata.scaleX
|
|
719
|
+
);
|
|
720
|
+
const fontFamily = ((_d = element.props) == null ? void 0 : _d.fontFamily) || DEFAULT_TEXT_PROPS.family;
|
|
721
|
+
const fontStyle = ((_e = element.props) == null ? void 0 : _e.fontStyle) || "normal";
|
|
722
|
+
const fontWeight = ((_f = element.props) == null ? void 0 : _f.fontWeight) || "normal";
|
|
723
|
+
let width;
|
|
724
|
+
if (((_g = element.props) == null ? void 0 : _g.width) != null && element.props.width > 0) {
|
|
725
|
+
width = element.props.width * canvasMetadata.scaleX;
|
|
726
|
+
if ((_h = element.props) == null ? void 0 : _h.maxWidth) {
|
|
727
|
+
width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
|
|
728
|
+
}
|
|
729
|
+
} else {
|
|
730
|
+
const textContent = ((_i = element.props) == null ? void 0 : _i.text) ?? element.t ?? "";
|
|
731
|
+
width = measureTextWidth(textContent, {
|
|
732
|
+
fontSize,
|
|
733
|
+
fontFamily,
|
|
734
|
+
fontStyle,
|
|
735
|
+
fontWeight
|
|
736
|
+
});
|
|
737
|
+
const padding = 4;
|
|
738
|
+
width = width + padding * 2;
|
|
739
|
+
if ((_j = element.props) == null ? void 0 : _j.maxWidth) {
|
|
740
|
+
width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
|
|
741
|
+
}
|
|
742
|
+
if (width <= 0) width = 100;
|
|
614
743
|
}
|
|
615
|
-
const
|
|
744
|
+
const backgroundColor = ((_k = element.props) == null ? void 0 : _k.backgroundColor) ? hexToRgba(
|
|
745
|
+
element.props.backgroundColor,
|
|
746
|
+
((_l = element.props) == null ? void 0 : _l.backgroundOpacity) ?? 1
|
|
747
|
+
) : void 0;
|
|
748
|
+
const text = new fabric.Textbox(((_m = element.props) == null ? void 0 : _m.text) || element.t || "", {
|
|
616
749
|
left: x,
|
|
617
750
|
top: y,
|
|
618
751
|
originX: "center",
|
|
619
752
|
originY: "center",
|
|
620
|
-
angle: ((
|
|
621
|
-
fontSize
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
fill: ((_k = element.props) == null ? void 0 : _k.fill) || DEFAULT_TEXT_PROPS.fill,
|
|
628
|
-
opacity: ((_l = element.props) == null ? void 0 : _l.opacity) ?? 1,
|
|
753
|
+
angle: ((_n = element.props) == null ? void 0 : _n.rotation) || 0,
|
|
754
|
+
fontSize,
|
|
755
|
+
fontFamily,
|
|
756
|
+
fontStyle,
|
|
757
|
+
fontWeight,
|
|
758
|
+
fill: ((_o = element.props) == null ? void 0 : _o.fill) || DEFAULT_TEXT_PROPS.fill,
|
|
759
|
+
opacity: ((_p = element.props) == null ? void 0 : _p.opacity) ?? 1,
|
|
629
760
|
width,
|
|
630
761
|
splitByGrapheme: false,
|
|
631
|
-
textAlign: ((
|
|
632
|
-
stroke: ((
|
|
633
|
-
strokeWidth: ((
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
762
|
+
textAlign: ((_q = element.props) == null ? void 0 : _q.textAlign) || "center",
|
|
763
|
+
stroke: ((_r = element.props) == null ? void 0 : _r.stroke) || DEFAULT_TEXT_PROPS.stroke,
|
|
764
|
+
strokeWidth: ((_s = element.props) == null ? void 0 : _s.lineWidth) || DEFAULT_TEXT_PROPS.lineWidth,
|
|
765
|
+
...backgroundColor && { backgroundColor },
|
|
766
|
+
shadow: ((_t = element.props) == null ? void 0 : _t.shadowColor) ? new fabric.Shadow({
|
|
767
|
+
offsetX: ((_v = (_u = element.props) == null ? void 0 : _u.shadowOffset) == null ? void 0 : _v.length) && ((_x = (_w = element.props) == null ? void 0 : _w.shadowOffset) == null ? void 0 : _x.length) > 1 ? element.props.shadowOffset[0] / 2 : 1,
|
|
768
|
+
offsetY: ((_z = (_y = element.props) == null ? void 0 : _y.shadowOffset) == null ? void 0 : _z.length) && ((_A = element.props) == null ? void 0 : _A.shadowOffset.length) > 1 ? element.props.shadowOffset[1] / 2 : 1,
|
|
769
|
+
blur: (((_B = element.props) == null ? void 0 : _B.shadowBlur) || 2) / 2,
|
|
770
|
+
color: (_C = element.props) == null ? void 0 : _C.shadowColor
|
|
639
771
|
}) : void 0
|
|
640
772
|
});
|
|
641
773
|
text.set("id", element.id);
|
|
@@ -656,7 +788,8 @@ const setImageProps = ({
|
|
|
656
788
|
img,
|
|
657
789
|
element,
|
|
658
790
|
index,
|
|
659
|
-
canvasMetadata
|
|
791
|
+
canvasMetadata,
|
|
792
|
+
lockAspectRatio = true
|
|
660
793
|
}) => {
|
|
661
794
|
var _a, _b, _c, _d, _e;
|
|
662
795
|
const width = (((_a = element.props) == null ? void 0 : _a.width) || 0) * canvasMetadata.scaleX || canvasMetadata.width;
|
|
@@ -676,13 +809,15 @@ const setImageProps = ({
|
|
|
676
809
|
img.set("selectable", true);
|
|
677
810
|
img.set("hasControls", true);
|
|
678
811
|
img.set("touchAction", "all");
|
|
812
|
+
img.set("lockUniScaling", lockAspectRatio);
|
|
679
813
|
};
|
|
680
814
|
const addCaptionElement = ({
|
|
681
815
|
element,
|
|
682
816
|
index,
|
|
683
817
|
canvas,
|
|
684
818
|
captionProps,
|
|
685
|
-
canvasMetadata
|
|
819
|
+
canvasMetadata,
|
|
820
|
+
lockAspectRatio = false
|
|
686
821
|
}) => {
|
|
687
822
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
|
|
688
823
|
const { x, y } = convertToCanvasPosition(
|
|
@@ -721,6 +856,7 @@ const addCaptionElement = ({
|
|
|
721
856
|
});
|
|
722
857
|
caption.set("id", element.id);
|
|
723
858
|
caption.set("zIndex", index);
|
|
859
|
+
caption.set("lockUniScaling", lockAspectRatio);
|
|
724
860
|
caption.controls.mt = disabledControl;
|
|
725
861
|
caption.controls.mb = disabledControl;
|
|
726
862
|
caption.controls.ml = disabledControl;
|
|
@@ -768,7 +904,8 @@ const addImageElement = async ({
|
|
|
768
904
|
index,
|
|
769
905
|
canvas,
|
|
770
906
|
canvasMetadata,
|
|
771
|
-
currentFrameEffect
|
|
907
|
+
currentFrameEffect,
|
|
908
|
+
lockAspectRatio = true
|
|
772
909
|
}) => {
|
|
773
910
|
try {
|
|
774
911
|
const img = await fabric.FabricImage.fromURL(imageUrl || element.props.src || "");
|
|
@@ -777,7 +914,7 @@ const addImageElement = async ({
|
|
|
777
914
|
originY: "center",
|
|
778
915
|
lockMovementX: false,
|
|
779
916
|
lockMovementY: false,
|
|
780
|
-
lockUniScaling:
|
|
917
|
+
lockUniScaling: lockAspectRatio,
|
|
781
918
|
hasControls: false,
|
|
782
919
|
selectable: false
|
|
783
920
|
});
|
|
@@ -788,10 +925,11 @@ const addImageElement = async ({
|
|
|
788
925
|
index,
|
|
789
926
|
canvas,
|
|
790
927
|
canvasMetadata,
|
|
791
|
-
currentFrameEffect
|
|
928
|
+
currentFrameEffect,
|
|
929
|
+
lockAspectRatio
|
|
792
930
|
});
|
|
793
931
|
} else {
|
|
794
|
-
setImageProps({ img, element, index, canvasMetadata });
|
|
932
|
+
setImageProps({ img, element, index, canvasMetadata, lockAspectRatio });
|
|
795
933
|
canvas.add(img);
|
|
796
934
|
return img;
|
|
797
935
|
}
|
|
@@ -804,7 +942,8 @@ const addMediaGroup = ({
|
|
|
804
942
|
index,
|
|
805
943
|
canvas,
|
|
806
944
|
canvasMetadata,
|
|
807
|
-
currentFrameEffect
|
|
945
|
+
currentFrameEffect,
|
|
946
|
+
lockAspectRatio = true
|
|
808
947
|
}) => {
|
|
809
948
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
810
949
|
let frameSize;
|
|
@@ -893,6 +1032,7 @@ const addMediaGroup = ({
|
|
|
893
1032
|
group.controls.mtr = rotateControl;
|
|
894
1033
|
group.set("id", element.id);
|
|
895
1034
|
group.set("zIndex", index);
|
|
1035
|
+
group.set("lockUniScaling", lockAspectRatio);
|
|
896
1036
|
canvas.add(group);
|
|
897
1037
|
return group;
|
|
898
1038
|
};
|
|
@@ -900,7 +1040,8 @@ const addRectElement = ({
|
|
|
900
1040
|
element,
|
|
901
1041
|
index,
|
|
902
1042
|
canvas,
|
|
903
|
-
canvasMetadata
|
|
1043
|
+
canvasMetadata,
|
|
1044
|
+
lockAspectRatio = false
|
|
904
1045
|
}) => {
|
|
905
1046
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
906
1047
|
const { x, y } = convertToCanvasPosition(
|
|
@@ -938,6 +1079,7 @@ const addRectElement = ({
|
|
|
938
1079
|
});
|
|
939
1080
|
rect.set("id", element.id);
|
|
940
1081
|
rect.set("zIndex", index);
|
|
1082
|
+
rect.set("lockUniScaling", lockAspectRatio);
|
|
941
1083
|
rect.controls.mtr = rotateControl;
|
|
942
1084
|
canvas.add(rect);
|
|
943
1085
|
return rect;
|
|
@@ -946,9 +1088,10 @@ const addCircleElement = ({
|
|
|
946
1088
|
element,
|
|
947
1089
|
index,
|
|
948
1090
|
canvas,
|
|
949
|
-
canvasMetadata
|
|
1091
|
+
canvasMetadata,
|
|
1092
|
+
lockAspectRatio = true
|
|
950
1093
|
}) => {
|
|
951
|
-
var _a, _b, _c, _d, _e, _f;
|
|
1094
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
952
1095
|
const { x, y } = convertToCanvasPosition(
|
|
953
1096
|
((_a = element.props) == null ? void 0 : _a.x) || 0,
|
|
954
1097
|
((_b = element.props) == null ? void 0 : _b.y) || 0,
|
|
@@ -964,7 +1107,9 @@ const addCircleElement = ({
|
|
|
964
1107
|
stroke: ((_e = element.props) == null ? void 0 : _e.stroke) || "#000000",
|
|
965
1108
|
strokeWidth: (((_f = element.props) == null ? void 0 : _f.lineWidth) || 0) * canvasMetadata.scaleX,
|
|
966
1109
|
originX: "center",
|
|
967
|
-
originY: "center"
|
|
1110
|
+
originY: "center",
|
|
1111
|
+
// Respect element opacity (0–1). Defaults to fully opaque.
|
|
1112
|
+
opacity: ((_g = element.props) == null ? void 0 : _g.opacity) ?? 1
|
|
968
1113
|
});
|
|
969
1114
|
circle.controls.mt = disabledControl;
|
|
970
1115
|
circle.controls.mb = disabledControl;
|
|
@@ -973,6 +1118,7 @@ const addCircleElement = ({
|
|
|
973
1118
|
circle.controls.mtr = disabledControl;
|
|
974
1119
|
circle.set("id", element.id);
|
|
975
1120
|
circle.set("zIndex", index);
|
|
1121
|
+
circle.set("lockUniScaling", lockAspectRatio);
|
|
976
1122
|
canvas.add(circle);
|
|
977
1123
|
return circle;
|
|
978
1124
|
};
|
|
@@ -1007,17 +1153,462 @@ const addBackgroundColor = ({
|
|
|
1007
1153
|
canvas.add(bgRect);
|
|
1008
1154
|
return bgRect;
|
|
1009
1155
|
};
|
|
1156
|
+
const VideoElement = {
|
|
1157
|
+
name: ELEMENT_TYPES.VIDEO,
|
|
1158
|
+
async add(params) {
|
|
1159
|
+
var _a, _b;
|
|
1160
|
+
const {
|
|
1161
|
+
element,
|
|
1162
|
+
index,
|
|
1163
|
+
canvas,
|
|
1164
|
+
canvasMetadata,
|
|
1165
|
+
seekTime = 0,
|
|
1166
|
+
elementFrameMapRef,
|
|
1167
|
+
getCurrentFrameEffect: getFrameEffect
|
|
1168
|
+
} = params;
|
|
1169
|
+
if (!getFrameEffect || !elementFrameMapRef) return;
|
|
1170
|
+
const currentFrameEffect = getFrameEffect(element, seekTime);
|
|
1171
|
+
elementFrameMapRef.current[element.id] = currentFrameEffect;
|
|
1172
|
+
const snapTime = (seekTime - ((element == null ? void 0 : element.s) ?? 0)) * (((_a = element == null ? void 0 : element.props) == null ? void 0 : _a.playbackRate) ?? 1) + (((_b = element == null ? void 0 : element.props) == null ? void 0 : _b.time) ?? 0);
|
|
1173
|
+
await addVideoElement({
|
|
1174
|
+
element,
|
|
1175
|
+
index,
|
|
1176
|
+
canvas,
|
|
1177
|
+
canvasMetadata,
|
|
1178
|
+
currentFrameEffect,
|
|
1179
|
+
snapTime
|
|
1180
|
+
});
|
|
1181
|
+
if (element.timelineType === "scene") {
|
|
1182
|
+
await addBackgroundColor({
|
|
1183
|
+
element,
|
|
1184
|
+
index,
|
|
1185
|
+
canvas,
|
|
1186
|
+
canvasMetadata
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
},
|
|
1190
|
+
updateFromFabricObject(object, element, context) {
|
|
1191
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1192
|
+
const { x, y } = convertToVideoPosition(
|
|
1193
|
+
canvasCenter.x,
|
|
1194
|
+
canvasCenter.y,
|
|
1195
|
+
context.canvasMetadata,
|
|
1196
|
+
context.videoSize
|
|
1197
|
+
);
|
|
1198
|
+
const scaledW = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
1199
|
+
const scaledH = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
1200
|
+
const { width: fw, height: fh } = convertToVideoDimensions(
|
|
1201
|
+
scaledW,
|
|
1202
|
+
scaledH,
|
|
1203
|
+
context.canvasMetadata
|
|
1204
|
+
);
|
|
1205
|
+
const updatedFrameSize = [fw, fh];
|
|
1206
|
+
const currentFrameEffect = context.elementFrameMapRef.current[element.id];
|
|
1207
|
+
if (currentFrameEffect) {
|
|
1208
|
+
context.elementFrameMapRef.current[element.id] = {
|
|
1209
|
+
...currentFrameEffect,
|
|
1210
|
+
props: {
|
|
1211
|
+
...currentFrameEffect.props,
|
|
1212
|
+
framePosition: { x, y },
|
|
1213
|
+
frameSize: updatedFrameSize
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
return {
|
|
1217
|
+
element: {
|
|
1218
|
+
...element,
|
|
1219
|
+
frameEffects: (element.frameEffects || []).map(
|
|
1220
|
+
(fe) => fe.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
|
|
1221
|
+
...fe,
|
|
1222
|
+
props: {
|
|
1223
|
+
...fe.props,
|
|
1224
|
+
framePosition: { x, y },
|
|
1225
|
+
frameSize: updatedFrameSize
|
|
1226
|
+
}
|
|
1227
|
+
} : fe
|
|
1228
|
+
)
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
const frame = element.frame;
|
|
1233
|
+
return {
|
|
1234
|
+
element: {
|
|
1235
|
+
...element,
|
|
1236
|
+
frame: {
|
|
1237
|
+
...frame,
|
|
1238
|
+
rotation: getObjectCanvasAngle(object),
|
|
1239
|
+
size: updatedFrameSize,
|
|
1240
|
+
x,
|
|
1241
|
+
y
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
const ImageElement = {
|
|
1248
|
+
name: ELEMENT_TYPES.IMAGE,
|
|
1249
|
+
async add(params) {
|
|
1250
|
+
var _a;
|
|
1251
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
1252
|
+
await addImageElement({
|
|
1253
|
+
element,
|
|
1254
|
+
index,
|
|
1255
|
+
canvas,
|
|
1256
|
+
canvasMetadata,
|
|
1257
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio)
|
|
1258
|
+
});
|
|
1259
|
+
if (element.timelineType === "scene") {
|
|
1260
|
+
await addBackgroundColor({
|
|
1261
|
+
element,
|
|
1262
|
+
index,
|
|
1263
|
+
canvas,
|
|
1264
|
+
canvasMetadata
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
},
|
|
1268
|
+
updateFromFabricObject(object, element, context) {
|
|
1269
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1270
|
+
const { x, y } = convertToVideoPosition(
|
|
1271
|
+
canvasCenter.x,
|
|
1272
|
+
canvasCenter.y,
|
|
1273
|
+
context.canvasMetadata,
|
|
1274
|
+
context.videoSize
|
|
1275
|
+
);
|
|
1276
|
+
const currentFrameEffect = context.elementFrameMapRef.current[element.id];
|
|
1277
|
+
if (object.type === "group") {
|
|
1278
|
+
const scaledW2 = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
1279
|
+
const scaledH2 = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
1280
|
+
const { width: fw, height: fh } = convertToVideoDimensions(
|
|
1281
|
+
scaledW2,
|
|
1282
|
+
scaledH2,
|
|
1283
|
+
context.canvasMetadata
|
|
1284
|
+
);
|
|
1285
|
+
const updatedFrameSize = [fw, fh];
|
|
1286
|
+
if (currentFrameEffect) {
|
|
1287
|
+
context.elementFrameMapRef.current[element.id] = {
|
|
1288
|
+
...currentFrameEffect,
|
|
1289
|
+
props: {
|
|
1290
|
+
...currentFrameEffect.props,
|
|
1291
|
+
framePosition: { x, y },
|
|
1292
|
+
frameSize: updatedFrameSize
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
return {
|
|
1296
|
+
element: {
|
|
1297
|
+
...element,
|
|
1298
|
+
// Keep the base frame in sync with the active frame effect
|
|
1299
|
+
// so visualizer `Rect {...element.frame}` reflects the same size/position.
|
|
1300
|
+
frame: element.frame ? {
|
|
1301
|
+
...element.frame,
|
|
1302
|
+
rotation: getObjectCanvasAngle(object),
|
|
1303
|
+
size: updatedFrameSize,
|
|
1304
|
+
x,
|
|
1305
|
+
y
|
|
1306
|
+
} : element.frame,
|
|
1307
|
+
frameEffects: (element.frameEffects || []).map(
|
|
1308
|
+
(fe) => fe.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
|
|
1309
|
+
...fe,
|
|
1310
|
+
props: {
|
|
1311
|
+
...fe.props,
|
|
1312
|
+
framePosition: { x, y },
|
|
1313
|
+
frameSize: updatedFrameSize
|
|
1314
|
+
}
|
|
1315
|
+
} : fe
|
|
1316
|
+
)
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
const frame = element.frame;
|
|
1321
|
+
return {
|
|
1322
|
+
element: {
|
|
1323
|
+
...element,
|
|
1324
|
+
frame: {
|
|
1325
|
+
...frame,
|
|
1326
|
+
rotation: getObjectCanvasAngle(object),
|
|
1327
|
+
size: updatedFrameSize,
|
|
1328
|
+
x,
|
|
1329
|
+
y
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
const scaledW = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
1335
|
+
const scaledH = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
1336
|
+
const { width, height } = convertToVideoDimensions(
|
|
1337
|
+
scaledW,
|
|
1338
|
+
scaledH,
|
|
1339
|
+
context.canvasMetadata
|
|
1340
|
+
);
|
|
1341
|
+
return {
|
|
1342
|
+
element: {
|
|
1343
|
+
...element,
|
|
1344
|
+
props: {
|
|
1345
|
+
...element.props,
|
|
1346
|
+
rotation: getObjectCanvasAngle(object),
|
|
1347
|
+
width,
|
|
1348
|
+
height,
|
|
1349
|
+
x,
|
|
1350
|
+
y
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
const RectElement = {
|
|
1357
|
+
name: ELEMENT_TYPES.RECT,
|
|
1358
|
+
async add(params) {
|
|
1359
|
+
var _a;
|
|
1360
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
1361
|
+
await addRectElement({
|
|
1362
|
+
element,
|
|
1363
|
+
index,
|
|
1364
|
+
canvas,
|
|
1365
|
+
canvasMetadata,
|
|
1366
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio)
|
|
1367
|
+
});
|
|
1368
|
+
},
|
|
1369
|
+
updateFromFabricObject(object, element, context) {
|
|
1370
|
+
var _a, _b;
|
|
1371
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1372
|
+
const { x, y } = convertToVideoPosition(
|
|
1373
|
+
canvasCenter.x,
|
|
1374
|
+
canvasCenter.y,
|
|
1375
|
+
context.canvasMetadata,
|
|
1376
|
+
context.videoSize
|
|
1377
|
+
);
|
|
1378
|
+
return {
|
|
1379
|
+
element: {
|
|
1380
|
+
...element,
|
|
1381
|
+
props: {
|
|
1382
|
+
...element.props,
|
|
1383
|
+
rotation: getObjectCanvasAngle(object),
|
|
1384
|
+
width: (((_a = element.props) == null ? void 0 : _a.width) ?? 0) * object.scaleX,
|
|
1385
|
+
height: (((_b = element.props) == null ? void 0 : _b.height) ?? 0) * object.scaleY,
|
|
1386
|
+
x,
|
|
1387
|
+
y
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
const CircleElement = {
|
|
1394
|
+
name: ELEMENT_TYPES.CIRCLE,
|
|
1395
|
+
async add(params) {
|
|
1396
|
+
var _a;
|
|
1397
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
1398
|
+
await addCircleElement({
|
|
1399
|
+
element,
|
|
1400
|
+
index,
|
|
1401
|
+
canvas,
|
|
1402
|
+
canvasMetadata,
|
|
1403
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio)
|
|
1404
|
+
});
|
|
1405
|
+
},
|
|
1406
|
+
updateFromFabricObject(object, element, context) {
|
|
1407
|
+
var _a, _b;
|
|
1408
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1409
|
+
const { x, y } = convertToVideoPosition(
|
|
1410
|
+
canvasCenter.x,
|
|
1411
|
+
canvasCenter.y,
|
|
1412
|
+
context.canvasMetadata,
|
|
1413
|
+
context.videoSize
|
|
1414
|
+
);
|
|
1415
|
+
const radius = Number(
|
|
1416
|
+
((((_a = element.props) == null ? void 0 : _a.radius) ?? 0) * object.scaleX).toFixed(2)
|
|
1417
|
+
);
|
|
1418
|
+
const opacity = object.opacity != null ? object.opacity : (_b = element.props) == null ? void 0 : _b.opacity;
|
|
1419
|
+
return {
|
|
1420
|
+
element: {
|
|
1421
|
+
...element,
|
|
1422
|
+
props: {
|
|
1423
|
+
...element.props,
|
|
1424
|
+
rotation: getObjectCanvasAngle(object),
|
|
1425
|
+
radius,
|
|
1426
|
+
height: radius * 2,
|
|
1427
|
+
width: radius * 2,
|
|
1428
|
+
x,
|
|
1429
|
+
y,
|
|
1430
|
+
...opacity != null && { opacity }
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
const TextElement = {
|
|
1437
|
+
name: ELEMENT_TYPES.TEXT,
|
|
1438
|
+
async add(params) {
|
|
1439
|
+
const { element, index, canvas, canvasMetadata } = params;
|
|
1440
|
+
await addTextElement({
|
|
1441
|
+
element,
|
|
1442
|
+
index,
|
|
1443
|
+
canvas,
|
|
1444
|
+
canvasMetadata
|
|
1445
|
+
});
|
|
1446
|
+
},
|
|
1447
|
+
updateFromFabricObject(object, element, context) {
|
|
1448
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1449
|
+
const { x, y } = convertToVideoPosition(
|
|
1450
|
+
canvasCenter.x,
|
|
1451
|
+
canvasCenter.y,
|
|
1452
|
+
context.canvasMetadata,
|
|
1453
|
+
context.videoSize
|
|
1454
|
+
);
|
|
1455
|
+
return {
|
|
1456
|
+
element: {
|
|
1457
|
+
...element,
|
|
1458
|
+
props: {
|
|
1459
|
+
...element.props,
|
|
1460
|
+
rotation: getObjectCanvasAngle(object),
|
|
1461
|
+
x,
|
|
1462
|
+
y
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
const CaptionElement = {
|
|
1469
|
+
name: ELEMENT_TYPES.CAPTION,
|
|
1470
|
+
async add(params) {
|
|
1471
|
+
var _a;
|
|
1472
|
+
const { element, index, canvas, captionProps, canvasMetadata, lockAspectRatio } = params;
|
|
1473
|
+
await addCaptionElement({
|
|
1474
|
+
element,
|
|
1475
|
+
index,
|
|
1476
|
+
canvas,
|
|
1477
|
+
captionProps: captionProps ?? {},
|
|
1478
|
+
canvasMetadata,
|
|
1479
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio)
|
|
1480
|
+
});
|
|
1481
|
+
},
|
|
1482
|
+
updateFromFabricObject(object, element, context) {
|
|
1483
|
+
var _a;
|
|
1484
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
1485
|
+
const { x, y } = convertToVideoPosition(
|
|
1486
|
+
canvasCenter.x,
|
|
1487
|
+
canvasCenter.y,
|
|
1488
|
+
context.canvasMetadata,
|
|
1489
|
+
context.videoSize
|
|
1490
|
+
);
|
|
1491
|
+
if ((_a = context.captionPropsRef.current) == null ? void 0 : _a.applyToAll) {
|
|
1492
|
+
return {
|
|
1493
|
+
element,
|
|
1494
|
+
operation: CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED,
|
|
1495
|
+
payload: {
|
|
1496
|
+
element,
|
|
1497
|
+
props: {
|
|
1498
|
+
...context.captionPropsRef.current,
|
|
1499
|
+
x,
|
|
1500
|
+
y
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
return {
|
|
1506
|
+
element: {
|
|
1507
|
+
...element,
|
|
1508
|
+
props: {
|
|
1509
|
+
...element.props,
|
|
1510
|
+
x,
|
|
1511
|
+
y
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
const WatermarkElement = {
|
|
1518
|
+
name: "watermark",
|
|
1519
|
+
async add(params) {
|
|
1520
|
+
const { element, index, canvas, canvasMetadata, watermarkPropsRef } = params;
|
|
1521
|
+
if (element.type === ELEMENT_TYPES.TEXT) {
|
|
1522
|
+
if (watermarkPropsRef) watermarkPropsRef.current = element.props;
|
|
1523
|
+
await addTextElement({
|
|
1524
|
+
element,
|
|
1525
|
+
index,
|
|
1526
|
+
canvas,
|
|
1527
|
+
canvasMetadata
|
|
1528
|
+
});
|
|
1529
|
+
} else if (element.type === ELEMENT_TYPES.IMAGE) {
|
|
1530
|
+
await addImageElement({
|
|
1531
|
+
element,
|
|
1532
|
+
index,
|
|
1533
|
+
canvas,
|
|
1534
|
+
canvasMetadata
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
updateFromFabricObject(object, element, context) {
|
|
1539
|
+
const { x, y } = convertToVideoPosition(
|
|
1540
|
+
object.left,
|
|
1541
|
+
object.top,
|
|
1542
|
+
context.canvasMetadata,
|
|
1543
|
+
context.videoSize
|
|
1544
|
+
);
|
|
1545
|
+
const rotation = object.angle != null ? object.angle : void 0;
|
|
1546
|
+
const opacity = object.opacity != null ? object.opacity : void 0;
|
|
1547
|
+
const baseProps = element.type === ELEMENT_TYPES.TEXT ? context.watermarkPropsRef.current ?? element.props ?? {} : { ...element.props };
|
|
1548
|
+
const props = element.type === ELEMENT_TYPES.IMAGE && (object.scaleX != null || object.scaleY != null) ? {
|
|
1549
|
+
...baseProps,
|
|
1550
|
+
width: baseProps.width != null && object.scaleX != null ? baseProps.width * object.scaleX : baseProps.width,
|
|
1551
|
+
height: baseProps.height != null && object.scaleY != null ? baseProps.height * object.scaleY : baseProps.height
|
|
1552
|
+
} : baseProps;
|
|
1553
|
+
const payload = {
|
|
1554
|
+
position: { x, y },
|
|
1555
|
+
...rotation != null && { rotation },
|
|
1556
|
+
...opacity != null && { opacity },
|
|
1557
|
+
...Object.keys(props).length > 0 && { props }
|
|
1558
|
+
};
|
|
1559
|
+
return {
|
|
1560
|
+
element: { ...element, props: { ...element.props, x, y, rotation, opacity, ...props } },
|
|
1561
|
+
operation: CANVAS_OPERATIONS.WATERMARK_UPDATED,
|
|
1562
|
+
payload
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
class ElementController {
|
|
1567
|
+
constructor() {
|
|
1568
|
+
__publicField(this, "elements", /* @__PURE__ */ new Map());
|
|
1569
|
+
}
|
|
1570
|
+
register(handler) {
|
|
1571
|
+
this.elements.set(handler.name, handler);
|
|
1572
|
+
}
|
|
1573
|
+
get(name) {
|
|
1574
|
+
return this.elements.get(name);
|
|
1575
|
+
}
|
|
1576
|
+
list() {
|
|
1577
|
+
return Array.from(this.elements.keys());
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
const elementController = new ElementController();
|
|
1581
|
+
function registerElements() {
|
|
1582
|
+
elementController.register(VideoElement);
|
|
1583
|
+
elementController.register(ImageElement);
|
|
1584
|
+
elementController.register(RectElement);
|
|
1585
|
+
elementController.register(CircleElement);
|
|
1586
|
+
elementController.register(TextElement);
|
|
1587
|
+
elementController.register(CaptionElement);
|
|
1588
|
+
elementController.register(WatermarkElement);
|
|
1589
|
+
}
|
|
1590
|
+
registerElements();
|
|
1010
1591
|
const useTwickCanvas = ({
|
|
1011
1592
|
onCanvasReady,
|
|
1012
|
-
onCanvasOperation
|
|
1593
|
+
onCanvasOperation,
|
|
1594
|
+
/**
|
|
1595
|
+
* When true, holding Shift while dragging an object will lock movement to
|
|
1596
|
+
* the dominant axis (horizontal or vertical). This mirrors behavior in
|
|
1597
|
+
* professional editors and improves precise alignment.
|
|
1598
|
+
*
|
|
1599
|
+
* Default: false (opt‑in to avoid surprising existing consumers).
|
|
1600
|
+
*/
|
|
1601
|
+
enableShiftAxisLock = false
|
|
1013
1602
|
}) => {
|
|
1014
1603
|
const [twickCanvas, setTwickCanvas] = react.useState(null);
|
|
1015
1604
|
const elementMap = react.useRef({});
|
|
1605
|
+
const watermarkPropsRef = react.useRef(null);
|
|
1016
1606
|
const elementFrameMap = react.useRef({});
|
|
1017
1607
|
const twickCanvasRef = react.useRef(null);
|
|
1018
1608
|
const videoSizeRef = react.useRef({ width: 1, height: 1 });
|
|
1019
1609
|
const canvasResolutionRef = react.useRef({ width: 1, height: 1 });
|
|
1020
1610
|
const captionPropsRef = react.useRef(null);
|
|
1611
|
+
const axisLockStateRef = react.useRef(null);
|
|
1021
1612
|
const canvasMetadataRef = react.useRef({
|
|
1022
1613
|
width: 0,
|
|
1023
1614
|
height: 0,
|
|
@@ -1032,6 +1623,57 @@ const useTwickCanvas = ({
|
|
|
1032
1623
|
canvasMetadataRef.current.scaleY = canvasMetadataRef.current.height / videoSize.height;
|
|
1033
1624
|
}
|
|
1034
1625
|
};
|
|
1626
|
+
const handleObjectMoving = (event) => {
|
|
1627
|
+
var _a;
|
|
1628
|
+
if (!enableShiftAxisLock) return;
|
|
1629
|
+
const target = event == null ? void 0 : event.target;
|
|
1630
|
+
const transform = event == null ? void 0 : event.transform;
|
|
1631
|
+
const pointerEvent = event == null ? void 0 : event.e;
|
|
1632
|
+
if (!target || !transform || !pointerEvent) {
|
|
1633
|
+
axisLockStateRef.current = null;
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
if (!pointerEvent.shiftKey) {
|
|
1637
|
+
axisLockStateRef.current = null;
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
const original = transform.original;
|
|
1641
|
+
if (!original || typeof target.left !== "number" || typeof target.top !== "number") {
|
|
1642
|
+
axisLockStateRef.current = null;
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
if (!axisLockStateRef.current) {
|
|
1646
|
+
const dx = Math.abs(target.left - original.left);
|
|
1647
|
+
const dy = Math.abs(target.top - original.top);
|
|
1648
|
+
axisLockStateRef.current = {
|
|
1649
|
+
axis: dx >= dy ? "x" : "y"
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
if (axisLockStateRef.current.axis === "x") {
|
|
1653
|
+
target.top = original.top;
|
|
1654
|
+
} else {
|
|
1655
|
+
target.left = original.left;
|
|
1656
|
+
}
|
|
1657
|
+
(_a = target.canvas) == null ? void 0 : _a.requestRenderAll();
|
|
1658
|
+
};
|
|
1659
|
+
const applyMarqueeSelectionControls = () => {
|
|
1660
|
+
const canvasInstance = twickCanvasRef.current;
|
|
1661
|
+
if (!canvasInstance) return;
|
|
1662
|
+
const activeObject = canvasInstance.getActiveObject();
|
|
1663
|
+
if (!activeObject) return;
|
|
1664
|
+
if (activeObject instanceof fabric.ActiveSelection) {
|
|
1665
|
+
activeObject.controls.mt = disabledControl;
|
|
1666
|
+
activeObject.controls.mb = disabledControl;
|
|
1667
|
+
activeObject.controls.ml = disabledControl;
|
|
1668
|
+
activeObject.controls.mr = disabledControl;
|
|
1669
|
+
activeObject.controls.bl = disabledControl;
|
|
1670
|
+
activeObject.controls.br = disabledControl;
|
|
1671
|
+
activeObject.controls.tl = disabledControl;
|
|
1672
|
+
activeObject.controls.tr = disabledControl;
|
|
1673
|
+
activeObject.controls.mtr = rotateControl;
|
|
1674
|
+
canvasInstance.requestRenderAll();
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1035
1677
|
const buildCanvas = ({
|
|
1036
1678
|
videoSize,
|
|
1037
1679
|
canvasSize,
|
|
@@ -1051,6 +1693,9 @@ const useTwickCanvas = ({
|
|
|
1051
1693
|
if (twickCanvasRef.current) {
|
|
1052
1694
|
twickCanvasRef.current.off("mouse:up", handleMouseUp);
|
|
1053
1695
|
twickCanvasRef.current.off("text:editing:exited", onTextEdit);
|
|
1696
|
+
twickCanvasRef.current.off("object:moving", handleObjectMoving);
|
|
1697
|
+
twickCanvasRef.current.off("selection:created", applyMarqueeSelectionControls);
|
|
1698
|
+
twickCanvasRef.current.off("selection:updated", applyMarqueeSelectionControls);
|
|
1054
1699
|
twickCanvasRef.current.dispose();
|
|
1055
1700
|
}
|
|
1056
1701
|
const { canvas, canvasMetadata } = createCanvas({
|
|
@@ -1068,6 +1713,9 @@ const useTwickCanvas = ({
|
|
|
1068
1713
|
videoSizeRef.current = videoSize;
|
|
1069
1714
|
canvas == null ? void 0 : canvas.on("mouse:up", handleMouseUp);
|
|
1070
1715
|
canvas == null ? void 0 : canvas.on("text:editing:exited", onTextEdit);
|
|
1716
|
+
canvas == null ? void 0 : canvas.on("object:moving", handleObjectMoving);
|
|
1717
|
+
canvas == null ? void 0 : canvas.on("selection:created", applyMarqueeSelectionControls);
|
|
1718
|
+
canvas == null ? void 0 : canvas.on("selection:updated", applyMarqueeSelectionControls);
|
|
1071
1719
|
canvasResolutionRef.current = canvasSize;
|
|
1072
1720
|
setTwickCanvas(canvas);
|
|
1073
1721
|
twickCanvasRef.current = canvas;
|
|
@@ -1097,7 +1745,8 @@ const useTwickCanvas = ({
|
|
|
1097
1745
|
if (event.target) {
|
|
1098
1746
|
const object = event.target;
|
|
1099
1747
|
const elementId = object.get("id");
|
|
1100
|
-
|
|
1748
|
+
const action = (_a = event.transform) == null ? void 0 : _a.action;
|
|
1749
|
+
if (action === "drag") {
|
|
1101
1750
|
const original = event.transform.original;
|
|
1102
1751
|
if (object.left === original.left && object.top === original.top) {
|
|
1103
1752
|
onCanvasOperation == null ? void 0 : onCanvasOperation(
|
|
@@ -1107,149 +1756,67 @@ const useTwickCanvas = ({
|
|
|
1107
1756
|
return;
|
|
1108
1757
|
}
|
|
1109
1758
|
}
|
|
1110
|
-
|
|
1759
|
+
const context = {
|
|
1760
|
+
canvasMetadata: canvasMetadataRef.current,
|
|
1761
|
+
videoSize: videoSizeRef.current,
|
|
1762
|
+
elementFrameMapRef: elementFrameMap,
|
|
1763
|
+
captionPropsRef,
|
|
1764
|
+
watermarkPropsRef
|
|
1765
|
+
};
|
|
1766
|
+
if (object instanceof fabric.ActiveSelection && (action === "drag" || action === "rotate")) {
|
|
1767
|
+
const objects = object.getObjects();
|
|
1768
|
+
for (const fabricObj of objects) {
|
|
1769
|
+
const id = fabricObj.get("id");
|
|
1770
|
+
if (!id || id === "e-watermark") continue;
|
|
1771
|
+
const currentElement = elementMap.current[id];
|
|
1772
|
+
if (!currentElement) continue;
|
|
1773
|
+
const handler = elementController.get(currentElement.type);
|
|
1774
|
+
const result = (_b = handler == null ? void 0 : handler.updateFromFabricObject) == null ? void 0 : _b.call(
|
|
1775
|
+
handler,
|
|
1776
|
+
fabricObj,
|
|
1777
|
+
currentElement,
|
|
1778
|
+
context
|
|
1779
|
+
);
|
|
1780
|
+
if (result) {
|
|
1781
|
+
elementMap.current[id] = result.element;
|
|
1782
|
+
onCanvasOperation == null ? void 0 : onCanvasOperation(
|
|
1783
|
+
result.operation ?? CANVAS_OPERATIONS.ITEM_UPDATED,
|
|
1784
|
+
result.payload ?? result.element
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
switch (action) {
|
|
1111
1791
|
case "drag":
|
|
1112
1792
|
case "scale":
|
|
1113
1793
|
case "scaleX":
|
|
1114
1794
|
case "scaleY":
|
|
1115
|
-
case "rotate":
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
canvasMetadataRef.current,
|
|
1120
|
-
videoSizeRef.current
|
|
1795
|
+
case "rotate": {
|
|
1796
|
+
const currentElement = elementMap.current[elementId];
|
|
1797
|
+
const handler = elementController.get(
|
|
1798
|
+
elementId === "e-watermark" ? "watermark" : currentElement == null ? void 0 : currentElement.type
|
|
1121
1799
|
);
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
element: elementMap.current[elementId],
|
|
1126
|
-
props: {
|
|
1127
|
-
...captionPropsRef.current,
|
|
1128
|
-
x,
|
|
1129
|
-
y
|
|
1130
|
-
}
|
|
1131
|
-
});
|
|
1132
|
-
} else {
|
|
1133
|
-
elementMap.current[elementId] = {
|
|
1134
|
-
...elementMap.current[elementId],
|
|
1135
|
-
props: {
|
|
1136
|
-
...elementMap.current[elementId].props,
|
|
1137
|
-
x,
|
|
1138
|
-
y
|
|
1139
|
-
}
|
|
1140
|
-
};
|
|
1141
|
-
onCanvasOperation == null ? void 0 : onCanvasOperation(
|
|
1142
|
-
CANVAS_OPERATIONS.ITEM_UPDATED,
|
|
1143
|
-
elementMap.current[elementId]
|
|
1144
|
-
);
|
|
1145
|
-
}
|
|
1146
|
-
} else {
|
|
1147
|
-
if ((object == null ? void 0 : object.type) === "group") {
|
|
1148
|
-
const currentFrameEffect = elementFrameMap.current[elementId];
|
|
1149
|
-
let updatedFrameSize;
|
|
1150
|
-
if (currentFrameEffect) {
|
|
1151
|
-
updatedFrameSize = [
|
|
1152
|
-
currentFrameEffect.props.frameSize[0] * object.scaleX,
|
|
1153
|
-
currentFrameEffect.props.frameSize[1] * object.scaleY
|
|
1154
|
-
];
|
|
1155
|
-
} else {
|
|
1156
|
-
updatedFrameSize = [
|
|
1157
|
-
elementMap.current[elementId].frame.size[0] * object.scaleX,
|
|
1158
|
-
elementMap.current[elementId].frame.size[1] * object.scaleY
|
|
1159
|
-
];
|
|
1160
|
-
}
|
|
1161
|
-
if (currentFrameEffect) {
|
|
1162
|
-
elementMap.current[elementId] = {
|
|
1163
|
-
...elementMap.current[elementId],
|
|
1164
|
-
frameEffects: (elementMap.current[elementId].frameEffects || []).map(
|
|
1165
|
-
(frameEffect) => frameEffect.id === (currentFrameEffect == null ? void 0 : currentFrameEffect.id) ? {
|
|
1166
|
-
...frameEffect,
|
|
1167
|
-
props: {
|
|
1168
|
-
...frameEffect.props,
|
|
1169
|
-
framePosition: {
|
|
1170
|
-
x,
|
|
1171
|
-
y
|
|
1172
|
-
},
|
|
1173
|
-
frameSize: updatedFrameSize
|
|
1174
|
-
}
|
|
1175
|
-
} : frameEffect
|
|
1176
|
-
)
|
|
1177
|
-
};
|
|
1178
|
-
elementFrameMap.current[elementId] = {
|
|
1179
|
-
...elementFrameMap.current[elementId],
|
|
1180
|
-
framePosition: {
|
|
1181
|
-
x,
|
|
1182
|
-
y
|
|
1183
|
-
},
|
|
1184
|
-
frameSize: updatedFrameSize
|
|
1185
|
-
};
|
|
1186
|
-
} else {
|
|
1187
|
-
elementMap.current[elementId] = {
|
|
1188
|
-
...elementMap.current[elementId],
|
|
1189
|
-
frame: {
|
|
1190
|
-
...elementMap.current[elementId].frame,
|
|
1191
|
-
rotation: object.angle,
|
|
1192
|
-
size: updatedFrameSize,
|
|
1193
|
-
x,
|
|
1194
|
-
y
|
|
1195
|
-
}
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1198
|
-
} else {
|
|
1199
|
-
if ((object == null ? void 0 : object.type) === "text") {
|
|
1200
|
-
elementMap.current[elementId] = {
|
|
1201
|
-
...elementMap.current[elementId],
|
|
1202
|
-
props: {
|
|
1203
|
-
...elementMap.current[elementId].props,
|
|
1204
|
-
rotation: object.angle,
|
|
1205
|
-
x,
|
|
1206
|
-
y
|
|
1207
|
-
}
|
|
1208
|
-
};
|
|
1209
|
-
} else if ((object == null ? void 0 : object.type) === "circle") {
|
|
1210
|
-
const radius = Number(
|
|
1211
|
-
(elementMap.current[elementId].props.radius * object.scaleX).toFixed(2)
|
|
1212
|
-
);
|
|
1213
|
-
elementMap.current[elementId] = {
|
|
1214
|
-
...elementMap.current[elementId],
|
|
1215
|
-
props: {
|
|
1216
|
-
...elementMap.current[elementId].props,
|
|
1217
|
-
rotation: object.angle,
|
|
1218
|
-
radius,
|
|
1219
|
-
height: radius * 2,
|
|
1220
|
-
width: radius * 2,
|
|
1221
|
-
x,
|
|
1222
|
-
y
|
|
1223
|
-
}
|
|
1224
|
-
};
|
|
1225
|
-
} else {
|
|
1226
|
-
elementMap.current[elementId] = {
|
|
1227
|
-
...elementMap.current[elementId],
|
|
1228
|
-
props: {
|
|
1229
|
-
...elementMap.current[elementId].props,
|
|
1230
|
-
rotation: object.angle,
|
|
1231
|
-
width: elementMap.current[elementId].props.width * object.scaleX,
|
|
1232
|
-
height: elementMap.current[elementId].props.height * object.scaleY,
|
|
1233
|
-
x,
|
|
1234
|
-
y
|
|
1235
|
-
}
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1800
|
+
const result = (_c = handler == null ? void 0 : handler.updateFromFabricObject) == null ? void 0 : _c.call(handler, object, currentElement ?? { id: elementId, type: "text", props: {} }, context);
|
|
1801
|
+
if (result) {
|
|
1802
|
+
elementMap.current[elementId] = result.element;
|
|
1239
1803
|
onCanvasOperation == null ? void 0 : onCanvasOperation(
|
|
1240
|
-
CANVAS_OPERATIONS.ITEM_UPDATED,
|
|
1241
|
-
|
|
1804
|
+
result.operation ?? CANVAS_OPERATIONS.ITEM_UPDATED,
|
|
1805
|
+
result.payload ?? result.element
|
|
1242
1806
|
);
|
|
1243
1807
|
}
|
|
1244
1808
|
break;
|
|
1809
|
+
}
|
|
1245
1810
|
}
|
|
1246
1811
|
}
|
|
1247
1812
|
};
|
|
1248
1813
|
const setCanvasElements = async ({
|
|
1249
1814
|
elements,
|
|
1815
|
+
watermark,
|
|
1250
1816
|
seekTime = 0,
|
|
1251
1817
|
captionProps,
|
|
1252
|
-
cleanAndAdd = false
|
|
1818
|
+
cleanAndAdd = false,
|
|
1819
|
+
lockAspectRatio
|
|
1253
1820
|
}) => {
|
|
1254
1821
|
if (!twickCanvas || !getCanvasContext(twickCanvas)) return;
|
|
1255
1822
|
try {
|
|
@@ -1262,21 +1829,36 @@ const useTwickCanvas = ({
|
|
|
1262
1829
|
}
|
|
1263
1830
|
}
|
|
1264
1831
|
captionPropsRef.current = captionProps;
|
|
1832
|
+
const uniqueElements = [];
|
|
1833
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1834
|
+
for (const el of elements) {
|
|
1835
|
+
if (!el || !el.id) continue;
|
|
1836
|
+
if (seenIds.has(el.id)) continue;
|
|
1837
|
+
seenIds.add(el.id);
|
|
1838
|
+
uniqueElements.push(el);
|
|
1839
|
+
}
|
|
1265
1840
|
await Promise.all(
|
|
1266
|
-
|
|
1841
|
+
uniqueElements.map(async (element, index) => {
|
|
1267
1842
|
try {
|
|
1268
1843
|
if (!element) return;
|
|
1844
|
+
const zOrder = element.zIndex ?? index;
|
|
1269
1845
|
await addElementToCanvas({
|
|
1270
1846
|
element,
|
|
1271
|
-
index,
|
|
1847
|
+
index: zOrder,
|
|
1272
1848
|
reorder: false,
|
|
1273
1849
|
seekTime,
|
|
1274
|
-
captionProps
|
|
1850
|
+
captionProps,
|
|
1851
|
+
lockAspectRatio
|
|
1275
1852
|
});
|
|
1276
1853
|
} catch {
|
|
1277
1854
|
}
|
|
1278
1855
|
})
|
|
1279
1856
|
);
|
|
1857
|
+
if (watermark) {
|
|
1858
|
+
addWatermarkToCanvas({
|
|
1859
|
+
element: watermark
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1280
1862
|
reorderElementsByZIndex(twickCanvas);
|
|
1281
1863
|
} catch {
|
|
1282
1864
|
}
|
|
@@ -1286,99 +1868,75 @@ const useTwickCanvas = ({
|
|
|
1286
1868
|
index,
|
|
1287
1869
|
reorder = true,
|
|
1288
1870
|
seekTime,
|
|
1289
|
-
captionProps
|
|
1871
|
+
captionProps,
|
|
1872
|
+
lockAspectRatio
|
|
1290
1873
|
}) => {
|
|
1291
|
-
var _a
|
|
1874
|
+
var _a;
|
|
1292
1875
|
if (!twickCanvas) return;
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
currentFrameEffect,
|
|
1307
|
-
snapTime
|
|
1308
|
-
});
|
|
1309
|
-
if (element.timelineType === "scene") {
|
|
1310
|
-
await addBackgroundColor({
|
|
1311
|
-
element,
|
|
1312
|
-
index,
|
|
1313
|
-
canvas: twickCanvas,
|
|
1314
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
break;
|
|
1318
|
-
case ELEMENT_TYPES.IMAGE:
|
|
1319
|
-
await addImageElement({
|
|
1320
|
-
element,
|
|
1321
|
-
index,
|
|
1322
|
-
canvas: twickCanvas,
|
|
1323
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1324
|
-
});
|
|
1325
|
-
if (element.timelineType === "scene") {
|
|
1326
|
-
await addBackgroundColor({
|
|
1327
|
-
element,
|
|
1328
|
-
index,
|
|
1329
|
-
canvas: twickCanvas,
|
|
1330
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1331
|
-
});
|
|
1332
|
-
}
|
|
1333
|
-
break;
|
|
1334
|
-
case ELEMENT_TYPES.RECT:
|
|
1335
|
-
await addRectElement({
|
|
1336
|
-
element,
|
|
1337
|
-
index,
|
|
1338
|
-
canvas: twickCanvas,
|
|
1339
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1340
|
-
});
|
|
1341
|
-
break;
|
|
1342
|
-
case ELEMENT_TYPES.CIRCLE:
|
|
1343
|
-
await addCircleElement({
|
|
1344
|
-
element,
|
|
1345
|
-
index,
|
|
1346
|
-
canvas: twickCanvas,
|
|
1347
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1348
|
-
});
|
|
1349
|
-
break;
|
|
1350
|
-
case ELEMENT_TYPES.TEXT:
|
|
1351
|
-
await addTextElement({
|
|
1352
|
-
element,
|
|
1353
|
-
index,
|
|
1354
|
-
canvas: twickCanvas,
|
|
1355
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1356
|
-
});
|
|
1357
|
-
break;
|
|
1358
|
-
case ELEMENT_TYPES.CAPTION:
|
|
1359
|
-
await addCaptionElement({
|
|
1360
|
-
element,
|
|
1361
|
-
index,
|
|
1362
|
-
canvas: twickCanvas,
|
|
1363
|
-
captionProps,
|
|
1364
|
-
canvasMetadata: canvasMetadataRef.current
|
|
1365
|
-
});
|
|
1366
|
-
break;
|
|
1876
|
+
const handler = elementController.get(element.type);
|
|
1877
|
+
if (handler) {
|
|
1878
|
+
await handler.add({
|
|
1879
|
+
element,
|
|
1880
|
+
index,
|
|
1881
|
+
canvas: twickCanvas,
|
|
1882
|
+
canvasMetadata: canvasMetadataRef.current,
|
|
1883
|
+
seekTime,
|
|
1884
|
+
captionProps: captionProps ?? null,
|
|
1885
|
+
elementFrameMapRef: elementFrameMap,
|
|
1886
|
+
getCurrentFrameEffect,
|
|
1887
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio)
|
|
1888
|
+
});
|
|
1367
1889
|
}
|
|
1368
|
-
elementMap.current[element.id] = element;
|
|
1890
|
+
elementMap.current[element.id] = { ...element, zIndex: element.zIndex ?? index };
|
|
1369
1891
|
if (reorder) {
|
|
1370
1892
|
reorderElementsByZIndex(twickCanvas);
|
|
1371
1893
|
}
|
|
1372
1894
|
};
|
|
1895
|
+
const addWatermarkToCanvas = ({
|
|
1896
|
+
element
|
|
1897
|
+
}) => {
|
|
1898
|
+
if (!twickCanvas) return;
|
|
1899
|
+
const handler = elementController.get("watermark");
|
|
1900
|
+
if (handler) {
|
|
1901
|
+
handler.add({
|
|
1902
|
+
element,
|
|
1903
|
+
index: Object.keys(elementMap.current).length,
|
|
1904
|
+
canvas: twickCanvas,
|
|
1905
|
+
canvasMetadata: canvasMetadataRef.current,
|
|
1906
|
+
watermarkPropsRef
|
|
1907
|
+
});
|
|
1908
|
+
elementMap.current[element.id] = element;
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
const applyZOrder = (elementId, direction) => {
|
|
1912
|
+
if (!twickCanvas) return false;
|
|
1913
|
+
const newZIndex = changeZOrder(twickCanvas, elementId, direction);
|
|
1914
|
+
if (newZIndex == null) return false;
|
|
1915
|
+
const element = elementMap.current[elementId];
|
|
1916
|
+
if (element) elementMap.current[elementId] = { ...element, zIndex: newZIndex };
|
|
1917
|
+
onCanvasOperation == null ? void 0 : onCanvasOperation(CANVAS_OPERATIONS.Z_ORDER_CHANGED, { elementId, direction });
|
|
1918
|
+
return true;
|
|
1919
|
+
};
|
|
1920
|
+
const bringToFront = (elementId) => applyZOrder(elementId, "front");
|
|
1921
|
+
const sendToBack = (elementId) => applyZOrder(elementId, "back");
|
|
1922
|
+
const bringForward = (elementId) => applyZOrder(elementId, "forward");
|
|
1923
|
+
const sendBackward = (elementId) => applyZOrder(elementId, "backward");
|
|
1373
1924
|
return {
|
|
1374
1925
|
twickCanvas,
|
|
1375
1926
|
buildCanvas,
|
|
1376
1927
|
onVideoSizeChange,
|
|
1928
|
+
addWatermarkToCanvas,
|
|
1377
1929
|
addElementToCanvas,
|
|
1378
|
-
setCanvasElements
|
|
1930
|
+
setCanvasElements,
|
|
1931
|
+
bringToFront,
|
|
1932
|
+
sendToBack,
|
|
1933
|
+
bringForward,
|
|
1934
|
+
sendBackward
|
|
1379
1935
|
};
|
|
1380
1936
|
};
|
|
1381
1937
|
exports.CANVAS_OPERATIONS = CANVAS_OPERATIONS;
|
|
1938
|
+
exports.ELEMENT_TYPES = ELEMENT_TYPES;
|
|
1939
|
+
exports.ElementController = ElementController;
|
|
1382
1940
|
exports.addBackgroundColor = addBackgroundColor;
|
|
1383
1941
|
exports.addCaptionElement = addCaptionElement;
|
|
1384
1942
|
exports.addImageElement = addImageElement;
|
|
@@ -1389,6 +1947,7 @@ exports.convertToCanvasPosition = convertToCanvasPosition;
|
|
|
1389
1947
|
exports.convertToVideoPosition = convertToVideoPosition;
|
|
1390
1948
|
exports.createCanvas = createCanvas;
|
|
1391
1949
|
exports.disabledControl = disabledControl;
|
|
1950
|
+
exports.elementController = elementController;
|
|
1392
1951
|
exports.getCurrentFrameEffect = getCurrentFrameEffect;
|
|
1393
1952
|
exports.reorderElementsByZIndex = reorderElementsByZIndex;
|
|
1394
1953
|
exports.rotateControl = rotateControl;
|