import { isString , isPlainObject , isNil , mix } from '@antv/util' ; import { IEdge , INode , ICombo } from '../interface/item' ; import { EdgeConfig , IPoint , NodeConfig , SourceTarget , Indexable , UpdateType } from '../types' ; import Item from './item' ; import Node from './node' ; const END_MAP = { source : 'start' , target : 'end' } ; const ITEM_NAME_SUFFIX = 'Node' ; const POINT_NAME_SUFFIX = 'Point' ; const ANCHOR_NAME_SUFFIX = 'Anchor' ; export default class Edge extends Item implements IEdge { protected getDefaultCfg ( ) { return { type : 'edge' , sourceNode : null , targetNode : null , startPoint : null , endPoint : null , linkCenter : false , } ; } private setEnd ( name , value ) { const pointName = END_MAP [ name ] + POINT_NAME_SUFFIX ; const itemName = name + ITEM_NAME_SUFFIX ; const preItem = this . get ( itemName ) ; if ( preItem && ! preItem . destroyed ) { preItem . removeEdge ( this ) ; } if ( isPlainObject ( value ) ) { this . set ( pointName , value ) ; this . set ( itemName , null ) ; } else if ( value ) { value ! . addEdge ( this ) ; this . set ( itemName , value ) ; this . set ( pointName , null ) ; } } param name param model param controlPoints private getLinkPoint ( name , model , controlPoints ) { const pointName = END_MAP [ name ] + POINT_NAME_SUFFIX ; const itemName = name + ITEM_NAME_SUFFIX ; let point = this . get ( pointName ) ; if ( ! point ) { const item = this . get ( itemName ) ; const anchorName = name + ANCHOR_NAME_SUFFIX ; const prePoint = this . getPrePoint ( name , controlPoints ) ; const anchorIndex = model [ anchorName ] ; if ( ! isNil ( anchorIndex ) ) { point = item . getLinkPointByAnchor ( anchorIndex ) ; } point = point || item . getLinkPoint ( prePoint ) ; if ( ! isNil ( point . index ) ) { this . set ( `${ name }AnchorIndex` , point . index ) ; } } return point ; } param name param controlPoints private getPrePoint ( name , controlPoints ) { if ( controlPoints && controlPoints . length ) { const index = name === 'source' ? 0 : controlPoints . length - 1 ; return controlPoints [ index ] ; } const oppositeName = name === 'source' ? 'target' : 'source' ; return this . getEndPoint ( oppositeName ) ; } param name private getEndPoint ( name ) { const itemName = name + ITEM_NAME_SUFFIX ; const pointName = END_MAP [ name ] + POINT_NAME_SUFFIX ; const item = this . get ( itemName ) ; if ( item ) { return item . get ( 'model' ) ; } return this . get ( pointName ) ; } param model private getControlPointsByCenter ( model ) { const sourcePoint = this . getEndPoint ( 'source' ) ; const targetPoint = this . getEndPoint ( 'target' ) ; const shapeFactory = this . get ( 'shapeFactory' ) ; const type = model . type ; return shapeFactory . getControlPoints ( type , { startPoint : sourcePoint , endPoint : targetPoint , } ) ; } private getEndCenter ( name ) { const itemName = name + ITEM_NAME_SUFFIX ; const pointName = END_MAP [ name ] + POINT_NAME_SUFFIX ; const item = this . get ( itemName ) ; if ( item ) { const bbox = item . getBBox ( ) ; return { x : bbox . centerX , y : bbox . centerY , } ; } return this . get ( pointName ) ; } protected init ( ) { super . init ( ) ; this . setSource ( this . get ( 'source' ) ) ; this . setTarget ( this . get ( 'target' ) ) ; } public getShapeCfg ( model , updateType ? ) { const self = this ; const linkCenter = self . get ( 'linkCenter' ) ; const cfg = updateType ?. includes ( 'move' ) ? model : super . getShapeCfg ( model ) as EdgeConfig ; if ( linkCenter ) { cfg . startPoint = self . getEndCenter ( 'source' ) ; cfg . endPoint = self . getEndCenter ( 'target' ) ; } else { const controlPoints = cfg . controlPoints || self . getControlPointsByCenter ( cfg ) ; cfg . startPoint = self . getLinkPoint ( 'source' , model , controlPoints ) ; cfg . endPoint = self . getLinkPoint ( 'target' , model , controlPoints ) ; } cfg . sourceNode = self . get ( 'sourceNode' ) ; cfg . targetNode = self . get ( 'targetNode' ) ; return cfg ; } /**
     * 获取边的数据模型
     */ public getModel ( ) { const out = this . get ( 'model' ) ; const sourceItem = this . get ( `source${ ITEM_NAME_SUFFIX }` ) ; const targetItem = this . get ( `target${ ITEM_NAME_SUFFIX }` ) ; if ( sourceItem ) { delete out [ `source${ ITEM_NAME_SUFFIX }` ] ; } else { out . source = this . get ( `start${ POINT_NAME_SUFFIX }` ) ; } if ( targetItem ) { delete out [ `target${ ITEM_NAME_SUFFIX }` ] ; } else { out . target = this . get ( `end${ POINT_NAME_SUFFIX }` ) ; } if ( ! isString ( out . source ) && ! isPlainObject ( out . source ) ) { out . source = ( out . source as any ) . getID ( ) ; } if ( ! isString ( out . target ) && ! isPlainObject ( out . target ) ) { out . target = ( out . target as any ) . getID ( ) ; } return out ; } public setSource ( source ) { this . setEnd ( 'source' , source ) ; this . set ( 'source' , source ) ; } public setTarget ( target ) { this . setEnd ( 'target' , target ) ; this . set ( 'target' , target ) ; } public getSource ( ) { return this . get ( 'source' ) ; } public getTarget ( ) { return this . get ( 'target' ) ; } public updatePosition ( ) { return false ; } param { object } cfg public update ( cfg , updateType = undefined ) { const model = this . get ( 'model' ) ; const oriVisible = model . visible ; const cfgVisible = cfg . visible ; if ( oriVisible !== cfgVisible && cfgVisible !== undefined ) this . changeVisibility ( cfgVisible ) ; const styles = this . get ( 'styles' ) ; if ( cfg . stateStyles ) { const { stateStyles } = cfg ; mix ( styles , stateStyles ) ; delete cfg . stateStyles ; } Object . assign ( model , cfg ) ; this . updateShape ( updateType ) ; this . afterUpdate ( ) ; this . clearCache ( ) ; } public destroy ( ) { const sourceItem = this . get ( `source${ ITEM_NAME_SUFFIX }` ) ; const targetItem = this . get ( `target${ ITEM_NAME_SUFFIX }` ) ; if ( sourceItem && ! sourceItem . destroyed ) { sourceItem . removeEdge ( this ) ; } if ( targetItem && ! targetItem . destroyed ) { targetItem . removeEdge ( this ) ; } super . destroy ( ) ; } }