feat: animate patch1
This commit is contained in:
@@ -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();
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
@@ -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