mirror of
https://gitee.com/antv/g6.git
synced 2024-12-02 19:58:46 +08:00
feat: update polyline
This commit is contained in:
parent
a082480db3
commit
a1a1f8a35a
@ -7,6 +7,7 @@ import { updateShapes } from '../util/shape';
|
||||
import { animateShapes } from '../util/animate';
|
||||
import { EdgeStyleSet } from '../types/theme';
|
||||
import { isSamePoint, getNearestPoint } from '../util/point';
|
||||
import { isPolylineWithObstacleAvoidance } from '../util/polyline';
|
||||
import Item from './item';
|
||||
import Node from './node';
|
||||
import Combo from './combo';
|
||||
@ -134,8 +135,9 @@ export default class Edge extends Item {
|
||||
* e.g. source and target nodes' position changed
|
||||
* @param force bypass the nodes position change check and force to re-draw
|
||||
*/
|
||||
public forceUpdate(force = false) {
|
||||
public forceUpdate() {
|
||||
if (this.destroyed) return;
|
||||
const force = isPolylineWithObstacleAvoidance(this.displayModel);
|
||||
const { sourcePoint, targetPoint, changed } = this.getEndPoints(
|
||||
this.displayModel,
|
||||
);
|
||||
@ -255,6 +257,7 @@ export default class Edge extends Item {
|
||||
targetItem: Node | Combo,
|
||||
shapeIds?: string[],
|
||||
disableAnimate?: boolean,
|
||||
visible?: boolean,
|
||||
transientItemMap?: Map<ID, Node | Edge | Combo | Group>,
|
||||
) {
|
||||
if (shapeIds?.length) {
|
||||
@ -302,6 +305,7 @@ export default class Edge extends Item {
|
||||
lodStrategy: this.lodStrategy,
|
||||
},
|
||||
});
|
||||
if (visible) return clonedEdge;
|
||||
Object.keys(this.shapeMap).forEach((shapeId) => {
|
||||
if (!this.shapeMap[shapeId].isVisible())
|
||||
clonedEdge.shapeMap[shapeId]?.hide();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Graph as GraphLib, ID } from '@antv/graphlib';
|
||||
import { clone, isArray, isObject } from '@antv/util';
|
||||
import { clone, isArray, isObject, uniq } from '@antv/util';
|
||||
import { AABB } from '@antv/g';
|
||||
import { registery as registry } from '../../stdlib';
|
||||
import { ComboModel, ComboUserModel, GraphData, IGraph } from '../../types';
|
||||
import { ComboUserModelData } from '../../types/combo';
|
||||
@ -36,6 +37,7 @@ import { getExtension } from '../../util/extension';
|
||||
import { convertToNumber } from '../../util/type';
|
||||
import { isTreeLayout } from '../../util/layout';
|
||||
import { hasTreeBehaviors } from '../../util/behavior';
|
||||
import { EdgeCollisionChecker, QuadTree } from '../../util/polyline';
|
||||
|
||||
/**
|
||||
* Manages the data transform extensions;
|
||||
@ -130,6 +132,50 @@ export class DataController {
|
||||
) {
|
||||
return this.graphCore.getRelatedEdges(nodeId, direction);
|
||||
}
|
||||
|
||||
public findNearEdges(nodeId: ID, transientItem?: Node) {
|
||||
const edges = this.graphCore.getAllEdges();
|
||||
|
||||
const canvasBBox = this.graph.getRenderBBox(undefined) as AABB;
|
||||
const quadTree = new QuadTree(canvasBBox, 4);
|
||||
|
||||
edges.forEach((edge) => {
|
||||
const {
|
||||
data: { x: sourceX, y: sourceY },
|
||||
} = this.graphCore.getNode(edge.source);
|
||||
const {
|
||||
data: { x: targetX, y: targetY },
|
||||
} = this.graphCore.getNode(edge.target);
|
||||
|
||||
quadTree.insert({
|
||||
id: edge.id,
|
||||
p1: { x: sourceX, y: sourceY },
|
||||
p2: { x: targetX, y: targetY },
|
||||
bbox: this.graph.getRenderBBox(edge.id) as AABB,
|
||||
});
|
||||
});
|
||||
const nodeBBox = this.graph.getRenderBBox(nodeId) as AABB;
|
||||
|
||||
if (transientItem) {
|
||||
// @ts-ignore
|
||||
const nodeData = transientItem.displayModel.data;
|
||||
if (nodeData) {
|
||||
nodeBBox.update(
|
||||
[nodeData.x as number, nodeData.y as number, 0],
|
||||
nodeBBox.halfExtents,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const checker = new EdgeCollisionChecker(quadTree);
|
||||
const collisions = checker.getCollidingEdges(nodeBBox);
|
||||
const collidingEdges = collisions.map((collision) =>
|
||||
this.graphCore.getEdge(collision.id),
|
||||
);
|
||||
|
||||
return collidingEdges;
|
||||
}
|
||||
|
||||
public findNeighborNodes(
|
||||
nodeId: ID,
|
||||
direction: 'in' | 'out' | 'both' = 'both',
|
||||
|
@ -64,9 +64,9 @@ import {
|
||||
import { getGroupedChanges } from '../../util/event';
|
||||
import { BaseNode } from '../../stdlib/item/node/base';
|
||||
import { BaseEdge } from '../../stdlib/item/edge/base';
|
||||
import { EdgeCollisionChecker, QuadTree } from '../../util/polyline';
|
||||
import { isBBoxInBBox, isPointInBBox } from '../../util/bbox';
|
||||
import { convertToNumber } from '../../util/type';
|
||||
import { isPointPreventPolylineOverlap } from '../../util/polyline';
|
||||
|
||||
/**
|
||||
* Manages and stores the node / edge / combo items.
|
||||
@ -136,6 +136,8 @@ export class ItemController {
|
||||
ID,
|
||||
Node | Edge | Combo | Group
|
||||
>();
|
||||
/** Caches */
|
||||
private nearEdgesCache: Map<ID, EdgeModel[]> = new Map<ID, EdgeModel[]>();
|
||||
|
||||
constructor(graph: IGraph<any, any>) {
|
||||
this.graph = graph;
|
||||
@ -519,15 +521,20 @@ export class ItemController {
|
||||
);
|
||||
}
|
||||
|
||||
const preventPolylineEdgeOverlap =
|
||||
innerModel?.data?.preventPolylineEdgeOverlap || false;
|
||||
const relatedEdgeInnerModels = preventPolylineEdgeOverlap
|
||||
? this.findNearEdgesByNode(id, graphCore).concat(
|
||||
graphCore.getRelatedEdges(id),
|
||||
const newNearEdges = this.graph.getNearEdgesData(id);
|
||||
const relatedEdges = graphCore.getRelatedEdges(id);
|
||||
const adjacentEdgeInnerModels = isPointPreventPolylineOverlap(
|
||||
innerModel,
|
||||
)
|
||||
? uniq(
|
||||
(this.nearEdgesCache.get(id) || [])
|
||||
.concat(newNearEdges)
|
||||
.concat(relatedEdges),
|
||||
)
|
||||
: graphCore.getRelatedEdges(id);
|
||||
: relatedEdges;
|
||||
this.nearEdgesCache.set(id, newNearEdges);
|
||||
|
||||
relatedEdgeInnerModels.forEach((edge) => {
|
||||
adjacentEdgeInnerModels.forEach((edge) => {
|
||||
edgeIdsToUpdate.add(edge.id);
|
||||
nodeRelatedIdsToUpdate.add(edge.id);
|
||||
});
|
||||
@ -661,33 +668,6 @@ export class ItemController {
|
||||
}
|
||||
});
|
||||
}
|
||||
// === 10. redraw part of polyline which enables automatic obstacle avoidance
|
||||
this.itemMap.forEach((item, id) => {
|
||||
if (item.getType() === 'edge') {
|
||||
const edgeModel = this.graph.getEdgeData(id);
|
||||
const obstacleAvoidance =
|
||||
// @ts-ignore
|
||||
edgeModel.data?.keyShape?.routeCfg?.obstacleAvoidance || false;
|
||||
// Only the edge enables automatic obstacle avoidance and the changed node is not the source/target, redrawing is forced.
|
||||
if (obstacleAvoidance) {
|
||||
const { NodeAdded, NodeDataUpdated, NodeRemoved } = groupedChanges;
|
||||
const relatedNodeIds = new Set(
|
||||
[...NodeAdded, ...NodeDataUpdated, ...NodeRemoved].map(
|
||||
(node) =>
|
||||
// @ts-ignore
|
||||
node.id,
|
||||
),
|
||||
);
|
||||
if (
|
||||
relatedNodeIds.has(edgeModel.source) ||
|
||||
relatedNodeIds.has(edgeModel.target)
|
||||
)
|
||||
return;
|
||||
|
||||
(item as Edge).forceUpdate(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -726,7 +706,6 @@ export class ItemController {
|
||||
graphCore: GraphCore;
|
||||
animate?: boolean;
|
||||
keepKeyShape?: boolean;
|
||||
edgeForceUpdate?: boolean;
|
||||
}) {
|
||||
const {
|
||||
ids,
|
||||
@ -734,7 +713,6 @@ export class ItemController {
|
||||
graphCore,
|
||||
animate = true,
|
||||
keepKeyShape = false,
|
||||
edgeForceUpdate = false,
|
||||
} = param;
|
||||
ids.forEach((id) => {
|
||||
const item = this.itemMap.get(id);
|
||||
@ -748,9 +726,7 @@ export class ItemController {
|
||||
if (value) {
|
||||
if (type === 'edge') {
|
||||
item.show(animate);
|
||||
if (edgeForceUpdate) {
|
||||
(item as Edge).forceUpdate(true);
|
||||
}
|
||||
(item as Edge).forceUpdate();
|
||||
} else {
|
||||
if (graphCore.hasTreeStructure('combo')) {
|
||||
let anccestorCollapsed = false;
|
||||
@ -992,7 +968,6 @@ export class ItemController {
|
||||
{ shapeIds, drawSource, drawTarget, visible },
|
||||
upsertAncestors,
|
||||
);
|
||||
|
||||
if (shapeIds) {
|
||||
// only update node positions to cloned node container(group)
|
||||
if (
|
||||
@ -1081,7 +1056,7 @@ export class ItemController {
|
||||
}
|
||||
|
||||
public getTransientItem(id: ID) {
|
||||
return this.transientItemMap[id];
|
||||
return this.transientItemMap.get(id);
|
||||
}
|
||||
|
||||
public findDisplayModel(id: ID) {
|
||||
@ -1426,56 +1401,6 @@ export class ItemController {
|
||||
return item.isVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify edges that are intersected by a particular node
|
||||
* @param nodeId node id
|
||||
* @param graphCore
|
||||
* @returns
|
||||
*/
|
||||
public findNearEdgesByNode(nodeId: ID, graphCore: GraphCore) {
|
||||
const edges = graphCore.getAllEdges();
|
||||
|
||||
const canvasBBox = this.graph.getRenderBBox(undefined) as AABB;
|
||||
const quadTree = new QuadTree(canvasBBox, 4);
|
||||
|
||||
each(edges, (edge) => {
|
||||
const {
|
||||
data: { x: sourceX, y: sourceY },
|
||||
} = graphCore.getNode(edge.source);
|
||||
const {
|
||||
data: { x: targetX, y: targetY },
|
||||
} = graphCore.getNode(edge.target);
|
||||
|
||||
quadTree.insert({
|
||||
id: edge.id,
|
||||
p1: { x: sourceX, y: sourceY },
|
||||
p2: { x: targetX, y: targetY },
|
||||
bbox: this.graph.getRenderBBox(edge.id) as AABB,
|
||||
});
|
||||
});
|
||||
|
||||
// update node position
|
||||
const node = (this.getTransientItem(nodeId) ||
|
||||
this.getItemById(nodeId)) as Node;
|
||||
const nodeBBox = this.graph.getRenderBBox(nodeId) as AABB;
|
||||
const nodeData = node?.model?.data;
|
||||
if (nodeData) {
|
||||
nodeBBox.update(
|
||||
[nodeData.x as number, nodeData.y as number, 0],
|
||||
nodeBBox.halfExtents,
|
||||
);
|
||||
}
|
||||
|
||||
const checker = new EdgeCollisionChecker(quadTree);
|
||||
const collisions = checker.getCollidingEdges(nodeBBox);
|
||||
|
||||
const collidingEdges = map(collisions, (collision) =>
|
||||
graphCore.getEdge(collision.id),
|
||||
);
|
||||
|
||||
return collidingEdges;
|
||||
}
|
||||
|
||||
public sortByComboTree(graphCore: GraphCore) {
|
||||
if (!graphCore.hasTreeStructure('combo')) return;
|
||||
graphCoreTreeDfs(graphCore, graphCore.getRoots('combo'), (node) => {
|
||||
|
@ -1026,6 +1026,17 @@ export class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
||||
): EdgeModel[] {
|
||||
return this.dataController.findRelatedEdges(nodeId, direction);
|
||||
}
|
||||
/**
|
||||
* Get nearby edges from a start node using quadtree collision detection.
|
||||
* @param nodeId id of the start node
|
||||
* @returns nearby edges' data array
|
||||
*/
|
||||
public getNearEdgesData(nodeId: ID): EdgeModel[] {
|
||||
const transientItem = this.itemController.getTransientItem(
|
||||
nodeId,
|
||||
) as unknown as Node;
|
||||
return this.dataController.findNearEdges(nodeId, transientItem);
|
||||
}
|
||||
/**
|
||||
* Get one-hop node ids from a start node.
|
||||
* @param nodeId id of the start node
|
||||
@ -1060,16 +1071,6 @@ export class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
||||
return this.itemController.findDisplayModel(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the nearby edges for a given node using quadtree collision detection.
|
||||
* @param nodeId node id
|
||||
* @group Data
|
||||
*/
|
||||
public getNearEdgesForNode(nodeId: ID): EdgeModel[] {
|
||||
const { graphCore } = this.dataController;
|
||||
return this.itemController.findNearEdgesByNode(nodeId, graphCore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find items which has the state.
|
||||
* @param itemType item type
|
||||
@ -1467,11 +1468,7 @@ export class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
||||
* @returns
|
||||
* @group Item
|
||||
*/
|
||||
public showItem(
|
||||
ids: ID | ID[],
|
||||
disableAnimate = false,
|
||||
edgeForceUpdate = false,
|
||||
) {
|
||||
public showItem(ids: ID | ID[], disableAnimate = false) {
|
||||
const idArr = isArray(ids) ? ids : [ids];
|
||||
if (isEmpty(idArr)) return;
|
||||
const changes = {
|
||||
@ -1483,7 +1480,6 @@ export class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
|
||||
value: true,
|
||||
graphCore: this.dataController.graphCore,
|
||||
animate: !disableAnimate,
|
||||
edgeForceUpdate,
|
||||
});
|
||||
this.emit('afteritemvisibilitychange', {
|
||||
ids,
|
||||
|
@ -5,6 +5,7 @@ import { Behavior } from '../../types/behavior';
|
||||
import { IG6GraphEvent } from '../../types/event';
|
||||
import { Point } from '../../types/common';
|
||||
import { graphComboTreeDfs } from '../../util/data';
|
||||
import { isPointPreventPolylineOverlap } from '../../util/polyline';
|
||||
|
||||
const DELEGATE_SHAPE_ID = 'g6-drag-node-delegate-shape';
|
||||
|
||||
@ -108,6 +109,7 @@ export class DragNode extends Behavior {
|
||||
private originPositions: Array<Position> = [];
|
||||
private pointerDown: Point | undefined = undefined;
|
||||
private dragging = false;
|
||||
private hiddenNearEdgesCache: EdgeModel[] = [];
|
||||
|
||||
constructor(options: Partial<DragNodeOptions>) {
|
||||
const finalOptions = Object.assign({}, DEFAULT_OPTIONS, options);
|
||||
@ -171,7 +173,7 @@ export class DragNode extends Behavior {
|
||||
/** Retrieve the nearby edges for a given node using quadtree collision detection. */
|
||||
private getNearEdgesForNodes(nodeIds: ID[]) {
|
||||
return uniq(
|
||||
nodeIds.flatMap((nodeId) => this.graph.getNearEdgesForNode(nodeId)),
|
||||
nodeIds.flatMap((nodeId) => this.graph.getNearEdgesData(nodeId)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -323,28 +325,38 @@ export class DragNode extends Behavior {
|
||||
}
|
||||
|
||||
/**
|
||||
* When dragging nodes, if nodes are set to `preventPolylineEdgeOverlap`,
|
||||
* use quadtree collision detection to identity nearby edges and dynamically update them
|
||||
* When dragging nodes, if nodes are set to `preventPolylineEdgeOverlap`, identity nearby edges and dynamically update them
|
||||
*/
|
||||
if (this.dragging && enableTransient) {
|
||||
const autoRoutedNodesIds = this.selectedNodeIds.filter((nodeId) => {
|
||||
return (
|
||||
this.graph.getNodeData(nodeId)?.data.preventPolylineEdgeOverlap ||
|
||||
false
|
||||
);
|
||||
});
|
||||
const preventPolylineOverlapNodeIds = this.selectedNodeIds.filter(
|
||||
(nodeId) => {
|
||||
const innerModel = this.graph.getNodeData(nodeId);
|
||||
return isPointPreventPolylineOverlap(innerModel);
|
||||
},
|
||||
);
|
||||
|
||||
if (autoRoutedNodesIds) {
|
||||
if (preventPolylineOverlapNodeIds.length) {
|
||||
const hiddenEdgesIds = this.hiddenEdges.map((edge) => edge.id);
|
||||
this.hiddenNearEdgesCache = this.hiddenNearEdges;
|
||||
|
||||
this.hiddenNearEdges = this.getNearEdgesForNodes(
|
||||
autoRoutedNodesIds,
|
||||
preventPolylineOverlapNodeIds,
|
||||
).filter((edge) => !hiddenEdgesIds.includes(edge.id));
|
||||
const hiddenNearEdgesIds = this.hiddenNearEdges.map((edge) => edge.id);
|
||||
|
||||
this.hiddenNearEdgesCache.forEach((edge) => {
|
||||
if (!hiddenNearEdgesIds.includes(edge.id)) {
|
||||
this.graph.drawTransient('edge', edge.id, { action: 'remove' });
|
||||
this.graph.showItem(edge.id);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.hiddenNearEdges.length) {
|
||||
this.hiddenNearEdges.forEach((edge) => {
|
||||
this.graph.drawTransient('edge', edge.id, {});
|
||||
this.graph.drawTransient('edge', edge.id, {
|
||||
visible: true,
|
||||
});
|
||||
});
|
||||
|
||||
this.graph.hideItem(
|
||||
this.hiddenNearEdges.map((edge) => edge.id),
|
||||
true,
|
||||
@ -490,7 +502,6 @@ export class DragNode extends Behavior {
|
||||
this.graph.showItem(
|
||||
this.hiddenNearEdges.map((edge) => edge.id),
|
||||
true,
|
||||
true,
|
||||
);
|
||||
this.hiddenNearEdges = [];
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ export const genBubbleSet = (
|
||||
// eslint-disable-next-line no-redeclare
|
||||
const options = Object.assign(defaultOps, ops);
|
||||
const centroid = getPointsCenter(
|
||||
members.map((model) => ({ x: model.data.x, y: model.data.y } as Point)),
|
||||
members.map((model) => ({ x: model.data.x, y: model.data.y }) as Point),
|
||||
);
|
||||
// 按照到中心距离远近排序
|
||||
members = members.sort(
|
||||
|
@ -21,7 +21,7 @@ export const genConvexHull = (models: (NodeModel | ComboModel)[]) => {
|
||||
({
|
||||
x: model.data.x,
|
||||
y: model.data.y,
|
||||
} as Point),
|
||||
}) as Point,
|
||||
);
|
||||
points.sort((a, b) => {
|
||||
return a.x === b.x ? a.y - b.y : a.x - b.x;
|
||||
|
@ -113,6 +113,12 @@ export interface IGraph<
|
||||
nodeId: ID,
|
||||
direction?: 'in' | 'out' | 'both',
|
||||
) => EdgeModel[];
|
||||
/**
|
||||
* Get nearby edges from a start node using quadtree collision detection.
|
||||
* @param nodeId id of the start node
|
||||
* @returns nearby edges' data array
|
||||
*/
|
||||
getNearEdgesData: (nodeId: ID) => EdgeModel[];
|
||||
/**
|
||||
* Get one-hop node ids from a start node.
|
||||
* @param nodeId id of the start node
|
||||
@ -123,12 +129,6 @@ export interface IGraph<
|
||||
nodeId: ID,
|
||||
direction?: 'in' | 'out' | 'both',
|
||||
) => NodeModel[];
|
||||
/**
|
||||
* Retrieve the nearby edges for a given node using quadtree collision detection.
|
||||
* @param nodeId target node's id
|
||||
* @returns edges
|
||||
*/
|
||||
getNearEdgesForNode: (nodeId: ID) => EdgeModel[];
|
||||
/*
|
||||
* Get the children's data of a combo.
|
||||
* @param comboId combo id
|
||||
@ -472,11 +472,7 @@ export interface IGraph<
|
||||
* @returns
|
||||
* @group Data
|
||||
*/
|
||||
showItem: (
|
||||
ids: ID | ID[],
|
||||
disableAnimate?: boolean,
|
||||
edgeForceUpdate?: boolean,
|
||||
) => void;
|
||||
showItem: (ids: ID | ID[], disableAnimate?: boolean) => void;
|
||||
/**
|
||||
* Hide the item(s).
|
||||
* @param ids the item id(s) to be hidden
|
||||
|
@ -89,7 +89,6 @@ export interface Hooks {
|
||||
enableStack?: boolean;
|
||||
changes?: any;
|
||||
keepKeyShape?: boolean;
|
||||
edgeForceUpdate?: boolean;
|
||||
}>;
|
||||
itemzindexchange: IHook<{
|
||||
ids: ID[];
|
||||
|
@ -92,6 +92,7 @@ export const upsertTransientItem = (
|
||||
target,
|
||||
shapeIds,
|
||||
true,
|
||||
visible,
|
||||
transientItemMap,
|
||||
) as Edge;
|
||||
} else {
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { AABB } from '@antv/g';
|
||||
import { each } from '@antv/util';
|
||||
import { ID } from '@antv/graphlib';
|
||||
import { EdgeDisplayModel } from '../types/edge';
|
||||
import { NodeDisplayModel } from '../types';
|
||||
import Node from '../item/node';
|
||||
import Item from '../item/item';
|
||||
import { Point, PolyPoint } from '../types/common';
|
||||
import {
|
||||
getBBoxFromPoint,
|
||||
@ -559,7 +562,10 @@ export class QuadTree {
|
||||
private southwest?: QuadTree;
|
||||
private southeast?: QuadTree;
|
||||
|
||||
constructor(public boundary: AABB, capacity: number) {
|
||||
constructor(
|
||||
public boundary: AABB,
|
||||
capacity: number,
|
||||
) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
@ -652,3 +658,28 @@ export class EdgeCollisionChecker {
|
||||
return potentialCollisions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the edge is a polyline and obstacle avoidance is enabled
|
||||
*/
|
||||
export const isPolylineWithObstacleAvoidance = (
|
||||
displayModel: EdgeDisplayModel,
|
||||
) => {
|
||||
const { type, keyShape } = displayModel.data;
|
||||
const isPolyline = type === 'polyline-edge';
|
||||
if (!isPolyline) return false;
|
||||
// @ts-ignore
|
||||
const isObstacleAvoidanceEnabled = (keyShape?.routeCfg as RouterCfg)
|
||||
?.enableObstacleAvoidance;
|
||||
return isObstacleAvoidanceEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the node prevents polyline edges from overlapping
|
||||
*/
|
||||
export const isPointPreventPolylineOverlap = (
|
||||
displayModel: NodeDisplayModel,
|
||||
) => {
|
||||
const { preventPolylineEdgeOverlap } = displayModel.data;
|
||||
return preventPolylineEdgeOverlap || false;
|
||||
};
|
||||
|
@ -44,12 +44,12 @@ export interface RouterCfg {
|
||||
* Whether to automatically avoid other nodes (obstacles) on the path
|
||||
* Defaults to false.
|
||||
*/
|
||||
obstacleAvoidance?: boolean;
|
||||
enableObstacleAvoidance?: boolean;
|
||||
}
|
||||
|
||||
const defaultCfg: RouterCfg = {
|
||||
name: 'orth',
|
||||
obstacleAvoidance: false,
|
||||
enableObstacleAvoidance: false,
|
||||
offset: 2,
|
||||
maxAllowedDirectionChange: Math.PI / 2,
|
||||
maximumLoops: 2000,
|
||||
@ -393,7 +393,7 @@ export const pathFinder = (
|
||||
|
||||
const cfg: RouterCfg = deepMix(defaultCfgs, routerCfg);
|
||||
|
||||
if (!cfg.obstacleAvoidance) {
|
||||
if (!cfg.enableObstacleAvoidance) {
|
||||
return cfg.fallbackRoute(startPoint, endPoint, startNode, endNode, cfg);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ export default () => {
|
||||
routeCfg: {
|
||||
gridSize: 10,
|
||||
maxAllowedDirectionChange: Math.PI / 2,
|
||||
obstacleAvoidance: true,
|
||||
enableObstacleAvoidance: true,
|
||||
},
|
||||
},
|
||||
// labelShape: {
|
||||
|
@ -76,7 +76,7 @@ export { default as timebar_chart } from './plugins/timebar-chart';
|
||||
|
||||
export {
|
||||
minimap,
|
||||
map,
|
||||
// map,
|
||||
mapper,
|
||||
anchor,
|
||||
animations_node_build_in,
|
||||
|
@ -234,7 +234,7 @@ const createControls = () => {
|
||||
data: {
|
||||
keyShape: {
|
||||
routeCfg: {
|
||||
obstacleAvoidance: true,
|
||||
enableObstacleAvoidance: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -246,7 +246,7 @@ const createControls = () => {
|
||||
data: {
|
||||
keyShape: {
|
||||
routeCfg: {
|
||||
obstacleAvoidance: false,
|
||||
enableObstacleAvoidance: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -104,7 +104,7 @@ export default (context: TestCaseContext) => {
|
||||
// lineWidth: 2,
|
||||
// stroke: '#C2C8D5',
|
||||
// routeCfg: {
|
||||
// obstacleAvoidance: true,
|
||||
// enableObstacleAvoidance: true,
|
||||
// },
|
||||
},
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
@ -85,7 +85,7 @@ describe('Items edge polyline', () => {
|
||||
const $obstacle = document.querySelectorAll(
|
||||
'input',
|
||||
)[5] as HTMLInputElement;
|
||||
const $obstacleAvoidance = document.querySelectorAll(
|
||||
const $enableObstacleAvoidance = document.querySelectorAll(
|
||||
'input',
|
||||
)[6] as HTMLInputElement;
|
||||
|
||||
@ -99,7 +99,7 @@ describe('Items edge polyline', () => {
|
||||
// 'input',
|
||||
// )[8] as HTMLInputElement;
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
// $preventObstacleOverlapEdges.click();
|
||||
// $moveObstacle.click();
|
||||
// await expect(canvas).toMatchCanvasSnapshot(
|
||||
@ -107,7 +107,7 @@ describe('Items edge polyline', () => {
|
||||
// 'items-edge-polyline-prevent-overlap-edges',
|
||||
// );
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
// $preventObstacleOverlapEdges.click();
|
||||
// $moveObstacle.click();
|
||||
|
||||
@ -189,17 +189,17 @@ describe('Items edge polyline', () => {
|
||||
const $obstacle = document.querySelectorAll(
|
||||
'input',
|
||||
)[5] as HTMLInputElement;
|
||||
const $obstacleAvoidance = document.querySelectorAll(
|
||||
const $enableObstacleAvoidance = document.querySelectorAll(
|
||||
'input',
|
||||
)[6] as HTMLInputElement;
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
// await expect(canvas).toMatchSVGSnapshot(
|
||||
// dir,
|
||||
// 'items-edge-polyline-obstacle-avoidance',
|
||||
// );
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
|
||||
/**
|
||||
* Click the checkbox to prevent obstacle to overlap edges.
|
||||
@ -211,7 +211,7 @@ describe('Items edge polyline', () => {
|
||||
// 'input',
|
||||
// )[8] as HTMLInputElement;
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
// $preventObstacleOverlapEdges.click();
|
||||
// $moveObstacle.click();
|
||||
// await expect(canvas).toMatchSVGSnapshot(
|
||||
@ -219,7 +219,7 @@ describe('Items edge polyline', () => {
|
||||
// 'items-edge-polyline-prevent-overlap-edges',
|
||||
// );
|
||||
// $obstacle.click();
|
||||
// $obstacleAvoidance.click();
|
||||
// $enableObstacleAvoidance.click();
|
||||
// $preventObstacleOverlapEdges.click();
|
||||
// $moveObstacle.click();
|
||||
|
||||
|
@ -345,6 +345,6 @@ interface RouterCfg {
|
||||
* Whether to automatically avoid other nodes (obstacles) on the path
|
||||
* Defaults to false.
|
||||
*/
|
||||
obstacleAvoidance?: boolean;
|
||||
enableObstacleAvoidance?: boolean;
|
||||
}
|
||||
```
|
||||
|
@ -338,6 +338,6 @@ interface RouterCfg {
|
||||
* Whether to automatically avoid other nodes (obstacles) on the path
|
||||
* Defaults to false.
|
||||
*/
|
||||
obstacleAvoidance?: boolean;
|
||||
enableObstacleAvoidance?: boolean;
|
||||
}
|
||||
```
|
||||
|
@ -705,7 +705,7 @@ You only need to configure the labelShape for the Hull instance, and you can spe
|
||||
|
||||
- Polyline supports automatic obstacle avoidance:
|
||||
|
||||
Set `keyShape.routeCfg.obstacleAvoidance: true` for the edge to automatically avoid nodes.
|
||||
Set `keyShape.routeCfg.enableObstacleAvoidance: true` for the edge to automatically avoid nodes.
|
||||
|
||||
[Polyline Obstacle Avoidance DEMO](https://g6-next.antv.antgroup.com/examples/item/defaultEdges/#polyline3)
|
||||
|
||||
|
@ -752,7 +752,7 @@ v4 的坐标系统(三套)见文档:https://g6.antv.antgroup.com/manual/ad
|
||||
|
||||
- 折线支持自动避障:
|
||||
|
||||
设置边的 `keyShape.routeCfg.obstacleAvoidance: true` 即可自动躲避节点。
|
||||
设置边的 `keyShape.routeCfg.enableObstacleAvoidance: true` 即可自动躲避节点。
|
||||
|
||||
[Polyline 避障 DEMO](https://g6-next.antv.antgroup.com/examples/item/defaultEdges/#polyline3)
|
||||
|
||||
|
@ -47,7 +47,7 @@ const data = {
|
||||
},
|
||||
keyShape: {
|
||||
routeCfg: {
|
||||
obstacleAvoidance: false
|
||||
enableObstacleAvoidance: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ const data = {
|
||||
* 是否开启自动避障,默认为 false
|
||||
* Whether to enable automatic obstacle avoidance, default is false
|
||||
*/
|
||||
obstacleAvoidance: true,
|
||||
enableObstacleAvoidance: true,
|
||||
},
|
||||
/**
|
||||
* 拐弯处的圆角弧度,默认为直角,值为 0
|
||||
|
@ -231,7 +231,7 @@ const graph = new ExtGraph({
|
||||
lineWidth: 2,
|
||||
stroke: '#C2C8D5',
|
||||
routeCfg: {
|
||||
obstacleAvoidance: true,
|
||||
enableObstacleAvoidance: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user