1.0.44 • Published 1 year ago

d8d-design-transform v1.0.44

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

D8D Design Transform

D8D Design Transform 是一个功能强大的React组件库,用于创建可缩放、可平移的画布,并支持拖拽、调整大小和嵌套的项目。这个库非常适合用于构建复杂的设计工具、图表编辑器或任何需要灵活交互的可视化应用。

目录

  1. 功能特点
  2. 安装
  3. 基本使用示例
  4. 高级使用示例
  5. 主要组件
  6. 项目结构
  7. 高级用法
  8. 性能优化
  9. 注意事项
  10. 贡献
  11. 许可证
  12. 联系方式

功能特点

  • 可缩放和平移的画布: 用户可以自由缩放和移动整个画布视图。
  • 绘制模式: 支持在画布上直接绘制新的矩形项目。
  • 框选模式: 允许用户通过拖动鼠标选择多个项目。
  • 项目操作:
    • 拖拽: 可以自由移动画布上的项目。
    • 调整大小: 支持通过拖动边缘或角落来调整项目尺寸。
    • 嵌套: 项目可以作为容器,包含其他项目。
  • 自动适应屏幕: 画布会自动调整以适应不同的屏幕尺寸。
  • 复制、粘贴、剪切和删除: 支持基本的编辑操作(目前仅打印日志)。
  • 自定义右键菜单: 可以为项目添加自定义的右键菜单选项(目前仅打印日志)。
  • 高度可定制: 使用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;
}

高级用法

  1. 自定义项目样式: 通过修改className属性,可以为每个项目应用不同的Tailwind CSS类。

  2. 嵌套项目: 通过设置containerId,可以创建项目的父子关系,实现嵌套效果。

  3. 自定义操作: 可以通过扩展TransformLayer组件来添加自定义的项目操作,如旋转、翻转等。

  4. 动态自定义属性: 使用回调函数为每个项目动态设置自定义类名和样式。

    例如:

    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 指定自定义类名和样式。

  5. 自定义项目菜单: 使用renderMenu属性为每个项目添加自定义的顶部菜单。

    例如:

    const renderMenu = (id) => (
      <div>
        <button onClick={() => console.log(`编辑 ${id}`)}>编辑</button>
        <button onClick={() => console.log(`删除 ${id}`)}>删除</button>
      </div>
    );
    
    return (
      <TransformLayer
        // ... 其他属性 ...
        renderMenu={renderMenu}
      />
    );

    这将在每个项目的顶部显示一个包含"编辑"和"删除"按钮的菜单。您可以根据需要自定义菜单的内容和样式。如果不提供renderMenu属性,则不会显示菜单。

  6. 容器回调: 使用 onEnterContaineronLeaveContainer 回调来监听项目进入或离开容器的事件。

    例如:

    const handleEnterContainer = (id, containerId) => {
      console.log(`项目 ${id} 进入容器 ${containerId}`);
      // 执行进入容器时的逻辑
    };
    
    const handleLeaveContainer = (id) => {
      console.log(`项目 ${id} 离开其容器`);
      // 执行离开容器时的逻辑
    };
    
    return (
      <TransformLayer
        // ... 其他属性 ...
        onEnterContainer={handleEnterContainer}
        onLeaveContainer={handleLeaveContainer}
      />
    );

    这允许您在项目进入或离开容器时执行自定义逻辑,例如更新状态、触发动画或发送网络请求等。

性能优化

对于大量项目的场景,考虑使用虚拟化技术来优化渲染性能。可以结合使用react-windowreact-virtualized等库。

注意事项

  • 确保正确导入了所有必要的样式文件。
  • 推荐使用Tailwind CSS来自定义组件样式,以保持一致性和灵活性。
  • 在处理大量项目时,注意性能优化,考虑使用虚拟化或分页加载技术。
  • 使用renderMenu属性时,请确保返回的React节点不会过于复杂,以避免性能问题。

贡献

欢迎提交问题和拉取请求。对于重大更改,请先开issue讨论您想要更改的内容。

许可证

MIT

联系方式

如有任何问题或建议,请联系我们: support@d8d.fun

访问我们的网站了解更多信息: https://d8d.fun

1.0.44

1 year ago

1.0.43

1 year ago

1.0.42

1 year ago

1.0.41

1 year ago

1.0.40

1 year ago

1.0.39

1 year ago

1.0.38

1 year ago

1.0.37

1 year ago

1.0.36

1 year ago

1.0.35

1 year ago

1.0.33

1 year ago

1.0.32

1 year ago

1.0.31

1 year ago

1.0.30

1 year ago

1.0.29

1 year ago

1.0.28

1 year ago

1.0.27

1 year ago

1.0.26

1 year ago

1.0.25

1 year ago

1.0.24

1 year ago

1.0.23

1 year ago

1.0.22

1 year ago

1.0.21

1 year ago

1.0.20

1 year ago

1.0.19

1 year ago

1.0.18

1 year ago

1.0.17

1 year ago

1.0.16

1 year ago

1.0.15

1 year ago

1.0.14

1 year ago

1.0.13

1 year ago

1.0.12

1 year ago

1.0.11

1 year ago

1.0.10

1 year ago

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago