Attachment Modal: Fix custom emoji playback in caption (#2759)
This commit is contained in:
parent
4090cf093d
commit
dd659cdb71
@ -16,7 +16,7 @@ import useSyncEffect from '../../hooks/useSyncEffect';
|
|||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
ref?: RefObject<HTMLDivElement>;
|
ref?: RefObject<HTMLDivElement>;
|
||||||
animationId?: string;
|
renderId?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
tgsUrl?: string;
|
tgsUrl?: string;
|
||||||
@ -60,7 +60,7 @@ setTimeout(ensureLottie, LOTTIE_LOAD_DELAY);
|
|||||||
|
|
||||||
const AnimatedSticker: FC<OwnProps> = ({
|
const AnimatedSticker: FC<OwnProps> = ({
|
||||||
ref,
|
ref,
|
||||||
animationId,
|
renderId,
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
tgsUrl,
|
tgsUrl,
|
||||||
@ -86,7 +86,7 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
containerRef = ref;
|
containerRef = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerId = useMemo(() => generateIdFor(ID_STORE, true), []);
|
const viewId = useMemo(() => generateIdFor(ID_STORE, true), []);
|
||||||
|
|
||||||
const [animation, setAnimation] = useState<RLottieInstance>();
|
const [animation, setAnimation] = useState<RLottieInstance>();
|
||||||
const animationRef = useRef<RLottieInstance>();
|
const animationRef = useRef<RLottieInstance>();
|
||||||
@ -128,11 +128,10 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newAnimation = RLottie.init(
|
const newAnimation = RLottie.init(
|
||||||
containerId,
|
|
||||||
container,
|
|
||||||
onLoad,
|
|
||||||
animationId || generateIdFor(ID_STORE, true),
|
|
||||||
tgsUrl,
|
tgsUrl,
|
||||||
|
container,
|
||||||
|
renderId || generateIdFor(ID_STORE, true),
|
||||||
|
viewId,
|
||||||
{
|
{
|
||||||
noLoop,
|
noLoop,
|
||||||
size,
|
size,
|
||||||
@ -141,6 +140,7 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
coords: sharedCanvasCoords,
|
coords: sharedCanvasCoords,
|
||||||
},
|
},
|
||||||
color,
|
color,
|
||||||
|
onLoad,
|
||||||
onEnded,
|
onEnded,
|
||||||
onLoop,
|
onLoop,
|
||||||
);
|
);
|
||||||
@ -165,8 +165,8 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
animation, animationId, tgsUrl, color, isLowPriority, noLoop, onLoad, quality, size, speed, onEnded, onLoop,
|
animation, renderId, tgsUrl, color, isLowPriority, noLoop, onLoad, quality, size, speed, onEnded, onLoop,
|
||||||
containerId, sharedCanvas, sharedCanvasCoords,
|
viewId, sharedCanvas, sharedCanvasCoords,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -177,27 +177,27 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
animationRef.current?.removeContainer(containerId);
|
animationRef.current?.removeView(viewId);
|
||||||
};
|
};
|
||||||
}, [containerId]);
|
}, [viewId]);
|
||||||
|
|
||||||
const playAnimation = useCallback((shouldRestart = false) => {
|
const playAnimation = useCallback((shouldRestart = false) => {
|
||||||
if (animation && (playRef.current || playSegmentRef.current)) {
|
if (animation && (playRef.current || playSegmentRef.current)) {
|
||||||
if (playSegmentRef.current) {
|
if (playSegmentRef.current) {
|
||||||
animation.playSegment(playSegmentRef.current);
|
animation.playSegment(playSegmentRef.current);
|
||||||
} else {
|
} else {
|
||||||
animation.play(shouldRestart, containerId);
|
animation.play(shouldRestart, viewId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [animation, containerId]);
|
}, [animation, viewId]);
|
||||||
|
|
||||||
const pauseAnimation = useCallback(() => {
|
const pauseAnimation = useCallback(() => {
|
||||||
if (!animation) {
|
if (!animation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
animation.pause(containerId);
|
animation.pause(viewId);
|
||||||
}, [animation, containerId]);
|
}, [animation, viewId]);
|
||||||
|
|
||||||
const freezeAnimation = useCallback(() => {
|
const freezeAnimation = useCallback(() => {
|
||||||
isFrozen.current = true;
|
isFrozen.current = true;
|
||||||
@ -234,9 +234,9 @@ const AnimatedSticker: FC<OwnProps> = ({
|
|||||||
|
|
||||||
useSyncEffect(([prevSharedCanvasCoords]) => {
|
useSyncEffect(([prevSharedCanvasCoords]) => {
|
||||||
if (prevSharedCanvasCoords !== undefined && sharedCanvasCoords !== prevSharedCanvasCoords) {
|
if (prevSharedCanvasCoords !== undefined && sharedCanvasCoords !== prevSharedCanvasCoords) {
|
||||||
animation?.setSharedCanvasCoords(containerId, sharedCanvasCoords);
|
animation?.setSharedCanvasCoords(viewId, sharedCanvasCoords);
|
||||||
}
|
}
|
||||||
}, [sharedCanvasCoords, containerId, animation]);
|
}, [sharedCanvasCoords, viewId, animation]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!animation) {
|
if (!animation) {
|
||||||
|
|||||||
@ -121,7 +121,7 @@ const StickerView: FC<OwnProps> = ({
|
|||||||
useMedia(previewMediaHash, !shouldLoad || !shouldPreloadPreview, undefined, cacheBuster);
|
useMedia(previewMediaHash, !shouldLoad || !shouldPreloadPreview, undefined, cacheBuster);
|
||||||
|
|
||||||
const randomIdPrefix = useMemo(() => generateIdFor(ID_STORE, true), []);
|
const randomIdPrefix = useMemo(() => generateIdFor(ID_STORE, true), []);
|
||||||
const idKey = [
|
const renderId = [
|
||||||
(withSharedAnimation ? SHARED_PREFIX : randomIdPrefix), id, realSize, customColor?.join(','),
|
(withSharedAnimation ? SHARED_PREFIX : randomIdPrefix), id, realSize, customColor?.join(','),
|
||||||
].filter(Boolean).join('_');
|
].filter(Boolean).join('_');
|
||||||
|
|
||||||
@ -141,8 +141,8 @@ const StickerView: FC<OwnProps> = ({
|
|||||||
/>
|
/>
|
||||||
{isLottie ? (
|
{isLottie ? (
|
||||||
<AnimatedSticker
|
<AnimatedSticker
|
||||||
key={idKey}
|
key={renderId}
|
||||||
animationId={idKey}
|
renderId={renderId}
|
||||||
size={realSize}
|
size={realSize}
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
styles.media,
|
styles.media,
|
||||||
|
|||||||
@ -155,7 +155,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
|||||||
sharedCanvasRef,
|
sharedCanvasRef,
|
||||||
sharedCanvasHqRef,
|
sharedCanvasHqRef,
|
||||||
absoluteContainerRef,
|
absoluteContainerRef,
|
||||||
isAttachmentModalInput ? 'attachment' : undefined,
|
isAttachmentModalInput ? 'attachment' : 'composer',
|
||||||
isActive,
|
isActive,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -40,18 +40,18 @@ export default function useInputCustomEmojis(
|
|||||||
sharedCanvasRef: React.RefObject<HTMLCanvasElement>,
|
sharedCanvasRef: React.RefObject<HTMLCanvasElement>,
|
||||||
sharedCanvasHqRef: React.RefObject<HTMLCanvasElement>,
|
sharedCanvasHqRef: React.RefObject<HTMLCanvasElement>,
|
||||||
absoluteContainerRef: React.RefObject<HTMLElement>,
|
absoluteContainerRef: React.RefObject<HTMLElement>,
|
||||||
prefixId?: string,
|
prefixId: string,
|
||||||
isActive?: boolean,
|
isActive?: boolean,
|
||||||
) {
|
) {
|
||||||
const { rgbColor: textColor } = useDynamicColorListener(inputRef);
|
const { rgbColor: textColor } = useDynamicColorListener(inputRef);
|
||||||
const mapRef = useRef<Map<string, CustomEmojiPlayer>>(new Map());
|
const playersById = useRef<Map<string, CustomEmojiPlayer>>(new Map());
|
||||||
|
|
||||||
const removeContainers = useCallback((ids: string[]) => {
|
const clearPlayers = useCallback((ids: string[]) => {
|
||||||
ids.forEach((id) => {
|
ids.forEach((id) => {
|
||||||
const player = mapRef.current.get(id);
|
const player = playersById.current.get(id);
|
||||||
if (player) {
|
if (player) {
|
||||||
player.destroy();
|
player.destroy();
|
||||||
mapRef.current.delete(id);
|
playersById.current.delete(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -59,17 +59,17 @@ export default function useInputCustomEmojis(
|
|||||||
const synchronizeElements = useCallback(() => {
|
const synchronizeElements = useCallback(() => {
|
||||||
if (!inputRef.current || !sharedCanvasRef.current || !sharedCanvasHqRef.current) return;
|
if (!inputRef.current || !sharedCanvasRef.current || !sharedCanvasHqRef.current) return;
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
const removedContainers = new Set(mapRef.current.keys());
|
const playerIdsToClear = new Set(playersById.current.keys());
|
||||||
const customEmojies = Array.from(inputRef.current.querySelectorAll<HTMLElement>('.custom-emoji'));
|
const customEmojis = Array.from(inputRef.current.querySelectorAll<HTMLElement>('.custom-emoji'));
|
||||||
|
|
||||||
customEmojies.forEach((element) => {
|
customEmojis.forEach((element) => {
|
||||||
if (!element.dataset.uniqueId) {
|
if (!element.dataset.uniqueId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const id = `${prefixId || ''}${element.dataset.uniqueId}${textColor?.join(',') || ''}`;
|
const playerId = `${prefixId}${element.dataset.uniqueId}${textColor?.join(',') || ''}`;
|
||||||
const documentId = element.dataset.documentId!;
|
const documentId = element.dataset.documentId!;
|
||||||
|
|
||||||
removedContainers.delete(id);
|
playerIdsToClear.delete(playerId);
|
||||||
|
|
||||||
const mediaUrl = getCustomEmojiMediaDataForInput(documentId);
|
const mediaUrl = getCustomEmojiMediaDataForInput(documentId);
|
||||||
if (!mediaUrl) {
|
if (!mediaUrl) {
|
||||||
@ -81,8 +81,8 @@ export default function useInputCustomEmojis(
|
|||||||
const x = round((elementBounds.left - canvasBounds.left) / canvasBounds.width, 4);
|
const x = round((elementBounds.left - canvasBounds.left) / canvasBounds.width, 4);
|
||||||
const y = round((elementBounds.top - canvasBounds.top) / canvasBounds.height, 4);
|
const y = round((elementBounds.top - canvasBounds.top) / canvasBounds.height, 4);
|
||||||
|
|
||||||
if (mapRef.current.has(id)) {
|
if (playersById.current.has(playerId)) {
|
||||||
const player = mapRef.current.get(id)!;
|
const player = playersById.current.get(playerId)!;
|
||||||
player.updatePosition(x, y);
|
player.updatePosition(x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -92,14 +92,17 @@ export default function useInputCustomEmojis(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const isHq = customEmoji?.stickerSetInfo && selectIsAlwaysHighPriorityEmoji(global, customEmoji.stickerSetInfo);
|
const isHq = customEmoji?.stickerSetInfo && selectIsAlwaysHighPriorityEmoji(global, customEmoji.stickerSetInfo);
|
||||||
|
const renderId = [
|
||||||
|
prefixId, documentId, textColor?.join(','),
|
||||||
|
].filter(Boolean).join('_');
|
||||||
|
|
||||||
const animation = createPlayer({
|
const animation = createPlayer({
|
||||||
customEmoji,
|
customEmoji,
|
||||||
sharedCanvasRef,
|
sharedCanvasRef,
|
||||||
sharedCanvasHqRef,
|
sharedCanvasHqRef,
|
||||||
absoluteContainerRef,
|
absoluteContainerRef,
|
||||||
uniqueId: id,
|
renderId,
|
||||||
containerId: prefixId || id,
|
viewId: playerId,
|
||||||
mediaUrl,
|
mediaUrl,
|
||||||
isHq,
|
isHq,
|
||||||
position: { x, y },
|
position: { x, y },
|
||||||
@ -107,11 +110,11 @@ export default function useInputCustomEmojis(
|
|||||||
});
|
});
|
||||||
animation.play();
|
animation.play();
|
||||||
|
|
||||||
mapRef.current.set(id, animation);
|
playersById.current.set(playerId, animation);
|
||||||
});
|
});
|
||||||
|
|
||||||
removeContainers(Array.from(removedContainers));
|
clearPlayers(Array.from(playerIdsToClear));
|
||||||
}, [absoluteContainerRef, textColor, inputRef, prefixId, removeContainers, sharedCanvasHqRef, sharedCanvasRef]);
|
}, [absoluteContainerRef, textColor, inputRef, prefixId, clearPlayers, sharedCanvasHqRef, sharedCanvasRef]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addCustomEmojiInputRenderCallback(synchronizeElements);
|
addCustomEmojiInputRenderCallback(synchronizeElements);
|
||||||
@ -123,7 +126,7 @@ export default function useInputCustomEmojis(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!getHtml() || !inputRef.current || !sharedCanvasRef.current || !isActive) {
|
if (!getHtml() || !inputRef.current || !sharedCanvasRef.current || !isActive) {
|
||||||
removeContainers(Array.from(mapRef.current.keys()));
|
clearPlayers(Array.from(playersById.current.keys()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +134,7 @@ export default function useInputCustomEmojis(
|
|||||||
fastRaf(() => {
|
fastRaf(() => {
|
||||||
synchronizeElements();
|
synchronizeElements();
|
||||||
});
|
});
|
||||||
}, [getHtml, synchronizeElements, inputRef, removeContainers, sharedCanvasRef, isActive]);
|
}, [getHtml, synchronizeElements, inputRef, clearPlayers, sharedCanvasRef, isActive]);
|
||||||
|
|
||||||
useEffectWithPrevDeps(([prevTextColor]) => {
|
useEffectWithPrevDeps(([prevTextColor]) => {
|
||||||
if (textColor !== prevTextColor) {
|
if (textColor !== prevTextColor) {
|
||||||
@ -148,13 +151,13 @@ export default function useInputCustomEmojis(
|
|||||||
useResizeObserver(sharedCanvasRef, throttledSynchronizeElements);
|
useResizeObserver(sharedCanvasRef, throttledSynchronizeElements);
|
||||||
|
|
||||||
const freezeAnimation = useCallback(() => {
|
const freezeAnimation = useCallback(() => {
|
||||||
mapRef.current.forEach((player) => {
|
playersById.current.forEach((player) => {
|
||||||
player.pause();
|
player.pause();
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const unfreezeAnimation = useCallback(() => {
|
const unfreezeAnimation = useCallback(() => {
|
||||||
mapRef.current.forEach((player) => {
|
playersById.current.forEach((player) => {
|
||||||
player.play();
|
player.play();
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -174,8 +177,8 @@ function createPlayer({
|
|||||||
sharedCanvasRef,
|
sharedCanvasRef,
|
||||||
sharedCanvasHqRef,
|
sharedCanvasHqRef,
|
||||||
absoluteContainerRef,
|
absoluteContainerRef,
|
||||||
uniqueId,
|
renderId,
|
||||||
containerId,
|
viewId,
|
||||||
mediaUrl,
|
mediaUrl,
|
||||||
position,
|
position,
|
||||||
isHq,
|
isHq,
|
||||||
@ -185,8 +188,8 @@ function createPlayer({
|
|||||||
sharedCanvasRef: React.RefObject<HTMLCanvasElement>;
|
sharedCanvasRef: React.RefObject<HTMLCanvasElement>;
|
||||||
sharedCanvasHqRef: React.RefObject<HTMLCanvasElement>;
|
sharedCanvasHqRef: React.RefObject<HTMLCanvasElement>;
|
||||||
absoluteContainerRef: React.RefObject<HTMLElement>;
|
absoluteContainerRef: React.RefObject<HTMLElement>;
|
||||||
uniqueId: string;
|
renderId: string;
|
||||||
containerId: string;
|
viewId: string;
|
||||||
mediaUrl: string;
|
mediaUrl: string;
|
||||||
position: { x: number; y: number };
|
position: { x: number; y: number };
|
||||||
isHq?: boolean;
|
isHq?: boolean;
|
||||||
@ -194,11 +197,10 @@ function createPlayer({
|
|||||||
}): CustomEmojiPlayer {
|
}): CustomEmojiPlayer {
|
||||||
if (customEmoji.isLottie) {
|
if (customEmoji.isLottie) {
|
||||||
const lottie = RLottie.init(
|
const lottie = RLottie.init(
|
||||||
containerId,
|
|
||||||
isHq ? sharedCanvasHqRef.current! : sharedCanvasRef.current!,
|
|
||||||
undefined,
|
|
||||||
uniqueId,
|
|
||||||
mediaUrl,
|
mediaUrl,
|
||||||
|
isHq ? sharedCanvasHqRef.current! : sharedCanvasRef.current!,
|
||||||
|
renderId,
|
||||||
|
viewId,
|
||||||
{
|
{
|
||||||
size: SIZE,
|
size: SIZE,
|
||||||
coords: position,
|
coords: position,
|
||||||
@ -210,9 +212,9 @@ function createPlayer({
|
|||||||
return {
|
return {
|
||||||
play: () => lottie.play(),
|
play: () => lottie.play(),
|
||||||
pause: () => lottie.pause(),
|
pause: () => lottie.pause(),
|
||||||
destroy: () => lottie.removeContainer(uniqueId),
|
destroy: () => lottie.removeView(viewId),
|
||||||
updatePosition: (x: number, y: number) => {
|
updatePosition: (x: number, y: number) => {
|
||||||
return lottie.setSharedCanvasCoords(uniqueId, { x, y });
|
return lottie.setSharedCanvasCoords(viewId, { x, y });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { createConnector } from '../../util/PostMessageConnector';
|
|||||||
import { animate } from '../../util/animation';
|
import { animate } from '../../util/animation';
|
||||||
import cycleRestrict from '../../util/cycleRestrict';
|
import cycleRestrict from '../../util/cycleRestrict';
|
||||||
import { fastRaf } from '../../util/schedulers';
|
import { fastRaf } from '../../util/schedulers';
|
||||||
|
import generateIdFor from '../../util/generateIdFor';
|
||||||
|
|
||||||
interface Params {
|
interface Params {
|
||||||
noLoop?: boolean;
|
noLoop?: boolean;
|
||||||
@ -28,8 +29,9 @@ const LOW_PRIORITY_QUALITY = IS_ANDROID ? 0.5 : 0.75;
|
|||||||
const LOW_PRIORITY_QUALITY_SIZE_THRESHOLD = 24;
|
const LOW_PRIORITY_QUALITY_SIZE_THRESHOLD = 24;
|
||||||
const HIGH_PRIORITY_CACHE_MODULO = IS_SAFARI ? 2 : 4;
|
const HIGH_PRIORITY_CACHE_MODULO = IS_SAFARI ? 2 : 4;
|
||||||
const LOW_PRIORITY_CACHE_MODULO = 0;
|
const LOW_PRIORITY_CACHE_MODULO = 0;
|
||||||
|
const ID_STORE = {};
|
||||||
|
|
||||||
const instancesById = new Map<string, RLottie>();
|
const instancesByRenderId = new Map<string, RLottie>();
|
||||||
|
|
||||||
const workers = new Array(MAX_WORKERS).fill(undefined).map(
|
const workers = new Array(MAX_WORKERS).fill(undefined).map(
|
||||||
() => createConnector<RLottieApi>(new Worker(new URL('./rlottie.worker.ts', import.meta.url))),
|
() => createConnector<RLottieApi>(new Worker(new URL('./rlottie.worker.ts', import.meta.url))),
|
||||||
@ -39,7 +41,7 @@ let lastWorkerIndex = -1;
|
|||||||
class RLottie {
|
class RLottie {
|
||||||
// Config
|
// Config
|
||||||
|
|
||||||
private containers = new Map<string, {
|
private views = new Map<string, {
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
isLoaded?: boolean;
|
isLoaded?: boolean;
|
||||||
@ -90,40 +92,46 @@ class RLottie {
|
|||||||
private lastRenderAt?: number;
|
private lastRenderAt?: number;
|
||||||
|
|
||||||
static init(...args: ConstructorParameters<typeof RLottie>) {
|
static init(...args: ConstructorParameters<typeof RLottie>) {
|
||||||
const [container, canvas, onLoad, id, , params] = args;
|
const [
|
||||||
let instance = instancesById.get(id);
|
, canvas,
|
||||||
|
renderId,
|
||||||
|
viewId = generateIdFor(ID_STORE, true),
|
||||||
|
params, ,
|
||||||
|
onLoad,
|
||||||
|
] = args;
|
||||||
|
let instance = instancesByRenderId.get(renderId);
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
// eslint-disable-next-line prefer-rest-params
|
// eslint-disable-next-line prefer-rest-params
|
||||||
instance = new RLottie(...args);
|
instance = new RLottie(...args);
|
||||||
instancesById.set(id, instance);
|
instancesByRenderId.set(renderId, instance);
|
||||||
} else {
|
} else {
|
||||||
instance.addContainer(container, canvas, onLoad, params?.coords);
|
instance.addView(viewId, canvas, onLoad, params?.coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
containerId: string,
|
|
||||||
container: HTMLDivElement | HTMLCanvasElement,
|
|
||||||
onLoad: NoneToVoidFunction | undefined,
|
|
||||||
private id: string,
|
|
||||||
private tgsUrl: string,
|
private tgsUrl: string,
|
||||||
private params: Params = { },
|
private container: HTMLDivElement | HTMLCanvasElement,
|
||||||
|
private renderId: string,
|
||||||
|
private viewId: string = generateIdFor(ID_STORE, true),
|
||||||
|
private params: Params = {},
|
||||||
private customColor?: [number, number, number],
|
private customColor?: [number, number, number],
|
||||||
|
private onLoad?: NoneToVoidFunction | undefined,
|
||||||
private onEnded?: (isDestroyed?: boolean) => void,
|
private onEnded?: (isDestroyed?: boolean) => void,
|
||||||
private onLoop?: () => void,
|
private onLoop?: () => void,
|
||||||
) {
|
) {
|
||||||
this.addContainer(containerId, container, onLoad, params.coords);
|
this.addView(viewId, container, onLoad, params.coords);
|
||||||
this.initConfig();
|
this.initConfig();
|
||||||
this.initRenderer();
|
this.initRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeContainer(containerId: string) {
|
public removeView(viewId: string) {
|
||||||
const {
|
const {
|
||||||
canvas, ctx, isSharedCanvas, coords,
|
canvas, ctx, isSharedCanvas, coords,
|
||||||
} = this.containers.get(containerId)!;
|
} = this.views.get(viewId)!;
|
||||||
|
|
||||||
if (isSharedCanvas) {
|
if (isSharedCanvas) {
|
||||||
ctx.clearRect(coords!.x, coords!.y, this.imgSize, this.imgSize);
|
ctx.clearRect(coords!.x, coords!.y, this.imgSize, this.imgSize);
|
||||||
@ -131,9 +139,9 @@ class RLottie {
|
|||||||
canvas.remove();
|
canvas.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.containers.delete(containerId);
|
this.views.delete(viewId);
|
||||||
|
|
||||||
if (!this.containers.size) {
|
if (!this.views.size) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,9 +150,9 @@ class RLottie {
|
|||||||
return this.isAnimating || this.isWaiting;
|
return this.isAnimating || this.isWaiting;
|
||||||
}
|
}
|
||||||
|
|
||||||
play(forceRestart = false, containerId?: string) {
|
play(forceRestart = false, viewId?: string) {
|
||||||
if (containerId) {
|
if (viewId) {
|
||||||
this.containers.get(containerId)!.isPaused = false;
|
this.views.get(viewId)!.isPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isEnded && forceRestart) {
|
if (this.isEnded && forceRestart) {
|
||||||
@ -156,11 +164,11 @@ class RLottie {
|
|||||||
this.doPlay();
|
this.doPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
pause(containerId?: string) {
|
pause(viewId?: string) {
|
||||||
if (containerId) {
|
if (viewId) {
|
||||||
this.containers.get(containerId)!.isPaused = true;
|
this.views.get(viewId)!.isPaused = true;
|
||||||
|
|
||||||
const areAllContainersPaused = Array.from(this.containers.values()).every(({ isPaused }) => isPaused);
|
const areAllContainersPaused = Array.from(this.views.values()).every(({ isPaused }) => isPaused);
|
||||||
if (!areAllContainersPaused) {
|
if (!areAllContainersPaused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -202,8 +210,8 @@ class RLottie {
|
|||||||
this.params.noLoop = noLoop;
|
this.params.noLoop = noLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSharedCanvasCoords(containerId: string, newCoords: Params['coords']) {
|
setSharedCanvasCoords(viewId: string, newCoords: Params['coords']) {
|
||||||
const containerInfo = this.containers.get(containerId)!;
|
const containerInfo = this.views.get(viewId)!;
|
||||||
const {
|
const {
|
||||||
canvas, ctx,
|
canvas, ctx,
|
||||||
} = containerInfo;
|
} = containerInfo;
|
||||||
@ -230,8 +238,8 @@ class RLottie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addContainer(
|
private addView(
|
||||||
containerId: string,
|
viewId: string,
|
||||||
container: HTMLDivElement | HTMLCanvasElement,
|
container: HTMLDivElement | HTMLCanvasElement,
|
||||||
onLoad?: NoneToVoidFunction,
|
onLoad?: NoneToVoidFunction,
|
||||||
coords?: Params['coords'],
|
coords?: Params['coords'],
|
||||||
@ -272,7 +280,7 @@ class RLottie {
|
|||||||
|
|
||||||
container.appendChild(canvas);
|
container.appendChild(canvas);
|
||||||
|
|
||||||
this.containers.set(containerId, {
|
this.views.set(viewId, {
|
||||||
canvas, ctx, onLoad,
|
canvas, ctx, onLoad,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -287,7 +295,7 @@ class RLottie {
|
|||||||
|
|
||||||
imgSize = Math.round(this.params.size! * sizeFactor);
|
imgSize = Math.round(this.params.size! * sizeFactor);
|
||||||
|
|
||||||
this.containers.set(containerId, {
|
this.views.set(viewId, {
|
||||||
canvas,
|
canvas,
|
||||||
ctx,
|
ctx,
|
||||||
isSharedCanvas: true,
|
isSharedCanvas: true,
|
||||||
@ -328,7 +336,7 @@ class RLottie {
|
|||||||
this.clearCache();
|
this.clearCache();
|
||||||
this.destroyRenderer();
|
this.destroyRenderer();
|
||||||
|
|
||||||
instancesById.delete(this.id);
|
instancesByRenderId.delete(this.renderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearCache() {
|
private clearCache() {
|
||||||
@ -359,7 +367,7 @@ class RLottie {
|
|||||||
workers[this.workerIndex].request({
|
workers[this.workerIndex].request({
|
||||||
name: 'init',
|
name: 'init',
|
||||||
args: [
|
args: [
|
||||||
this.id,
|
this.renderId,
|
||||||
this.tgsUrl,
|
this.tgsUrl,
|
||||||
this.imgSize,
|
this.imgSize,
|
||||||
this.params.isLowPriority || false,
|
this.params.isLowPriority || false,
|
||||||
@ -372,7 +380,7 @@ class RLottie {
|
|||||||
private destroyRenderer() {
|
private destroyRenderer() {
|
||||||
workers[this.workerIndex].request({
|
workers[this.workerIndex].request({
|
||||||
name: 'destroy',
|
name: 'destroy',
|
||||||
args: [this.id],
|
args: [this.renderId],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +403,7 @@ class RLottie {
|
|||||||
workers[this.workerIndex].request({
|
workers[this.workerIndex].request({
|
||||||
name: 'changeData',
|
name: 'changeData',
|
||||||
args: [
|
args: [
|
||||||
this.id,
|
this.renderId,
|
||||||
this.tgsUrl,
|
this.tgsUrl,
|
||||||
this.params.isLowPriority || false,
|
this.params.isLowPriority || false,
|
||||||
this.onChangeData.bind(this),
|
this.onChangeData.bind(this),
|
||||||
@ -441,7 +449,7 @@ class RLottie {
|
|||||||
|
|
||||||
// Paused from outside
|
// Paused from outside
|
||||||
if (!this.isAnimating) {
|
if (!this.isAnimating) {
|
||||||
const areAllLoaded = Array.from(this.containers.values()).every(({ isLoaded }) => isLoaded);
|
const areAllLoaded = Array.from(this.views.values()).every(({ isLoaded }) => isLoaded);
|
||||||
if (areAllLoaded) {
|
if (areAllLoaded) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -464,7 +472,7 @@ class RLottie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frameIndex !== this.prevFrameIndex) {
|
if (frameIndex !== this.prevFrameIndex) {
|
||||||
this.containers.forEach((containerData) => {
|
this.views.forEach((containerData) => {
|
||||||
const {
|
const {
|
||||||
ctx, isLoaded, isPaused, coords: { x, y } = {}, onLoad,
|
ctx, isLoaded, isPaused, coords: { x, y } = {}, onLoad,
|
||||||
} = containerData;
|
} = containerData;
|
||||||
@ -554,7 +562,7 @@ class RLottie {
|
|||||||
|
|
||||||
workers[this.workerIndex].request({
|
workers[this.workerIndex].request({
|
||||||
name: 'renderFrames',
|
name: 'renderFrames',
|
||||||
args: [this.id, frameIndex, this.onFrameLoad.bind(this)],
|
args: [this.renderId, frameIndex, this.onFrameLoad.bind(this)],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user