feat: animate patch1

This commit is contained in:
hufeixiong
2022-01-28 18:05:29 +08:00
parent 3322fd69b8
commit 253dfe14b3
6 changed files with 172 additions and 134 deletions

View File

@@ -118,7 +118,7 @@ const repeat = ['1', '2', '3', '4', '5', 'infinite'];
const timeFunction: Record<string, string> = {
: 'linear',
: 'ease in',
: 'ease-in',
};
let lastAnimate: AnimateItem[] = [];
@@ -302,12 +302,13 @@ function AnimateControl(props: AnimateControlProps) {
<Row style={{ padding: padding, justifyContent: 'space-around' }}>
{animate.length > 0 && (
<Button
onClick={() => {
onClick={async () => {
if (!isOmit) {
isOmit = true;
props.config.waitAnimate = true;
const cacheProps = animate;
await props.config.timelineNeedleConfig.resetFunc();
const data: IStoreData = deepCopy(store.getData());
props.config.waitAnimate = true;
data.block.forEach((v) => {
if (v.id === props.current.id) {
v.animate = [];
@@ -323,10 +324,9 @@ function AnimateControl(props: AnimateControlProps) {
});
isOmit = false;
props.config.waitAnimate = false;
store.cleanLast();
props.config.timelineNeedleConfig.status = 'start';
store.setData(clone);
store.cleanLast();
props.config.timelineNeedleConfig.resetFunc();
});
}
}}

View File

@@ -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;
}

View File

@@ -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',

View File

@@ -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);

View File

@@ -361,6 +361,7 @@ export class UserConfig {
resetFunc: () => {},
current: 0,
};
public blockForceUpdate: Array<Function> = [];
public waitAnimate = false;
public wrapperMoveState = wrapperMoveState;
public iframeWrapperMoveState = iframeWrapperMoveState;

View 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];
}