update 0.8.1
This commit is contained in:
		| @@ -2,7 +2,7 @@ | ||||
|  * @Author: yehuozhili | ||||
|  * @Date: 2021-03-14 04:29:09 | ||||
|  * @LastEditors: yehuozhili | ||||
|  * @LastEditTime: 2021-07-20 11:24:39 | ||||
|  * @LastEditTime: 2021-08-11 16:39:24 | ||||
|  * @FilePath: \dooringx\packages\dooringx-lib\src\components\IframeWrapperMove\index.tsx | ||||
|  */ | ||||
| import { AllHTMLAttributes, CSSProperties, PropsWithChildren, ReactNode, useRef } from 'react'; | ||||
| @@ -11,6 +11,7 @@ import { onWheelEventIframe } from '../../core/scale'; | ||||
| import React from 'react'; | ||||
| import Ticker from './ticker'; | ||||
| import UserConfig from '../../config'; | ||||
| import TimeLine from '../timeLine/timeline'; | ||||
|  | ||||
| export interface ContainerWrapperProps extends AllHTMLAttributes<HTMLDivElement> { | ||||
| 	config: UserConfig; | ||||
| @@ -48,6 +49,7 @@ function ContainerWrapper(props: PropsWithChildren<ContainerWrapperProps>) { | ||||
| 			{...onWheelEventIframe(props.config, scaleState)} | ||||
| 			{...rest} | ||||
| 		> | ||||
| 			{config.timeline && <TimeLine config={config}></TimeLine>} | ||||
| 			<div | ||||
| 				style={{ | ||||
| 					position: 'absolute', | ||||
|   | ||||
| @@ -128,7 +128,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 		}); | ||||
| 		return select; | ||||
| 	}, [props.data.animate]); | ||||
| 	console.log(animateProps); | ||||
|  | ||||
| 	const render = useMemo(() => { | ||||
| 		// 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。 | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import { | ||||
| 	MenuOutlined, | ||||
| 	SyncOutlined, | ||||
| 	UnorderedListOutlined, | ||||
| 	VideoCameraOutlined, | ||||
| } from '@ant-design/icons'; | ||||
| import { Button, Divider, Form, Input, List, Modal, Popconfirm, Popover } from 'antd'; | ||||
| import React, { CSSProperties, PropsWithChildren, useState } from 'react'; | ||||
| @@ -189,6 +190,13 @@ export function Control(props: PropsWithChildren<ControlProps>) { | ||||
| 					<Button icon={<GatewayOutlined />}></Button> | ||||
| 				</Popover> | ||||
|  | ||||
| 				<Button | ||||
| 					icon={<VideoCameraOutlined />} | ||||
| 					onClick={() => { | ||||
| 						props.config.timeline = !props.config.timeline; | ||||
| 						props.config.getStore().forceUpdate(); | ||||
| 					}} | ||||
| 				></Button> | ||||
| 				<Button | ||||
| 					icon={<SyncOutlined />} | ||||
| 					onClick={() => { | ||||
|   | ||||
							
								
								
									
										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; | ||||
							
								
								
									
										108
									
								
								packages/dooringx-lib/src/components/timeLine/timelineItem.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								packages/dooringx-lib/src/components/timeLine/timelineItem.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| /* | ||||
|  * @Author: yehuozhili | ||||
|  * @Date: 2021-08-10 20:26:44 | ||||
|  * @LastEditors: yehuozhili | ||||
|  * @LastEditTime: 2021-08-11 15:34:46 | ||||
|  * @FilePath: \dooringx\packages\dooringx-lib\src\components\timeLine\timelineItem.tsx | ||||
|  */ | ||||
| import React from 'react'; | ||||
| import { AnimateItem } from '../../core/store/storetype'; | ||||
|  | ||||
| export const itemHeight = 25; | ||||
| const diff = 6; | ||||
| // 需要根据animate属性渲染div | ||||
|  | ||||
| export interface TimeLineItemProps { | ||||
| 	animate: AnimateItem[]; | ||||
| } | ||||
| const bgColor = [ | ||||
| 	'#4af', | ||||
| 	'rgb(93, 128, 158)', | ||||
| 	'rgb(158, 130, 93)', | ||||
| 	'rgb(219, 72, 34)', | ||||
| 	'rgb(255, 68, 168)', | ||||
| 	'#4af', | ||||
| 	'rgb(93, 128, 158)', | ||||
| 	'rgb(158, 130, 93)', | ||||
| 	'rgb(219, 72, 34)', | ||||
| 	'rgb(255, 68, 168)', | ||||
| ]; | ||||
|  | ||||
| interface MoveStateTypes { | ||||
| 	startX: number; | ||||
| 	isMove: boolean; | ||||
| 	uid: string; | ||||
| 	dom: null | HTMLDivElement; | ||||
| } | ||||
|  | ||||
| const moveState: MoveStateTypes = { | ||||
| 	startX: 0, | ||||
| 	isMove: false, | ||||
| 	uid: '', | ||||
| 	dom: null, | ||||
| }; | ||||
|  | ||||
| export const interval = 19; | ||||
| const times = interval + 1; | ||||
|  | ||||
| export const TimeLineItemMouseMove = function ( | ||||
| 	e: React.MouseEvent<HTMLDivElement, MouseEvent>, | ||||
| 	animate: AnimateItem[], | ||||
| 	forceUpdate: React.Dispatch<React.SetStateAction<number>> | ||||
| ) { | ||||
| 	if (moveState.isMove) { | ||||
| 		//修改源属性 | ||||
| 		const diff = e.screenX - moveState.startX; | ||||
| 		animate.forEach((v) => { | ||||
| 			if (v.uid === moveState.uid) { | ||||
| 				const f = parseFloat((v.animationDelay + diff / times).toFixed(1)); | ||||
| 				v.animationDelay = f < 0 ? 0 : f; | ||||
| 				forceUpdate((p) => p + 1); | ||||
| 			} | ||||
| 		}); | ||||
| 		moveState.startX = e.screenX; | ||||
| 	} | ||||
| }; | ||||
| export const TimeLineItemMouseOver = function () { | ||||
| 	moveState.isMove = false; | ||||
| 	moveState.startX = 0; | ||||
| 	moveState.uid = ''; | ||||
| 	if (moveState.dom) { | ||||
| 		moveState.dom.style.cursor = 'default'; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export function TimeLineItem(props: TimeLineItemProps) { | ||||
| 	return ( | ||||
| 		<> | ||||
| 			{props.animate.map((v) => { | ||||
| 				const left = v.animationDelay * times + interval; | ||||
| 				const repeat = | ||||
| 					v.animationIterationCount === 'infinite' ? 500 : parseInt(v.animationIterationCount); | ||||
| 				const width = v.animationDuration * times * repeat; | ||||
| 				const index = v.uid.charCodeAt(0) % 10; | ||||
| 				return ( | ||||
| 					<div | ||||
| 						key={v.uid} | ||||
| 						onMouseDown={(e) => { | ||||
| 							moveState.startX = e.screenX; | ||||
| 							moveState.uid = v.uid; | ||||
| 							moveState.isMove = true; | ||||
| 							const dom = e.target as HTMLDivElement; | ||||
| 							dom.style.cursor = 'move'; | ||||
| 							moveState.dom = dom; | ||||
| 						}} | ||||
| 						style={{ | ||||
| 							position: 'absolute', | ||||
| 							top: diff / 2, | ||||
| 							left: left, | ||||
| 							width: width, | ||||
| 							height: itemHeight - diff, | ||||
| 							background: bgColor[index], | ||||
| 						}} | ||||
| 					></div> | ||||
| 				); | ||||
| 			})} | ||||
| 		</> | ||||
| 	); | ||||
| } | ||||
| @@ -2,7 +2,7 @@ | ||||
|  * @Author: yehuozhili | ||||
|  * @Date: 2021-03-14 04:29:09 | ||||
|  * @LastEditors: yehuozhili | ||||
|  * @LastEditTime: 2021-07-27 10:17:01 | ||||
|  * @LastEditTime: 2021-08-11 16:16:30 | ||||
|  * @FilePath: \dooringx\packages\dooringx-lib\src\components\wrapperMove\index.tsx | ||||
|  */ | ||||
| import { AllHTMLAttributes, CSSProperties, PropsWithChildren, useRef } from 'react'; | ||||
| @@ -11,6 +11,7 @@ import { onWheelEvent } from '../../core/scale'; | ||||
| import React from 'react'; | ||||
| import Ticker from './ticker'; | ||||
| import UserConfig from '../../config'; | ||||
| import TimeLine from '../timeLine/timeline'; | ||||
|  | ||||
| export interface ContainerWrapperProps extends AllHTMLAttributes<HTMLDivElement> { | ||||
| 	config: UserConfig; | ||||
| @@ -42,6 +43,7 @@ function ContainerWrapper(props: PropsWithChildren<ContainerWrapperProps>) { | ||||
| 			{...onWheelEvent(props.config)} | ||||
| 			{...rest} | ||||
| 		> | ||||
| 			{config.timeline && <TimeLine config={config}></TimeLine>} | ||||
| 			{children} | ||||
| 			{ticker && <Ticker config={props.config}></Ticker>} | ||||
| 		</div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hufeixiong
					hufeixiong