Skip to content

Commit

Permalink
refactor: use CSS var for scale
Browse files Browse the repository at this point in the history
  • Loading branch information
weizhenye committed Jun 23, 2024
1 parent 80224a7 commit fede529
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 64 deletions.
5 changes: 5 additions & 0 deletions src/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@
top: 0;
left: 0;
}
.ASS-scroll-area {
position: absolute;
width: 100%;
overflow: hidden;
}
20 changes: 8 additions & 12 deletions src/internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ export function clear(store) {
}

function framing(store) {
const { video, dialogues, actives, resampledRes } = store;
const { video, dialogues, actives } = store;
const vct = video.currentTime - store.delay;
for (let i = actives.length - 1; i >= 0; i -= 1) {
const dia = actives[i];
let { end } = dia;
if (dia.effect && /scroll/.test(dia.effect.name)) {
const { y1, y2, delay } = dia.effect;
const duration = ((y2 || resampledRes.height) - y1) / (1000 / delay);
end = Math.min(end, dia.start + duration);
}
const { end } = dia;
if (end < vct) {
dia.$div.remove();
dia.$clipPath?.remove();
Expand All @@ -39,7 +34,7 @@ function framing(store) {
if (vct < dialogues[store.index].end) {
const dia = renderer(dialogues[store.index], store);
if (!video.paused) {
batchAnimate(dia.$div, 'play');
batchAnimate(dia, 'play');
}
actives.push(dia);
}
Expand Down Expand Up @@ -81,8 +76,8 @@ export function createPlay(store) {
};
cancelAnimationFrame(store.requestId);
store.requestId = requestAnimationFrame(frame);
store.actives.forEach(({ $div }) => {
batchAnimate($div, 'play');
store.actives.forEach((dia) => {
batchAnimate(dia, 'play');
});
};
}
Expand All @@ -91,8 +86,8 @@ export function createPause(store) {
return function pause() {
cancelAnimationFrame(store.requestId);
store.requestId = 0;
store.actives.forEach(({ $div }) => {
batchAnimate($div, 'pause');
store.actives.forEach((dia) => {
batchAnimate(dia, 'pause');
});
};
}
Expand Down Expand Up @@ -135,6 +130,7 @@ export function createResize(that, store) {
+ `left:${(cw - bw) / 2}px;`
);
box.style.cssText = cssText;
box.style.setProperty('--ass-scale', store.scale);
svg.style.cssText = cssText;
svg.setAttributeNS(null, 'viewBox', `0 0 ${sw} ${sh}`);

Expand Down
36 changes: 17 additions & 19 deletions src/renderer/animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,37 @@ function mergeT(ts) {
}, []);
}

function createEffectKeyframes({ effect, duration }, store) {
export function createEffectKeyframes({ effect, duration }) {
// TODO: when effect and move both exist, its behavior is weird, for now only move works.
const { name, delay, lefttoright, y1 } = effect;
const y2 = effect.y2 || store.resampledRes.height;
const { name, delay, leftToRight } = effect;
if (name === 'banner') {
const tx = store.scale * (duration / delay) * (lefttoright ? 1 : -1);
return [0, `${tx}px`].map((x, i) => ({
const tx = (duration / (delay || 1)) * (leftToRight ? 1 : -1);
return [0, `calc(var(--ass-scale) * ${tx}px)`].map((x, i) => ({
offset: i,
transform: `translateX(${x})`,
}));
}
if (name.startsWith('scroll')) {
// speed is 1000px/s when delay=1
const updown = /up/.test(name) ? -1 : 1;
const dp = (y2 - y1) / (duration / delay);
return [y1, y2]
.map((y) => store.scale * y * updown)
.map((y, i) => ({
offset: Math.min(i, dp),
transform: `translateY${y}`,
}));
const y = duration / (delay || 1) * updown;
return [
{ offset: 0, transform: 'translateY(-100%)' },
{ offset: 1, transform: `translateY(calc(var(--ass-scale) * ${y}px))` },
];
}
return [];
}

function createMoveKeyframes({ move, duration, dialogue }, store) {
function createMoveKeyframes({ move, duration, dialogue }) {
const { x1, y1, x2, y2, t1, t2 } = move;
const t = [t1, t2 || duration];
const pos = dialogue.pos || { x: 0, y: 0 };
return [[x1, y1], [x2, y2]]
.map(([x, y]) => [store.scale * (x - pos.x), store.scale * (y - pos.y)])
.map(([x, y]) => [(x - pos.x), (y - pos.y)])
.map(([x, y], index) => ({
offset: Math.min(t[index] / duration, 1),
transform: `translate(${x}px, ${y}px)`,
transform: `translate(calc(var(--ass-scale) * ${x}px), calc(var(--ass-scale) * ${y}px))`,
}));
}

Expand Down Expand Up @@ -105,8 +103,8 @@ export function setKeyframes(dialogue, store) {
const { start, end, effect, move, fade, slices } = dialogue;
const duration = (end - start) * 1000;
const keyframes = [
...(effect && !move ? createEffectKeyframes({ effect, duration }, store) : []),
...(move ? createMoveKeyframes({ move, duration, dialogue }, store) : []),
...(effect && !move ? createEffectKeyframes({ effect, duration }) : []),
...(move ? createMoveKeyframes({ move, duration, dialogue }) : []),
...(fade ? createFadeKeyframes(fade, duration) : []),
].sort((a, b) => a.offset - b.offset);
if (keyframes.length > 0) {
Expand Down Expand Up @@ -140,8 +138,8 @@ export function setKeyframes(dialogue, store) {
// TODO: border and shadow, should animate CSS vars
return {
offset: t2 / fDuration,
...(tag.fs && { 'font-size': `${store.scale * getRealFontSize(tag.fn, tag.fs)}px` }),
...(tag.fsp && { 'letter-spacing': `${store.scale * tag.fsp}px` }),
...(tag.fs && { 'font-size': `calc(calc(var(--ass-scale) * ${getRealFontSize(tag.fn, tag.fs)}px)` }),
...(tag.fsp && { 'letter-spacing': `calc(calc(var(--ass-scale) * ${tag.fsp}px)` }),
...((tag.c1 || (tag.a1 && !hasAlpha)) && {
color: color2rgba((tag.a1 || fromTag.a1) + (tag.c1 || fromTag.c1)),
}),
Expand Down
15 changes: 8 additions & 7 deletions src/renderer/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function createDialogue(dialogue, store) {
delay: Math.min(0, start - (video.currentTime - store.delay)) * 1000,
fill: 'forwards',
};
$div.animations = [];
const animations = [];
slices.forEach((slice) => {
const sliceTag = styles[slice.style].tag;
const borderStyle = styles[slice.style].style.BorderStyle;
Expand All @@ -33,7 +33,7 @@ export function createDialogue(dialogue, store) {
const cssVars = [];
if (!drawing) {
cssText += `line-height:normal;font-family:"${tag.fn}",Arial;`;
cssText += `font-size:${store.scale * getRealFontSize(tag.fn, tag.fs)}px;`;
cssText += `font-size:calc(var(--ass-scale) * ${getRealFontSize(tag.fn, tag.fs)}px);`;
cssText += `color:${color2rgba(tag.a1 + tag.c1)};`;
const scale = /yes/i.test(info.ScaledBorderAndShadow) ? store.scale : 1;
if (borderStyle === 1) {
Expand All @@ -58,7 +58,7 @@ export function createDialogue(dialogue, store) {
cssText += tag.b ? `font-weight:${tag.b === 1 ? 'bold' : tag.b};` : '';
cssText += tag.i ? 'font-style:italic;' : '';
cssText += (tag.u || tag.s) ? `text-decoration:${tag.u ? 'underline' : ''} ${tag.s ? 'line-through' : ''};` : '';
cssText += tag.fsp ? `letter-spacing:${store.scale * tag.fsp}px;` : '';
cssText += tag.fsp ? `letter-spacing:calc(var(--ass-scale) * ${tag.fsp}px);` : '';
// TODO: q0 and q3 is same for now, at least better than nothing.
if (tag.q === 0 || tag.q === 3) {
cssText += 'text-wrap:balance;';
Expand All @@ -80,8 +80,8 @@ export function createDialogue(dialogue, store) {
}
}
if (drawing && tag.pbo) {
const pbo = store.scale * -tag.pbo * (tag.fscy || 100) / 100;
cssText += `vertical-align:${pbo}px;`;
const pbo = -tag.pbo * (tag.fscy || 100) / 100;
cssText += `vertical-align:calc(var(--ass-scale) * ${pbo}px);`;
}

const hasRotate = /"fr[x-z]":[^0]/.test(JSON.stringify(tag));
Expand Down Expand Up @@ -116,15 +116,16 @@ export function createDialogue(dialogue, store) {
fragment.keyframes,
{ ...animationOptions, duration: fragment.duration },
);
$div.animations.push(animation);
animations.push(animation);
}
df.append($span);
});
});
});
if (dialogue.keyframes) {
$div.animations.push(initAnimation($div, dialogue.keyframes, animationOptions));
animations.push(initAnimation($div, dialogue.keyframes, animationOptions));
}
dialogue.animations = animations;
$div.append(df);
return $div;
}
16 changes: 7 additions & 9 deletions src/renderer/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,13 @@ export function getPosition(dialogue, store) {
const { effect, move, align, width, height, margin, slices } = dialogue;
let x = 0;
let y = 0;
if (effect) {
if (effect.name === 'banner') {
x = effect.lefttoright ? -width : store.width;
y = [
store.height - height - margin.vertical,
(store.height - height) / 2,
margin.vertical,
][align.v];
}
if (effect && effect.name === 'banner') {
x = effect.lefttoright ? -width : store.width;
y = [
store.height - height - margin.vertical,
(store.height - height) / 2,
margin.vertical,
][align.v];
} else if (dialogue.pos || move) {
const pos = dialogue.pos || { x: 0, y: 0 };
const sx = scale * pos.x;
Expand Down
6 changes: 5 additions & 1 deletion src/renderer/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { createDialogue } from './dom.js';
import { getPosition } from './position.js';
import { createStyle } from './style.js';
import { setTransformOrigin } from './transform.js';
import { getScrollEffect } from './scroll.js';

export function renderer(dialogue, store) {
const $div = createDialogue(dialogue, store);
Object.assign(dialogue, { $div });
store.box.append($div);
const { width } = $div.getBoundingClientRect();
Object.assign(dialogue, { width });
$div.style.cssText += createStyle(dialogue, store);
$div.style.cssText += createStyle(dialogue);
// height may be changed after createStyle
const { height } = $div.getBoundingClientRect();
Object.assign(dialogue, { height });
Expand All @@ -19,5 +20,8 @@ export function renderer(dialogue, store) {
$div.style.cssText += `width:${width}px;height:${height}px;left:${x}px;top:${y}px;`;
setTransformOrigin(dialogue, store.scale);
Object.assign(dialogue, getClipPath(dialogue, store));
if (dialogue.effect?.name?.startsWith('scroll')) {
Object.assign(dialogue, getScrollEffect(dialogue, store));
}
return dialogue;
}
19 changes: 19 additions & 0 deletions src/renderer/scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function getScrollEffect(dialogue, store) {
const $scrollArea = document.createElement('div');
$scrollArea.className = 'ASS-scroll-area';
store.box.insertBefore($scrollArea, dialogue.$div);
$scrollArea.append(dialogue.$div);
const { height } = store.scriptRes;
const { name, y1, y2 } = dialogue.effect;
const min = Math.min(y1, y2);
const max = Math.max(y1, y2);
const top = min / height * 100;
const bottom = (height - max) / height * 100;
$scrollArea.style.cssText += `top:${top}%;bottom:${bottom}%;`;
const up = /up/.test(name);
// eslint-disable-next-line no-param-reassign
dialogue.$div.style.cssText += up ? 'top:100%;' : 'top:0%;';
return {
$div: $scrollArea,
};
}
19 changes: 7 additions & 12 deletions src/renderer/style.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
export function createStyle(dialogue, store) {
const { layer, align, effect, pos, margin, width } = dialogue;
export function createStyle(dialogue) {
const { layer, align, effect, pos, margin } = dialogue;
let cssText = '';
if (layer) cssText += `z-index:${layer};`;
cssText += `text-align:${['left', 'center', 'right'][align.h]};`;
if (!effect) {
const mw = store.width - store.scale * (margin.left + margin.right);
cssText += `max-width:${mw}px;`;
cssText += `max-width:calc(100% - var(--ass-scale) * ${margin.left + margin.right}px);`;
if (!pos) {
if (align.h === 0) {
cssText += `margin-left:${store.scale * margin.left}px;`;
if (align.h !== 0) {
cssText += `margin-right:calc(var(--ass-scale) * ${margin.right}px);`;
}
if (align.h === 2) {
cssText += `margin-right:${store.scale * margin.right}px;`;
}
if (width > store.width - store.scale * (margin.left + margin.right)) {
cssText += `margin-left:${store.scale * margin.left}px;`;
cssText += `margin-right:${store.scale * margin.right}px;`;
if (align.h !== 2) {
cssText += `margin-left:calc(var(--ass-scale) * ${margin.left}px);`;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function initAnimation($el, keyframes, options) {
return animation;
}

export function batchAnimate($el, action) {
($el.animations || []).forEach((animation) => {
export function batchAnimate(dia, action) {
(dia.animations || []).forEach((animation) => {
animation[action]();
});
}
Loading

0 comments on commit fede529

Please sign in to comment.