Skip to content

Commit ff68ced

Browse files
authored
Merge pull request #15428 from kongmoumou/feat-simple-graph-draggable
feat(graph): simple graph draggable. close #14510
2 parents 08d010a + 155364a commit ff68ced

4 files changed

Lines changed: 549 additions & 47 deletions

File tree

src/chart/graph/GraphView.ts

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ import SeriesData from '../../data/SeriesData';
3737
import Line from '../helper/Line';
3838
import { getECData } from '../../util/innerStore';
3939

40+
import { simpleLayoutEdge } from './simpleLayoutHelper';
41+
import { circularLayout, rotateNodeLabel } from './circularLayoutHelper';
42+
4043
function isViewCoordSys(coordSys: CoordinateSystem): coordSys is View {
4144
return coordSys.type === 'view';
4245
}
@@ -122,6 +125,8 @@ class GraphView extends ChartView {
122125
this._startForceLayoutIteration(forceLayout, layoutAnimation);
123126
}
124127

128+
const layout = seriesModel.get('layout');
129+
125130
data.graph.eachNode((node) => {
126131
const idx = node.dataIndex;
127132
const el = node.getGraphicEl() as Symbol;
@@ -130,22 +135,39 @@ class GraphView extends ChartView {
130135
el.off('drag').off('dragend');
131136
const draggable = itemModel.get('draggable');
132137
if (draggable) {
133-
el.on('drag', () => {
134-
if (forceLayout) {
135-
forceLayout.warmUp();
136-
!this._layouting
137-
&& this._startForceLayoutIteration(forceLayout, layoutAnimation);
138-
forceLayout.setFixed(idx);
139-
// Write position back to layout
140-
data.setItemLayout(idx, [el.x, el.y]);
138+
el.on('drag', (e) => {
139+
switch (layout) {
140+
case 'force':
141+
forceLayout.warmUp();
142+
!this._layouting
143+
&& this._startForceLayoutIteration(forceLayout, layoutAnimation);
144+
forceLayout.setFixed(idx);
145+
// Write position back to layout
146+
data.setItemLayout(idx, [el.x, el.y]);
147+
break;
148+
case 'circular':
149+
data.setItemLayout(idx, [el.x, el.y]);
150+
// mark node fixed
151+
node.setLayout({ fixed: true }, true);
152+
// recalculate circular layout
153+
circularLayout(seriesModel, 'symbolSize', node, [e.offsetX, e.offsetY]);
154+
this.updateLayout(seriesModel);
155+
break;
156+
case 'none':
157+
default:
158+
data.setItemLayout(idx, [el.x, el.y]);
159+
// update edge
160+
simpleLayoutEdge(seriesModel.getGraph(), seriesModel);
161+
this.updateLayout(seriesModel);
162+
break;
141163
}
142164
}).on('dragend', () => {
143165
if (forceLayout) {
144166
forceLayout.setUnfixed(idx);
145167
}
146168
});
147169
}
148-
el.setDraggable(draggable && !!forceLayout);
170+
el.setDraggable(draggable);
149171

150172
const focus = itemModel.get(['emphasis', 'focus']);
151173

@@ -170,37 +192,8 @@ class GraphView extends ChartView {
170192
&& seriesModel.get(['circular', 'rotateLabel']);
171193
const cx = data.getLayout('cx');
172194
const cy = data.getLayout('cy');
173-
data.eachItemGraphicEl(function (el: Symbol, idx) {
174-
const itemModel = data.getItemModel<GraphNodeItemOption>(idx);
175-
let labelRotate = itemModel.get(['label', 'rotate']) || 0;
176-
const symbolPath = el.getSymbolPath();
177-
if (circularRotateLabel) {
178-
const pos = data.getItemLayout(idx);
179-
let rad = Math.atan2(pos[1] - cy, pos[0] - cx);
180-
if (rad < 0) {
181-
rad = Math.PI * 2 + rad;
182-
}
183-
const isLeft = pos[0] < cx;
184-
if (isLeft) {
185-
rad = rad - Math.PI;
186-
}
187-
const textPosition = isLeft ? 'left' as const : 'right' as const;
188-
189-
symbolPath.setTextConfig({
190-
rotation: -rad,
191-
position: textPosition,
192-
origin: 'center'
193-
});
194-
const emphasisState = symbolPath.ensureState('emphasis');
195-
zrUtil.extend(emphasisState.textConfig || (emphasisState.textConfig = {}), {
196-
position: textPosition
197-
});
198-
}
199-
else {
200-
symbolPath.setTextConfig({
201-
rotation: labelRotate *= Math.PI / 180
202-
});
203-
}
195+
data.graph.eachNode((node) => {
196+
rotateNodeLabel(node, circularRotateLabel, cx, cy);
204197
});
205198

206199
this._firstRender = false;

src/chart/graph/circularLayoutHelper.ts

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020

2121
import * as vec2 from 'zrender/src/core/vector';
2222
import {getSymbolSize, getNodeGlobalScale} from './graphHelper';
23-
import GraphSeriesModel, { GraphEdgeItemOption } from './GraphSeries';
24-
import Graph from '../../data/Graph';
23+
import GraphSeriesModel, { GraphEdgeItemOption, GraphNodeItemOption } from './GraphSeries';
24+
import Graph, { GraphNode } from '../../data/Graph';
25+
import Symbol from '../helper/Symbol';
2526
import SeriesData from '../../data/SeriesData';
2627
import * as zrUtil from 'zrender/src/core/util';
2728
import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper';
@@ -51,7 +52,9 @@ const _symbolRadiansHalf: number[] = [];
5152
*/
5253
export function circularLayout(
5354
seriesModel: GraphSeriesModel,
54-
basedOn: 'value' | 'symbolSize'
55+
basedOn: 'value' | 'symbolSize',
56+
draggingNode?: GraphNode,
57+
pointer?: [number, number]
5558
) {
5659
const coordSys = seriesModel.coordinateSystem;
5760
if (coordSys && coordSys.type !== 'view') {
@@ -77,6 +80,17 @@ export function circularLayout(
7780
return;
7881
}
7982

83+
if (draggingNode) {
84+
const [tempX, tempY] = coordSys.pointToData(pointer) as [number, number];
85+
const v = [tempX - cx, tempY - cy];
86+
vec2.normalize(v, v);
87+
vec2.scale(v, v, r);
88+
draggingNode.setLayout([cx + v[0], cy + v[1]], true);
89+
90+
const circularRotateLabel = seriesModel.get(['circular', 'rotateLabel']);
91+
rotateNodeLabel(draggingNode, circularRotateLabel, cx, cy);
92+
}
93+
8094
_layoutNodesBasedOn[basedOn](seriesModel, graph, nodeData, r, cx, cy, count);
8195

8296
graph.eachEdge(function (edge, index) {
@@ -163,11 +177,58 @@ const _layoutNodesBasedOn: Record<'value' | 'symbolSize', LayoutNode> = {
163177
const radianHalf = halfRemainRadian + _symbolRadiansHalf[node.dataIndex];
164178

165179
angle += radianHalf;
166-
node.setLayout([
180+
// init circular layout for
181+
// 1. layout undefined node
182+
// 2. not fixed node
183+
(!node.getLayout() || !node.getLayout().fixed)
184+
&& node.setLayout([
167185
r * Math.cos(angle) + cx,
168186
r * Math.sin(angle) + cy
169187
]);
170188
angle += radianHalf;
171189
});
172190
}
173191
};
192+
193+
export function rotateNodeLabel(
194+
node: GraphNode,
195+
circularRotateLabel: boolean,
196+
cx: number,
197+
cy: number
198+
) {
199+
const el = node.getGraphicEl() as Symbol;
200+
// need to check if el exists. '-' value may not create node element.
201+
if (!el) {
202+
return;
203+
}
204+
const nodeModel = node.getModel<GraphNodeItemOption>();
205+
let labelRotate = nodeModel.get(['label', 'rotate']) || 0;
206+
const symbolPath = el.getSymbolPath();
207+
if (circularRotateLabel) {
208+
const pos = node.getLayout();
209+
let rad = Math.atan2(pos[1] - cy, pos[0] - cx);
210+
if (rad < 0) {
211+
rad = Math.PI * 2 + rad;
212+
}
213+
const isLeft = pos[0] < cx;
214+
if (isLeft) {
215+
rad = rad - Math.PI;
216+
}
217+
const textPosition = isLeft ? 'left' as const : 'right' as const;
218+
219+
symbolPath.setTextConfig({
220+
rotation: -rad,
221+
position: textPosition,
222+
origin: 'center'
223+
});
224+
const emphasisState = symbolPath.ensureState('emphasis');
225+
zrUtil.extend(emphasisState.textConfig || (emphasisState.textConfig = {}), {
226+
position: textPosition
227+
});
228+
}
229+
else {
230+
symbolPath.setTextConfig({
231+
rotation: labelRotate *= Math.PI / 180
232+
});
233+
}
234+
}

src/component/helper/RoamController.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,19 @@ class RoamController extends Eventful<{
173173
}
174174

175175
private _mousedownHandler(e: ZRElementEvent) {
176-
if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)
177-
|| (e.target && e.target.draggable)
178-
) {
176+
if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
179177
return;
180178
}
181179

180+
let el = e.target;
181+
while (el) {
182+
if (el.draggable) {
183+
return;
184+
}
185+
// check if host is draggable
186+
el = el.__hostTarget || el.parent;
187+
}
188+
182189
const x = e.offsetX;
183190
const y = e.offsetY;
184191

0 commit comments

Comments
 (0)