@twick/canvas 0.14.3 → 0.14.5

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.mjs CHANGED
@@ -129,10 +129,19 @@ const reorderElementsByZIndex = (canvas) => {
129
129
  objects.forEach((obj) => canvas.add(obj));
130
130
  canvas.renderAll();
131
131
  };
132
+ const getCanvasContext = (canvas) => {
133
+ var _a, _b, _c, _d;
134
+ if (!canvas || !((_b = (_a = canvas.elements) == null ? void 0 : _a.lower) == null ? void 0 : _b.ctx)) return;
135
+ return (_d = (_c = canvas.elements) == null ? void 0 : _c.lower) == null ? void 0 : _d.ctx;
136
+ };
132
137
  const clearCanvas = (canvas) => {
133
- if (!canvas) return;
134
- canvas.clear();
135
- canvas.renderAll();
138
+ try {
139
+ if (!canvas || !getCanvasContext(canvas)) return;
140
+ canvas.clear();
141
+ canvas.renderAll();
142
+ } catch (error) {
143
+ console.warn("Error clearing canvas:", error);
144
+ }
136
145
  };
137
146
  const convertToCanvasPosition = (x, y, canvasMetadata) => {
138
147
  return {
@@ -142,8 +151,8 @@ const convertToCanvasPosition = (x, y, canvasMetadata) => {
142
151
  };
143
152
  const convertToVideoPosition = (x, y, canvasMetadata, videoSize) => {
144
153
  return {
145
- x: x / canvasMetadata.scaleX - videoSize.width / 2,
146
- y: y / canvasMetadata.scaleY - videoSize.height / 2
154
+ x: Number((x / canvasMetadata.scaleX - videoSize.width / 2).toFixed(2)),
155
+ y: Number((y / canvasMetadata.scaleY - videoSize.height / 2).toFixed(2))
147
156
  };
148
157
  };
149
158
  const getCurrentFrameEffect = (item, seekTime) => {
@@ -178,7 +187,7 @@ const disabledControl = new Control({
178
187
  ctx.save();
179
188
  ctx.translate(left, top);
180
189
  ctx.fillStyle = "#red";
181
- ctx.fillRect(-0 / 2, -0 / 2, size, size);
190
+ ctx.fillRect(-size / 2, -size / 2, size, size);
182
191
  ctx.restore();
183
192
  }
184
193
  });
@@ -278,7 +287,7 @@ const getThumbnail = async (videoUrl, seekTime = 0.1, playbackRate = 1) => {
278
287
  timeoutId = window.setTimeout(() => {
279
288
  cleanup();
280
289
  reject(new Error("Video loading timed out"));
281
- }, 5e3);
290
+ }, 15e3);
282
291
  video.src = videoUrl;
283
292
  document.body.appendChild(video);
284
293
  });
@@ -329,7 +338,7 @@ const addTextElement = ({
329
338
  canvas,
330
339
  canvasMetadata
331
340
  }) => {
332
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
341
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
333
342
  const { x, y } = convertToCanvasPosition(
334
343
  ((_a = element.props) == null ? void 0 : _a.x) || 0,
335
344
  ((_b = element.props) == null ? void 0 : _b.y) || 0,
@@ -348,15 +357,16 @@ const addTextElement = ({
348
357
  fontStyle: ((_g = element.props) == null ? void 0 : _g.fontStyle) || "normal",
349
358
  fontWeight: ((_h = element.props) == null ? void 0 : _h.fontWeight) || "normal",
350
359
  fill: ((_i = element.props) == null ? void 0 : _i.fill) || DEFAULT_TEXT_PROPS.fill,
360
+ opacity: ((_j = element.props) == null ? void 0 : _j.opacity) ?? 1,
351
361
  skipWrapping: false,
352
- textAlign: ((_j = element.props) == null ? void 0 : _j.textAlign) || "center",
353
- stroke: ((_k = element.props) == null ? void 0 : _k.stroke) || DEFAULT_TEXT_PROPS.stroke,
354
- strokeWidth: ((_l = element.props) == null ? void 0 : _l.lineWidth) || DEFAULT_TEXT_PROPS.lineWidth,
355
- shadow: ((_m = element.props) == null ? void 0 : _m.shadowColor) ? new Shadow({
356
- offsetX: ((_o = (_n = element.props) == null ? void 0 : _n.shadowOffset) == null ? void 0 : _o.length) && ((_q = (_p = element.props) == null ? void 0 : _p.shadowOffset) == null ? void 0 : _q.length) > 1 ? element.props.shadowOffset[0] / 2 : 1,
357
- offsetY: ((_s = (_r = element.props) == null ? void 0 : _r.shadowOffset) == null ? void 0 : _s.length) && ((_t = element.props) == null ? void 0 : _t.shadowOffset.length) > 1 ? element.props.shadowOffset[1] / 2 : 1,
358
- blur: (((_u = element.props) == null ? void 0 : _u.shadowBlur) || 2) / 2,
359
- color: (_v = element.props) == null ? void 0 : _v.shadowColor
362
+ textAlign: ((_k = element.props) == null ? void 0 : _k.textAlign) || "center",
363
+ stroke: ((_l = element.props) == null ? void 0 : _l.stroke) || DEFAULT_TEXT_PROPS.stroke,
364
+ strokeWidth: ((_m = element.props) == null ? void 0 : _m.lineWidth) || DEFAULT_TEXT_PROPS.lineWidth,
365
+ shadow: ((_n = element.props) == null ? void 0 : _n.shadowColor) ? new Shadow({
366
+ offsetX: ((_p = (_o = element.props) == null ? void 0 : _o.shadowOffset) == null ? void 0 : _p.length) && ((_r = (_q = element.props) == null ? void 0 : _q.shadowOffset) == null ? void 0 : _r.length) > 1 ? element.props.shadowOffset[0] / 2 : 1,
367
+ offsetY: ((_t = (_s = element.props) == null ? void 0 : _s.shadowOffset) == null ? void 0 : _t.length) && ((_u = element.props) == null ? void 0 : _u.shadowOffset.length) > 1 ? element.props.shadowOffset[1] / 2 : 1,
368
+ blur: (((_v = element.props) == null ? void 0 : _v.shadowBlur) || 2) / 2,
369
+ color: (_w = element.props) == null ? void 0 : _w.shadowColor
360
370
  }) : void 0
361
371
  });
362
372
  text.set("id", element.id);
@@ -379,7 +389,7 @@ const setImageProps = ({
379
389
  index,
380
390
  canvasMetadata
381
391
  }) => {
382
- var _a, _b, _c, _d;
392
+ var _a, _b, _c, _d, _e;
383
393
  const width = (((_a = element.props) == null ? void 0 : _a.width) || 0) * canvasMetadata.scaleX || canvasMetadata.width;
384
394
  const height = (((_b = element.props) == null ? void 0 : _b.height) || 0) * canvasMetadata.scaleY || canvasMetadata.height;
385
395
  const { x, y } = convertToCanvasPosition(
@@ -394,6 +404,7 @@ const setImageProps = ({
394
404
  img.set("height", height);
395
405
  img.set("left", x);
396
406
  img.set("top", y);
407
+ img.set("opacity", ((_e = element.props) == null ? void 0 : _e.opacity) ?? 1);
397
408
  img.set("selectable", true);
398
409
  img.set("hasControls", true);
399
410
  img.set("touchAction", "all");
@@ -405,7 +416,7 @@ const addCaptionElement = ({
405
416
  captionProps,
406
417
  canvasMetadata
407
418
  }) => {
408
- 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;
419
+ 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;
409
420
  const { x, y } = convertToCanvasPosition(
410
421
  ((_b = (_a = element.props) == null ? void 0 : _a.pos) == null ? void 0 : _b.x) || ((_c = captionProps == null ? void 0 : captionProps.pos) == null ? void 0 : _c.x) || 0,
411
422
  ((_e = (_d = element.props) == null ? void 0 : _d.pos) == null ? void 0 : _e.y) || ((_f = captionProps == null ? void 0 : captionProps.pos) == null ? void 0 : _f.y) || 0,
@@ -424,13 +435,14 @@ const addCaptionElement = ({
424
435
  fill: ((_o = element.props) == null ? void 0 : _o.fill) || ((_p = captionProps.color) == null ? void 0 : _p.text) || DEFAULT_CAPTION_PROPS.fill,
425
436
  fontWeight: DEFAULT_CAPTION_PROPS.fontWeight,
426
437
  stroke: ((_q = element.props) == null ? void 0 : _q.stroke) || DEFAULT_CAPTION_PROPS.stroke,
438
+ opacity: ((_r = element.props) == null ? void 0 : _r.opacity) ?? 1,
427
439
  shadow: new Shadow({
428
- offsetX: ((_s = (_r = element.props) == null ? void 0 : _r.shadowOffset) == null ? void 0 : _s[0]) || ((_t = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _t[0]),
429
- offsetY: ((_v = (_u = element.props) == null ? void 0 : _u.shadowOffset) == null ? void 0 : _v[1]) || ((_w = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _w[1]),
430
- blur: ((_x = element.props) == null ? void 0 : _x.shadowBlur) || DEFAULT_CAPTION_PROPS.shadowBlur,
431
- color: ((_y = element.props) == null ? void 0 : _y.shadowColor) || DEFAULT_CAPTION_PROPS.shadowColor
440
+ offsetX: ((_t = (_s = element.props) == null ? void 0 : _s.shadowOffset) == null ? void 0 : _t[0]) || ((_u = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _u[0]),
441
+ offsetY: ((_w = (_v = element.props) == null ? void 0 : _v.shadowOffset) == null ? void 0 : _w[1]) || ((_x = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _x[1]),
442
+ blur: ((_y = element.props) == null ? void 0 : _y.shadowBlur) || DEFAULT_CAPTION_PROPS.shadowBlur,
443
+ color: ((_z = element.props) == null ? void 0 : _z.shadowColor) || DEFAULT_CAPTION_PROPS.shadowColor
432
444
  }),
433
- strokeWidth: ((_z = element.props) == null ? void 0 : _z.lineWidth) || DEFAULT_CAPTION_PROPS.lineWidth
445
+ strokeWidth: ((_A = element.props) == null ? void 0 : _A.lineWidth) || DEFAULT_CAPTION_PROPS.lineWidth
434
446
  });
435
447
  caption.set("id", element.id);
436
448
  caption.set("zIndex", index);
@@ -521,7 +533,7 @@ const addMediaGroup = ({
521
533
  canvasMetadata,
522
534
  currentFrameEffect
523
535
  }) => {
524
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
536
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
525
537
  let frameSize;
526
538
  let angle;
527
539
  let framePosition;
@@ -576,7 +588,8 @@ const addMediaGroup = ({
576
588
  originX: "center",
577
589
  originY: "center",
578
590
  scaleX: newSize.width / img.width,
579
- scaleY: newSize.height / img.height
591
+ scaleY: newSize.height / img.height,
592
+ opacity: ((_n = element.props) == null ? void 0 : _n.opacity) ?? 1
580
593
  });
581
594
  const { x, y } = convertToCanvasPosition(
582
595
  (framePosition == null ? void 0 : framePosition.x) || 0,
@@ -696,6 +709,7 @@ const useTwickCanvas = ({
696
709
  const elementFrameMap = useRef({});
697
710
  const twickCanvasRef = useRef(null);
698
711
  const videoSizeRef = useRef({ width: 1, height: 1 });
712
+ const canvasResolutionRef = useRef({ width: 1, height: 1 });
699
713
  const canvasMetadataRef = useRef({
700
714
  width: 0,
701
715
  height: 0,
@@ -719,9 +733,13 @@ const useTwickCanvas = ({
719
733
  selectionLineWidth = 2,
720
734
  uniScaleTransform = true,
721
735
  enableRetinaScaling = true,
722
- touchZoomThreshold = 10
736
+ touchZoomThreshold = 10,
737
+ forceBuild = false
723
738
  }) => {
724
739
  if (!canvasRef) return;
740
+ if (!forceBuild && canvasResolutionRef.current.width === canvasSize.width && canvasResolutionRef.current.height === canvasSize.height) {
741
+ return;
742
+ }
725
743
  if (twickCanvasRef.current) {
726
744
  console.log("Destroying twickCanvas");
727
745
  twickCanvasRef.current.off("mouse:up", handleMouseUp);
@@ -741,6 +759,7 @@ const useTwickCanvas = ({
741
759
  canvasMetadataRef.current = canvasMetadata;
742
760
  videoSizeRef.current = videoSize;
743
761
  canvas == null ? void 0 : canvas.on("mouse:up", handleMouseUp);
762
+ canvasResolutionRef.current = canvasSize;
744
763
  setTwickCanvas(canvas);
745
764
  twickCanvasRef.current = canvas;
746
765
  if (onCanvasReady) {
@@ -881,13 +900,18 @@ const useTwickCanvas = ({
881
900
  captionProps,
882
901
  cleanAndAdd = false
883
902
  }) => {
884
- if (!twickCanvas) {
885
- console.warn("Canvas not initialized");
903
+ if (!twickCanvas || !getCanvasContext(twickCanvas)) {
904
+ console.warn("Canvas not properly initialized");
886
905
  return;
887
906
  }
888
907
  try {
889
- if (cleanAndAdd) {
908
+ if (cleanAndAdd && getCanvasContext(twickCanvas)) {
909
+ const backgroundColor = twickCanvas.backgroundColor;
890
910
  clearCanvas(twickCanvas);
911
+ if (backgroundColor) {
912
+ twickCanvas.backgroundColor = backgroundColor;
913
+ twickCanvas.renderAll();
914
+ }
891
915
  }
892
916
  await Promise.all(
893
917
  elements.map(async (element, index) => {