|
@@ -2,35 +2,29 @@ import { CompoundedComponent } from "@/types";
|
|
import { register } from "@antv/x6-react-shape";
|
|
import { register } from "@antv/x6-react-shape";
|
|
import { Graph, Node } from "@antv/x6";
|
|
import { Graph, Node } from "@antv/x6";
|
|
import { defaultData } from "../data";
|
|
import { defaultData } from "../data";
|
|
-import CustomInput from "../CustomInput";
|
|
|
|
import { useSizeHook, useShapeProps } from "@/hooks";
|
|
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 component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
const {
|
|
const {
|
|
- poolName,
|
|
|
|
- text,
|
|
|
|
fill,
|
|
fill,
|
|
stroke,
|
|
stroke,
|
|
opacity,
|
|
opacity,
|
|
- lane,
|
|
|
|
- stage,
|
|
|
|
- direction,
|
|
|
|
- textDirection,
|
|
|
|
- headerHeight,
|
|
|
|
- stageWidth,
|
|
|
|
} = node.getData();
|
|
} = node.getData();
|
|
|
|
+
|
|
const [showSetting, setShowSetting] = useState(false);
|
|
const [showSetting, setShowSetting] = useState(false);
|
|
const { size, ref } = useSizeHook();
|
|
const { size, ref } = useSizeHook();
|
|
- const lister = useRef<any>();
|
|
|
|
const { fillContent, strokeColor, strokeWidth } = useShapeProps(
|
|
const { fillContent, strokeColor, strokeWidth } = useShapeProps(
|
|
fill,
|
|
fill,
|
|
size,
|
|
size,
|
|
stroke
|
|
stroke
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+ const { handleChangeLane } = useLane(node, graph);
|
|
|
|
+
|
|
graph.on("node:selected", (args) => {
|
|
graph.on("node:selected", (args) => {
|
|
setShowSetting(
|
|
setShowSetting(
|
|
graph.getSelectedCells().length === 1 && node.id === args.node.id
|
|
graph.getSelectedCells().length === 1 && node.id === args.node.id
|
|
@@ -40,224 +34,9 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
if (node.id === args.node.id) setShowSetting(false);
|
|
if (node.id === args.node.id) setShowSetting(false);
|
|
});
|
|
});
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
- let width = node.getSize().width;
|
|
|
|
- let height = node.getSize().height;
|
|
|
|
-
|
|
|
|
- if (lane.length) {
|
|
|
|
- width = lane.reduce(
|
|
|
|
- (a: number, b: LaneItem) => a + b.width + strokeWidth,
|
|
|
|
- 0
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- if (stage.length) {
|
|
|
|
- width += 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 offsetX =
|
|
|
|
- (args?.current?.width || 0) -
|
|
|
|
- originWidth -
|
|
|
|
- (stage.length ? stageWidth : 0);
|
|
|
|
-
|
|
|
|
- if (offsetX) {
|
|
|
|
- node.setData({
|
|
|
|
- lane: lane.map((item: LaneItem) => {
|
|
|
|
- return {
|
|
|
|
- ...item,
|
|
|
|
- width: item.width + offsetX / lane.length - strokeWidth,
|
|
|
|
- };
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // 更新阶段高度
|
|
|
|
- if (stage.length) {
|
|
|
|
- const originHeight = stage.reduce(
|
|
|
|
- (a: number, b: StageItem) => a + b.height,
|
|
|
|
- 0
|
|
|
|
- );
|
|
|
|
- const offsetY =
|
|
|
|
- (args?.current?.height || 0) -
|
|
|
|
- originHeight - headerHeight;
|
|
|
|
-
|
|
|
|
- if (offsetY) {
|
|
|
|
- node.setData({
|
|
|
|
- stage: stage.map((item: StageItem) => {
|
|
|
|
- return {
|
|
|
|
- ...item,
|
|
|
|
- height: item.height + offsetY / 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 h1 = y - node.getPosition().y - headerHeight;
|
|
|
|
- // 无阶段 从中切开
|
|
|
|
- if (!stage.length) {
|
|
|
|
- const h2 = height - h1 - headerHeight;
|
|
|
|
- node.setData({
|
|
|
|
- stage: [
|
|
|
|
- {
|
|
|
|
- name: "阶段",
|
|
|
|
- height: h1,
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- name: "阶段",
|
|
|
|
- height: h2,
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- });
|
|
|
|
- node.setSize({
|
|
|
|
- width: width + stageWidth,
|
|
|
|
- height
|
|
|
|
- })
|
|
|
|
- } else {
|
|
|
|
- // 有阶段 则找出在哪一段内 再分成两段
|
|
|
|
- let temp = 0; // 记录长度
|
|
|
|
- for (let i = 0; i < stage.length; i++) {
|
|
|
|
- const item = stage[i];
|
|
|
|
- temp += item.height;
|
|
|
|
- if (temp > h1) {
|
|
|
|
- // 插入
|
|
|
|
- const h3 = temp - h1;
|
|
|
|
- const h4 = item.height - h3;
|
|
|
|
- const newStages = [
|
|
|
|
- {
|
|
|
|
- name: "阶段",
|
|
|
|
- height: h4,
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- ...item,
|
|
|
|
- height: h3,
|
|
|
|
- },
|
|
|
|
- ];
|
|
|
|
- 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().width - (stage.length ? stageWidth : 0)
|
|
|
|
- }]
|
|
|
|
- })
|
|
|
|
- } else {
|
|
|
|
- // 判断在哪一个泳道内
|
|
|
|
- let temp = 0;
|
|
|
|
- const w1 = x - node.getPosition().x;
|
|
|
|
- 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 (
|
|
return (
|
|
<>
|
|
<>
|
|
|
|
+ {showSetting && <Setting node={node} onChangeLane={handleChangeLane} />}
|
|
<div
|
|
<div
|
|
className="relative text-0 w-full h-full"
|
|
className="relative text-0 w-full h-full"
|
|
style={{
|
|
style={{
|
|
@@ -266,132 +45,12 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
}}
|
|
}}
|
|
ref={ref}
|
|
ref={ref}
|
|
>
|
|
>
|
|
- {showSetting && <Setting node={node} onChangeLane={handleChangeLane} />}
|
|
|
|
- <div
|
|
|
|
- className="w-full relative cursor-move"
|
|
|
|
- style={{
|
|
|
|
- height: headerHeight,
|
|
|
|
- background: fillContent,
|
|
|
|
- borderBottom: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
|
- }}
|
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
|
- >
|
|
|
|
- <CustomInput
|
|
|
|
- value={poolName}
|
|
|
|
- styles={text}
|
|
|
|
- node={node}
|
|
|
|
- onChange={(val) => node.setData({ poolName: val })}
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
- <div
|
|
|
|
- className="relative content"
|
|
|
|
- style={{ height: `calc(100% - ${headerHeight}px)` }}
|
|
|
|
- >
|
|
|
|
- {/* 阶段 */}
|
|
|
|
- {stage.length ? (
|
|
|
|
- <div
|
|
|
|
- className="stage h-full w-full absolute left-0 top-0"
|
|
|
|
- >
|
|
|
|
- {stage.map((stageItem: StageItem, index: number) => {
|
|
|
|
- return (
|
|
|
|
- <div key={index}
|
|
|
|
- style={{
|
|
|
|
- width: '100%',
|
|
|
|
- height: stageItem.height - strokeWidth,
|
|
|
|
- borderBottom:
|
|
|
|
- index < stage.length - 1
|
|
|
|
- ? `solid ${strokeWidth}px ${strokeColor}`
|
|
|
|
- : "node",
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- className="relative stage-item cursor-move"
|
|
|
|
- style={{
|
|
|
|
- width: stageWidth,
|
|
|
|
- background: fillContent,
|
|
|
|
- height: stageItem.height - 2 * strokeWidth,
|
|
|
|
- borderRight: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
|
- }}
|
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
|
- >
|
|
|
|
- <CustomInput
|
|
|
|
- value={stageItem.name}
|
|
|
|
- styles={text}
|
|
|
|
- node={node}
|
|
|
|
- txtStyle={{
|
|
|
|
- transform: `rotate(-90deg) translateX(-${stageItem.height}px)`,
|
|
|
|
- transformOrigin: "0 0",
|
|
|
|
- height: stageWidth,
|
|
|
|
- width: stageItem.height,
|
|
|
|
- }}
|
|
|
|
- onChange={(val) => {
|
|
|
|
- node.setData({
|
|
|
|
- stage: stage.map((item: StageItem, i: number) => {
|
|
|
|
- if (index === i) {
|
|
|
|
- return {
|
|
|
|
- ...item,
|
|
|
|
- name: val,
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- }}
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </div>
|
|
|
|
- ) : (
|
|
|
|
- ""
|
|
|
|
- )}
|
|
|
|
- {/* 泳道 */}
|
|
|
|
- <div className="lane flex h-full absolute top-0" style={{ left: stage.length ? stageWidth : 0 }}>
|
|
|
|
- {lane.map((item: any, index: number) => (
|
|
|
|
- <div
|
|
|
|
- key={index}
|
|
|
|
- style={{
|
|
|
|
- width: item.width,
|
|
|
|
- borderRight:
|
|
|
|
- index === lane.length - 1
|
|
|
|
- ? "none"
|
|
|
|
- : `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- className="flex-1 w-full h-40px relative cursor-move"
|
|
|
|
- style={{
|
|
|
|
- background: fillContent,
|
|
|
|
- borderBottom: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
|
- }}
|
|
|
|
- onMouseEnter={handleStartMove}
|
|
|
|
- onMouseLeave={handleEndMove}
|
|
|
|
- >
|
|
|
|
- <CustomInput
|
|
|
|
- value={item.name}
|
|
|
|
- styles={text}
|
|
|
|
- node={node}
|
|
|
|
- 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>
|
|
</div>
|
|
</>
|
|
</>
|
|
);
|
|
);
|
|
@@ -418,8 +77,10 @@ const verticalPool: CompoundedComponent = {
|
|
lane: [],
|
|
lane: [],
|
|
// 阶段
|
|
// 阶段
|
|
stage: [],
|
|
stage: [],
|
|
- // 泳道名称高度
|
|
|
|
|
|
+ // 泳池名称高度
|
|
headerHeight: 40,
|
|
headerHeight: 40,
|
|
|
|
+ // 泳道名称高度
|
|
|
|
+ laneHeadHeight: 40,
|
|
// 阶段宽度
|
|
// 阶段宽度
|
|
stageWidth: 20,
|
|
stageWidth: 20,
|
|
// 泳池方向
|
|
// 泳池方向
|