Location>code7788 >text

Front-end Visual Designer with Konva (19) - Connecting Lines - Straight Lines, Folding Lines

Popularity:156 ℃/2024-08-01 23:12:36

This chapter responds to the feedback of partners, in addition to the algorithm automatically draw the connection line (still need to optimize the perfect), the realization of a straight line can be drawn manually, folding line connection line function.

Please give me a free Star!

If you find any bugs, please feel free to raise an Issue!

github source code

gitee source code

sample address (computing)

Mode switching

image

pre-production

Connection line Mode type

// src/Render/
export enum LinkType {
  'auto' = 'auto', // straight
  'straight' = 'straight', // straight line
  'manual' = 'manual' // manually folded line
}

Connection line Mode status

// src/Render/draws/

// Link lines (temporary)
export interface LinkDrawState {
  // Omitted
  linkType: // Link type
  linkManualing: boolean // Whether the inflection point is being manipulated.
}

Connection cable Mode switching method

// src/Render/draws/

  /**
   * Modify the current link type
   * @param linkType
   */
  changeLinkType(linkType: ) {
     = linkType
    ? .on?.linkTypeChange? ()
  }

Connection cable Mode switching button

<! -- src/ -->!

<button @click="onLinkTypeChange()"
        :disabled="currentLinkType === ">Link line: auto</button>
<button @click="onLinkTypeChange()"
        :disabled="currentLinkType === ">Link line: straight</button>
<button @click="onLinkTypeChange()"
        :disabled="currentLinkType === ">Link line: manual</button>

Connection line Mode switch event

// src/
const currentLinkType = ref()
​
function onLinkTypeChange(linkType: ) {
  (render?.draws[] as ).changeLinkType(linkType)
}

Current pair Record current cable mode

// src/Render/draws/

export class LinkDraw extends implements {
  // summarize
  override draw() {
    // summarize
  
    // connection point
    for (const point of points) {
      // summarize
    
      // unselect
      if (group && !('selected')) {
        // summarize
        const anchor = (`#${}`)

        if (anchor) {
          // summarize
          ('mouseup', () => {
            if () {
              // summarize
              
              // 不同connection point
              if (() !== ()) {
                // summarize
                if (toGroup) {
                  // summarize
                  if (fromPoint) {
                    // summarize
                    if (toPoint) {
                      if (()) {
                         = [
                          ...,
                          {
                            // summarize
                            
                            linkType: // recording line typology
                          }
                        ]
                      }
                      // summarize
                    }
                  }
                }
              }
              // summarize
            }
          })
          // summarize
        }
      }
    }
  }
}

straightness

image

Drawing a line is relatively simple. You can draw a line from the starting point to the end point by determining the pattern of the lines recorded in the pair:

// src/Render/draws/

export class LinkDraw extends implements {
  // summarize
  override draw() {
    // summarize
  
    // connection line
    for (const pair of pairs) {
        if ( === ) {
          // summarize,Manual Folding Line
        } else if ( === ) {
          // straightness

          if (fromGroup && toGroup && fromPoint && toPoint) {
            const fromAnchor = (`#${}`)
            const toAnchor = (`#${}`)

            // Anchor information
            const fromAnchorPos = (fromAnchor)
            const toAnchorPos = (toAnchor)

            const linkLine = new ({
              name: 'link-line',
              // 用于删除connection line
              groupId: (),
              pointId: ,
              pairId: ,
              linkType: ,

              points: _.flatten([
                [
                  (),
                  ()
                ],
                [(), ()]
              ]),
              stroke: 'red',
              strokeWidth: 2
            })

            (linkLine)
          }
        } else {
          // summarize,原算法画connection line逻辑
        }
    }
  }
}

broken line (continuous figure made up of straight line segments)

image

To draw a polyline, there are 3 kinds of "points" defined: 1) Connection point, which is the original one. 2) Point of inflection (to be inflected), which is blue and has never been dragged. 2, point of inflection (to be inflection), blue, never dragged, once dragged, will be added to the inflection point record. 3, inflection point (already inflection), green, has been dragged, can still be dragged, but will not add new inflection point records.

image

Note the comments in the code below, key:

  • The fromGroup records manualPoints.
  • Linking lines are drawn from Start -> Turning Points -> LinkPoints.
  • Draws a temporary dashed Line while the inflection point is being dragged.
  • The point of inflection (to be inflected) and the point of inflection (already inflected) are handled separately.

The main difference between dealing with a point of inflection (to be inflected) and a point of inflection (already inflected) is:

  • To handle inflection points (to be inflected), linkPoints are traversed in pairs.
  • To handle inflection points (already inflected), the start and end points are skipped when traversing linkPoints.
  • Dragging an inflection point (to be inflected) adds a new inflection point record.
  • Dragging an inflection point (already inflected) does not add a new inflection point record.
// src/Render/draws/
​
export class LinkDraw extends  implements  {
  // summarize
  override draw() {
    // summarize
  
    // connection line
    for (const pair of pairs) {
        if ( === ) {
          // Manual Folding Line
​
          if (fromGroup && toGroup && fromPoint && toPoint) {
            const fromAnchor = (`#${}`)
            const toAnchor = (`#${}`)
​
            // Anchor information
            const fromAnchorPos = (fromAnchor)
            const toAnchorPos = (toAnchor)
​
            // inflexion point (math., a point of a curve at which the curvature changes sign)(abducted)record (in sports etc)
            const manualPoints: Array<{ x: number; y: number }> = (
              ('manualPoints')
            )
              ? ('manualPoints')
              : []
​
            // connection point + inflexion point (math., a point of a curve at which the curvature changes sign)
            const linkPoints = [
              [
                (),
                ()
              ],
              ...((o) => [, ]),
              [(), ()]
            ]
​
            // connection line
            const linkLine = new ({
              name: 'link-line',
              // 用于删除connection line
              groupId: (),
              pointId: ,
              pairId: ,
              linkType: ,
​
              points: _.flatten(linkPoints),
              stroke: 'red',
              strokeWidth: 2
            })
​
            (linkLine)
​
            // Drag effect in progress
            const manualingLine = new ({
              stroke: '#ff0000',
              strokeWidth: 2,
              points: [],
              dash: [4, 4]
            })
            (manualingLine)
​
            // inflexion point (math., a point of a curve at which the curvature changes sign)
​
            // inflexion point (math., a point of a curve at which the curvature changes sign)(awaiting abduction)
            for (let i = 0; i <  - 1; i++) {
              const circle = new ({
                id: nanoid(),
                pairId: ,
                x: (linkPoints[i][0] + linkPoints[i + 1][0]) / 2,
                y: (linkPoints[i][1] + linkPoints[i + 1][1]) / 2,
                radius: ( / 2),
                stroke: 'rgba(0,0,255,0.1)',
                strokeWidth: (1),
                name: 'link-manual-point',
                // opacity: 0,
                linkManualIndex: i // 当前inflexion point (math., a point of a curve at which the curvature changes sign)位置
              })
​
              // hover effect
              ('mouseenter', () => {
                ('rgba(0,0,255,0.8)')
                 = 'pointer'
              })
              ('mouseleave', () => {
                if (!) {
                  ('rgba(0,0,255,0.1)')
                   = 'default'
                }
              })
​
              // inflexion point (math., a point of a curve at which the curvature changes sign)操作
              ('mousedown', () => {
                const pos = ()
​
                // record (in sports etc)操作开始state of affairs
                ({
                  // Starting coordinates
                  dragStartX: ,
                  dragStartY: ,
                  // in operation
                  dragStart: true
                })
​
                // marking status - in operationinflexion point (math., a point of a curve at which the curvature changes sign)
                 = true
              })
              ('mousemove', () => {
                if () {
                  // in operation
                  const pos = ()
                  if (pos) {
                    // paste paste (e.g. on a computer screen)
                    const { pos: transformerPos } = ({
                      x: ,
                      y: ,
                      width: 1,
                      height: 1
                    })
​
                    // 移动inflexion point (math., a point of a curve at which the curvature changes sign)
                    (transformerPos)
​
                    // Drag effect in progress
                    const tempPoints = [...linkPoints]
                    ( + 1, 0, [
                      ( - ),
                      ( - )
                    ])
                    (_.flatten(tempPoints))
                  }
                }
              })
              ('mouseup', () => {
                const pos = ()
​
                if (
                  ( - ) >  ||
                  ( - ) > 
                ) {
                  // Operation travel distance reaches threshold
​
                  // stage state of affairs
                  const stageState = ()
​
                  // record (in sports etc)(stick)inflexion point (math., a point of a curve at which the curvature changes sign)
                  (, 0, {
                    x: ( - ),
                    y: ( - )
                  })
                  ('manualPoints', manualPoints)
                }
​
                // End of operation
                ({
                  dragStart: false
                })
​
                // state End of operation
                 = false
​
                // destroy (by melting or burning)
                ()
                ()
​
                // Update History
                ()
​
                // repaint
                ()
              })
​
              (circle)
            }
​
            // inflexion point (math., a point of a curve at which the curvature changes sign)(abducted)
            for (let i = 1; i <  - 1; i++) {
              const circle = new ({
                id: nanoid(),
                pairId: ,
                x: linkPoints[i][0],
                y: linkPoints[i][1],
                radius: ( / 2),
                stroke: 'rgba(0,100,0,0.1)',
                strokeWidth: (1),
                name: 'link-manual-point',
                // opacity: 0,
                linkManualIndex: i // 当前inflexion point (math., a point of a curve at which the curvature changes sign)位置
              })
​
              // hover effect
              ('mouseenter', () => {
                ('rgba(0,100,0,1)')
                 = 'pointer'
              })
              ('mouseleave', () => {
                if (!) {
                  ('rgba(0,100,0,0.1)')
                   = 'default'
                }
              })
​
              // inflexion point (math., a point of a curve at which the curvature changes sign)操作
              ('mousedown', () => {
                const pos = ()
​
                // record (in sports etc)操作开始state of affairs
                ({
                  dragStartX: ,
                  dragStartY: ,
                  dragStart: true
                })
​
                // marking status - in operationinflexion point (math., a point of a curve at which the curvature changes sign)
                 = true
              })
              ('mousemove', () => {
                if () {
                  // in operation
                  const pos = ()
                  if (pos) {
                    // paste paste (e.g. on a computer screen)
                    const { pos: transformerPos } = ({
                      x: ,
                      y: ,
                      width: 1,
                      height: 1
                    })
​
                    // 移动inflexion point (math., a point of a curve at which the curvature changes sign)
                    (transformerPos)
​
                    // Drag effect in progress
                    const tempPoints = [...linkPoints]
                    tempPoints[] = [
                      ( - ),
                      ( - )
                    ]
                    (_.flatten(tempPoints))
                  }
                }
              })
              ('mouseup', () => {
                const pos = ()
​
                if (
                  ( - ) >  ||
                  ( - ) > 
                ) {
                  // Operation travel distance reaches threshold
​
                  // stage state of affairs
                  const stageState = ()
​
                  // record (in sports etc)(update)inflexion point (math., a point of a curve at which the curvature changes sign)
                  manualPoints[ - 1] = {
                    x: ( - ),
                    y: ( - )
                  }
                  ('manualPoints', manualPoints)
                }
​
                // End of operation
                ({
                  dragStart: false
                })
​
                // state End of operation
                 = false
​
                // destroy (by melting or burning)
                ()
                ()
​
                // Update History
                ()
​
                // repaint
                ()
              })
​
              (circle)
            }
          }
        } else if ( === ) {
          // summarize,straightness
        } else {
          // summarize,原算法画connection line逻辑
        }
    }
  }
}

Finally, regarding the linkManualing state, it will be used in 2 places to avoid conflicts with other interactions:

// src/Render/handlers/

// summarize

export class DragHandlers implements {
  // summarize
  handlers = {
    stage: {
      mousedown: (e: <GlobalEventHandlersEventMap['mousedown']>) => {
        // Inflection point in operation,Prevents abnormal dragging
        if (!([] as ).) {
          // summarize
        }
      },
      // summarize
    }
  }
}
// src/Render/tools/

// summarize
export class LinkTool {
  // summarize

  pointsVisible(visible: boolean, group?: ) {
    // summarize

    // Inflection point in operation,No repainting here
    if (!([] as ).) {
      // repaint
      ()
    }
  }
  // summarize
}

Done!

More Stars please!

source code (computing)

gitee source code

sample address (computing)