update 0.8.1
This commit is contained in:
307
packages/dooringx-lib/src/components/timeLine/timeline.tsx
Normal file
307
packages/dooringx-lib/src/components/timeLine/timeline.tsx
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-08-09 15:15:25
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-08-11 17:03:54
|
||||
* @FilePath: \dooringx\packages\dooringx-lib\src\components\timeLine\timeline.tsx
|
||||
*/
|
||||
import deepcopy from 'deepcopy';
|
||||
import React, { CSSProperties, useState } from 'react';
|
||||
import { SortableContainer, SortableElement, SortableHandle, SortEnd } from 'react-sortable-hoc';
|
||||
import UserConfig from '../../config';
|
||||
import { IBlockType, IStoreData } from '../../core/store/storetype';
|
||||
import { arrayMove } from '../../core/utils';
|
||||
import { MenuOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
TimeLineItem,
|
||||
itemHeight,
|
||||
TimeLineItemMouseMove,
|
||||
TimeLineItemMouseOver,
|
||||
interval,
|
||||
} from './timelineItem';
|
||||
|
||||
export interface TimeLineProps {
|
||||
style?: CSSProperties;
|
||||
classes?: string;
|
||||
config: UserConfig;
|
||||
}
|
||||
|
||||
const iter = 500;
|
||||
const animateTicker = new Array(iter).fill(1).map((_, y) => y);
|
||||
|
||||
const DragHandle = SortableHandle(() => <MenuOutlined />);
|
||||
|
||||
const leftWidth = 200;
|
||||
let WAIT = false;
|
||||
|
||||
const widthInterval = interval * 10 + 9;
|
||||
const ruleWidth = (widthInterval * iter) / 10 + 10;
|
||||
const borderColor = '1px solid rgb(204, 204, 204)';
|
||||
|
||||
const SortableItem = SortableElement(
|
||||
({ value }: { value: { value: IBlockType; config: UserConfig } }) => (
|
||||
<div
|
||||
style={{
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
zIndex: 101,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: leftWidth,
|
||||
overflow: 'auto',
|
||||
minWidth: leftWidth,
|
||||
borderRight: borderColor,
|
||||
borderBottom: borderColor,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 30, cursor: 'move' }}>
|
||||
<DragHandle></DragHandle>
|
||||
</div>
|
||||
<div>{value.config.getComponentRegister().getMap()[value.value.name].display}</div>
|
||||
<div>{value.value.id.slice(-6)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
const SortableList = SortableContainer(
|
||||
({ items }: { items: { data: IBlockType[]; config: UserConfig } }) => {
|
||||
return (
|
||||
<div>
|
||||
{items.data.map((value, index: number) => (
|
||||
<SortableItem key={value.id} index={index} value={{ value, config: items.config }} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function TimeLine(props: TimeLineProps) {
|
||||
const store = props.config.getStore();
|
||||
const data = store.getData().block;
|
||||
const forceUpdate = useState(0)[1];
|
||||
const onSortEnd = (sort: SortEnd) => {
|
||||
const { oldIndex, newIndex } = sort;
|
||||
const newblocks: IBlockType[] = arrayMove(data, oldIndex, newIndex);
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
if (isEdit) {
|
||||
const firstType = newblocks[0].name;
|
||||
if (firstType !== 'modalMask') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const store = props.config.getStore();
|
||||
const cloneData: IStoreData = deepcopy(store.getData());
|
||||
cloneData.block = newblocks;
|
||||
store.setData(cloneData);
|
||||
};
|
||||
|
||||
const [state, setState] = useState(0);
|
||||
const [scrollx, setScrollx] = useState(0);
|
||||
|
||||
const content = (
|
||||
<div style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
|
||||
<div style={{ transform: `translate(0, -${state}px)` }}>
|
||||
<SortableList
|
||||
distance={2}
|
||||
useDragHandle
|
||||
items={{
|
||||
data,
|
||||
config: props.config,
|
||||
}}
|
||||
onSortEnd={onSortEnd}
|
||||
axis="y"
|
||||
></SortableList>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={props.classes}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
width: '100%',
|
||||
position: 'absolute',
|
||||
height: '150px',
|
||||
bottom: '0',
|
||||
zIndex: 100,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
...props.style,
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
lineHeight: '24px',
|
||||
paddingLeft: 10,
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
width: leftWidth,
|
||||
borderRight: '1px solid #dadada',
|
||||
minWidth: leftWidth,
|
||||
borderBottom: '1px solid #dadada',
|
||||
height: itemHeight,
|
||||
}}
|
||||
>
|
||||
组件名称
|
||||
<span
|
||||
title="play"
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
marginLeft: '20px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() => {
|
||||
//缓存所有animate后执行
|
||||
if (!WAIT) {
|
||||
WAIT = 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;
|
||||
store.setData(cloneData);
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
</span>
|
||||
</div>
|
||||
{content}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
width: `calc(100% - ${leftWidth}px)`,
|
||||
borderBottom: '1px solid #dadada',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
height: itemHeight,
|
||||
alignItems: 'flex-end',
|
||||
borderBottom: borderColor,
|
||||
width: ruleWidth,
|
||||
overflow: 'hidden',
|
||||
transform: `translate(-${scrollx}px, 0px)`,
|
||||
}}
|
||||
>
|
||||
{animateTicker.map((v) => {
|
||||
if (v % 10 === 0) {
|
||||
return (
|
||||
<div
|
||||
key={v}
|
||||
style={{
|
||||
marginLeft: interval,
|
||||
height: '8px',
|
||||
borderLeft: borderColor,
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '-20px',
|
||||
transform: 'translate(-50%, 0px)',
|
||||
}}
|
||||
>
|
||||
{v}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
key={v}
|
||||
style={{
|
||||
marginLeft: interval,
|
||||
height: '6px',
|
||||
borderLeft: borderColor,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
onScroll={(e) => {
|
||||
const target = e.target as HTMLDivElement;
|
||||
setState(target.scrollTop);
|
||||
setScrollx(target.scrollLeft);
|
||||
}}
|
||||
style={{ overflow: 'auto', height: `calc(100% - ${itemHeight}px)` }}
|
||||
>
|
||||
{data.map((v) => {
|
||||
return (
|
||||
<div
|
||||
key={v.id}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
paddingLeft: interval,
|
||||
borderBottom: borderColor,
|
||||
width: ruleWidth,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
onMouseMove={(e) => {
|
||||
TimeLineItemMouseMove(e, v.animate, forceUpdate);
|
||||
}}
|
||||
onMouseLeave={() => TimeLineItemMouseOver()}
|
||||
onMouseUp={() => TimeLineItemMouseOver()}
|
||||
>
|
||||
<TimeLineItem animate={v.animate}></TimeLineItem>
|
||||
{animateTicker.map((v) => {
|
||||
if (v % 10 === 0) {
|
||||
return (
|
||||
<div
|
||||
key={v}
|
||||
style={{
|
||||
marginRight: widthInterval, // 左右2根线
|
||||
borderLeft: borderColor,
|
||||
position: 'relative',
|
||||
height: itemHeight - 1,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TimeLine;
|
Reference in New Issue
Block a user