搜索插件、代码仓与 APP 分类

diagram_editor 封面
插件详情v1.0.0

diagram_editor

一个用于构建交互式图表编辑器的 Flutter 库,支持类型安全的组件、链接、平移/缩放以及序列化。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
1110
喜欢数
184
Pub 分数
160

安装插件

flutter pub add diagram_editor

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

一个专为创建交互式图表编辑器而设计的Flutter库,支持类型安全的组件、动态链接、平移和缩放功能以及无缝序列化。它使开发者能够使用一致且可重用的UI元素构建丰富的可视化工具,用于流程图、线框图及其他类型的图表。该库跨平台,支持Android、iOS、Web、macOS、Windows和Linux,非常适合需要实时图表操作和数据持久化的应用。专注于开发人员体验,它提供了直观的API来管理图表状态和交互。

适合场景

  • 创建流程图构建器
  • 设计线框图工具
  • 构建可视化编程界面
  • 开发协作式绘图应用
  • 实现网络拓扑可视化工具

主要特点

  • 类型安全的组件系统
  • 交互式链接管理
  • 内置的平移和缩放控件
  • 数据持久化的序列化
  • 跨平台兼容性
  • 可扩展的插件架构

适合对象

  • UI/UX 开发人员构建视觉工具
  • 教育类应用开发者
  • 设计工作流系统的软件架构师
  • 需要跨平台绘图解决方案的团队
  • 快速原型化交互式图表

使用建议

  • 需要理解 Flutter 的 widget 树
  • 可能需要自定义样式以处理复杂图表
  • 大型图表带来的性能影响
  • 有限的内置形状库(可扩展)
  • 高级功能的初始学习曲线

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

diagram_editor

pub package

Flutter library for building interactive diagram editors. Create, connect, and manipulate nodes and links with pan, zoom, and full gesture support.

Quick Start

import 'package:diagram_editor/diagram_editor.dart';
import 'package:flutter/material.dart';

class MyDiagram extends StatelessWidget {
  MyDiagram({super.key});

  final controller = DiagramController<void, void>();

  @override
  Widget build(BuildContext context) {
    return DiagramEditor<void, void>(
      controller: controller,
      componentBuilder: (context, component) => Container(
        color: Colors.blue,
        child: Center(child: Text(component.id)),
      ),
      onCanvasTapUp: (details) {
        controller.addComponent(ComponentData(
          size: const Size(96, 72),
          position: controller.fromCanvasCoordinates(details.localPosition),
        ));
      },
      onComponentTap: (id) => controller.removeComponent(id),
    );
  }
}

Pan, zoom, link joints, and link control all work out of the box.

Type-Safe Custom Data

Use generic type parameters to attach typed data to components and links:

class MyNodeData {
  final Color color;
  final String label;
  MyNodeData({required this.color, required this.label});
}

final controller = DiagramController<MyNodeData, void>(
  componentDataCodec: JsonCodec(
    encode: (d) => {'color': d.color.toHex(), 'label': d.label},
    decode: (j) => MyNodeData(
      color: Color(int.parse(j['color'] as String, radix: 16)),
      label: j['label'] as String,
    ),
  ),
);

// No more casting — data is typed
controller.addComponent(ComponentData(
  data: MyNodeData(color: Colors.blue, label: 'Start'),
  size: const Size(96, 72),
));

// Access data without casting
final node = controller.getComponent('id');
final color = node.data?.color; // Color, not dynamic

Connecting Components

final linkId = controller.connect(
  sourceComponentId: 'node-1',
  targetComponentId: 'node-2',
  linkStyle: LinkStyle(
    arrowType: ArrowType.arrow,
    lineWidth: 2,
    color: Colors.grey,
  ),
);

Configuration

DiagramEditor<MyNodeData, void>(
  controller: controller,
  componentBuilder: (context, data) => MyNodeWidget(data),

  // Canvas config
  canvasConfig: const CanvasConfig(
    backgroundColor: Color(0xFFF5F5F5),
    minScale: 0.2,
    maxScale: 5.0,
  ),

  // Link endpoint alignment strategy
  linkEndpointAlignment: LinkAttachment.oval(),

  // Disable defaults if you want full control
  enableDefaultPanZoom: true,       // default
  enableDefaultLinkControl: true,   // default
  enableDefaultJointControl: true,  // default

  // Links rendered on top of components
  linksOnTop: true,                 // default

  // All gesture callbacks
  onCanvasTapUp: (details) { /* ... */ },
  onComponentTap: (id) { /* ... */ },
  onComponentScaleUpdate: (id, details) { /* ... */ },
  onLinkTap: (id) { /* ... */ },

  // Custom layers
  backgroundBuilder: (context) => [CustomPaint(painter: GridPainter())],
  foregroundBuilder: (context) => [/* selection UI, toolbars, etc. */],
  componentOverlayBuilder: (context, data) => /* resize handles, etc. */,
);

Serialization

// Save
final json = controller.serialize();

// Load
controller.deserialize(json);

Custom data is serialized via the JsonCodec passed to the controller.

API Overview

DiagramController

The central class managing all diagram state.

Category Methods
Components addComponent, removeComponent, moveComponent, getComponent, componentExists, components, componentsSorted
Links connect, removeLink, getLink, linkExists, links
Z-order bringToFront, sendToBack, setComponentZOrder
Parent-child setComponentParent, removeComponentParent
Canvas setCanvasPosition, panCanvas, zoomCanvas, resetCanvasView, fromCanvasCoordinates, toCanvasCoordinates
Joints insertLinkJoint, removeLinkJoint, showLinkJoints, hideLinkJoints
Serialization serialize, deserialize
Link Endpoint Alignment
Strategy Method
Rectangular LinkAttachment.rectangular() (default)
Oval LinkAttachment.oval()
Crystal/Diamond LinkAttachment.crystal()
Center LinkAttachment.center()
Link Styles
  • Arrow types: none, arrow, pointedArrow, circle, centerCircle, semiCircle
  • Line types: solid, dashed, dotted
Built-in Painters
  • GridPainter — canvas grid background
  • ComponentHighlightPainter — selection highlight
  • DeleteIconPainter — delete icon overlay

Migration from v0.x

See the full Migration Prompt for a detailed mapping of every old API surface to its new equivalent, including complete before/after examples.

Key changes:

  • PolicySet with mixins -> DiagramEditor with callbacks
  • canvasWriter.model.addComponent(...) -> controller.addComponent(...)
  • componentData.data as MyType -> componentData.data (typed generics)
  • provider dependency removed (uses built-in ListenableBuilder)

所属分类

依赖

依赖清单 1 项

源码仓库

使用此插件的项目

暂无相关数据。