Update app.py
Browse files
app.py
CHANGED
|
@@ -45,7 +45,7 @@ body{{font-family:-apple-system,BlinkMacSystemFont,sans-serif;background:#f5f5f7
|
|
| 45 |
.media-item-dur{{position:absolute;top:2px;right:2px;background:rgba(0,0,0,0.7);padding:1px 3px;border-radius:2px;font-size:8px;color:#fff}}
|
| 46 |
.preview-area{{flex:1;display:flex;flex-direction:column;background:#1a1a1a;margin:6px;border-radius:8px;overflow:hidden}}
|
| 47 |
.preview-box{{flex:1;display:flex;align-items:center;justify-content:center;background:#000;overflow:hidden}}
|
| 48 |
-
#previewCanvas{{background:#000;box-shadow:0 0 20px rgba(0,0,0,0.5)}}
|
| 49 |
.controls{{height:45px;background:#222;display:flex;align-items:center;justify-content:center;gap:6px}}
|
| 50 |
.ctrl-btn{{width:28px;height:28px;border:none;border-radius:50%;background:rgba(255,255,255,0.1);color:#fff;cursor:pointer;font-size:12px}}
|
| 51 |
.ctrl-btn:hover{{background:rgba(255,255,255,0.2)}}
|
|
@@ -267,6 +267,88 @@ S.canvas=document.getElementById('previewCanvas');
|
|
| 267 |
S.ctx=S.canvas.getContext('2d');
|
| 268 |
updateCanvasSize();
|
| 269 |
drawPlaceholder();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
}}
|
| 271 |
|
| 272 |
function updateCanvasSize(){{
|
|
@@ -528,6 +610,8 @@ if(c.type==='text'){{
|
|
| 528 |
box.innerHTML='<div class="prop-group"><div class="prop-label">ํ
์คํธ</div><input class="prop-input" value="'+c.text+'" onchange="setProp(\\'text\\',this.value)"></div>'+
|
| 529 |
'<div class="prop-group"><div class="prop-label">์์</div><input class="prop-input" type="number" step="0.1" value="'+c.start+'" onchange="setProp(\\'start\\',parseFloat(this.value))"></div>'+
|
| 530 |
'<div class="prop-group"><div class="prop-label">๊ธธ์ด: '+fmt(len)+'</div></div>'+
|
|
|
|
|
|
|
| 531 |
'<div class="prop-group"><div class="prop-label">๊ธ์ ํฌ๊ธฐ</div><select class="prop-input" onchange="setProp(\\'fontSize\\',parseInt(this.value))">'+
|
| 532 |
'<option value="24"'+(c.fontSize===24?' selected':'')+'>์๊ฒ</option>'+
|
| 533 |
'<option value="36"'+(c.fontSize===36?' selected':'')+'>๋ณดํต</option>'+
|
|
@@ -820,7 +904,9 @@ text:text,
|
|
| 820 |
fontSize:parseInt(document.getElementById('textSize').value),
|
| 821 |
fontColor:document.getElementById('textColor').value,
|
| 822 |
bgStyle:document.getElementById('textBgStyle').value,
|
| 823 |
-
bgColor:document.getElementById('textBgColor').value
|
|
|
|
|
|
|
| 824 |
}});
|
| 825 |
closeTextModal();
|
| 826 |
renderTL();
|
|
@@ -843,6 +929,8 @@ var fontSize=clip.fontSize||48;
|
|
| 843 |
var fontColor=clip.fontColor||'#ffffff';
|
| 844 |
var bgStyle=clip.bgStyle||'none';
|
| 845 |
var bgColor=clip.bgColor||'#000000';
|
|
|
|
|
|
|
| 846 |
|
| 847 |
ctx.font='bold '+fontSize+'px -apple-system,BlinkMacSystemFont,sans-serif';
|
| 848 |
ctx.textAlign='center';
|
|
@@ -851,8 +939,16 @@ ctx.textBaseline='middle';
|
|
| 851 |
var metrics=ctx.measureText(text);
|
| 852 |
var textW=metrics.width;
|
| 853 |
var textH=fontSize;
|
| 854 |
-
var x=dw
|
| 855 |
-
var y=dh
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 856 |
|
| 857 |
if(bgStyle!=='none'){{
|
| 858 |
var padding=fontSize*0.3;
|
|
@@ -861,7 +957,7 @@ var bgY=y-textH/2-padding/2;
|
|
| 861 |
var bgW=textW+padding*2;
|
| 862 |
var bgH=textH+padding;
|
| 863 |
|
| 864 |
-
ctx.fillStyle=bgColor+'cc';
|
| 865 |
if(bgStyle==='rounded'){{
|
| 866 |
ctx.beginPath();
|
| 867 |
ctx.roundRect(bgX,bgY,bgW,bgH,10);
|
|
@@ -878,6 +974,15 @@ ctx.fillText(text,x+2,y+2);
|
|
| 878 |
// ํ
์คํธ
|
| 879 |
ctx.fillStyle=fontColor;
|
| 880 |
ctx.fillText(text,x,y);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 881 |
}}
|
| 882 |
function setZoom(v){{S.zoom=parseFloat(v);renderTL();updateHead()}}
|
| 883 |
function tlClick(e){{
|
|
@@ -1115,10 +1220,12 @@ ctx.drawImage(frameCanvas,fx,fy,fw,fh);
|
|
| 1115 |
// ๋ด๋ณด๋ด๊ธฐ์ฉ ํ
์คํธ ๋ ๋๋ง
|
| 1116 |
function drawTextExport(ctx,clip,dw,dh){{
|
| 1117 |
var text=clip.text;
|
| 1118 |
-
var fontSize=Math.round(clip.fontSize*(dw/640))||72;
|
| 1119 |
var fontColor=clip.fontColor||'#ffffff';
|
| 1120 |
var bgStyle=clip.bgStyle||'none';
|
| 1121 |
var bgColor=clip.bgColor||'#000000';
|
|
|
|
|
|
|
| 1122 |
|
| 1123 |
ctx.font='bold '+fontSize+'px -apple-system,BlinkMacSystemFont,sans-serif';
|
| 1124 |
ctx.textAlign='center';
|
|
@@ -1127,8 +1234,8 @@ ctx.textBaseline='middle';
|
|
| 1127 |
var metrics=ctx.measureText(text);
|
| 1128 |
var textW=metrics.width;
|
| 1129 |
var textH=fontSize;
|
| 1130 |
-
var x=dw
|
| 1131 |
-
var y=dh
|
| 1132 |
|
| 1133 |
if(bgStyle!=='none'){{
|
| 1134 |
var padding=fontSize*0.3;
|
|
|
|
| 45 |
.media-item-dur{{position:absolute;top:2px;right:2px;background:rgba(0,0,0,0.7);padding:1px 3px;border-radius:2px;font-size:8px;color:#fff}}
|
| 46 |
.preview-area{{flex:1;display:flex;flex-direction:column;background:#1a1a1a;margin:6px;border-radius:8px;overflow:hidden}}
|
| 47 |
.preview-box{{flex:1;display:flex;align-items:center;justify-content:center;background:#000;overflow:hidden}}
|
| 48 |
+
#previewCanvas{{background:#000;box-shadow:0 0 20px rgba(0,0,0,0.5);cursor:default}}
|
| 49 |
.controls{{height:45px;background:#222;display:flex;align-items:center;justify-content:center;gap:6px}}
|
| 50 |
.ctrl-btn{{width:28px;height:28px;border:none;border-radius:50%;background:rgba(255,255,255,0.1);color:#fff;cursor:pointer;font-size:12px}}
|
| 51 |
.ctrl-btn:hover{{background:rgba(255,255,255,0.2)}}
|
|
|
|
| 267 |
S.ctx=S.canvas.getContext('2d');
|
| 268 |
updateCanvasSize();
|
| 269 |
drawPlaceholder();
|
| 270 |
+
setupCanvasDrag();
|
| 271 |
+
}}
|
| 272 |
+
|
| 273 |
+
// ์บ๋ฒ์ค์์ ํ
์คํธ ๋๋๊ทธ ์ค์
|
| 274 |
+
function setupCanvasDrag(){{
|
| 275 |
+
var canvas=S.canvas;
|
| 276 |
+
var dragging=null;
|
| 277 |
+
var dragOffsetX=0,dragOffsetY=0;
|
| 278 |
+
|
| 279 |
+
canvas.addEventListener('mousedown',function(e){{
|
| 280 |
+
var rect=canvas.getBoundingClientRect();
|
| 281 |
+
var scaleX=canvas.width/rect.width;
|
| 282 |
+
var scaleY=canvas.height/rect.height;
|
| 283 |
+
var mx=(e.clientX-rect.left)*scaleX;
|
| 284 |
+
var my=(e.clientY-rect.top)*scaleY;
|
| 285 |
+
|
| 286 |
+
// ํ์ฌ ์๊ฐ์ ํ
์คํธ ํด๋ฆฝ ์ค ํด๋ฆญ๋ ๊ฒ ์ฐพ๊ธฐ
|
| 287 |
+
var textClips=getTextClipsAt(S.time);
|
| 288 |
+
for(var i=textClips.length-1;i>=0;i--){{
|
| 289 |
+
var tc=textClips[i];
|
| 290 |
+
if(tc._bounds){{
|
| 291 |
+
var b=tc._bounds;
|
| 292 |
+
if(mx>=b.x&&mx<=b.x+b.w&&my>=b.y&&my<=b.y+b.h){{
|
| 293 |
+
dragging=tc;
|
| 294 |
+
selClip(tc.id);
|
| 295 |
+
var size=S.ratioSizes[S.ratio];
|
| 296 |
+
dragOffsetX=mx-size.pw*tc.posX;
|
| 297 |
+
dragOffsetY=my-size.ph*tc.posY;
|
| 298 |
+
canvas.style.cursor='move';
|
| 299 |
+
e.preventDefault();
|
| 300 |
+
return;
|
| 301 |
+
}}
|
| 302 |
+
}}
|
| 303 |
+
}}
|
| 304 |
+
}});
|
| 305 |
+
|
| 306 |
+
canvas.addEventListener('mousemove',function(e){{
|
| 307 |
+
var rect=canvas.getBoundingClientRect();
|
| 308 |
+
var scaleX=canvas.width/rect.width;
|
| 309 |
+
var scaleY=canvas.height/rect.height;
|
| 310 |
+
var mx=(e.clientX-rect.left)*scaleX;
|
| 311 |
+
var my=(e.clientY-rect.top)*scaleY;
|
| 312 |
+
|
| 313 |
+
if(dragging){{
|
| 314 |
+
var size=S.ratioSizes[S.ratio];
|
| 315 |
+
dragging.posX=Math.max(0.1,Math.min(0.9,(mx-dragOffsetX)/size.pw));
|
| 316 |
+
dragging.posY=Math.max(0.1,Math.min(0.9,(my-dragOffsetY)/size.ph));
|
| 317 |
+
drawFrame();
|
| 318 |
+
}}else{{
|
| 319 |
+
// ํธ๋ฒ ์ปค์ ๋ณ๊ฒฝ
|
| 320 |
+
var textClips=getTextClipsAt(S.time);
|
| 321 |
+
var onText=false;
|
| 322 |
+
for(var i=0;i<textClips.length;i++){{
|
| 323 |
+
var tc=textClips[i];
|
| 324 |
+
if(tc._bounds){{
|
| 325 |
+
var b=tc._bounds;
|
| 326 |
+
if(mx>=b.x&&mx<=b.x+b.w&&my>=b.y&&my<=b.y+b.h){{
|
| 327 |
+
onText=true;
|
| 328 |
+
break;
|
| 329 |
+
}}
|
| 330 |
+
}}
|
| 331 |
+
}}
|
| 332 |
+
canvas.style.cursor=onText?'move':'default';
|
| 333 |
+
}}
|
| 334 |
+
}});
|
| 335 |
+
|
| 336 |
+
canvas.addEventListener('mouseup',function(){{
|
| 337 |
+
if(dragging){{
|
| 338 |
+
save();
|
| 339 |
+
dragging=null;
|
| 340 |
+
canvas.style.cursor='default';
|
| 341 |
+
renderProps();
|
| 342 |
+
}}
|
| 343 |
+
}});
|
| 344 |
+
|
| 345 |
+
canvas.addEventListener('mouseleave',function(){{
|
| 346 |
+
if(dragging){{
|
| 347 |
+
save();
|
| 348 |
+
dragging=null;
|
| 349 |
+
canvas.style.cursor='default';
|
| 350 |
+
}}
|
| 351 |
+
}});
|
| 352 |
}}
|
| 353 |
|
| 354 |
function updateCanvasSize(){{
|
|
|
|
| 610 |
box.innerHTML='<div class="prop-group"><div class="prop-label">ํ
์คํธ</div><input class="prop-input" value="'+c.text+'" onchange="setProp(\\'text\\',this.value)"></div>'+
|
| 611 |
'<div class="prop-group"><div class="prop-label">์์</div><input class="prop-input" type="number" step="0.1" value="'+c.start+'" onchange="setProp(\\'start\\',parseFloat(this.value))"></div>'+
|
| 612 |
'<div class="prop-group"><div class="prop-label">๊ธธ์ด: '+fmt(len)+'</div></div>'+
|
| 613 |
+
'<div class="prop-group"><div class="prop-label">์์น X ('+Math.round((c.posX||0.5)*100)+'%)</div><input class="prop-input" type="range" min="0.05" max="0.95" step="0.01" value="'+(c.posX||0.5)+'" oninput="setProp(\\'posX\\',parseFloat(this.value))"></div>'+
|
| 614 |
+
'<div class="prop-group"><div class="prop-label">์์น Y ('+Math.round((c.posY||0.85)*100)+'%)</div><input class="prop-input" type="range" min="0.05" max="0.95" step="0.01" value="'+(c.posY||0.85)+'" oninput="setProp(\\'posY\\',parseFloat(this.value))"></div>'+
|
| 615 |
'<div class="prop-group"><div class="prop-label">๊ธ์ ํฌ๊ธฐ</div><select class="prop-input" onchange="setProp(\\'fontSize\\',parseInt(this.value))">'+
|
| 616 |
'<option value="24"'+(c.fontSize===24?' selected':'')+'>์๊ฒ</option>'+
|
| 617 |
'<option value="36"'+(c.fontSize===36?' selected':'')+'>๋ณดํต</option>'+
|
|
|
|
| 904 |
fontSize:parseInt(document.getElementById('textSize').value),
|
| 905 |
fontColor:document.getElementById('textColor').value,
|
| 906 |
bgStyle:document.getElementById('textBgStyle').value,
|
| 907 |
+
bgColor:document.getElementById('textBgColor').value,
|
| 908 |
+
posX:0.5, // 0~1 ๋น์จ (๊ฐ์ด๋ฐ)
|
| 909 |
+
posY:0.85 // 0~1 ๋น์จ (ํ๋จ)
|
| 910 |
}});
|
| 911 |
closeTextModal();
|
| 912 |
renderTL();
|
|
|
|
| 929 |
var fontColor=clip.fontColor||'#ffffff';
|
| 930 |
var bgStyle=clip.bgStyle||'none';
|
| 931 |
var bgColor=clip.bgColor||'#000000';
|
| 932 |
+
var posX=clip.posX!==undefined?clip.posX:0.5;
|
| 933 |
+
var posY=clip.posY!==undefined?clip.posY:0.85;
|
| 934 |
|
| 935 |
ctx.font='bold '+fontSize+'px -apple-system,BlinkMacSystemFont,sans-serif';
|
| 936 |
ctx.textAlign='center';
|
|
|
|
| 939 |
var metrics=ctx.measureText(text);
|
| 940 |
var textW=metrics.width;
|
| 941 |
var textH=fontSize;
|
| 942 |
+
var x=dw*posX;
|
| 943 |
+
var y=dh*posY;
|
| 944 |
+
|
| 945 |
+
// ํ
์คํธ ์์ญ ์ ์ฅ (ํด๋ฆญ ๊ฐ์ง์ฉ)
|
| 946 |
+
clip._bounds={{
|
| 947 |
+
x:x-textW/2-fontSize*0.3,
|
| 948 |
+
y:y-textH/2-fontSize*0.15,
|
| 949 |
+
w:textW+fontSize*0.6,
|
| 950 |
+
h:textH+fontSize*0.3
|
| 951 |
+
}};
|
| 952 |
|
| 953 |
if(bgStyle!=='none'){{
|
| 954 |
var padding=fontSize*0.3;
|
|
|
|
| 957 |
var bgW=textW+padding*2;
|
| 958 |
var bgH=textH+padding;
|
| 959 |
|
| 960 |
+
ctx.fillStyle=bgColor+'cc';
|
| 961 |
if(bgStyle==='rounded'){{
|
| 962 |
ctx.beginPath();
|
| 963 |
ctx.roundRect(bgX,bgY,bgW,bgH,10);
|
|
|
|
| 974 |
// ํ
์คํธ
|
| 975 |
ctx.fillStyle=fontColor;
|
| 976 |
ctx.fillText(text,x,y);
|
| 977 |
+
|
| 978 |
+
// ์ ํ๋ ํ
์คํธ๋ฉด ํ
๋๋ฆฌ ํ์
|
| 979 |
+
if(S.sel===clip.id){{
|
| 980 |
+
ctx.strokeStyle='#6366f1';
|
| 981 |
+
ctx.lineWidth=2;
|
| 982 |
+
ctx.setLineDash([5,3]);
|
| 983 |
+
ctx.strokeRect(clip._bounds.x,clip._bounds.y,clip._bounds.w,clip._bounds.h);
|
| 984 |
+
ctx.setLineDash([]);
|
| 985 |
+
}}
|
| 986 |
}}
|
| 987 |
function setZoom(v){{S.zoom=parseFloat(v);renderTL();updateHead()}}
|
| 988 |
function tlClick(e){{
|
|
|
|
| 1220 |
// ๋ด๋ณด๋ด๊ธฐ์ฉ ํ
์คํธ ๋ ๋๋ง
|
| 1221 |
function drawTextExport(ctx,clip,dw,dh){{
|
| 1222 |
var text=clip.text;
|
| 1223 |
+
var fontSize=Math.round(clip.fontSize*(dw/640))||72;
|
| 1224 |
var fontColor=clip.fontColor||'#ffffff';
|
| 1225 |
var bgStyle=clip.bgStyle||'none';
|
| 1226 |
var bgColor=clip.bgColor||'#000000';
|
| 1227 |
+
var posX=clip.posX!==undefined?clip.posX:0.5;
|
| 1228 |
+
var posY=clip.posY!==undefined?clip.posY:0.85;
|
| 1229 |
|
| 1230 |
ctx.font='bold '+fontSize+'px -apple-system,BlinkMacSystemFont,sans-serif';
|
| 1231 |
ctx.textAlign='center';
|
|
|
|
| 1234 |
var metrics=ctx.measureText(text);
|
| 1235 |
var textW=metrics.width;
|
| 1236 |
var textH=fontSize;
|
| 1237 |
+
var x=dw*posX;
|
| 1238 |
+
var y=dh*posY;
|
| 1239 |
|
| 1240 |
if(bgStyle!=='none'){{
|
| 1241 |
var padding=fontSize*0.3;
|