@versa_ai/vmml-editor 1.0.17 → 1.0.19
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 +28 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/EditorCanvas.tsx +25 -20
- package/src/index.tsx +6 -2
- package/src/utils/VmmlConverter.ts +16 -3
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.19",
|
|
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.17",
|
|
20
20
|
"@versa_ai/vmml-utils": "1.0.15"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
@@ -335,12 +335,14 @@ const EditorCanvas = forwardRef(
|
|
|
335
335
|
}
|
|
336
336
|
const { width, height } = vmml.template.dimension;
|
|
337
337
|
const fontSize = getFontSize(width, height);
|
|
338
|
-
const { textContent, backgroundColor, textColor, posParam, fontAssetUrl, alignType } = clip.textClip;
|
|
338
|
+
const { textContent, backgroundColor, textColor, posParam, fontAssetUrl, alignType, strokeColor, strokeWidth } = clip.textClip;
|
|
339
339
|
const scaleX = posParam.scaleX * fontSize / 22 / widthScaleRef.current;
|
|
340
340
|
const scaleY = posParam.scaleY * fontSize / 22 / heightScaleRef.current;
|
|
341
|
+
const strokeW = strokeWidth ? (strokeWidth * 22 / fontSize) : 0;
|
|
341
342
|
const left = canvasSize.width * posParam.centerX;
|
|
342
343
|
const top = canvasSize.height * posParam.centerY;
|
|
343
344
|
const bgColor = backgroundColor ? argbToRgba(backgroundColor) : 'transparent';
|
|
345
|
+
const stColor = strokeColor ? argbToRgba(strokeColor) : 'transparent';
|
|
344
346
|
const isAiError = textContent === '请输入文案' && textColor === '#00000000';
|
|
345
347
|
const textFill = argbToRgba(isAiError ? '#ffffffff' : (textColor || '#ffffffff'));
|
|
346
348
|
const textBasicInfo = {
|
|
@@ -349,7 +351,7 @@ const EditorCanvas = forwardRef(
|
|
|
349
351
|
colorName: 'custom',
|
|
350
352
|
textAlign: alignType === 1 ? 'center' : (alignType === 2 ? 'right' : 'left')
|
|
351
353
|
}
|
|
352
|
-
const textImgData = await createTextImg({ textContent, bgColor, textColor: textFill, fontAssetUrl, textBasicInfo });
|
|
354
|
+
const textImgData = await createTextImg({ textContent, bgColor, stColor, strokeW, textColor: textFill, fontAssetUrl, textBasicInfo });
|
|
353
355
|
const fontJSON = localStorage.getItem("VMML_PLAYER_FONTSMAP");
|
|
354
356
|
let fontMap: any = {};
|
|
355
357
|
try {
|
|
@@ -407,23 +409,22 @@ const EditorCanvas = forwardRef(
|
|
|
407
409
|
});
|
|
408
410
|
}
|
|
409
411
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
};
|
|
412
|
+
// 生成简短的字体名称
|
|
413
|
+
const getFontFamilyName = (url: string) => {
|
|
414
|
+
const filename = url.split('/').pop() || '';
|
|
415
|
+
const name = filename.replace(/\.(ttf|otf|woff2?|eot)$/i, '');
|
|
416
|
+
return `CustomFont_${name.substring(0, 20)}`; // 限制长度
|
|
417
|
+
};
|
|
417
418
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
419
|
+
// 检测字体格式
|
|
420
|
+
const detectFontFormat = (url: string) => {
|
|
421
|
+
const lower = url.toLowerCase();
|
|
422
|
+
if (lower.includes('.woff2')) return 'woff2';
|
|
423
|
+
if (lower.includes('.woff')) return 'woff';
|
|
424
|
+
if (lower.includes('.otf')) return 'opentype';
|
|
425
|
+
if (lower.includes('.ttf')) return 'truetype';
|
|
426
|
+
return null;
|
|
427
|
+
};
|
|
427
428
|
|
|
428
429
|
const embedFontInSVG = async (svgString: string, url: string) => {
|
|
429
430
|
if (url) {
|
|
@@ -445,7 +446,7 @@ const EditorCanvas = forwardRef(
|
|
|
445
446
|
}
|
|
446
447
|
|
|
447
448
|
//文字转图片
|
|
448
|
-
const createTextImg = async ({ textContent, bgColor, textColor, fontAssetUrl = null, textBasicInfo }: any) => {
|
|
449
|
+
const createTextImg = async ({ textContent, bgColor, textColor, stColor, strokeW, fontAssetUrl = null, textBasicInfo }: any) => {
|
|
449
450
|
const container = document.createElement('div');
|
|
450
451
|
container.style.backgroundColor = bgColor
|
|
451
452
|
// container.style.width = `fit-content`
|
|
@@ -462,8 +463,12 @@ const EditorCanvas = forwardRef(
|
|
|
462
463
|
p.style.lineHeight = '22px'
|
|
463
464
|
p.style.fontFamily = fontFamily;
|
|
464
465
|
p.style.whiteSpace = "nowrap"
|
|
465
|
-
// p.style.backgroundColor = bgColor;
|
|
466
466
|
p.style.padding = '0';
|
|
467
|
+
p.style.margin = '0';
|
|
468
|
+
|
|
469
|
+
p.style.webkitTextStrokeWidth = `${strokeW ?? 0}px`;
|
|
470
|
+
p.style.webkitTextStrokeColor = stColor;
|
|
471
|
+
|
|
467
472
|
p.textContent = line || " "
|
|
468
473
|
container.appendChild(p);
|
|
469
474
|
})
|
package/src/index.tsx
CHANGED
|
@@ -55,7 +55,7 @@ const EditorFn = <Schema extends AnyZodObject, Props>(
|
|
|
55
55
|
const videoList = useRef<any>([]);
|
|
56
56
|
const [signList, setSignList] = useState<any>([]);
|
|
57
57
|
const [tips, setTips] = useState("");
|
|
58
|
-
const [dragState, setDragState] = useState(0);
|
|
58
|
+
const [dragState, setDragState] = useState(0); // 1: onPointerDown 2: onPointerMove 3: onPointerUp 4: onClickSign
|
|
59
59
|
const vmmlConverterRef = useRef<any>(null);
|
|
60
60
|
const [initFcObjs, setInitFcObjs] = useState([]);
|
|
61
61
|
const [editClips, setEditClips] = useState<any[]>([]); // 可编辑的 clips
|
|
@@ -76,10 +76,12 @@ const EditorFn = <Schema extends AnyZodObject, Props>(
|
|
|
76
76
|
const onPlayerReady = () => {
|
|
77
77
|
const { current }: any = vmmlPlayerRef;
|
|
78
78
|
vmmlFlag.current = false;
|
|
79
|
+
let show = false
|
|
79
80
|
if (current && current.playerRef) {
|
|
80
81
|
setPlayer(current.playerRef);
|
|
81
82
|
current.unmute();
|
|
82
83
|
if (!once.current) {
|
|
84
|
+
show = true
|
|
83
85
|
once.current = true;
|
|
84
86
|
} else {
|
|
85
87
|
if (needPlay.current) {
|
|
@@ -89,7 +91,7 @@ const EditorFn = <Schema extends AnyZodObject, Props>(
|
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
|
-
setShowCanvas(
|
|
94
|
+
setShowCanvas(show);
|
|
93
95
|
setLoading(false);
|
|
94
96
|
};
|
|
95
97
|
|
|
@@ -264,9 +266,11 @@ const EditorFn = <Schema extends AnyZodObject, Props>(
|
|
|
264
266
|
setFrame(e.detail.frame)
|
|
265
267
|
};
|
|
266
268
|
const onPlay = () => {
|
|
269
|
+
setShowCanvas(false)
|
|
267
270
|
setIsPlaying(true);
|
|
268
271
|
};
|
|
269
272
|
const onPause = () => {
|
|
273
|
+
setShowCanvas(true)
|
|
270
274
|
setIsPlaying(false);
|
|
271
275
|
};
|
|
272
276
|
const onWaiting = () => {
|
|
@@ -28,7 +28,7 @@ class VmmlConverter {
|
|
|
28
28
|
//更新位置
|
|
29
29
|
private setPosParam(fObj: any): object {
|
|
30
30
|
const {
|
|
31
|
-
clipData: { type },
|
|
31
|
+
clipData: { type, originClip },
|
|
32
32
|
centerPoint,
|
|
33
33
|
scaleX,
|
|
34
34
|
scaleY,
|
|
@@ -36,28 +36,41 @@ class VmmlConverter {
|
|
|
36
36
|
width,
|
|
37
37
|
height,
|
|
38
38
|
} = fObj;
|
|
39
|
-
let _scaleX, _scaleY, _centerX, _centerY;
|
|
40
|
-
|
|
39
|
+
let _scaleX, _scaleY, _centerX, _centerY, _scaleZ, _centerZ, _rotationX, _rotationY;
|
|
40
|
+
let key = '';
|
|
41
41
|
if (type === "文字") {
|
|
42
42
|
// const [rect, textbox] = fObj.objects;
|
|
43
43
|
_scaleX = (22 * scaleX * this.widthScale) / this.fontSize;
|
|
44
44
|
_scaleY = (22 * scaleY * this.heightScale) / this.fontSize;
|
|
45
45
|
_centerX = centerPoint.x / this.canvasSize.width;
|
|
46
46
|
_centerY = centerPoint.y / this.canvasSize.height;
|
|
47
|
+
|
|
48
|
+
key = 'textClip'
|
|
47
49
|
// fObj.clipData.lineSpacing = 22 * textbox.lineHeight * scaleY * this.heightScale;
|
|
48
50
|
} else if (type === "表情包") {
|
|
49
51
|
_scaleX = (width * scaleX * this.widthScale) / width;
|
|
50
52
|
_scaleY = (height * scaleY * this.heightScale) / height;
|
|
51
53
|
_centerX = centerPoint.x / this.canvasSize.width;
|
|
52
54
|
_centerY = centerPoint.y / this.canvasSize.height;
|
|
55
|
+
|
|
56
|
+
key = 'videoClip'
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
_scaleZ = originClip?.[key]?.posParam?.scaleZ ?? 1;
|
|
60
|
+
_centerZ = originClip?.[key]?.posParam?.centerZ ?? 0.5;
|
|
61
|
+
_rotationX = originClip?.[key]?.posParam?.rotationX ?? 0;
|
|
62
|
+
_rotationY = originClip?.[key]?.posParam?.rotationY ?? 0;
|
|
63
|
+
|
|
55
64
|
return {
|
|
56
65
|
scaleX: _scaleX,
|
|
57
66
|
scaleY: _scaleY,
|
|
67
|
+
scaleZ: _scaleZ,
|
|
58
68
|
centerX: _centerX,
|
|
59
69
|
centerY: _centerY,
|
|
70
|
+
centerZ: _centerZ,
|
|
60
71
|
rotationZ: angle,
|
|
72
|
+
rotationX: _rotationX,
|
|
73
|
+
rotationY: _rotationY,
|
|
61
74
|
};
|
|
62
75
|
}
|
|
63
76
|
|