@pisell/materials 1.8.54 → 1.8.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/meta.js +3 -3
- package/build/lowcode/render/default/view.css +1 -1
- package/build/lowcode/render/default/view.js +35 -35
- package/build/lowcode/view.css +1 -1
- package/build/lowcode/view.js +35 -35
- package/es/components/buttonGroupPreview/index.js +8 -4
- package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +207 -49
- package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
- package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
- package/es/components/pisellFloorMapLayout/components/EdgeLayer.js +252 -0
- package/es/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
- package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
- package/es/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
- package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +131 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +5 -4
- package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
- package/es/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
- package/es/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
- package/es/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.js +290 -147
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +81 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +21 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
- package/es/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
- package/es/components/pisellFloorMapLayout/components/NodePortMarkers.js +70 -0
- package/es/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
- package/es/components/pisellFloorMapLayout/components/ViewControls.js +13 -5
- package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
- package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
- package/es/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +340 -0
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +102 -0
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +244 -84
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
- package/es/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
- package/es/components/pisellFloorMapLayout/index.d.ts +5 -1
- package/es/components/pisellFloorMapLayout/locales-ja.js +14 -2
- package/es/components/pisellFloorMapLayout/locales-pt.js +14 -2
- package/es/components/pisellFloorMapLayout/locales.js +161 -8
- package/es/components/pisellFloorMapLayout/types.d.ts +86 -4
- package/es/components/pisellFloorMapLayout/types.js +5 -1
- package/es/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
- package/es/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +86 -0
- package/es/components/pisellFloorMapLayout/utils/edgeRouting.js +942 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -1
- package/es/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
- package/es/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +20 -3
- package/es/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
- package/es/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +62 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +51 -0
- package/es/components/productCard/cartSkuCard/components/BookingItem/index.js +14 -0
- package/es/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
- package/es/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
- package/es/components/productCard/cartSkuCard/index.js +17 -11
- package/es/components/productCard/lineItem/BookingLineItem.js +6 -4
- package/es/components/productCard/lineItem/components/Resources/index.js +45 -0
- package/es/components/productCard/lineItem/components/TimeRange/index.js +64 -0
- package/es/components/productCard/lineItem/index.js +2 -1
- package/es/components/productCard/lineItem/index.less +21 -10
- package/es/index.d.ts +6 -2
- package/es/index.js +6 -2
- package/es/pisell-materials.tw.css +3 -0
- package/lib/components/buttonGroupPreview/index.js +8 -4
- package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +206 -48
- package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
- package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
- package/lib/components/pisellFloorMapLayout/components/EdgeLayer.js +255 -0
- package/lib/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
- package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
- package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
- package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +134 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +4 -3
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
- package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
- package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.js +287 -144
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +84 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +23 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
- package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
- package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.js +73 -0
- package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
- package/lib/components/pisellFloorMapLayout/components/ViewControls.js +12 -4
- package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
- package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
- package/lib/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +341 -0
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +103 -0
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +242 -82
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
- package/lib/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
- package/lib/components/pisellFloorMapLayout/index.d.ts +5 -1
- package/lib/components/pisellFloorMapLayout/locales-ja.js +14 -2
- package/lib/components/pisellFloorMapLayout/locales-pt.js +14 -2
- package/lib/components/pisellFloorMapLayout/locales.js +161 -8
- package/lib/components/pisellFloorMapLayout/types.d.ts +86 -4
- package/lib/components/pisellFloorMapLayout/types.js +5 -0
- package/lib/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
- package/lib/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +87 -0
- package/lib/components/pisellFloorMapLayout/utils/edgeRouting.js +956 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
- package/lib/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +21 -2
- package/lib/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
- package/lib/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +64 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +54 -0
- package/lib/components/productCard/cartSkuCard/components/BookingItem/index.js +17 -0
- package/lib/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
- package/lib/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
- package/lib/components/productCard/cartSkuCard/index.js +17 -11
- package/lib/components/productCard/lineItem/BookingLineItem.js +6 -4
- package/lib/components/productCard/lineItem/components/Resources/index.js +47 -0
- package/lib/components/productCard/lineItem/components/TimeRange/index.js +67 -0
- package/lib/components/productCard/lineItem/index.js +2 -1
- package/lib/components/productCard/lineItem/index.less +21 -10
- package/lib/index.d.ts +6 -2
- package/lib/index.js +11 -0
- package/lib/pisell-materials.tw.css +3 -0
- package/package.json +4 -1
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
require("../../../_virtual/_rolldown/runtime.js");
|
|
2
|
+
const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
|
|
3
|
+
const require_edgeRouting = require("../utils/edgeRouting.js");
|
|
4
|
+
const require_useFloorMapEdgeViewModel = require("./useFloorMapEdgeViewModel.js");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
//#region src/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.ts
|
|
7
|
+
/**
|
|
8
|
+
* 平面图编辑态:连线选中、拉线、草稿 edges 更新
|
|
9
|
+
*/
|
|
10
|
+
function newEdgeId() {
|
|
11
|
+
return `edge_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
12
|
+
}
|
|
13
|
+
function useFloorMapEdgeEditing(params) {
|
|
14
|
+
var _config$edges, _rectsById$get;
|
|
15
|
+
const { enabled, config, items, mergedItems, cellSize, itemUnit, itemGap, contentOffsetRef, selectedId, setSelectedId, commitDraft, mapContentRef, scale = 1 } = params;
|
|
16
|
+
const [selectedEdgeId, setSelectedEdgeId] = (0, react.useState)(null);
|
|
17
|
+
const [drawing, setDrawing] = (0, react.useState)(null);
|
|
18
|
+
const [ghostEnd, setGhostEnd] = (0, react.useState)(null);
|
|
19
|
+
/** 拉线时当前悬停的目标图元与吸附端口 */
|
|
20
|
+
const [drawingTarget, setDrawingTarget] = (0, react.useState)(null);
|
|
21
|
+
const [pendingRectsById, setPendingRectsById] = (0, react.useState)({});
|
|
22
|
+
/** 拖动中段手柄时的临时 routing 覆盖(pointerup 后写入 edge.routing) */
|
|
23
|
+
const [pendingRoutingByEdge, setPendingRoutingByEdge] = (0, react.useState)({});
|
|
24
|
+
const edges = (_config$edges = config === null || config === void 0 ? void 0 : config.edges) !== null && _config$edges !== void 0 ? _config$edges : [];
|
|
25
|
+
const { routes, rectsById } = require_useFloorMapEdgeViewModel.useFloorMapEdgeViewModel({
|
|
26
|
+
edges,
|
|
27
|
+
items,
|
|
28
|
+
cellSize,
|
|
29
|
+
itemUnit,
|
|
30
|
+
itemGap,
|
|
31
|
+
pendingRectsById,
|
|
32
|
+
pendingRoutingByEdge
|
|
33
|
+
});
|
|
34
|
+
const clearEdgeSelection = (0, react.useCallback)(() => {
|
|
35
|
+
setSelectedEdgeId(null);
|
|
36
|
+
}, []);
|
|
37
|
+
const selectEdge = (0, react.useCallback)((edgeId) => {
|
|
38
|
+
if (drawing) return;
|
|
39
|
+
setSelectedEdgeId(edgeId);
|
|
40
|
+
if (edgeId) setSelectedId(null);
|
|
41
|
+
}, [drawing, setSelectedId]);
|
|
42
|
+
const selectNode = (0, react.useCallback)((id) => {
|
|
43
|
+
if (drawing) return;
|
|
44
|
+
setSelectedId(id);
|
|
45
|
+
if (id) setSelectedEdgeId(null);
|
|
46
|
+
}, [drawing, setSelectedId]);
|
|
47
|
+
const clientToContent = (0, react.useCallback)((clientX, clientY) => {
|
|
48
|
+
const el = mapContentRef.current;
|
|
49
|
+
if (!el) return null;
|
|
50
|
+
const rect = el.getBoundingClientRect();
|
|
51
|
+
const off = contentOffsetRef.current;
|
|
52
|
+
return {
|
|
53
|
+
x: (clientX - rect.left) / scale - off.x,
|
|
54
|
+
y: (clientY - rect.top) / scale - off.y
|
|
55
|
+
};
|
|
56
|
+
}, [
|
|
57
|
+
mapContentRef,
|
|
58
|
+
contentOffsetRef,
|
|
59
|
+
scale
|
|
60
|
+
]);
|
|
61
|
+
const ghostPathD = (0, react.useMemo)(() => {
|
|
62
|
+
var _drawingTarget$anchor;
|
|
63
|
+
if (!drawing || !ghostEnd) return null;
|
|
64
|
+
const srcRect = rectsById.get(drawing.fromInstanceId);
|
|
65
|
+
if (!srcRect) return null;
|
|
66
|
+
const sourcePt = require_edgeRouting.getAnchorPoint(srcRect, drawing.fromAnchor);
|
|
67
|
+
const tgtRect = drawingTarget ? rectsById.get(drawingTarget.instanceId) : null;
|
|
68
|
+
const targetSide = (_drawingTarget$anchor = drawingTarget === null || drawingTarget === void 0 ? void 0 : drawingTarget.anchor) !== null && _drawingTarget$anchor !== void 0 ? _drawingTarget$anchor : "left";
|
|
69
|
+
const targetPt = tgtRect ? require_edgeRouting.getAnchorPoint(tgtRect, targetSide) : ghostEnd;
|
|
70
|
+
return require_edgeRouting.pathFromPoints(require_edgeRouting.routeOrthogonal(sourcePt, drawing.fromAnchor, targetPt, targetSide, void 0, srcRect && tgtRect ? {
|
|
71
|
+
sourceRect: srcRect,
|
|
72
|
+
targetRect: tgtRect
|
|
73
|
+
} : void 0));
|
|
74
|
+
}, [
|
|
75
|
+
drawing,
|
|
76
|
+
ghostEnd,
|
|
77
|
+
drawingTarget,
|
|
78
|
+
rectsById
|
|
79
|
+
]);
|
|
80
|
+
const drawingTargetPreview = (0, react.useMemo)(() => {
|
|
81
|
+
if (!drawing || !drawingTarget) return null;
|
|
82
|
+
const rect = rectsById.get(drawingTarget.instanceId);
|
|
83
|
+
if (!rect) return null;
|
|
84
|
+
return {
|
|
85
|
+
instanceId: drawingTarget.instanceId,
|
|
86
|
+
rect,
|
|
87
|
+
anchor: drawingTarget.anchor
|
|
88
|
+
};
|
|
89
|
+
}, [
|
|
90
|
+
drawing,
|
|
91
|
+
drawingTarget,
|
|
92
|
+
rectsById
|
|
93
|
+
]);
|
|
94
|
+
const startDrawingFromAnchor = (0, react.useCallback)((instanceId, anchor) => {
|
|
95
|
+
setDrawing({
|
|
96
|
+
fromInstanceId: instanceId,
|
|
97
|
+
fromAnchor: anchor
|
|
98
|
+
});
|
|
99
|
+
setDrawingTarget(null);
|
|
100
|
+
setGhostEnd(null);
|
|
101
|
+
setSelectedEdgeId(null);
|
|
102
|
+
setSelectedId(instanceId);
|
|
103
|
+
}, [setSelectedId]);
|
|
104
|
+
const finishDrawing = (0, react.useCallback)((clientX, clientY) => {
|
|
105
|
+
var _resolved$instanceId;
|
|
106
|
+
if (!drawing || !config) {
|
|
107
|
+
setDrawing(null);
|
|
108
|
+
setGhostEnd(null);
|
|
109
|
+
setDrawingTarget(null);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const pt = clientToContent(clientX, clientY);
|
|
113
|
+
if (!pt) {
|
|
114
|
+
setDrawing(null);
|
|
115
|
+
setGhostEnd(null);
|
|
116
|
+
setDrawingTarget(null);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const resolved = drawingTarget !== null && drawingTarget !== void 0 ? drawingTarget : require_edgeRouting.resolveDrawingTargetAtPoint(pt, mergedItems.map((m) => m.id), rectsById, drawing.fromInstanceId);
|
|
120
|
+
const targetId = (_resolved$instanceId = resolved === null || resolved === void 0 ? void 0 : resolved.instanceId) !== null && _resolved$instanceId !== void 0 ? _resolved$instanceId : null;
|
|
121
|
+
const targetAnchor = resolved === null || resolved === void 0 ? void 0 : resolved.anchor;
|
|
122
|
+
if (targetId && targetId !== drawing.fromInstanceId) {
|
|
123
|
+
const edge = {
|
|
124
|
+
id: newEdgeId(),
|
|
125
|
+
sourceId: drawing.fromInstanceId,
|
|
126
|
+
targetId,
|
|
127
|
+
sourceAnchor: drawing.fromAnchor,
|
|
128
|
+
targetAnchor,
|
|
129
|
+
status: "online"
|
|
130
|
+
};
|
|
131
|
+
commitDraft((prev) => {
|
|
132
|
+
var _prev$edges;
|
|
133
|
+
return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { edges: [...(_prev$edges = prev.edges) !== null && _prev$edges !== void 0 ? _prev$edges : [], edge] });
|
|
134
|
+
});
|
|
135
|
+
setSelectedEdgeId(edge.id);
|
|
136
|
+
setSelectedId(null);
|
|
137
|
+
}
|
|
138
|
+
setDrawing(null);
|
|
139
|
+
setGhostEnd(null);
|
|
140
|
+
setDrawingTarget(null);
|
|
141
|
+
}, [
|
|
142
|
+
drawing,
|
|
143
|
+
drawingTarget,
|
|
144
|
+
config,
|
|
145
|
+
clientToContent,
|
|
146
|
+
mergedItems,
|
|
147
|
+
rectsById,
|
|
148
|
+
commitDraft,
|
|
149
|
+
setSelectedId
|
|
150
|
+
]);
|
|
151
|
+
(0, react.useEffect)(() => {
|
|
152
|
+
if (!drawing) return;
|
|
153
|
+
const onMove = (ev) => {
|
|
154
|
+
const pt = clientToContent(ev.clientX, ev.clientY);
|
|
155
|
+
if (!pt) return;
|
|
156
|
+
const hit = require_edgeRouting.resolveDrawingTargetAtPoint(pt, mergedItems.map((m) => m.id), rectsById, drawing.fromInstanceId);
|
|
157
|
+
setDrawingTarget(hit);
|
|
158
|
+
if (hit) {
|
|
159
|
+
const rect = rectsById.get(hit.instanceId);
|
|
160
|
+
if (rect) {
|
|
161
|
+
setGhostEnd(require_edgeRouting.getAnchorPoint(rect, hit.anchor));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
setGhostEnd(pt);
|
|
166
|
+
};
|
|
167
|
+
const onUp = (ev) => {
|
|
168
|
+
finishDrawing(ev.clientX, ev.clientY);
|
|
169
|
+
};
|
|
170
|
+
window.addEventListener("pointermove", onMove);
|
|
171
|
+
window.addEventListener("pointerup", onUp);
|
|
172
|
+
return () => {
|
|
173
|
+
window.removeEventListener("pointermove", onMove);
|
|
174
|
+
window.removeEventListener("pointerup", onUp);
|
|
175
|
+
};
|
|
176
|
+
}, [
|
|
177
|
+
drawing,
|
|
178
|
+
clientToContent,
|
|
179
|
+
finishDrawing,
|
|
180
|
+
mergedItems,
|
|
181
|
+
rectsById
|
|
182
|
+
]);
|
|
183
|
+
const updateEdge = (0, react.useCallback)((edgeId, patch) => {
|
|
184
|
+
commitDraft((prev) => {
|
|
185
|
+
var _prev$edges2;
|
|
186
|
+
return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { edges: ((_prev$edges2 = prev.edges) !== null && _prev$edges2 !== void 0 ? _prev$edges2 : []).map((e) => e.id === edgeId ? require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, e), patch) : e) });
|
|
187
|
+
});
|
|
188
|
+
}, [commitDraft]);
|
|
189
|
+
/**
|
|
190
|
+
* 拖动连线段手柄:所有拖动都直接对「path snapshot」做形变。
|
|
191
|
+
* - `role='inner'`:把指定 segmentIndex 的主轴坐标平移到鼠标位置。
|
|
192
|
+
* - `role='first'`:在 snapshot 前面插入一对新点(短 stub + 新被拖动段),
|
|
193
|
+
* 随后拖动改新被拖动段的主轴。即「拖首段 = 新增一个角」,可以无限叠加。
|
|
194
|
+
* - `role='last'`:对称地在末尾追加一对新点。
|
|
195
|
+
* 释放后把「working snapshot」一次性写入 edge.routing.pathSnapshot。
|
|
196
|
+
*/
|
|
197
|
+
const draggingSegmentRef = (0, react.useRef)(null);
|
|
198
|
+
const startDraggingSegment = (0, react.useCallback)((params) => {
|
|
199
|
+
const edge = edges.find((e) => e.id === params.edgeId);
|
|
200
|
+
if (!edge) return;
|
|
201
|
+
const currentRoute = routes.find((r) => r.edgeId === params.edgeId);
|
|
202
|
+
if (!currentRoute) return;
|
|
203
|
+
/** 始终用「当前 view-model 渲染的 path」(已对齐到最新图元锚点)作为 working 起点。
|
|
204
|
+
* 再做一次共线化简,确保 applySourceStub/Target 不会被冗余共线点干扰
|
|
205
|
+
* (否则插入 stub 后改 y/x,后续共线点未跟随会出斜段)。 */
|
|
206
|
+
const baseSnapshot = require_edgeRouting.simplifyCollinearPath(currentRoute.points);
|
|
207
|
+
let workingSnapshot = baseSnapshot;
|
|
208
|
+
let targetSegIndex;
|
|
209
|
+
if (params.role === "first") {
|
|
210
|
+
var _edge$sourceAnchor, _params$segmentLength;
|
|
211
|
+
const srcRect = rectsById.get(edge.sourceId);
|
|
212
|
+
const tgtRect = rectsById.get(edge.targetId);
|
|
213
|
+
const sourceAnchor = (_edge$sourceAnchor = edge.sourceAnchor) !== null && _edge$sourceAnchor !== void 0 ? _edge$sourceAnchor : srcRect && tgtRect ? require_edgeRouting.pickAutoAnchor(srcRect, tgtRect) : "right";
|
|
214
|
+
const segLen = (_params$segmentLength = params.segmentLength) !== null && _params$segmentLength !== void 0 ? _params$segmentLength : 48;
|
|
215
|
+
workingSnapshot = require_edgeRouting.applySourceStub(baseSnapshot, Math.min(24, segLen / 2), sourceAnchor);
|
|
216
|
+
/** stub 后被拖动段 = path 的 segment 2(即 snapshot[2]→snapshot[3]) */
|
|
217
|
+
targetSegIndex = 2;
|
|
218
|
+
} else if (params.role === "last") {
|
|
219
|
+
var _edge$targetAnchor, _params$segmentLength2;
|
|
220
|
+
const srcRect = rectsById.get(edge.sourceId);
|
|
221
|
+
const tgtRect = rectsById.get(edge.targetId);
|
|
222
|
+
const targetAnchor = (_edge$targetAnchor = edge.targetAnchor) !== null && _edge$targetAnchor !== void 0 ? _edge$targetAnchor : srcRect && tgtRect ? require_edgeRouting.pickAutoAnchor(tgtRect, srcRect) : "left";
|
|
223
|
+
const segLen = (_params$segmentLength2 = params.segmentLength) !== null && _params$segmentLength2 !== void 0 ? _params$segmentLength2 : 48;
|
|
224
|
+
workingSnapshot = require_edgeRouting.applyTargetStub(baseSnapshot, Math.min(24, segLen / 2), targetAnchor);
|
|
225
|
+
/** stub 后被拖动段 = path 的 segment (n-3)(即 snapshot[n-4]→snapshot[n-3]) */
|
|
226
|
+
targetSegIndex = workingSnapshot.length - 4;
|
|
227
|
+
} else targetSegIndex = params.segmentIndex;
|
|
228
|
+
draggingSegmentRef.current = {
|
|
229
|
+
edgeId: params.edgeId,
|
|
230
|
+
workingSnapshot,
|
|
231
|
+
targetSegIndex,
|
|
232
|
+
axis: params.axis,
|
|
233
|
+
startClientX: params.clientX,
|
|
234
|
+
startClientY: params.clientY,
|
|
235
|
+
startPosition: params.startPosition
|
|
236
|
+
};
|
|
237
|
+
setPendingRoutingByEdge((prev) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { [params.edgeId]: { pathSnapshot: workingSnapshot } }));
|
|
238
|
+
setSelectedEdgeId(params.edgeId);
|
|
239
|
+
}, [
|
|
240
|
+
edges,
|
|
241
|
+
routes,
|
|
242
|
+
rectsById
|
|
243
|
+
]);
|
|
244
|
+
(0, react.useEffect)(() => {
|
|
245
|
+
const onMove = (ev) => {
|
|
246
|
+
const drag = draggingSegmentRef.current;
|
|
247
|
+
if (!drag) return;
|
|
248
|
+
const dx = (ev.clientX - drag.startClientX) / scale;
|
|
249
|
+
const dy = (ev.clientY - drag.startClientY) / scale;
|
|
250
|
+
const delta = drag.axis === "h" ? dy : dx;
|
|
251
|
+
const nextPos = drag.startPosition + delta;
|
|
252
|
+
const snap = drag.workingSnapshot.map((p) => [p[0], p[1]]);
|
|
253
|
+
const i = drag.targetSegIndex;
|
|
254
|
+
if (i < 0 || i + 1 >= snap.length) return;
|
|
255
|
+
if (drag.axis === "h") {
|
|
256
|
+
snap[i] = [snap[i][0], nextPos];
|
|
257
|
+
snap[i + 1] = [snap[i + 1][0], nextPos];
|
|
258
|
+
} else {
|
|
259
|
+
snap[i] = [nextPos, snap[i][1]];
|
|
260
|
+
snap[i + 1] = [nextPos, snap[i + 1][1]];
|
|
261
|
+
}
|
|
262
|
+
setPendingRoutingByEdge((prev) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { [drag.edgeId]: { pathSnapshot: snap } }));
|
|
263
|
+
};
|
|
264
|
+
const onUp = () => {
|
|
265
|
+
const drag = draggingSegmentRef.current;
|
|
266
|
+
draggingSegmentRef.current = null;
|
|
267
|
+
if (!drag) return;
|
|
268
|
+
setPendingRoutingByEdge((prev) => {
|
|
269
|
+
const next = require_objectSpread2._objectSpread2({}, prev);
|
|
270
|
+
const finalRouting = next[drag.edgeId];
|
|
271
|
+
delete next[drag.edgeId];
|
|
272
|
+
if (finalRouting) updateEdge(drag.edgeId, { routing: finalRouting });
|
|
273
|
+
return next;
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
window.addEventListener("pointermove", onMove);
|
|
277
|
+
window.addEventListener("pointerup", onUp);
|
|
278
|
+
return () => {
|
|
279
|
+
window.removeEventListener("pointermove", onMove);
|
|
280
|
+
window.removeEventListener("pointerup", onUp);
|
|
281
|
+
};
|
|
282
|
+
}, [scale, updateEdge]);
|
|
283
|
+
const deleteEdge = (0, react.useCallback)((edgeId) => {
|
|
284
|
+
commitDraft((prev) => {
|
|
285
|
+
var _prev$edges3;
|
|
286
|
+
return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, prev), {}, { edges: ((_prev$edges3 = prev.edges) !== null && _prev$edges3 !== void 0 ? _prev$edges3 : []).filter((e) => e.id !== edgeId) });
|
|
287
|
+
});
|
|
288
|
+
setSelectedEdgeId((id) => id === edgeId ? null : id);
|
|
289
|
+
}, [commitDraft]);
|
|
290
|
+
const handleEdgeClick = (0, react.useCallback)((edgeId) => {
|
|
291
|
+
selectEdge(edgeId);
|
|
292
|
+
}, [selectEdge]);
|
|
293
|
+
const handleMapBackgroundClick = (0, react.useCallback)(() => {
|
|
294
|
+
if (drawing) return;
|
|
295
|
+
setSelectedEdgeId(null);
|
|
296
|
+
setSelectedId(null);
|
|
297
|
+
}, [drawing, setSelectedId]);
|
|
298
|
+
(0, react.useEffect)(() => {
|
|
299
|
+
if (!enabled) return;
|
|
300
|
+
const onKey = (ev) => {
|
|
301
|
+
if (ev.key !== "Delete" && ev.key !== "Backspace") return;
|
|
302
|
+
if (!selectedEdgeId) return;
|
|
303
|
+
const t = ev.target;
|
|
304
|
+
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
|
|
305
|
+
ev.preventDefault();
|
|
306
|
+
deleteEdge(selectedEdgeId);
|
|
307
|
+
};
|
|
308
|
+
window.addEventListener("keydown", onKey);
|
|
309
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
310
|
+
}, [
|
|
311
|
+
enabled,
|
|
312
|
+
selectedEdgeId,
|
|
313
|
+
deleteEdge
|
|
314
|
+
]);
|
|
315
|
+
return {
|
|
316
|
+
edges,
|
|
317
|
+
routes,
|
|
318
|
+
rectsById,
|
|
319
|
+
selectedEdgeId,
|
|
320
|
+
selectedEdge: (0, react.useMemo)(() => {
|
|
321
|
+
var _edges$find;
|
|
322
|
+
return (_edges$find = edges.find((e) => e.id === selectedEdgeId)) !== null && _edges$find !== void 0 ? _edges$find : null;
|
|
323
|
+
}, [edges, selectedEdgeId]),
|
|
324
|
+
selectedNodeRect: selectedId ? (_rectsById$get = rectsById.get(selectedId)) !== null && _rectsById$get !== void 0 ? _rectsById$get : null : null,
|
|
325
|
+
drawing,
|
|
326
|
+
drawingTargetPreview,
|
|
327
|
+
ghostPathD,
|
|
328
|
+
selectNode,
|
|
329
|
+
selectEdge,
|
|
330
|
+
clearEdgeSelection,
|
|
331
|
+
startDrawingFromAnchor,
|
|
332
|
+
handleEdgeClick,
|
|
333
|
+
handleMapBackgroundClick,
|
|
334
|
+
updateEdge,
|
|
335
|
+
deleteEdge,
|
|
336
|
+
setPendingRectsById,
|
|
337
|
+
startDraggingSegment
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
//#endregion
|
|
341
|
+
exports.useFloorMapEdgeEditing = useFloorMapEdgeEditing;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require("../../../_virtual/_rolldown/runtime.js");
|
|
2
|
+
const require_edgeRouting = require("../utils/edgeRouting.js");
|
|
3
|
+
let react = require("react");
|
|
4
|
+
//#region src/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.ts
|
|
5
|
+
/**
|
|
6
|
+
* 根据 edges + 图元矩形计算连线路由
|
|
7
|
+
*/
|
|
8
|
+
function extractRouteSegments(points) {
|
|
9
|
+
const segs = [];
|
|
10
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
11
|
+
const [x1, y1] = points[i];
|
|
12
|
+
const [x2, y2] = points[i + 1];
|
|
13
|
+
if (y1 === y2 && x1 !== x2) segs.push({
|
|
14
|
+
orientation: "h",
|
|
15
|
+
key: y1,
|
|
16
|
+
a: Math.min(x1, x2),
|
|
17
|
+
b: Math.max(x1, x2)
|
|
18
|
+
});
|
|
19
|
+
else if (x1 === x2 && y1 !== y2) segs.push({
|
|
20
|
+
orientation: "v",
|
|
21
|
+
key: x1,
|
|
22
|
+
a: Math.min(y1, y2),
|
|
23
|
+
b: Math.max(y1, y2)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return segs;
|
|
27
|
+
}
|
|
28
|
+
function segmentsOverlap(a, b) {
|
|
29
|
+
if (a.orientation !== b.orientation) return false;
|
|
30
|
+
if (a.key !== b.key) return false;
|
|
31
|
+
return Math.max(a.a, b.a) < Math.min(a.b, b.b);
|
|
32
|
+
}
|
|
33
|
+
function routesShareChannel(a, b) {
|
|
34
|
+
const segsA = extractRouteSegments(a);
|
|
35
|
+
const segsB = extractRouteSegments(b);
|
|
36
|
+
for (const sa of segsA) for (const sb of segsB) if (segmentsOverlap(sa, sb)) return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
/** 同一目标的多条边在末段竖线处必然共线,需主动分配通道错位 */
|
|
40
|
+
function edgesShareTarget(a, b) {
|
|
41
|
+
return a.targetId === b.targetId || a.sourceId === b.sourceId;
|
|
42
|
+
}
|
|
43
|
+
function useFloorMapEdgeViewModel(params) {
|
|
44
|
+
const { edges = [], items, cellSize, itemUnit, itemGap, pendingRectsById, pendingRoutingByEdge } = params;
|
|
45
|
+
return (0, react.useMemo)(() => {
|
|
46
|
+
const rectsById = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const item of items) rectsById.set(item.id, require_edgeRouting.getItemPixelRect(item, {
|
|
48
|
+
cellSize,
|
|
49
|
+
itemUnit,
|
|
50
|
+
itemGap,
|
|
51
|
+
override: pendingRectsById === null || pendingRectsById === void 0 ? void 0 : pendingRectsById[item.id]
|
|
52
|
+
}));
|
|
53
|
+
/** Pass 1:所有 edge 用默认通道(offset = 0)计算一次 */
|
|
54
|
+
const naive = edges.map((edge) => ({
|
|
55
|
+
edge,
|
|
56
|
+
route: require_edgeRouting.buildEdgeRoute(edge, rectsById, { routingOverride: pendingRoutingByEdge === null || pendingRoutingByEdge === void 0 ? void 0 : pendingRoutingByEdge[edge.id] })
|
|
57
|
+
}));
|
|
58
|
+
/**
|
|
59
|
+
* Pass 2:对共享通道的 edges 分配错位 offset。
|
|
60
|
+
* 用 union-find 风格:按 edges 出现顺序遍历,与已选 routes 比对,若冲突则用下一个 offset。
|
|
61
|
+
*/
|
|
62
|
+
const routes = [];
|
|
63
|
+
const accepted = [];
|
|
64
|
+
const acceptedEdges = [];
|
|
65
|
+
for (let i = 0; i < naive.length; i++) {
|
|
66
|
+
const { edge, route } = naive[i];
|
|
67
|
+
if (!route) continue;
|
|
68
|
+
let chosen = route;
|
|
69
|
+
let attempt = 0;
|
|
70
|
+
const maxAttempts = 10;
|
|
71
|
+
while (attempt < maxAttempts) {
|
|
72
|
+
if (!accepted.some((r, idx) => {
|
|
73
|
+
const other = acceptedEdges[idx];
|
|
74
|
+
return routesShareChannel(chosen.points, r.points) || other != null && edgesShareTarget(edge, other);
|
|
75
|
+
})) break;
|
|
76
|
+
attempt += 1;
|
|
77
|
+
const re = require_edgeRouting.buildEdgeRoute(edge, rectsById, {
|
|
78
|
+
channelOffset: require_edgeRouting.getEdgeChannelOffset(attempt),
|
|
79
|
+
routingOverride: pendingRoutingByEdge === null || pendingRoutingByEdge === void 0 ? void 0 : pendingRoutingByEdge[edge.id]
|
|
80
|
+
});
|
|
81
|
+
if (!re) break;
|
|
82
|
+
chosen = re;
|
|
83
|
+
}
|
|
84
|
+
accepted.push(chosen);
|
|
85
|
+
acceptedEdges.push(edge);
|
|
86
|
+
routes.push(chosen);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
routes,
|
|
90
|
+
rectsById
|
|
91
|
+
};
|
|
92
|
+
}, [
|
|
93
|
+
edges,
|
|
94
|
+
items,
|
|
95
|
+
cellSize,
|
|
96
|
+
itemUnit,
|
|
97
|
+
itemGap,
|
|
98
|
+
pendingRectsById,
|
|
99
|
+
pendingRoutingByEdge
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
exports.useFloorMapEdgeViewModel = useFloorMapEdgeViewModel;
|