feat: animate patch1
This commit is contained in:
		| @@ -8,6 +8,8 @@ import { transfer } from '../core/transfer'; | ||||
| import { UserConfig } from '../config'; | ||||
| import styles from '../index.less'; | ||||
| import { RotateReset, RotateResizer } from '../core/rotateHandler'; | ||||
| import { mergeAnimate } from '../core/utils/animate'; | ||||
|  | ||||
| interface BlockProps { | ||||
| 	data: IBlockType; | ||||
| 	context: 'edit' | 'preview'; | ||||
| @@ -95,39 +97,36 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 		props.data.fixed, | ||||
| 	]); | ||||
|  | ||||
| 	const animateProps: CSSProperties = useMemo(() => { | ||||
| 		const select: CSSProperties = { | ||||
| 			animationName: '', | ||||
| 			animationDelay: '', | ||||
| 			animationDuration: '', | ||||
| 			animationIterationCount: '', | ||||
| 			//	animationFillMode: 'forwards',// 这个属性和transform冲突 | ||||
| 			animationTimingFunction: '', | ||||
| 	const [force, animateForce] = useState(0); | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		const fn = () => { | ||||
| 			animateForce((p) => p + 1); | ||||
| 		}; | ||||
| 		props.data.animate.forEach((v) => { | ||||
| 			select.animationName = | ||||
| 				select.animationName === '' | ||||
| 					? v.animationName | ||||
| 					: select.animationName + ',' + v.animationName; | ||||
| 			select.animationDelay = | ||||
| 				select.animationDelay === '' | ||||
| 					? v.animationDelay + 's' | ||||
| 					: select.animationDelay + ',' + v.animationDelay + 's'; | ||||
| 			select.animationDuration = | ||||
| 				select.animationDuration === '' | ||||
| 					? v.animationDuration + 's' | ||||
| 					: select.animationDuration + ',' + v.animationDuration + 's'; | ||||
| 			select.animationIterationCount = | ||||
| 				select.animationIterationCount === '' | ||||
| 					? v.animationIterationCount | ||||
| 					: select.animationIterationCount + ',' + v.animationIterationCount; | ||||
| 			select.animationTimingFunction = | ||||
| 				select.animationTimingFunction === '' | ||||
| 					? v.animationTimingFunction | ||||
| 					: select.animationTimingFunction + ',' + v.animationTimingFunction; | ||||
| 		props.config.blockForceUpdate.push(fn); | ||||
| 		const unload = () => { | ||||
| 			props.config.blockForceUpdate = props.config.blockForceUpdate.filter((v) => v !== fn); | ||||
| 		}; | ||||
| 		return () => { | ||||
| 			unload(); | ||||
| 		}; | ||||
| 	}, [animateForce, props.config]); | ||||
|  | ||||
| 	const [animateProps, animationEdit]: [CSSProperties, CSSProperties] = useMemo(() => { | ||||
| 		const [normal, editProps] = mergeAnimate(props.data.animate, { | ||||
| 			isPause: props.config.timelineNeedleConfig.status === 'pause' ? true : false, | ||||
| 			delay: props.config.timelineNeedleConfig.current, | ||||
| 		}); | ||||
| 		return select; | ||||
| 	}, [props.data.animate]); | ||||
| 		return [ | ||||
| 			{ | ||||
| 				animation: normal, | ||||
| 			}, | ||||
| 			{ | ||||
| 				animation: editProps, | ||||
| 			}, | ||||
| 		]; | ||||
| 		// eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| 	}, [props.data.animate, props.config.timelineNeedleConfig, force]); | ||||
|  | ||||
| 	const render = useMemo(() => { | ||||
| 		// 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。 | ||||
| @@ -167,7 +166,7 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								...style, | ||||
| 								...animateProps, | ||||
| 								...animationEdit, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| @@ -180,7 +179,7 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 								pointerEvents: 'none', | ||||
| 								width: '100%', | ||||
| 								height: '100%', | ||||
| 								...animateProps, | ||||
| 								...animationEdit, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| @@ -191,7 +190,7 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 						<span | ||||
| 							style={{ | ||||
| 								pointerEvents: 'none', | ||||
| 								...animateProps, | ||||
| 								...animationEdit, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| @@ -214,10 +213,9 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 						zIndex: props.data.zIndex, | ||||
| 						display: props.data.display, | ||||
| 						transform: `rotate(${props.data.rotate.value}deg)`, | ||||
| 						...animateProps, | ||||
| 					}} | ||||
| 				> | ||||
| 					{state} | ||||
| 					<div style={{ ...animateProps }}>{state}</div> | ||||
| 				</div> | ||||
| 			); | ||||
| 		} | ||||
| @@ -225,14 +223,15 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 		state, | ||||
| 		props.context, | ||||
| 		props.data, | ||||
| 		props.config, | ||||
| 		props.iframe, | ||||
| 		props.config, | ||||
| 		innerDragData, | ||||
| 		animateProps, | ||||
| 		animationEdit, | ||||
| 		previewState.top, | ||||
| 		previewState.left, | ||||
| 		previewState.width, | ||||
| 		previewState.height, | ||||
| 		animateProps, | ||||
| 	]); | ||||
| 	return render; | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,9 @@ import { | ||||
| 	EyeInvisibleOutlined, | ||||
| 	EyeOutlined, | ||||
| 	MenuOutlined, | ||||
| 	PauseCircleOutlined, | ||||
| 	PlayCircleOutlined, | ||||
| 	ReloadOutlined, | ||||
| } from '@ant-design/icons'; | ||||
| import { | ||||
| 	TimeLineItem, | ||||
| @@ -165,9 +167,9 @@ const SortableList = SortableContainer( | ||||
|  | ||||
| let cacheBlock: IBlockType[] = []; | ||||
|  | ||||
| // const needleWidth = 2; | ||||
| // const initialLeft = 20 - needleWidth / 2; | ||||
| // let timer: number | null = null; | ||||
| const needleWidth = 2; | ||||
| const initialLeft = 20 - needleWidth / 2; | ||||
| let timer: number | null = null; | ||||
| export function TimeLine(props: TimeLineProps) { | ||||
| 	const store = props.config.getStore(); | ||||
| 	const data = store.getData().block; | ||||
| @@ -223,70 +225,89 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 		} | ||||
| 	}, [props.config]); | ||||
|  | ||||
| 	// const [needle, setNeedle] = useState(initialLeft); | ||||
| 	const [needle, setNeedle] = useState(initialLeft); | ||||
|  | ||||
| 	//const needleStart = () => { | ||||
| 	// props.config.timelineNeedleConfig.current = 0; | ||||
| 	// setNeedle(initialLeft); | ||||
| 	// //每过0.1秒移动2 | ||||
| 	// if (timer) { | ||||
| 	// 	window.clearInterval(timer); | ||||
| 	// } | ||||
| 	// props.config.timelineNeedleConfig.status = 'start'; | ||||
| 	// const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 	// store.setData(cloneData); | ||||
| 	// store.cleanLast(); | ||||
| 	// timer = window.setInterval(() => { | ||||
| 	// 	if (needle < ruleWidth) { | ||||
| 	// 		setNeedle((pre) => { | ||||
| 	// 			props.config.timelineNeedleConfig.current = (pre - initialLeft) / 20; | ||||
| 	// 			console.log(props.config.timelineNeedleConfig.current); | ||||
| 	// 			return pre + 2; | ||||
| 	// 		}); | ||||
| 	// 	} | ||||
| 	// }, 100); | ||||
| 	//	}; | ||||
| 	const resetAnimate = async () => { | ||||
| 		// 重置动画后才能调整delay | ||||
| 		return new Promise<void>((res) => { | ||||
| 			if (!WAIT) { | ||||
| 				WAIT = true; | ||||
| 				props.config.waitAnimate = true; | ||||
| 				const cache = data.map((v) => { | ||||
| 					return v.animate; | ||||
| 				}); | ||||
| 				const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 				cloneData.block.forEach((v) => { | ||||
| 					v.animate = []; | ||||
| 				}); | ||||
| 				store.setData(cloneData); | ||||
| 				setTimeout(() => { | ||||
| 					props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 					const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 					cloneData.block.forEach((v, i) => { | ||||
| 						v.animate = cache[i]; | ||||
| 					}); | ||||
| 					WAIT = false; | ||||
| 					props.config.waitAnimate = false; | ||||
| 					store.setData(cloneData); | ||||
| 					store.cleanLast(); | ||||
| 					res(); | ||||
| 				}); | ||||
| 			} | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	// const needlePlay = async () => { | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	await resetAnimate(); | ||||
| 	// 	setTimeout(() => { | ||||
| 	// 		props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 		timer = window.setInterval(() => { | ||||
| 	// 			if (needle < ruleWidth) { | ||||
| 	// 				setNeedle((pre) => { | ||||
| 	// 					props.config.timelineNeedleConfig.current = (pre - initialLeft) / 20; | ||||
| 	// 					return pre + 2; | ||||
| 	// 				}); | ||||
| 	// 			} | ||||
| 	// 		}, 100); | ||||
| 	// 	}); | ||||
| 	// }; | ||||
| 	const needlePlay = async () => { | ||||
| 		if (timer) { | ||||
| 			window.clearInterval(timer); | ||||
| 		} | ||||
| 		//判断如果status不是pause,则要执行reset | ||||
| 		if (props.config.timelineNeedleConfig.status !== 'pause') { | ||||
| 			await needleReset(); | ||||
| 		} | ||||
| 		setTimeout(() => { | ||||
| 			timer = window.setInterval(() => { | ||||
| 				if (needle < ruleWidth) { | ||||
| 					setNeedle((pre) => { | ||||
| 						props.config.timelineNeedleConfig.current = (pre - initialLeft) / 20; | ||||
| 						return pre + 2; | ||||
| 					}); | ||||
| 					props.config.blockForceUpdate.forEach((v) => v()); | ||||
| 				} | ||||
| 			}, 100); | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	// const needleReset = () => { | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 	props.config.timelineNeedleConfig.current = 0; | ||||
| 	// 	resetAnimate(); | ||||
| 	// 	setNeedle(initialLeft); | ||||
| 	// 	store.cleanLast(); | ||||
| 	// }; | ||||
| 	const needleReset = async () => { | ||||
| 		if (timer) { | ||||
| 			window.clearInterval(timer); | ||||
| 		} | ||||
| 		props.config.timelineNeedleConfig.status = 'start'; | ||||
| 		await resetAnimate(); | ||||
| 		return new Promise<void>((res) => { | ||||
| 			setTimeout(() => { | ||||
| 				props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 				props.config.timelineNeedleConfig.current = 0; | ||||
| 				setNeedle(initialLeft); | ||||
| 				const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 				store.setData(cloneData); | ||||
| 				store.cleanLast(); | ||||
| 				res(); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	// const needlePause = () => { | ||||
| 	// 	props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 	// 	store.setData(cloneData); | ||||
| 	// 	store.cleanLast(); | ||||
| 	// }; | ||||
| 	const needlePause = () => { | ||||
| 		props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 		if (timer) { | ||||
| 			window.clearInterval(timer); | ||||
| 		} | ||||
| 		const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 		store.setData(cloneData); | ||||
| 		store.cleanLast(); | ||||
| 	}; | ||||
|  | ||||
| 	// props.config.timelineNeedleConfig.resetFunc = needleReset; | ||||
| 	props.config.timelineNeedleConfig.resetFunc = needleReset; | ||||
| 	// props.config.timelineNeedleConfig.runFunc = needleStart; | ||||
|  | ||||
| 	return ( | ||||
| @@ -330,14 +351,18 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 									textAlign: 'right', | ||||
| 								}} | ||||
| 							> | ||||
| 								{/* <span | ||||
| 								<span | ||||
| 									style={{ | ||||
| 										display: 'inline-block', | ||||
| 										cursor: 'pointer', | ||||
| 										marginRight: '10px', | ||||
| 									}} | ||||
| 								> | ||||
| 									<ReloadOutlined onClick={() => needleReset()} /> | ||||
| 									<ReloadOutlined | ||||
| 										onClick={() => { | ||||
| 											needleReset(); | ||||
| 										}} | ||||
| 									/> | ||||
| 								</span> | ||||
| 								<span | ||||
| 									style={{ | ||||
| @@ -346,8 +371,12 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 										marginRight: '10px', | ||||
| 									}} | ||||
| 								> | ||||
| 									<PauseCircleOutlined onClick={() => needlePause()} /> | ||||
| 								</span> */} | ||||
| 									<PauseCircleOutlined | ||||
| 										onClick={() => { | ||||
| 											needlePause(); | ||||
| 										}} | ||||
| 									/> | ||||
| 								</span> | ||||
| 								<span | ||||
| 									title="play" | ||||
| 									style={{ | ||||
| @@ -356,29 +385,7 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 										cursor: 'pointer', | ||||
| 									}} | ||||
| 									onClick={() => { | ||||
| 										//缓存所有animate后执行 | ||||
| 										if (!WAIT) { | ||||
| 											WAIT = true; | ||||
| 											props.config.waitAnimate = true; | ||||
| 											const cache = data.map((v) => { | ||||
| 												return v.animate; | ||||
| 											}); | ||||
| 											const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 											cloneData.block.forEach((v) => { | ||||
| 												v.animate = []; | ||||
| 											}); | ||||
| 											store.setData(cloneData); | ||||
| 											setTimeout(() => { | ||||
| 												const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 												cloneData.block.forEach((v, i) => { | ||||
| 													v.animate = cache[i]; | ||||
| 												}); | ||||
| 												WAIT = false; | ||||
| 												props.config.waitAnimate = false; | ||||
| 												store.setData(cloneData); | ||||
| 												store.cleanLast(); | ||||
| 											}); | ||||
| 										} | ||||
| 										needlePlay(); | ||||
| 									}} | ||||
| 								> | ||||
| 									<PlayCircleOutlined /> | ||||
| @@ -396,7 +403,7 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 							position: 'relative', | ||||
| 						}} | ||||
| 					> | ||||
| 						{/* <div | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								position: 'absolute', | ||||
| 								transform: `translate(-${scrollx}px, 0px)`, | ||||
| @@ -407,8 +414,9 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 								left: needle, | ||||
| 								transition: 'left linear', | ||||
| 								willChange: 'left', | ||||
| 								pointerEvents: 'none', | ||||
| 							}} | ||||
| 						></div> */} | ||||
| 						></div> | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								display: 'flex', | ||||
|   | ||||
| @@ -158,12 +158,14 @@ export function TimeLineItem(props: TimeLineItemProps) { | ||||
| 						}} | ||||
| 					> | ||||
| 						<div | ||||
| 							className="yh-timeline-item-left" | ||||
| 							style={{ ...commonCss, left: -square }} | ||||
| 							onMouseDown={(e) => { | ||||
| 								resizeMouseDown(e, v, true); | ||||
| 							}} | ||||
| 						></div> | ||||
| 						<div | ||||
| 							className="yh-timeline-item-right" | ||||
| 							style={{ ...commonCss, right: -square }} | ||||
| 							onMouseDown={(e) => { | ||||
| 								resizeMouseDown(e, v, false); | ||||
|   | ||||
| @@ -361,6 +361,7 @@ export class UserConfig { | ||||
| 		resetFunc: () => {}, | ||||
| 		current: 0, | ||||
| 	}; | ||||
| 	public blockForceUpdate: Array<Function> = []; | ||||
| 	public waitAnimate = false; | ||||
| 	public wrapperMoveState = wrapperMoveState; | ||||
| 	public iframeWrapperMoveState = iframeWrapperMoveState; | ||||
|   | ||||
							
								
								
									
										28
									
								
								packages/dooringx-lib/src/core/utils/animate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								packages/dooringx-lib/src/core/utils/animate.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import { AnimateItem } from '../store/storetype'; | ||||
| // duration | ||||
| // 1s ease 1s 1 forwards paused bounce , | ||||
| export function mergeAnimate( | ||||
| 	animate: AnimateItem[], | ||||
| 	config = { | ||||
| 		delay: 0, | ||||
| 		isPause: false, | ||||
| 	} | ||||
| ) { | ||||
| 	let configstr = ''; | ||||
| 	let str = ''; | ||||
| 	animate.forEach((v) => { | ||||
| 		configstr = | ||||
| 			(configstr === '' ? configstr : configstr + ',') + | ||||
| 			`${v.animationDuration}s ${v.animationTimingFunction} ${( | ||||
| 				v.animationDelay - config.delay | ||||
| 			).toFixed(1)}s ${v.animationIterationCount} forwards ${ | ||||
| 				config.isPause ? 'paused' : 'running' | ||||
| 			} ${v.animationName}`; | ||||
| 		str = | ||||
| 			(str === '' ? str : str + ',') + | ||||
| 			`${v.animationDuration}s ${v.animationTimingFunction} ${v.animationDelay}s ${ | ||||
| 				v.animationIterationCount | ||||
| 			} forwards ${'running'} ${v.animationName}`; | ||||
| 	}); | ||||
| 	return [str, configstr]; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 hufeixiong
					hufeixiong