Files
yys-editor/docs/2design/StyleAndAppearance.md

5.2 KiB
Raw Blame History

样式与节点结构说明v1

背景

  • 目标:统一节点的样式字段与渲染消费路径,避免各节点分散管理填充/描边/阴影/文字等样式。
  • 数据载体:沿用 LogicFlow 的 GraphData,仅约定 node.properties 内的业务字段与样式字段。

样式模型:properties.style

位于每个节点 properties.style,是尺寸与外观的单一事实来源;渲染时会同步 style.width/height 到节点的 width/height

interface NodeStyle {
  // 尺寸与变换
  width: number;        // px必填
  height: number;       // px必填
  rotate?: number;      // deg逆时针围绕节点中心

  // 形状
  fill?: string;        // 背景填充色
  stroke?: string;      // 描边色
  strokeWidth?: number; // ≥0px
  radius?: number | [number, number, number, number]; // 圆角rect 生效)
  opacity?: number;     // 0..1

  // 阴影
  shadow?: { color?: string; blur?: number; offsetX?: number; offsetY?: number };

  // 文本样式text 节点或带文本的节点)
  textStyle?: {
    color?: string;
    fontFamily?: string;
    fontSize?: number;          // px
    fontWeight?: number | string;
    lineHeight?: number;        // 推荐 1..3
    align?: 'left' | 'center' | 'right';
    verticalAlign?: 'top' | 'middle' | 'bottom';
    letterSpacing?: number;     // px
    padding?: [number, number, number, number];
    background?: string;
  };
}

默认值参考 src/ts/schema.ts:DefaultNodeStyle

  • width=180, height=120, rotate=0
  • fill='#ffffff', stroke='#dcdfe6', strokeWidth=1, radius=4, opacity=1
  • shadow={ color:'rgba(0,0,0,0.1)', blur:4, offsetX:0, offsetY:2 }
  • textStyle={ color:'#303133', fontFamily:'system-ui', fontSize:14, fontWeight:400, lineHeight:1.4, align:'left', verticalAlign:'top', letterSpacing:0, padding:[8,8,8,8] }

归一化与工具(src/ts/nodeStyle.ts

  • normalizeNodeStyle(style, sizeFallback)补全缺省数值钳制opacity ∈[0,1]),将散落的 width/height 收敛到 style。
  • normalizePropertiesWithStyle(props):返回带规范化 style 的 props并镜像 width/height
  • toContainerStyle / toTextStyle:将 NodeStyle 转为 Vue 行内样式(背景、描边、圆角、阴影、透明度 / 文字)。
  • styleEquals:归一化后比较,避免重复 setProperties。

节点元信息:properties.meta

interface NodeMeta {
  z?: number;         // 层级
  locked?: boolean;   // 锁定
  visible?: boolean;  // 可见
  groupId?: string;   // 分组
  name?: string;
  createdAt?: number;
  updatedAt?: number;
}

FlowEditor 在渲染/normalize 时会补齐 meta.visible=truemeta.locked=false 并应用到节点模型(可见性、可拖拽等)。

监听与渲染路径

  1. 归一化入口FlowEditor.normalizeNodeModel 在节点创建/属性变更/渲染后执行:
    • 归一化 properties.stylemeta,必要时回写 lf.setProperties
    • 同步 style.width/height 到节点模型,保证渲染尺寸一致。
  2. 事件监听:节点组件通过 composable 监听 NODE_PROPERTIES_CHANGE,实时更新样式与自定义数据。

复用方案:useNodeAppearancesrc/ts/useNodeAppearance.ts

作用:在节点组件中统一获取样式和属性变更。

const { containerStyle, textStyle } = useNodeAppearance({
  onPropsChange(props, node) {
    // 可在这里同步业务字段,例如 image url、shikigami 数据等
  }
});

内部行为:

  • 注入 getNode/getGraph,挂载时读取当前节点 props。
  • 监听 NODE_PROPERTIES_CHANGE,调用 normalizeNodeStyle,输出 containerStyle/textStyle
  • 自动解绑监听,减少重复代码。

已接入的节点组件:

  • 图片节点 src/components/flow/nodes/common/ImageNode.vue
  • 式神节点 .../yys/ShikigamiSelectNode.vue
  • 御魂节点 .../yys/YuhunSelectNode.vue
  • 属性节点 .../yys/PropertySelectNode.vue

编辑入口PropertyPanel

  • 样式面板 src/components/flow/panels/StylePanel.vue 写入 properties.style
    • 填充色、描边色/线宽、圆角、阴影(色/模糊/偏移)、透明度
    • 文本对齐、行高、字重
  • 图片面板 ImagePanel.vue 写入宽高/fit/url并保持与 style.width/height 同步。
  • 其他面板(式神/御魂/属性)仅写业务字段,样式统一由 useNodeAppearance 消费。

持久化与 schema

  • 顶层导出结构:RootDocument(见 docs/2design/DataModel.md),包含 schemaVersion
  • 保存/导入路径:useFilesStore 写出/读入 schemaVersion;缺省数据走 migrateToV1 将散落的宽高/可见/锁定补齐到 properties.style/meta

校验建议

  • width/height > 0strokeWidth ≥ 0radius ≥ 0 或四元组合法opacity ∈ [0,1]。
  • 文本fontSize > 0lineHeight 合理1~3padding 四元组 ≥ 0。
  • 圆角仅对 rect 类节点生效;其他 kind 忽略 radius。

后续扩展建议

  • 文本节点接入富文本:在 textStyle 扩展行高倍数、字间距、背景/描边。
  • 叠加高级效果blendMode/filter保持向后兼容新增字段时通过 schemaVersion 控制迁移。
  • 矢量节点:在 vector 节点中消费同一套 style,并在编辑面板复用 StylePanel