|
@@ -2,30 +2,20 @@ import { CompoundedComponent } from "@/types";
|
|
|
import { register } from "@antv/x6-react-shape";
|
|
|
import { Graph, Node } from "@antv/x6";
|
|
|
import { defaultData } from "../data";
|
|
|
-import CustomInput from "../CustomInput";
|
|
|
import { useSizeHook, useShapeProps } from "@/hooks";
|
|
|
-import { useEffect, useRef, useState } from "react";
|
|
|
-import Setting from "./setting";
|
|
|
-import { LaneItem, StageItem } from "@/types";
|
|
|
+import { useState } from "react";
|
|
|
+import Setting from "./Setting";
|
|
|
+import Pool from "./Pool";
|
|
|
+import { useLane } from "./hooks/useLane";
|
|
|
|
|
|
const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
const {
|
|
|
- poolName,
|
|
|
- text,
|
|
|
fill,
|
|
|
stroke,
|
|
|
opacity,
|
|
|
- lane,
|
|
|
- stage,
|
|
|
- direction,
|
|
|
- textDirection,
|
|
|
- headerHeight,
|
|
|
- stageWidth,
|
|
|
- laneHeadHeight,
|
|
|
} = node.getData();
|
|
|
const [showSetting, setShowSetting] = useState(false);
|
|
|
const { size, ref } = useSizeHook();
|
|
|
- const lister = useRef<any>();
|
|
|
const { fillContent, strokeColor, strokeWidth } = useShapeProps(
|
|
|
fill,
|
|
|
size,
|
|
@@ -41,371 +31,25 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
if (node.id === args.node.id) setShowSetting(false);
|
|
|
});
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- let width = node.getSize().width;
|
|
|
- let height = node.getSize().height;
|
|
|
+ const { handleChangeLane } = useLane(node, graph);
|
|
|
|
|
|
- if (lane.length) {
|
|
|
- height = lane.reduce(
|
|
|
- (a: number, b: LaneItem) => a + b.width + strokeWidth,
|
|
|
- 0
|
|
|
- );
|
|
|
- }
|
|
|
- if (stage.length) {
|
|
|
- height += stageWidth;
|
|
|
- }
|
|
|
-
|
|
|
- node.setSize({ width, height });
|
|
|
- }, [lane.length]);
|
|
|
-
|
|
|
- // 监听宽高变化
|
|
|
- if (!lister.current) {
|
|
|
- lister.current = node.on("change:size", (args) => {
|
|
|
- const lane = node.data.lane;
|
|
|
- const stage = node.data.stage;
|
|
|
- // 更新泳道宽度
|
|
|
- if (lane.length) {
|
|
|
- const originWidth = lane.reduce(
|
|
|
- (a: number, b: LaneItem) => a + b.width,
|
|
|
- 0
|
|
|
- );
|
|
|
- const offsetY =
|
|
|
- (args?.current?.height || 0) -
|
|
|
- originWidth -
|
|
|
- (stage.length ? stageWidth : 0);
|
|
|
-
|
|
|
- if (offsetY) {
|
|
|
- node.setData({
|
|
|
- lane: lane.map((item: LaneItem) => {
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- width: item.width + offsetY / lane.length - strokeWidth,
|
|
|
- };
|
|
|
- }),
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- // 更新阶段高度
|
|
|
- if (stage.length) {
|
|
|
- const originHeight = stage.reduce(
|
|
|
- (a: number, b: StageItem) => a + b.height,
|
|
|
- 0
|
|
|
- );
|
|
|
- const offsetX =
|
|
|
- (args?.current?.width || 0) -
|
|
|
- originHeight - headerHeight;
|
|
|
-
|
|
|
- if (offsetX) {
|
|
|
- node.setData({
|
|
|
- stage: stage.map((item: StageItem) => {
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- height: item.height + offsetX / stage.length - strokeWidth,
|
|
|
- };
|
|
|
- }),
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- const handleStartMove = () => {
|
|
|
- node.setData({
|
|
|
- ignoreDrag: false,
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- const handleEndMove = () => {
|
|
|
- node.setData({
|
|
|
- ignoreDrag: true,
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- // 插入阶段
|
|
|
- const handleInsertStage = (x: number, y: number) => {
|
|
|
- const stage = node.data.stage || [];
|
|
|
- const { width, height } = node.getSize();
|
|
|
- // 新阶段位置
|
|
|
- const w1 = x - node.getPosition().x - headerHeight;
|
|
|
- // 无阶段 从中切开
|
|
|
- if (!stage.length) {
|
|
|
- const w2 = width - w1 - headerHeight;
|
|
|
- node.setData({
|
|
|
- stage: [
|
|
|
- {
|
|
|
- name: "阶段",
|
|
|
- height: w1,
|
|
|
- },
|
|
|
- {
|
|
|
- name: "阶段",
|
|
|
- height: w2,
|
|
|
- },
|
|
|
- ],
|
|
|
- });
|
|
|
- node.setSize({
|
|
|
- width,
|
|
|
- height: height + stageWidth
|
|
|
- })
|
|
|
- } else {
|
|
|
- // 有阶段 则找出在哪一段内 再分成两段
|
|
|
- let temp = 0; // 记录长度
|
|
|
- for (let i = 0; i < stage.length; i++) {
|
|
|
- const item = stage[i];
|
|
|
- temp += item.height;
|
|
|
- if (temp > w1) {
|
|
|
- // 插入
|
|
|
- const w3 = temp - w1;
|
|
|
- const w4 = item.height - w3;
|
|
|
- const newStages = [
|
|
|
- {
|
|
|
- name: "阶段",
|
|
|
- height: w4,
|
|
|
- },
|
|
|
- {
|
|
|
- ...item,
|
|
|
- height: w3,
|
|
|
- },
|
|
|
- ];
|
|
|
- stage.splice(i, 1, ...newStages);
|
|
|
- node.setData(
|
|
|
- {
|
|
|
- stage: [...stage],
|
|
|
- },
|
|
|
- {
|
|
|
- deep: false,
|
|
|
- }
|
|
|
- );
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 插入泳道
|
|
|
- const handleInsertLane = (x: number, _y: number) => {
|
|
|
- console.log('插入泳道');
|
|
|
- const lane = node.data.lane || [];
|
|
|
- const stage = node.data.stage || [];
|
|
|
- if(!lane.length) {
|
|
|
- node.setData({
|
|
|
- lane: [{
|
|
|
- name: "",
|
|
|
- width: node.getSize().height - (stage.length ? stageWidth : 0)
|
|
|
- }]
|
|
|
- })
|
|
|
- } else {
|
|
|
- // 判断在哪一个泳道内
|
|
|
- let temp = 0;
|
|
|
- const w1 = x - node.getPosition().y;
|
|
|
- for (let i = 0; i < lane.length; i++) {
|
|
|
- const item = lane[i];
|
|
|
- temp += item.width;
|
|
|
- if (temp > w1) {
|
|
|
- // 插入
|
|
|
- lane.splice(i, 0, {
|
|
|
- name: "",
|
|
|
- width: lane[lane.length - 1].width
|
|
|
- })
|
|
|
- node.setData({
|
|
|
- lane: [...lane]
|
|
|
- });
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- const listerEmbedded = useRef<any>();
|
|
|
- if (!listerEmbedded.current) {
|
|
|
- listerEmbedded.current = graph.on("node:embedded", (args) => {
|
|
|
- const {isSeparator, isLane, separatorDiration, laneDirection } = args.node.data || {};
|
|
|
- // 分隔符
|
|
|
- if (isSeparator && separatorDiration !== direction) {
|
|
|
- const bbox = node.getBBox();
|
|
|
- if (bbox.isIntersectWithRect(args.node.getBBox())) {
|
|
|
- handleInsertStage(args.x, args.y);
|
|
|
- }
|
|
|
- }
|
|
|
- // 泳道
|
|
|
- if (isLane && laneDirection === direction) {
|
|
|
- const bbox = node.getBBox();
|
|
|
- if (bbox.isIntersectWithRect(args.node.getBBox())) {
|
|
|
- handleInsertLane(args.x, args.y);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- const handleChangeLane = (val: number | null) => {
|
|
|
- if (!val) {
|
|
|
- node.setData({ lane: [] }, { deep: false });
|
|
|
- return;
|
|
|
- }
|
|
|
- const currentLanes = node.data.lane || [];
|
|
|
- const currentLength = currentLanes.length;
|
|
|
-
|
|
|
- if (currentLength < val) {
|
|
|
- let width = node.getSize().width;
|
|
|
- if (currentLength > 0) {
|
|
|
- width = currentLanes[currentLength - 1].width;
|
|
|
- }
|
|
|
- const newLanes = new Array(val - currentLength).fill({ width, name: "" });
|
|
|
- node.setData({ lane: [...(node.data.lane || []), ...newLanes] });
|
|
|
- } else {
|
|
|
- node.updateData({
|
|
|
- lane: currentLanes.slice(0, val),
|
|
|
- });
|
|
|
- }
|
|
|
- };
|
|
|
return (
|
|
|
<>
|
|
|
{showSetting && <Setting node={node} onChangeLane={handleChangeLane} />}
|
|
|
<div
|
|
|
- className="relative text-0 w-full h-full flex"
|
|
|
+ className="relative text-0 w-full h-full"
|
|
|
style={{
|
|
|
opacity: opacity / 100,
|
|
|
border: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
}}
|
|
|
ref={ref}
|
|
|
>
|
|
|
- <div
|
|
|
- className="h-full relative cursor-move"
|
|
|
- style={{
|
|
|
- width: headerHeight,
|
|
|
- background: fillContent,
|
|
|
- borderRight: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
- }}
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
- >
|
|
|
- <CustomInput
|
|
|
- value={poolName}
|
|
|
- styles={text}
|
|
|
- node={node}
|
|
|
- onChange={(val) => node.setData({ poolName: val })}
|
|
|
- txtStyle={{
|
|
|
- transform: `rotate(-90deg) translateX(-${size.height}px)`,
|
|
|
- transformOrigin: '0 0',
|
|
|
- width: size.height,
|
|
|
- height: headerHeight,
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div
|
|
|
- className="relative content h-full"
|
|
|
- style={{ width: `calc(100% - ${headerHeight}px)` }}
|
|
|
- >
|
|
|
- {/* 阶段 */}
|
|
|
- {stage.length ? (
|
|
|
- <div
|
|
|
- className="stage h-full w-full absolute top-0 left-0 flex"
|
|
|
- >
|
|
|
- {stage.map((stageItem: StageItem, index: number) => {
|
|
|
- return (
|
|
|
- <div key={index}
|
|
|
- style={{
|
|
|
- width: stageItem.height - strokeWidth,
|
|
|
- height: '100%',
|
|
|
- borderRight:
|
|
|
- index < stage.length - 1
|
|
|
- ? `solid ${strokeWidth}px ${strokeColor}`
|
|
|
- : "node",
|
|
|
- }}
|
|
|
- >
|
|
|
- <div
|
|
|
- className="relative stage-item cursor-move"
|
|
|
- style={{
|
|
|
- width: stageItem.height - 2 * strokeWidth,
|
|
|
- background: fillContent,
|
|
|
- height: stageWidth,
|
|
|
- borderBottom: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
- }}
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
- >
|
|
|
- <CustomInput
|
|
|
- value={stageItem.name}
|
|
|
- styles={text}
|
|
|
- node={node}
|
|
|
- onChange={(val) => {
|
|
|
- node.setData({
|
|
|
- stage: stage.map((item: StageItem, i: number) => {
|
|
|
- if (index === i) {
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- name: val,
|
|
|
- };
|
|
|
- }
|
|
|
- }),
|
|
|
- });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- );
|
|
|
- })}
|
|
|
- </div>
|
|
|
- ) : (
|
|
|
- ""
|
|
|
- )}
|
|
|
- {/* 泳道 */}
|
|
|
- <div className="lane absolute left-0" style={{
|
|
|
- top: stage.length ? stageWidth : 0,
|
|
|
- width: `100%`,
|
|
|
- height: `calc(100% - ${stage.length ? stageWidth : 0}px)`
|
|
|
- }}>
|
|
|
- {lane.map((item: LaneItem, index: number) => (
|
|
|
- <div
|
|
|
- key={index}
|
|
|
- style={{
|
|
|
- width: '100%',
|
|
|
- height: item.width,
|
|
|
- borderBottom:
|
|
|
- index === lane.length - 1
|
|
|
- ? "none"
|
|
|
- : `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
- }}
|
|
|
- >
|
|
|
- <div
|
|
|
- className="flex-1 w-full relative cursor-move"
|
|
|
- style={{
|
|
|
- width: laneHeadHeight,
|
|
|
- height: '100%',
|
|
|
- background: fillContent,
|
|
|
- borderRight: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
- }}
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
- >
|
|
|
- <CustomInput
|
|
|
- value={item.name}
|
|
|
- styles={text}
|
|
|
- node={node}
|
|
|
- txtStyle={{
|
|
|
- transform: `rotate(-90deg) translateX(-${item.width}px)`,
|
|
|
- transformOrigin: '0 0',
|
|
|
- width: item.width - strokeWidth,
|
|
|
- height: laneHeadHeight,
|
|
|
- }}
|
|
|
- onChange={(val) => {
|
|
|
- node.setData({
|
|
|
- lane: lane.map((item: LaneItem, i: number) => {
|
|
|
- if (index === i) {
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- name: val,
|
|
|
- };
|
|
|
- }
|
|
|
- return item;
|
|
|
- }),
|
|
|
- });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <Pool
|
|
|
+ node={node}
|
|
|
+ fillContent={fillContent}
|
|
|
+ strokeWidth={strokeWidth}
|
|
|
+ strokeColor={strokeColor}
|
|
|
+ />
|
|
|
</div>
|
|
|
</>
|
|
|
);
|