Commit 8ed5e9af authored by haiyoucuv's avatar haiyoucuv

init & svga

parent c32b7f75
import React, { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
import { Player } from 'svga';
import { loadSvga } from "../utils/loader.ts";
import { loadImage, loadSvga } from "../utils/loader.ts";
import { VideoSprite } from "svga/dist/types";
export interface BaseSvgaPlayerProps {
className?: string;
styles?: { icon: React.CSSProperties };
src: string;
autoplay?: boolean;
loop?: boolean;
loop?: number;
startFrame?: number,
endFrame?: number,
onProcess?: (current: number, total: number) => void;
onStart?: () => void;
onPause?: () => void;
onResume?: () => void;
onStop?: () => void;
onEnd?: () => void;
}
......@@ -22,17 +25,21 @@ export interface BaseSvgaPlayerProps {
type MergedHTMLAttributes = Omit<
React.HTMLAttributes<HTMLElement> &
React.CanvasHTMLAttributes<HTMLElement>,
'type' | 'color'
'onPause'
>;
export type HTMLDisplayElement = HTMLImageElement | HTMLCanvasElement | ImageBitmap;
export interface SvgaPlayerRef {
nativeElement: HTMLCanvasElement;
player: Player;
getPlayer: () => Player;
start: () => Player;
pause: () => Player;
resume: () => Player;
stop: () => Player;
replaceImage: (name: string, img: string | HTMLDisplayElement) => Promise<HTMLDisplayElement>;
addImage: (parentName: string, targetName: string, img: string | HTMLDisplayElement, width?: number, height?: number) => void;
removeImage: (targetName: string) => void;
}
......@@ -49,7 +56,8 @@ export const SvgaPlayer = forwardRef<
src, autoplay = true, loop = true,
startFrame = 0,
endFrame = 0,
onStart, onEnd,
onStart, onPause, onResume, onStop, onEnd,
onProcess,
} = props;
const canvasRef = useRef<HTMLCanvasElement>(null);
......@@ -63,7 +71,7 @@ export const SvgaPlayer = forwardRef<
useImperativeHandle(ref, () => ({
nativeElement: canvasRef.current,
player: playInfo.current.player,
getPlayer: () => playInfo.current.player,
start: () => {
playInfo.current.player.start();
return playInfo.current.player;
......@@ -79,30 +87,88 @@ export const SvgaPlayer = forwardRef<
stop: () => {
playInfo.current.player.stop();
return playInfo.current.player;
}
},
async replaceImage(name: string, img: string | HTMLDisplayElement): Promise<HTMLDisplayElement> {
const player = playInfo.current.player;
if (playInfo.current.player && playInfo.current.player.videoEntity) {
if (typeof img === 'string') {
img = await loadImage(img)
}
// @ts-ignore
player.bitmapsCache[name] = img
return img;
}
},
async addImage(parentName: string, targetName: string, img: string | HTMLDisplayElement, width?: number, height?: number) {
const player = playInfo.current.player;
if (player && player.videoEntity) {
let videoItem = player.videoEntity
let parent, target, parentIndex
videoItem.sprites.forEach((sprite, index) => {
if (sprite.imageKey === parentName) {
parent = sprite
parentIndex = index
}
if (sprite.imageKey === targetName) {
target = sprite
}
})
if (!parent) {
console.warn(`父节点[${parentName}]不存在`)
return
}
if (target) {
console.warn(`节点[${targetName}]已存在`)
} else {
const imgEl = await this.replaceImage(targetName, img)
let targetFrames = JSON.parse(JSON.stringify(parent.frames))
for (let { layout, transform } of targetFrames) {
layout.width = width || imgEl.width;
layout.height = height || imgEl.height;
transform._tx = transform.tx;
transform._ty = transform.ty;
}
let frame = {
imageKey: targetName,
frames: targetFrames,
}
videoItem.sprites.splice(parentIndex + 1, 0, frame)
}
}
},
removeImage(targetName: string) {
const player = playInfo.current.player;
if (player && player.videoEntity) {
let videoItem = player.videoEntity
let target: VideoSprite
videoItem.sprites.forEach((sprite, index) => {
if (sprite.imageKey === targetName) {
target = sprite
videoItem.sprites.splice(index, 1)
}
})
if (!target) {
console.warn(`节点[${targetName}]不存在`)
}
}
},
}));
useEffect(() => {
const player = new Player({ container: canvasRef.current });
playInfo.current.player = player;
player.onStart = () => {
onStart && onStart();
}
player.onResume = () => {
console.log('onResume')
}
player.onPause = () => {
console.log('onPause')
}
player.onStop = () => {
console.log('onStop')
}
// player.onProcess = () => console.log('onProcess', player);
player.onEnd = () => {
console.log('onEnd')
onEnd && onEnd();
}
player.onStart = () => onStart && onStart();
player.onPause = () => onPause && onPause();
player.onResume = () => onResume && onResume();
player.onStop = () => onStop && onStop();
player.onProcess = () => onProcess && onProcess(player.currentFrame, player.totalFrames);
player.onEnd = () => onEnd && onEnd();
return () => {
player.destroy();
......
......@@ -55,3 +55,17 @@ export const loadSvgaList = async (srcList: string[]) => {
return await Promise.all(ps);
}
export function loadImage(src: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function () {
resolve(img);
};
img.onerror = function (e) {
reject(e);
};
img.src = src;
});
}
\ No newline at end of file
......@@ -4,6 +4,7 @@
height: 100px;
position: absolute;
}
.svgaTest2 {
background: rgba(0, 0, 0, 0.5);
width: 300px;
......@@ -23,8 +24,8 @@
}
.button {
width: 100px;
height: 40px;
margin: 5px;
padding: 10px;
border: 1px solid black;
border-radius: 15px;
display: flex;
......@@ -32,14 +33,17 @@
justify-content: center;
}
.container{
.container {
position: absolute;
left: 0;
top: 800px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
justify-content: start;
flex-wrap: wrap;
}
.play {
}
\ No newline at end of file
......@@ -4,6 +4,8 @@ import styles from "./App.module.less";
import svga from "./assets/svga/1红色标题.svga";
import svga2 from "./assets/svga/2输出加载页氛围.svga";
import icon from "./assets/react.svg";
import { useEffect, useRef } from "react";
function App() {
......@@ -12,7 +14,7 @@ function App() {
const svgaRef = useRef<SvgaPlayerRef>(null);
useEffect(() => {
console.log(svgaRef.current);
console.log(svgaRef.current.getPlayer());
});
const clickPlay = () => {
......@@ -22,6 +24,14 @@ function App() {
svgaRef.current?.stop();
}
const clickReplaceImage = () => {
svgaRef.current?.addImage("img_3929", "5555", icon, 200, 200);
}
const clickRemoveImage = () => {
svgaRef.current?.removeImage("5555");
}
return <>
<SvgaPlayer
......@@ -37,11 +47,11 @@ function App() {
className={styles.svgaTest3}
src={svga2}
/>
<div
className={styles.container}
>
<div className={styles.container}>
<div className={styles.button} onClick={clickPlay}>play</div>
<div className={styles.button} onClick={clickStop}>stop</div>
<div className={styles.button} onClick={clickReplaceImage}>replaceImage</div>
<div className={styles.button} onClick={clickRemoveImage}>removeImage</div>
</div>
</>
}
......
......@@ -15,7 +15,7 @@
"jsx": "react-jsx",
/* Linting */
"strict": true,
"strict": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment