@@ -5,10 +5,13 @@ import { createSvgGroup, editSvgText } from './utils/svg'
55import type { CustomSvg , Topic } from './types/dom'
66import type { MindElixirInstance , Uid } from './index'
77
8- // p1: starting point
9- // p2: control point of starting point
10- // p3: control point of ending point
11- // p4: ending point
8+ /**
9+ * FYI
10+ * p1: starting point
11+ * p2: control point of starting point
12+ * p3: control point of ending point
13+ * p4: ending point
14+ */
1215
1316export type Arrow = {
1417 id : string
@@ -23,6 +26,7 @@ export type Arrow = {
2326 x : number
2427 y : number
2528 }
29+ bidirectional ?: boolean
2630}
2731export type DivData = {
2832 cx : number // center x
@@ -32,7 +36,13 @@ export type DivData = {
3236 ctrlX : number // control point x
3337 ctrlY : number // control point y
3438}
39+ export type ArrowOptions = {
40+ bidirectional ?: boolean
41+ }
3542
43+ /**
44+ * calc control point, center point and div size
45+ */
3646function calcCtrlP ( mei : MindElixirInstance , tpc : Topic , delta : { x : number ; y : number } ) {
3747 const { offsetLeft : x , offsetTop : y } = getOffsetLT ( mei . nodes , tpc )
3848 const w = tpc . offsetWidth
@@ -51,7 +61,9 @@ function calcCtrlP(mei: MindElixirInstance, tpc: Topic, delta: { x: number; y: n
5161 }
5262}
5363
54- // calc starting and ending point using control point and div status
64+ /**
65+ * calc starting and ending point using control point and div status
66+ */
5567function calcP ( data : DivData ) {
5668 let x , y
5769 const k = ( data . cy - data . ctrlY ) / ( data . ctrlX - data . cx )
@@ -104,12 +116,15 @@ const drawArrow = function (mei: MindElixirInstance, from: Topic, to: Topic, obj
104116 const { ctrlX : p3x , ctrlY : p3y } = toData
105117 const { x : p4x , y : p4y } = calcP ( toData )
106118
107- const arrowPoint = getArrowPoints ( p3x , p3y , p4x , p4y )
119+ const arrowT = getArrowPoints ( p3x , p3y , p4x , p4y )
108120
109- const newSvgGroup = createSvgGroup (
110- `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` ,
111- `M ${ arrowPoint . x1 } ${ arrowPoint . y1 } L ${ p4x } ${ p4y } L ${ arrowPoint . x2 } ${ arrowPoint . y2 } `
112- )
121+ const toArrow = `M ${ arrowT . x1 } ${ arrowT . y1 } L ${ p4x } ${ p4y } L ${ arrowT . x2 } ${ arrowT . y2 } `
122+ let fromArrow = ''
123+ if ( obj . bidirectional ) {
124+ const arrowF = getArrowPoints ( p2x , p2y , p1x , p1y )
125+ fromArrow = `M ${ arrowF . x1 } ${ arrowF . y1 } L ${ p1x } ${ p1y } L ${ arrowF . x2 } ${ arrowF . y2 } `
126+ }
127+ const newSvgGroup = createSvgGroup ( `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` , toArrow , fromArrow )
113128
114129 const halfx = p1x / 8 + ( p2x * 3 ) / 8 + ( p3x * 3 ) / 8 + p4x / 8
115130 const halfy = p1y / 8 + ( p2y * 3 ) / 8 + ( p3y * 3 ) / 8 + p4y / 8
@@ -128,7 +143,7 @@ const drawArrow = function (mei: MindElixirInstance, from: Topic, to: Topic, obj
128143 console . log ( `DrawArrow Execution time: ${ end - start } ms` )
129144}
130145
131- export const createArrow = function ( this : MindElixirInstance , from : Topic , to : Topic ) {
146+ export const createArrow = function ( this : MindElixirInstance , from : Topic , to : Topic , options : ArrowOptions = { } ) {
132147 const arrowObj = {
133148 id : generateUUID ( ) ,
134149 label : 'Custom Link' ,
@@ -142,6 +157,7 @@ export const createArrow = function (this: MindElixirInstance, from: Topic, to:
142157 x : 0 ,
143158 y : - 200 ,
144159 } ,
160+ ...options ,
145161 }
146162 drawArrow ( this , from , to , arrowObj )
147163
@@ -229,8 +245,8 @@ const showLinkController = function (mei: MindElixirInstance, linkItem: Arrow, f
229245 mei . helper1 = LinkDragMoveHelper . create ( mei . P2 )
230246 mei . helper2 = LinkDragMoveHelper . create ( mei . P3 )
231247
232- // TODO: generate cb function
233248 mei . helper1 . init ( mei . map , ( deltaX , deltaY ) => {
249+ if ( ! mei . currentArrow ) return
234250 // recalc key points
235251 p2x = p2x + deltaX / mei . scaleVal
236252 p2y = p2y + deltaY / mei . scaleVal
@@ -242,8 +258,12 @@ const showLinkController = function (mei: MindElixirInstance, linkItem: Arrow, f
242258 // update dom position
243259 mei . P2 . style . top = p2y + 'px'
244260 mei . P2 . style . left = p2x + 'px'
245- mei . currentArrow ?. children [ 0 ] . setAttribute ( 'd' , `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` )
246- setAttributes ( mei . currentArrow ! . children [ 2 ] , {
261+ mei . currentArrow . children [ 0 ] . setAttribute ( 'd' , `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` )
262+ if ( linkItem . bidirectional ) {
263+ const arrowPoint = getArrowPoints ( p2x , p2y , p1x , p1y )
264+ mei . currentArrow . children [ 2 ] . setAttribute ( 'd' , `M ${ arrowPoint . x1 } ${ arrowPoint . y1 } L ${ p1x } ${ p1y } L ${ arrowPoint . x2 } ${ arrowPoint . y2 } ` )
265+ }
266+ setAttributes ( mei . currentArrow . children [ 3 ] , {
247267 x : halfx + '' ,
248268 y : halfy + '' ,
249269 } )
@@ -259,6 +279,7 @@ const showLinkController = function (mei: MindElixirInstance, linkItem: Arrow, f
259279 } )
260280
261281 mei . helper2 . init ( mei . map , ( deltaX , deltaY ) => {
282+ if ( ! mei . currentArrow ) return
262283 p3x = p3x + deltaX / mei . scaleVal
263284 p3y = p3y + deltaY / mei . scaleVal
264285 const p4 = calcP ( { ...toData , ctrlX : p3x , ctrlY : p3y } )
@@ -270,9 +291,9 @@ const showLinkController = function (mei: MindElixirInstance, linkItem: Arrow, f
270291
271292 mei . P3 . style . top = p3y + 'px'
272293 mei . P3 . style . left = p3x + 'px'
273- mei . currentArrow ? .children [ 0 ] . setAttribute ( 'd' , `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` )
274- mei . currentArrow ? .children [ 1 ] . setAttribute ( 'd' , `M ${ arrowPoint . x1 } ${ arrowPoint . y1 } L ${ p4x } ${ p4y } L ${ arrowPoint . x2 } ${ arrowPoint . y2 } ` )
275- setAttributes ( mei . currentArrow ! . children [ 2 ] , {
294+ mei . currentArrow . children [ 0 ] . setAttribute ( 'd' , `M ${ p1x } ${ p1y } C ${ p2x } ${ p2y } ${ p3x } ${ p3y } ${ p4x } ${ p4y } ` )
295+ mei . currentArrow . children [ 1 ] . setAttribute ( 'd' , `M ${ arrowPoint . x1 } ${ arrowPoint . y1 } L ${ p4x } ${ p4y } L ${ arrowPoint . x2 } ${ arrowPoint . y2 } ` )
296+ setAttributes ( mei . currentArrow . children [ 3 ] , {
276297 x : halfx + '' ,
277298 y : halfy + '' ,
278299 } )
@@ -304,7 +325,7 @@ export function renderArrow(this: MindElixirInstance) {
304325export function editArrowLabel ( this : MindElixirInstance , el : CustomSvg ) {
305326 console . time ( 'editSummary' )
306327 if ( ! el ) return
307- const textEl = el . children [ 2 ]
328+ const textEl = el . children [ 3 ]
308329 editSvgText ( this , textEl , div => {
309330 const node = el . arrowObj
310331 const text = div . textContent ?. trim ( ) || ''
0 commit comments