d8d-design-transform v1.0.44
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
联系方式
如有任何问题或建议,请联系我们: support@d8d.fun
访问我们的网站了解更多信息: https://d8d.fun
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago