@versa_ai/vmml-editor 1.0.38 → 1.0.40
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/.turbo/turbo-build.log +8 -8
- package/dist/index.js +174 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/EditorCanvas.tsx +252 -90
- package/src/utils/VmmlConverter.ts +26 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versa_ai/vmml-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"module": "dist/index.mjs",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"remotion": "4.0.166",
|
|
17
17
|
"uuid": "^10.0.0",
|
|
18
18
|
"zod": "^3.23.8",
|
|
19
|
-
"@versa_ai/vmml-player": "1.1.
|
|
19
|
+
"@versa_ai/vmml-player": "1.1.21",
|
|
20
20
|
"@versa_ai/vmml-utils": "1.0.15"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
@@ -9,16 +9,17 @@ import { toSvg } from 'dom-to-image'
|
|
|
9
9
|
|
|
10
10
|
const EditorCanvas = forwardRef(
|
|
11
11
|
({ previewState, showCanvas, canvasSize, enterPreview, intoTextEdit, frame, vmml, dragState, initFcObjs, editClips = [], onVideoChange, isBatchModify, hideConfig, textWarapCenter }: any, ref: any) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
const [fc, setFc] = useState<any>(null);
|
|
13
|
+
const [history, setHistory] = useState<any>(null);
|
|
14
|
+
const [canvasReady, setCanvasReady] = useState(false);
|
|
15
|
+
const editRenderTime = useRef(0);
|
|
16
|
+
const waitFcTasks = useRef<any>([]);
|
|
17
|
+
const vmmlConverterRef = useRef<any>(null);
|
|
18
|
+
const heightScaleRef = useRef<number>(1);
|
|
19
|
+
const widthScaleRef = useRef<number>(1);
|
|
20
|
+
const fontCacheRef = useRef<Map<string, Promise<string | null>>>(new Map());
|
|
21
|
+
|
|
22
|
+
const initCanvas = () => {
|
|
22
23
|
const canvas = new fabric.Canvas("canvas", {
|
|
23
24
|
width: canvasSize.width,
|
|
24
25
|
height: canvasSize.height,
|
|
@@ -58,9 +59,9 @@ const EditorCanvas = forwardRef(
|
|
|
58
59
|
const objects = fc.getObjects();
|
|
59
60
|
objects.forEach((item: any) => {
|
|
60
61
|
if (item?.clipData?.type === "文字") {
|
|
61
|
-
item.set("visible", ns >= item.clipData.inPoint && ns < item.clipData.inPoint + (item.clipData.duration || vmml.template.duration));
|
|
62
|
+
item.set("visible", item.clipData.duration >0 && ns >= item.clipData.inPoint && ns < item.clipData.inPoint + (item.clipData.duration || vmml.template.duration));
|
|
62
63
|
} else {
|
|
63
|
-
item.set("visible", ns >= item.clipData.inPoint && ns < item.clipData.inPoint + item.clipData?.fileUrl?.duration);
|
|
64
|
+
item.set("visible", item.clipData.duration >0 && ns >= item.clipData.inPoint && ns < item.clipData.inPoint + item.clipData?.fileUrl?.duration);
|
|
64
65
|
}
|
|
65
66
|
});
|
|
66
67
|
fc.discardActiveObject();
|
|
@@ -225,7 +226,7 @@ const EditorCanvas = forwardRef(
|
|
|
225
226
|
return createImageFromClip(clip);
|
|
226
227
|
}
|
|
227
228
|
if (clip.textClip && !clip.audioClip) {
|
|
228
|
-
return
|
|
229
|
+
return createTextFromClipCanvas(clip);
|
|
229
230
|
}
|
|
230
231
|
});
|
|
231
232
|
const res = await Promise.allSettled(promises);
|
|
@@ -235,6 +236,7 @@ const EditorCanvas = forwardRef(
|
|
|
235
236
|
objects.push(item.value);
|
|
236
237
|
}
|
|
237
238
|
});
|
|
239
|
+
console.log(editRenderTime.current === time, 'editRenderTime.current === time')
|
|
238
240
|
if (editRenderTime.current === time) {
|
|
239
241
|
canvas.add(...objects).renderAll();
|
|
240
242
|
checkObjectInPoint()
|
|
@@ -327,6 +329,151 @@ const EditorCanvas = forwardRef(
|
|
|
327
329
|
}
|
|
328
330
|
|
|
329
331
|
// 创建可编辑的textclip
|
|
332
|
+
const createTextFromClipCanvas = async (clip: any, fc2?: fabric.Canvas) => {
|
|
333
|
+
return new Promise<fabric.Group>(async (resolve) => {
|
|
334
|
+
const canvas = fc || fc2;
|
|
335
|
+
if (!canvas) return null;
|
|
336
|
+
|
|
337
|
+
const { width, height } = vmml.template.dimension;
|
|
338
|
+
const fontSize = getFontSize(width, height);
|
|
339
|
+
|
|
340
|
+
const { textContent, backgroundColor, textColor, posParam, fontAssetUrl, alignType, strokeColor, strokeWidth, letterSpacing } = clip.textClip;
|
|
341
|
+
|
|
342
|
+
const scaleX = posParam.scaleX * fontSize / 22 / widthScaleRef.current;
|
|
343
|
+
const scaleY = posParam.scaleY * fontSize / 22 / heightScaleRef.current;
|
|
344
|
+
const left = canvasSize.width * posParam.centerX;
|
|
345
|
+
const top = canvasSize.height * posParam.centerY
|
|
346
|
+
const bgColor = backgroundColor ? argbToRgba(backgroundColor) : 'transparent';
|
|
347
|
+
const stColor = strokeColor ? argbToRgba(strokeColor) : 'transparent';
|
|
348
|
+
const textFill = argbToRgba(textColor || '#ffffffff');
|
|
349
|
+
const strokeW = strokeColor&& strokeWidth ? strokeWidth * 26 * 1.5 / fontSize : 0;
|
|
350
|
+
const letterSpace = letterSpacing * 22 / fontSize;
|
|
351
|
+
|
|
352
|
+
// 加载字体
|
|
353
|
+
let fontFamily = 'sansMedium';
|
|
354
|
+
if (fontAssetUrl) {
|
|
355
|
+
const base64 = await loadFont(fontAssetUrl);
|
|
356
|
+
if (base64) {
|
|
357
|
+
fontFamily = getFontFamilyName(fontAssetUrl);
|
|
358
|
+
await document.fonts.ready;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const lines = textContent.split('\n').filter((item: string) => item);
|
|
362
|
+
const lineHeight = 22 + strokeW; // 行高
|
|
363
|
+
const textHeight = lines.length * lineHeight;
|
|
364
|
+
const groupWidth = Math.max(...lines.map((l: any) => {
|
|
365
|
+
const temp = new fabric.Text(l || ' ', { fontSize: 22, fontFamily, charSpacing: (letterSpace || 0) * 50, strokeWidth: strokeW ?? 0});
|
|
366
|
+
return temp?.width ?? 0;
|
|
367
|
+
})) + 14;
|
|
368
|
+
const groupHeight = textHeight + 13; // padding
|
|
369
|
+
|
|
370
|
+
// 创建双层文字
|
|
371
|
+
const textObjs: fabric.Object[] = [];
|
|
372
|
+
lines.forEach((line: string, idx: number) => {
|
|
373
|
+
const y = (groupHeight - textHeight) / 2 + idx * lineHeight + lineHeight / 2 + 1;
|
|
374
|
+
|
|
375
|
+
// 描边文字
|
|
376
|
+
const strokeText = new fabric.Text(line || ' ', {
|
|
377
|
+
fontFamily,
|
|
378
|
+
fontSize: 22,
|
|
379
|
+
fill: 'transparent',
|
|
380
|
+
stroke: stColor,
|
|
381
|
+
strokeWidth: strokeW,
|
|
382
|
+
originX: 'center',
|
|
383
|
+
originY: 'center',
|
|
384
|
+
left: groupWidth / 2, // 水平居中
|
|
385
|
+
top: y,
|
|
386
|
+
charSpacing: (letterSpace || 0) * 50,
|
|
387
|
+
textAlign: alignType === 1 ? 'center' : alignType === 2 ? 'right' : 'left',
|
|
388
|
+
objectCaching: false,
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// 填充文字
|
|
392
|
+
const fillText = new fabric.Text(line || ' ', {
|
|
393
|
+
fontFamily,
|
|
394
|
+
fontSize: 22,
|
|
395
|
+
fill: textFill,
|
|
396
|
+
stroke: 'transparent',
|
|
397
|
+
originX: 'center',
|
|
398
|
+
originY: 'center',
|
|
399
|
+
strokeWidth: 0,
|
|
400
|
+
left: groupWidth / 2, // 水平居中
|
|
401
|
+
top: y,
|
|
402
|
+
charSpacing: (letterSpace || 0) * 50,
|
|
403
|
+
textAlign: alignType === 1 ? 'center' : alignType === 2 ? 'right' : 'left',
|
|
404
|
+
objectCaching: false,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
textObjs.push(strokeText, fillText);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// 背景矩形
|
|
411
|
+
const bgRect = new fabric.Rect({
|
|
412
|
+
width: groupWidth,
|
|
413
|
+
height: groupHeight,
|
|
414
|
+
fill: bgColor,
|
|
415
|
+
originX: 'left',
|
|
416
|
+
originY: 'top',
|
|
417
|
+
rx: 5,
|
|
418
|
+
ry: 5,
|
|
419
|
+
left: 0,
|
|
420
|
+
top: 0,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const textBasicInfo = {
|
|
424
|
+
isBack: backgroundColor ? true : false,
|
|
425
|
+
colorValue: textFill,
|
|
426
|
+
colorName: 'custom',
|
|
427
|
+
textAlign: alignType === 1 ? 'center' : (alignType === 2 ? 'right' : 'left')
|
|
428
|
+
}
|
|
429
|
+
// 组合 group
|
|
430
|
+
const group = new fabric.Group([bgRect, ...textObjs], {
|
|
431
|
+
left,
|
|
432
|
+
top,
|
|
433
|
+
scaleX,
|
|
434
|
+
scaleY,
|
|
435
|
+
angle: posParam.rotationZ,
|
|
436
|
+
originX: 'center',
|
|
437
|
+
originY: 'center',
|
|
438
|
+
clipData: {
|
|
439
|
+
id: clip.id,
|
|
440
|
+
inPoint: clip.inPoint,
|
|
441
|
+
inFrame: getFrames(clip.inPoint, 30),
|
|
442
|
+
type: "文字",
|
|
443
|
+
textColor: textFill,
|
|
444
|
+
text: textContent,
|
|
445
|
+
bgColor,
|
|
446
|
+
originClip: clip,
|
|
447
|
+
fontAssetUrl,
|
|
448
|
+
fontFamily,
|
|
449
|
+
textBasicInfo,
|
|
450
|
+
duration: clip.duration
|
|
451
|
+
},
|
|
452
|
+
objectCaching: false,
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// 事件
|
|
456
|
+
group.on("selected", (options: any) => {
|
|
457
|
+
options.target.isSelected = -1;
|
|
458
|
+
});
|
|
459
|
+
group.on("moving", (options: any) => {
|
|
460
|
+
options.transform.target.isSelected = 0;
|
|
461
|
+
});
|
|
462
|
+
group.on('modified', () => {
|
|
463
|
+
const fObj = convertToJSON(group);
|
|
464
|
+
if (fObj.clipData.isAiError) {
|
|
465
|
+
fObj.clipData.textColor = 'rgba(0, 0, 0, 0)';
|
|
466
|
+
}
|
|
467
|
+
if (isBatchModify) {
|
|
468
|
+
onBatchModify(fObj, canvas)
|
|
469
|
+
} else {
|
|
470
|
+
vmmlConverterRef.current.updateClip(fObj);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
resolve(group);
|
|
475
|
+
});
|
|
476
|
+
};
|
|
330
477
|
const createTextFromClip = async (clip: any, fc2?: any) => {
|
|
331
478
|
return new Promise(async (resolve) => {
|
|
332
479
|
const canvas = fc || fc2;
|
|
@@ -407,6 +554,7 @@ const EditorCanvas = forwardRef(
|
|
|
407
554
|
vmmlConverterRef.current.updateClip(fObj);
|
|
408
555
|
}
|
|
409
556
|
});
|
|
557
|
+
console.log('fabricjs>>>end>>>>>>>>>>>>')
|
|
410
558
|
resolve(imgData);
|
|
411
559
|
});
|
|
412
560
|
});
|
|
@@ -451,18 +599,30 @@ const EditorCanvas = forwardRef(
|
|
|
451
599
|
|
|
452
600
|
const loadFont = async (url: any) => {
|
|
453
601
|
if (!url) return null
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const fontFace = new FontFace(fontFamilyName, `url(${base64})${format ? ` format('${format}')` : ''}`);
|
|
460
|
-
await fontFace.load();
|
|
461
|
-
(document.fonts as any).add(fontFace);
|
|
462
|
-
return base64
|
|
463
|
-
} catch (e) {
|
|
464
|
-
return null
|
|
602
|
+
|
|
603
|
+
// 检查缓存
|
|
604
|
+
if (fontCacheRef.current.has(url)) {
|
|
605
|
+
return fontCacheRef.current.get(url)!;
|
|
465
606
|
}
|
|
607
|
+
|
|
608
|
+
const loadPromise = (async () => {
|
|
609
|
+
try {
|
|
610
|
+
const base64 = await urlToBlob({ url });
|
|
611
|
+
const fontFamilyName = getFontFamilyName(url);
|
|
612
|
+
const format = detectFontFormat(url);
|
|
613
|
+
|
|
614
|
+
const fontFace = new FontFace(fontFamilyName, `url(${base64})${format ? ` format('${format}')` : ''}`)
|
|
615
|
+
await fontFace.load();
|
|
616
|
+
(document.fonts as any).add(fontFace);
|
|
617
|
+
return base64
|
|
618
|
+
} catch (e) {
|
|
619
|
+
console.error('Font load failed:', url, e);
|
|
620
|
+
return null
|
|
621
|
+
}
|
|
622
|
+
})();
|
|
623
|
+
|
|
624
|
+
fontCacheRef.current.set(url, loadPromise as any);
|
|
625
|
+
return loadPromise;
|
|
466
626
|
}
|
|
467
627
|
|
|
468
628
|
const setTextAlign = (p: any, stroke: any, direction: 'left' | 'center' | 'right') => {
|
|
@@ -487,11 +647,9 @@ const EditorCanvas = forwardRef(
|
|
|
487
647
|
|
|
488
648
|
//文字转图片
|
|
489
649
|
const createTextImg = async ({ textContent, bgColor, textColor, stColor, strokeW, fontAssetUrl = null, textBasicInfo, letterSpacing }: any) => {
|
|
490
|
-
const fontBase64 = await loadFont(fontAssetUrl)
|
|
650
|
+
const fontBase64 = await loadFont(fontAssetUrl);
|
|
491
651
|
const container = document.createElement('div');
|
|
492
652
|
container.style.backgroundColor = bgColor
|
|
493
|
-
// container.style.width = `fit-content`
|
|
494
|
-
// container.style.height = `fit-content`
|
|
495
653
|
container.style.boxSizing = 'content-box'
|
|
496
654
|
container.style.display = 'inline-block'
|
|
497
655
|
container.style.textAlign = textBasicInfo.textAlign || 'left';
|
|
@@ -553,72 +711,72 @@ const EditorCanvas = forwardRef(
|
|
|
553
711
|
const base64Image = await embedFontInSVG(dataurl, fontAssetUrl, fontBase64);
|
|
554
712
|
return { base64Image, height, width };
|
|
555
713
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
clipData: {
|
|
571
|
-
id: uuidv4(),
|
|
572
|
-
inPoint: Math.floor((frame / 30) * 1000000),
|
|
573
|
-
inFrame: frame,
|
|
574
|
-
type: "文字",
|
|
575
|
-
textBasicInfo,
|
|
576
|
-
textColor: textColor,
|
|
577
|
-
text: textContent,
|
|
578
|
-
bgColor: bgColor
|
|
579
|
-
},
|
|
580
|
-
})
|
|
581
|
-
imgData.on("selected", (options: any) => {
|
|
582
|
-
options.target.isSelected = -1;
|
|
583
|
-
});
|
|
584
|
-
imgData.on("moving", (options: any) => {
|
|
585
|
-
options.transform.target.isSelected = 0;
|
|
586
|
-
});
|
|
587
|
-
imgData.on('modified', () => {
|
|
588
|
-
const fObj = convertToJSON(imgData)
|
|
589
|
-
vmmlConverterRef.current.updateClip(fObj);
|
|
590
|
-
});
|
|
591
|
-
canvas.centerObject(imgData);
|
|
592
|
-
canvas.add(imgData)
|
|
593
|
-
setTimeout(()=>{
|
|
594
|
-
canvas.renderAll();
|
|
595
|
-
})
|
|
596
|
-
onVideoChange(imgData.clipData);
|
|
597
|
-
vmmlConverterRef.current.addTextClip(convertToJSON(imgData));
|
|
598
|
-
resolve(true);
|
|
599
|
-
})
|
|
600
|
-
})
|
|
601
|
-
};
|
|
602
|
-
const updateText = async ({ id, textContent, bgColor, textColor, textBasicInfo, fontAssetUrl }: any) => {
|
|
603
|
-
const textImgData = await createTextImg({ textContent, bgColor, textColor, fontAssetUrl, textBasicInfo });
|
|
604
|
-
const target = fc.getObjects().find((item: any) => item.clipData.id === id);
|
|
605
|
-
target.setSrc(textImgData.base64Image, (img: any) => {
|
|
606
|
-
img.set({
|
|
607
|
-
visible: true,
|
|
714
|
+
const createText = async ({ textContent, bgColor, textColor, position, textBasicInfo, id }: any, fc2: any) => {
|
|
715
|
+
const canvas = fc || fc2;
|
|
716
|
+
const { left, top, angle, scaleX, scaleY, zoomX, zoomY } = position;
|
|
717
|
+
const textImgData = await createTextImg({ textContent, bgColor, textColor, textBasicInfo });
|
|
718
|
+
return new Promise((resolve, reject) => {
|
|
719
|
+
fabric.Image.fromURL(textImgData.base64Image, (imgData: any) => {
|
|
720
|
+
imgData.set({
|
|
721
|
+
left,
|
|
722
|
+
top,
|
|
723
|
+
angle,
|
|
724
|
+
width: textImgData.width,
|
|
725
|
+
height: textImgData.height,
|
|
726
|
+
scaleX,
|
|
727
|
+
scaleY,
|
|
608
728
|
clipData: {
|
|
609
|
-
|
|
729
|
+
id: uuidv4(),
|
|
730
|
+
inPoint: Math.floor((frame / 30) * 1000000),
|
|
731
|
+
inFrame: frame,
|
|
732
|
+
type: "文字",
|
|
610
733
|
textBasicInfo,
|
|
611
734
|
textColor: textColor,
|
|
612
735
|
text: textContent,
|
|
613
|
-
bgColor: bgColor
|
|
614
|
-
|
|
615
|
-
}
|
|
736
|
+
bgColor: bgColor
|
|
737
|
+
},
|
|
616
738
|
})
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
739
|
+
imgData.on("selected", (options: any) => {
|
|
740
|
+
options.target.isSelected = -1;
|
|
741
|
+
});
|
|
742
|
+
imgData.on("moving", (options: any) => {
|
|
743
|
+
options.transform.target.isSelected = 0;
|
|
744
|
+
});
|
|
745
|
+
imgData.on('modified', () => {
|
|
746
|
+
const fObj = convertToJSON(imgData)
|
|
747
|
+
vmmlConverterRef.current.updateClip(fObj);
|
|
748
|
+
});
|
|
749
|
+
canvas.centerObject(imgData);
|
|
750
|
+
canvas.add(imgData)
|
|
751
|
+
setTimeout(()=>{
|
|
752
|
+
canvas.renderAll();
|
|
753
|
+
})
|
|
754
|
+
onVideoChange(imgData.clipData);
|
|
755
|
+
vmmlConverterRef.current.addTextClip(convertToJSON(imgData));
|
|
756
|
+
resolve(true);
|
|
757
|
+
})
|
|
758
|
+
})
|
|
759
|
+
};
|
|
760
|
+
const updateText = async ({ id, textContent, bgColor, textColor, textBasicInfo, fontAssetUrl }: any) => {
|
|
761
|
+
const textImgData = await createTextImg({ textContent, bgColor, textColor, fontAssetUrl, textBasicInfo });
|
|
762
|
+
const target = fc.getObjects().find((item: any) => item.clipData.id === id);
|
|
763
|
+
target.setSrc(textImgData.base64Image, (img: any) => {
|
|
764
|
+
img.set({
|
|
765
|
+
visible: true,
|
|
766
|
+
clipData: {
|
|
767
|
+
...img.clipData,
|
|
768
|
+
textBasicInfo,
|
|
769
|
+
textColor: textColor,
|
|
770
|
+
text: textContent,
|
|
771
|
+
bgColor: bgColor,
|
|
772
|
+
isAiError: false
|
|
773
|
+
}
|
|
774
|
+
})
|
|
775
|
+
img.setCoords();
|
|
776
|
+
fc.renderAll();
|
|
777
|
+
vmmlConverterRef.current.updateClip(convertToJSON(img));
|
|
778
|
+
});
|
|
779
|
+
}
|
|
622
780
|
const changeObjectVisible = (id: string, visible: boolean = true) => {
|
|
623
781
|
const target = fc.getObjects().find((item: any) => item.clipData.id === id);
|
|
624
782
|
target.set({ visible });
|
|
@@ -673,8 +831,12 @@ const EditorCanvas = forwardRef(
|
|
|
673
831
|
}, [fc, dragState])
|
|
674
832
|
|
|
675
833
|
useEffect(() => {
|
|
676
|
-
if (canvasSize.width && canvasSize.height
|
|
677
|
-
vmmlConverterRef.current
|
|
834
|
+
if (canvasSize.width && canvasSize.height) {
|
|
835
|
+
if (vmmlConverterRef.current) {
|
|
836
|
+
|
|
837
|
+
} else {
|
|
838
|
+
vmmlConverterRef.current = new VmmlConverter({ vmml, canvasSize });
|
|
839
|
+
}
|
|
678
840
|
}
|
|
679
841
|
}, [canvasSize, vmml]);
|
|
680
842
|
|
|
@@ -176,26 +176,30 @@ class VmmlConverter {
|
|
|
176
176
|
* @param fObj - 画布fObj
|
|
177
177
|
*/
|
|
178
178
|
public updateClip(fObj: any) {
|
|
179
|
-
console.log("updateClip fObj", fObj);
|
|
179
|
+
console.log("updateClip fObj", fObj, this.tracks);
|
|
180
180
|
const posParam = this.setPosParam(fObj);
|
|
181
181
|
const {
|
|
182
|
-
// clipData: { id, type, lineSpacing },
|
|
183
182
|
clipData: { id, type, lineSpacing, originClip },
|
|
184
183
|
} = fObj;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
184
|
+
let existClip = null;
|
|
185
|
+
if (originClip) {
|
|
186
|
+
for (const track of this.tracks) {
|
|
187
|
+
const clip = (track.clips || []).find((c: any) => c.id === originClip.id);
|
|
188
|
+
if (clip) {
|
|
189
|
+
existClip = clip;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
192
|
}
|
|
193
|
+
} else {
|
|
194
|
+
const editorTrack = this.tracks.find((track: any) => track.editorType === type);
|
|
195
|
+
existClip = (editorTrack?.clips || []).find((clip: any) => clip.id === id);
|
|
196
|
+
}
|
|
193
197
|
|
|
194
198
|
if (existClip) {
|
|
195
199
|
//修改现有clip的代码
|
|
196
200
|
!originClip && (existClip.fObj = fObj);
|
|
197
201
|
if (type === "表情包") {
|
|
198
|
-
|
|
202
|
+
existClip.videoClip.posParam = posParam;
|
|
199
203
|
} else if (type === "文字") {
|
|
200
204
|
const { clipData: { text, textColor, bgColor}} = fObj;
|
|
201
205
|
const scale = this.fontSize / 22;
|
|
@@ -213,7 +217,7 @@ class VmmlConverter {
|
|
|
213
217
|
}
|
|
214
218
|
}
|
|
215
219
|
|
|
216
|
-
console.log("updateClip 最终vmml", this.vmml);
|
|
220
|
+
// console.log("updateClip 最终vmml", this.vmml);
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
/**
|
|
@@ -222,13 +226,18 @@ class VmmlConverter {
|
|
|
222
226
|
* @param type - 实例 类型
|
|
223
227
|
*/
|
|
224
228
|
public deleteClip({ id, type, originClip }: { id: string; type: string, originClip: any }): void {
|
|
225
|
-
// 模板内的可编辑clip
|
|
226
229
|
if (originClip) {
|
|
227
|
-
|
|
230
|
+
for (const track of this.tracks) {
|
|
231
|
+
const clip = (track.clips || []).find((c: any) => c.id === originClip.id);
|
|
232
|
+
if (clip) {
|
|
233
|
+
clip.duration = 0;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
228
237
|
} else {
|
|
229
238
|
const editorTrack = this.tracks.find((track: any) => track.editorType === type);
|
|
230
239
|
const index = editorTrack.clips.findIndex((item: any) => item.id === id);
|
|
231
|
-
|
|
240
|
+
|
|
232
241
|
if (index !== -1) {
|
|
233
242
|
if (editorTrack.clips[index + 1] && editorTrack.clips[index + 1].audioClip) {
|
|
234
243
|
editorTrack.clips.splice(index, 2); // 删除当前元素及下一个 audio 元素
|
|
@@ -244,8 +253,10 @@ class VmmlConverter {
|
|
|
244
253
|
}
|
|
245
254
|
}
|
|
246
255
|
}
|
|
256
|
+
}
|
|
247
257
|
|
|
248
|
-
|
|
258
|
+
changeVmml (newVmml: any) {
|
|
259
|
+
this.vmml = newVmml;
|
|
249
260
|
}
|
|
250
261
|
|
|
251
262
|
//切换静音 视频/音频
|