import CustomColorPicker from "@/components/CustomColorPicker"; import { BoldOutlined, ColumnHeightOutlined, FontSizeOutlined, ItalicOutlined, PictureOutlined, StrikethroughOutlined, SwapOutlined, UnderlineOutlined, VerticalAlignBottomOutlined, VerticalAlignMiddleOutlined, VerticalAlignTopOutlined, } from "@ant-design/icons"; import { Button, Col, Divider, Form, Input, InputNumber, Row, Select, Tooltip, } from "antd"; import { arrowOptions } from "@/pages/flow/data"; import { useModel } from "umi"; import { useEffect, useRef, useState } from "react"; import { ImageFillType, ConnectorType, LineType } from "@/enum"; import { set, cloneDeep } from "lodash-es"; import { Cell } from "@antv/x6"; import { fontFamilyOptions, alignOptionData } from '@/pages/flow/data'; import { alignCell, matchSize } from '@/utils'; type FormModel = { opacity: number; width: number; height: number; x: number; y: number; rotation: number; text: { fontFamily: string; color: string; fontSize: number; lineHeight: number; textAlign: "left" | "center" | "right"; textVAlign: "top" | "middle" | "bottom"; bold: boolean; italic: boolean; textDecoration: "underline" | "line-through" | "none"; }; connectorType: ConnectorType; startArrow: string; endArrow: string; fill: { fillType: "color" | "gradient" | "image"; color1: string; color2: string; gradientType: "linear" | "radial"; gradientValue: number; objectFit: ImageFillType; imageUrl: string; }; stroke: { type: "solid" | "dashed" | "dotted" | "dashdot"; color: string; width: number; }; }; export default function GraphStyle() { const { selectedCell } = useModel("graphModel"); const [isMulit, setIsMulit] = useState(false); const [hasEdge, setHasEdge] = useState(false); const eventNodeList = useRef([]); const [formModel, setFormModel] = useState({ opacity: 100, width: 20, height: 20, x: 0, y: 0, rotation: 0, text: { fontFamily: "normal", color: "#000000", fontSize: 14, lineHeight: 1.25, textAlign: "center", textVAlign: "middle", bold: false, italic: false, textDecoration: "none", }, fill: { fillType: "color", color1: "#FFFFFF", color2: "#eeeeee", gradientType: "linear", gradientValue: 0, objectFit: ImageFillType.Fill, imageUrl: "", }, stroke: { type: "solid", color: "#323232", width: 1, }, connectorType: ConnectorType.Normal, startArrow: "", endArrow: "", }); useEffect(() => { const firstNode = selectedCell?.find((item) => item.isNode()); const firstEdge = selectedCell?.find((item) => item.isEdge()); eventNodeList.current = []; if (firstNode) { const position = firstNode.position(); const size = firstNode.size(); const data = firstNode.getData(); setFormModel({ ...formModel, x: position.x, y: position.y, width: size.width, height: size.height, rotation: firstNode.angle(), text: data.text, fill: data.fill, stroke: data.stroke, connectorType: ConnectorType.Normal, startArrow: "", endArrow: "", }); // 监听当前选中节点的属性变化 if (!eventNodeList.current.find((item) => item.id === firstNode.id)) { eventNodeList.current.push(firstNode); firstNode.on("change:*", (args) => { if (args.key === "position") { setFormModel((state) => { return { ...state, x: parseInt(args.current.x), y: parseInt(args.current.y), }; }); } if (args.key === "size") { setFormModel((state) => { return { ...state, width: args.current.width, height: args.current.height, }; }); } if (args.key === "data") { setFormModel((state) => { return { ...state, text: args.current.text, fill: args.current.fill, stroke: args.current.stroke, }; }); } }); } } if(firstEdge) { const data = firstEdge.getData(); const attrs = firstEdge.attrs || {}; const sourceMarker = attrs.line?.sourceMarker as Record; const targetMarker = attrs.line?.targetMarker as Record; const lineType = attrs.line?.strokeDasharray === LineType.solid ? "solid" : attrs.line?.strokeDasharray === LineType.dashed ? "dashed" : attrs.line?.strokeDasharray === LineType.dotted ? "dotted" : "dashdot"; let obj = {}; if(!firstNode) { obj = { stroke: { type: lineType, color: attrs.line?.stroke || "#000000", width: attrs.line?.strokeWidth || 1, } } } setFormModel((state) => { return { ...state, ...obj, startArrow: sourceMarker?.name, endArrow: targetMarker?.name, } }) } let nodeCount = 0; selectedCell?.forEach((cell) => { if (cell.isEdge()) { // 存在边线 setHasEdge(true); } if (cell.isNode()) nodeCount++; }); // 多个节点 setIsMulit(nodeCount > 1); }, [selectedCell]); // 表单值改变,修改元素属性 const handleChange = (model: FormModel) => { selectedCell?.forEach((cell) => { if (cell.isNode()) { cell.setPosition(model.x, model.y); cell.setSize(model.width, model.height); cell.rotate(model.rotation, { absolute: true }); cell.setData({ text: model.text, fill: model.fill, stroke: model.stroke, opacity: model.opacity, }); } if (cell.isEdge()) { const attr = cell.attrs; const sourceMarker = attr?.line?.sourceMarker as Record; const targetMarker = attr?.line?.targetMarker as Record; cell.setAttrs({ line: { ...(attr?.line || {}), stroke: model.stroke.color, strokeWidth: model.stroke.width, strokeDasharray: LineType[model.stroke.type], targetMarker: { ...(targetMarker || {}), name: model.endArrow, args: { size: model.stroke.width + 8, } }, sourceMarker: { ...(sourceMarker || {}), name: model.startArrow, args: { size: model.stroke.width + 8, } } } }) } }); }; // 设置对齐方式 const handleAlign = (type: string) => { selectedCell && alignCell(type, selectedCell); }; // 匹配宽高 const handleMatchSize = (type: "width" | "height" | "auto") => { selectedCell && matchSize(type, selectedCell); }; // 调换渐变色颜色 const handleSwapColor = () => { const { color1, color2 } = formModel.fill; handleSetFormModel("fill", { ...formModel.fill, color1: color2, color2: color1, }); }; // 设置表单数据 const handleSetFormModel = (key: string, value: any) => { const obj = cloneDeep(formModel); set(obj, key, value); setFormModel(obj); handleChange(obj); }; return (
{alignOptionData.map((item) => (
`${val}%`} disabled={!selectedCell?.length} value={formModel.opacity} onChange={(val) => handleSetFormModel("opacity", val)} />
布局
`${val}px`} disabled={!selectedCell?.length} value={formModel.width} onChange={(val) => handleSetFormModel("width", val)} /> `${val}px`} disabled={!selectedCell?.length} value={formModel.height} onChange={(val) => handleSetFormModel("height", val)} /> `${val}px`} disabled={!selectedCell?.length} value={formModel.x} onChange={(val) => handleSetFormModel("x", val)} /> `${val}px`} disabled={!selectedCell?.length} value={formModel.y} onChange={(val) => handleSetFormModel("y", val)} />
`${val}°`} suffix={} disabled={!selectedCell?.length} value={formModel.rotation} onChange={(val) => handleSetFormModel("rotation", val)} />
文本
} options={[ { label: "1.0", value: 1 }, { label: "1.25", value: 1.25 }, { label: "1.5", value: 1.5 }, { label: "2.0", value: 2 }, { label: "2.5", value: 2.5 }, { label: "3.0", value: 3 }, ]} disabled={!selectedCell?.length} value={formModel.text.lineHeight} onChange={(val) => handleSetFormModel("text.lineHeight", val)} />
填充
} value={formModel.fill.imageUrl} onChange={(e) => handleSetFormModel("fill.imageUrl", e.target.value) } /> { handleSetFormModel("fill.gradientType", value); }} /> {formModel.fill.fillType === "gradient" && ( <> {formModel.fill.gradientType === "linear" && ( `${val}°`} suffix={ } disabled={!selectedCell?.length} value={formModel.fill.gradientValue} onChange={(val) => handleSetFormModel("fill.gradientValue", val) } /> )} {formModel.fill.gradientType === "radial" && ( `${val}%`} suffix={ } disabled={!selectedCell?.length} value={formModel.fill.gradientValue} onChange={(val) => handleSetFormModel("fill.gradientValue", val) } /> )} )}
)}
线条
{ return { value: item.name, label: , }; })} disabled={!hasEdge} value={formModel.startArrow} onChange={(value) => handleSetFormModel("startArrow", value)} />