d8d-design-transform
v1.0.44
Published
D8D Design Transform is a powerful React component library designed for creating scalable and pannable canvases. It supports features such as dragging, resizing, and nesting of items. This library is highly suitable for building complex design tools, char
Downloads
58
Readme
D8D Design Transform
D8D Design Transform 是一个功能强大的React组件库,用于创建可缩放、可平移的画布,并支持拖拽、调整大小和嵌套的项目。这个库非常适合用于构建复杂的设计工具、图表编辑器或任何需要灵活交互的可视化应用。
目录
功能特点
- 可缩放和平移的画布: 用户可以自由缩放和移动整个画布视图。
- 绘制模式: 支持在画布上直接绘制新的矩形项目。
- 框选模式: 允许用户通过拖动鼠标选择多个项目。
- 项目操作:
- 拖拽: 可以自由移动画布上的项目。
- 调整大小: 支持通过拖动边缘或角落来调整项目尺寸。
- 嵌套: 项目可以作为容器,包含其他项目。
- 自动适应屏幕: 画布会自动调整以适应不同的屏幕尺寸。
- 复制、粘贴、剪切和删除: 支持基本的编辑操作(目前仅打印日志)。
- 自定义右键菜单: 可以为项目添加自定义的右键菜单选项(目前仅打印日志)。
- 高度可定制: 使用Tailwind CSS,可以轻松自定义组件样式。
安装
使用npm安装:
npm install d8d-design-transform d8d-design-canvas
基本使用示例
以下是一个基本的使用示例:
import React, { useRef, useState, useLayoutEffect } from 'react';
import { Canvas, type CanvasRef } from "d8d-design-canvas";
import { TransformLayer, ItemsContainer } from "d8d-design-transform";
import "d8d-design-canvas/dist/style.css";
import "d8d-design-transform/dist/style.css";
function App() {
const canvasRef = useRef<CanvasRef>(null);
const [drawMode, setDrawMode] = useState(false);
const [selectMode, setSelectMode] = useState(false);
const [scale, setScale] = useState(1);
const [items, setItems] = useState<Item[]>(initialItems);
const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
useLayoutEffect(() => {
if (canvasRef.current) {
setTimeout(() => {
canvasRef.current?.fitToScreen("transform-layer");
}, 1000);
}
}, []);
const handleDrawComplete = (rect: { x: number; y: number; width: number; height: number }) => {
const newItem: Item = {
id: Date.now().toString(),
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
containerId: null,
className: `bg-${getRandomColor()}-500`,
};
setItems((prevItems) => [...prevItems, newItem]);
setDrawMode(false);
};
const handleSelectComplete = (rect: { x: number; y: number; width: number; height: number }) => {
const selectedIds = items.filter(item =>
item.x < rect.x + rect.width &&
item.x + item.width > rect.x &&
item.y < rect.y + rect.height &&
item.y + item.height > rect.y
).map(item => item.id);
setSelectedItems(new Set(selectedIds));
};
return (
<div className="app-container">
<Canvas
ref={canvasRef}
controlledScale={scale}
onScaleChange={setScale}
drawMode={drawMode}
selectMode={selectMode}
onDrawComplete={handleDrawComplete}
onSelectComplete={handleSelectComplete}
>
<ItemsContainer items={items} />
<TransformLayer
items={items}
onItemsChange={setItems}
selectedItems={selectedItems}
onSelectedItemsChange={setSelectedItems}
/>
</Canvas>
</div>
);
}
export default App;
高级使用示例
以下是一个包含编辑功能和容器回调的高级使用示例:
import React, { useRef, useState, useLayoutEffect } from 'react';
import { Canvas, type CanvasRef } from "d8d-design-canvas";
import { TransformLayer, ItemsContainer, TransformLayerRef, TTransformItem, EditableDiv } from "d8d-design-transform";
import "d8d-design-canvas/dist/style.css";
import "d8d-design-transform/dist/style.css";
function App() {
const canvasRef = useRef<CanvasRef>(null);
const [drawMode, setDrawMode] = useState(false);
const [selectMode, setSelectMode] = useState(false);
const [scale, setScale] = useState(1);
const [items, setItems] = useState<Item[]>(initialItems);
const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
useLayoutEffect(() => {
if (canvasRef.current) {
setTimeout(() => {
canvasRef.current?.fitToScreen("transform-layer");
}, 1000);
}
}, []);
const handleDrawComplete = (rect: { x: number; y: number; width: number; height: number }) => {
const newItem: Item = {
id: Date.now().toString(),
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
containerId: null,
className: `bg-${getRandomColor()}-500`,
};
setItems((prevItems) => [...prevItems, newItem]);
setDrawMode(false);
};
const handleSelectComplete = (rect: { x: number; y: number; width: number; height: number }) => {
const selectedIds = items.filter(item =>
item.x < rect.x + rect.width &&
item.x + item.width > rect.x &&
item.y < rect.y + rect.height &&
item.y + item.height > rect.y
).map(item => item.id);
setSelectedItems(new Set(selectedIds));
};
const handleEnterContainer = (id: string, containerId: string) => {
console.log(`项目 ${id} 进入容器 ${containerId}`);
// 在这里执行进入容器时的逻辑
};
const handleLeaveContainer = (id: string) => {
console.log(`项目 ${id} 离开其容器`);
// 在这里执行离开容器时的逻辑
};
return (
<div className="app-container">
<Canvas
ref={canvasRef}
controlledScale={scale}
onScaleChange={setScale}
drawMode={drawMode}
selectMode={selectMode}
onDrawComplete={handleDrawComplete}
onSelectComplete={handleSelectComplete}
>
<ItemsContainer items={items} />
<TransformLayer
items={items}
onItemsChange={setItems}
selectedItems={selectedItems}
onSelectedItemsChange={setSelectedItems}
onEnterContainer={handleEnterContainer}
onLeaveContainer={handleLeaveContainer}
/>
</Canvas>
</div>
);
}
export default App;
主要组件
Canvas
Canvas
组件是整个画布的基础,提供了缩放、平移、绘制和选择的功能。
主要属性:
controlledScale
: 控制画布的缩放比例onScaleChange
: 缩放比例变化时的回调函数drawMode
: 是否启用绘制模式selectMode
: 是否启用框选模式onDrawComplete
: 绘制完成时的回调函数onSelectComplete
: 框选完成时的回调函数
TransformLayer
TransformLayer
组件处理项目的拖拽、调整大小等交互操作。
主要属性:
items
: 画布上的所有项目数组onItemsChange
: 项目发生变化时的回调函数selectedItems
: 当前选中的项目ID集合onSelectedItemsChange
: 选中项目发生变化时的回调函数onEnterContainer
: 项目进入容器时的回调函数onLeaveContainer
: 项目离开容器时的回调函数
ItemsContainer
ItemsContainer
组件负责渲染画布上的所有项目。
主要属性:
items
: 要渲染的项目数组
项目结构
项目的基本结构如下:
interface Item {
id: string;
x: number;
y: number;
width: number;
height: number;
containerId: string | null;
className: string;
}
高级用法
自定义项目样式: 通过修改
className
属性,可以为每个项目应用不同的Tailwind CSS类。嵌套项目: 通过设置
containerId
,可以创建项目的父子关系,实现嵌套效果。自定义操作: 可以通过扩展
TransformLayer
组件来添加自定义的项目操作,如旋转、翻转等。动态自定义属性: 使用回调函数为每个项目动态设置自定义类名和样式。
例如:
const getCustomProps = (item) => { if (item.id === 'item1') { return { className: 'my-custom-class-1', style: { backgroundColor: 'red' } }; } if (item.id === 'item2') { return { className: 'my-custom-class-2', style: { border: '2px solid blue' } }; } return {}; }; return ( <TransformLayer // ... 其他属性 ... getCustomProps={getCustomProps} /> );
这允许您根据项目的属性、状态或任何其他条件动态地为每个 TransformItem 指定自定义类名和样式。
自定义项目菜单: 使用
renderMenu
属性为每个项目添加自定义的顶部菜单。例如:
const renderMenu = (id) => ( <div> <button onClick={() => console.log(`编辑 ${id}`)}>编辑</button> <button onClick={() => console.log(`删除 ${id}`)}>删除</button> </div> ); return ( <TransformLayer // ... 其他属性 ... renderMenu={renderMenu} /> );
这将在每个项目的顶部显示一个包含"编辑"和"删除"按钮的菜单。您可以根据需要自定义菜单的内容和样式。如果不提供
renderMenu
属性,则不会显示菜单。容器回调: 使用
onEnterContainer
和onLeaveContainer
回调来监听项目进入或离开容器的事件。例如:
const handleEnterContainer = (id, containerId) => { console.log(`项目 ${id} 进入容器 ${containerId}`); // 执行进入容器时的逻辑 }; const handleLeaveContainer = (id) => { console.log(`项目 ${id} 离开其容器`); // 执行离开容器时的逻辑 }; return ( <TransformLayer // ... 其他属性 ... onEnterContainer={handleEnterContainer} onLeaveContainer={handleLeaveContainer} /> );
这允许您在项目进入或离开容器时执行自定义逻辑,例如更新状态、触发动画或发送网络请求等。
性能优化
对于大量项目的场景,考虑使用虚拟化技术来优化渲染性能。可以结合使用react-window
或react-virtualized
等库。
注意事项
- 确保正确导入了所有必要的样式文件。
- 推荐使用Tailwind CSS来自定义组件样式,以保持一致性和灵活性。
- 在处理大量项目时,注意性能优化,考虑使用虚拟化或分页加载技术。
- 使用
renderMenu
属性时,请确保返回的React节点不会过于复杂,以避免性能问题。
贡献
欢迎提交问题和拉取请求。对于重大更改,请先开issue讨论您想要更改的内容。
许可证
MIT
联系方式
如有任何问题或建议,请联系我们: [email protected]
访问我们的网站了解更多信息: https://d8d.fun