g6中如何开发一个文本自动换行组件

g6有两种模式,一种是svg,另一种是canvas,如果是svg的话,直接使用html制作,下面给出两种的做法,

效果图:

const createTextAreaShapeEvent = (cfg: any, group: any, graph: any, dragCb: Function) => {
  const graphEleRect = graph.value.cfg.container.getBoundingClientRect()
  const compTextAreaBox = group.find((element: any) => element.get('key') === 'compTextAreaBox')
  const dragGroup = group.find((element: any) => element.get('name') === 'dragGroup')

  compTextAreaBox.on('click', (e: any) => {
    dragGroup && dragGroup.show()
    e.stopPropagation()
  })

  compTextAreaBox.on('mouseover', (e: any) => {
    //dragGroup && dragGroup.show()
    //const findToolbarShape = findToolbar(group.cfg.item.getContainer())
    //findToolbarShape.hide()
  })

  graph.value.on('click', () => {
    dragGroup && dragGroup.hide()
    const model = group.cfg.item.getModel()
    model.node.data.nodeParams.textAreaBoxClicked = false
    group.cfg.item.update(model)
  })

  const bottomCenterMousedown = () => {
    document.onselectstart = () => {
      return false
    }

    const mouseMove = (moveEvent: MouseEvent) => {
      dragCb(true)
      const mouseY = moveEvent.clientY - graphEleRect.y - 12 - 28
      let val = 0
      if (mouseY >= cfg.y) {
        val = mouseY - cfg.y
      }

      if (val > 0) {
        const st = setTimeout(() => {
          clearTimeout(st)
          const model = group.cfg.item.getModel()
          model.size = [model.size[0], val + 28 + 12]
          model.node.data.nodeParams.textAreaBoxClicked = true
          group.cfg.item.update(model)
          dragCb(false)
        }, 0)
        //dragGroup && dragGroup.show()
        //const findToolbarShape = findToolbar(group.cfg.item.getContainer())
        //findToolbarShape.hide()
      }
    }
    const mouseUp = () => {
      document.removeEventListener('mousemove', mouseMove)
      document.removeEventListener('mouseup', mouseUp)
      document.onselectstart = () => {
        return true
      }
      const model = group.cfg.item.getModel()
      model.node.data.nodeParams.textAreaBoxClicked = false
    }
    document.addEventListener('mousemove', mouseMove)
    document.addEventListener('mouseup', mouseUp)
  }

  const dragPointBottomCenter = group.find(
    (element: any) => element.get('name') === 'dragPointBottomCenter'
  )

  dragPointBottomCenter.on('mousedown', bottomCenterMousedown)

  const rightMousedown = () => {
    document.onselectstart = () => {
      return false
    }

    const mouseMove = (moveEvent: MouseEvent) => {
      dragCb(true)
      const mouseX = moveEvent.clientX - graphEleRect.x - 100
      let val = 0
      if (mouseX >= cfg.x) {
        val = mouseX - cfg.x
      }

      if (val > 0) {
        const st = setTimeout(() => {
          clearTimeout(st)
          const model = group.cfg.item.getModel()
          model.size = [val + 100, model.size[1]]
          model.node.data.nodeParams.textAreaBoxClicked = true
          group.cfg.item.update(model)
          dragCb(false)
        }, 0)
      }
    }
    const mouseUp = () => {
      document.removeEventListener('mousemove', mouseMove)
      document.removeEventListener('mouseup', mouseUp)
      document.onselectstart = () => {
        return true
      }
      const model = group.cfg.item.getModel()
      model.node.data.nodeParams.textAreaBoxClicked = false
    }
    document.addEventListener('mousemove', mouseMove)
    document.addEventListener('mouseup', mouseUp)
  }

  const dragPointRight = group.find((element: any) => element.get('name') === 'dragPointRight')

  dragPointRight.on('mousedown', rightMousedown)

  /*const bottomRightMousedown = () => {
    document.onselectstart = () => {
      return false
    }

    const mouseMove = (moveEvent: MouseEvent) => {
      dragCb(true)
      const mouseX = moveEvent.clientX - graphEleRect.x - 100
      const mouseY = moveEvent.clientY - graphEleRect.y - 12 - 28
      const model = group.cfg.item.getModel()

      let yVal = 0
      if (mouseY >= cfg.y) {
        yVal = mouseY - cfg.y + 28 + 12
      } else {
        yVal = model.size[1]
      }

      let xVal = 0
      if (mouseX >= cfg.x) {
        xVal = mouseX - cfg.x + 100
      } else {
        xVal = model.size[0]
      }

      if (xVal > 0 || yVal > 0) {
        console.info(xVal,yVal)
        model.size = [xVal, yVal]
        group.cfg.item.update(model)
        dragCb(false)
      }
    }
    const mouseUp = () => {
      document.removeEventListener('mousemove', mouseMove)
      document.removeEventListener('mouseup', mouseUp)
      document.onselectstart = () => {
        return true
      }
    }
    document.addEventListener('mousemove', mouseMove)
    document.addEventListener('mouseup', mouseUp)
  }
  const dragPointBottomRight = group.find(
    (element: any) => element.get('name') === 'dragPointBottomRight'
  )

  dragPointBottomRight.on('mousedown', bottomRightMousedown)*/
}

const createTextAreaDargPoint = (
  group: any,
  cfg: any,
  dragPointSize: number,
  lineWidth: number,
  stroke: string,
  fill: string
) => {
  const size = cfg.size

  const dragGroup = group.addGroup({
    name: 'dragGroup'
  })

  dragGroup.addShape('rect', {
    draggable: false,
    attrs: {
      x: -1 + size[0] / 2,
      y: size[1] + dragPointSize,
      width: dragPointSize,
      height: dragPointSize,
      lineWidth: lineWidth,
      stroke: stroke,
      fill: fill
    },
    name: 'dragPointBottomCenter'
  })

  dragGroup.addShape('rect', {
    draggable: false,
    attrs: {
      x: size[0] - dragPointSize / 2,
      y: size[1] / 2 + dragPointSize / 2,
      width: dragPointSize,
      height: dragPointSize,
      lineWidth: lineWidth,
      stroke: stroke,
      fill: fill
    },
    name: 'dragPointRight'
  })

  if (cfg.node.data.nodeParams.textAreaBoxClicked) {
    dragGroup.show()
  } else {
    dragGroup.hide()
  }
}


G6.registerNode(
      'compTextAreaSvg',
      {
        draw: (cfg: any, group: any) => {
          group.addShape('dom', {
            attrs: {
              width: cfg.size[0] + 9,
              height: cfg.size[1],
              x: 0,
              y: 12,
              html: `
              <div class="editor-content-view">
              <pre  style="
               position: absolute;
               top:0,
               left:0,
               z-index:0;
               user-select: none;
               width:100%;
               height:100%;
               padding:${cfg.node.style.padding}px; 
               word-wrap: break-word;
               word-break: normal;
               border-radius:${cfg.node.style.boxRadius}px;
               white-space: pre-line;
               border:${cfg.node.style.boxLineWidth}px ${cfg.node.style.boxLineType} ${
                cfg.node.style.boxStroke
              };
               overflow-y:auto;
               background-color:${cfg.node.style.boxFill};
               "  >
               ${
                 cfg.node &&
                 cfg.node.data &&
                 cfg.node.data.nodeParams &&
                 cfg.node.data.nodeParams.text
                   ? cfg.node.data.nodeParams.text
                   : ''
               }
              </pre>
              </div>
              `
            },
            name: 'compTextAreaDom',
            draggable: false
          })

          const shape = group.addShape('rect', {
            draggable: true,
            attrs: {
              x: 0,
              y: 0,
              width: cfg.size[0],
              height: cfg.size[1] + 12,
              stroke: 'rgba(0,0,0,0)',
              fill: 'rgba(0,0,0,0)'
            },
            key: 'compTextAreaBox'
          })

          createTextAreaDargPoint(group, cfg, 8, 1.5, '#d98205', '#fff')
          //createToolbar(cfg, group, 3)

          return shape
        },
        afterDraw: (cfg: any, group: any) => {
          createTextAreaShapeEvent(cfg, group, graph, (val: boolean) => {})
        },
        update: undefined,
        setState(name, value, node) {
          if (name) {
            const eventNames = name.split(':')

            if (eventNames.length > 1) {
              const shapeName = eventNames[1]
              //对工具栏处理
              if (eventNames[0] === 'tooblar') {
                if (node) {
                  const group = node.get('group')
                  const model: any = node.getModel()

                  const find = model.toolbar.btns.find((item: any) => {
                    return item.data.name === shapeName
                  })

                  toolbarHoverStyle(group, find, value)
                }
              }
            } else {
              //节点鼠标hover处理
              /*if (eventNames[0] === 'nodeHover') {
                if (node) {
                  const findToolbarShape = findToolbar(node.getContainer())
                  if (value) {
                    findToolbarShape.show()
                  } else {
                    findToolbarShape.hide()
                  }
                }
              }*/
            }
          }
        }
      },
      'single-node'
    )

canvas做法:

const wrapTextIntoLines = (text: string, charsPerLine: number, fontSize: number) => {
  let lines = []
  while (true) {
    let endIndex = 1
    let width = 0
    for (let i = 0; i < text.length; i++) {
      endIndex++
      if (text[i] == '\n') {
        endIndex = endIndex - 1
        break
      }
      width += getLetterWidth(text[i], fontSize) + 0.135
      if (width >= charsPerLine) {
        endIndex = endIndex - 2
        break
      }
    }
    const subTxt = text.substring(0, endIndex)
    lines.push(replaceLastNewline(subTxt))
    text = text.substring(endIndex, text.length)
    if (text.length == 0) {
      break
    }
  }

  return lines.join('\n')
}

const isNumeric = (str: string) => {
  return /^\d+$/.test(str)
}

const isWhitespace = (str: string) => {
  return str.trim().length === 0
}

const isEnglishPunctuation = (str: string) => {
  return /^[.,?!;:'"()\[\]{}]+$/.test(str)
}

const replaceLastNewline = (str: string) => {
  return str.replace(/\n$/, '')
}

const isUpperCase = (str:string)=> {
  return /[A-Z]/.test(str);
}

const getLetterWidth = (letter: any, fontSize: number) => {
  let width = 0
  if (isNumeric(letter)) {
    return fontSize * 0.478572
  } else if (isWhitespace(letter)) {
    return 3.5
  } else if (isEnglishPunctuation(letter)) {
    return fontSize * 0.357143
  }else if(isUpperCase(letter)){
    return fontSize * 0.665
  } else {
    width = G6.Util.getLetterWidth(letter, fontSize)
  }
  return width
}

G6.registerNode(
      'compTextArea',
      {
        draw: (cfg: any, group: any) => {
          const width = cfg.size[0]
          const height = cfg.size[1] + 12
          const padding = cfg.node.style.padding
          const fontSize = cfg.node.style.fontSize
          const text =
            cfg.node &&
            cfg.node.data &&
            cfg.node.data.nodeParams &&
            cfg.node.data.nodeParams.textContent
              ? cfg.node.data.nodeParams.textContent
              : ''

          const compTextAreaTextWidth = width - padding * 2
          const compTextAreaTextHeight = height - padding * 2

          const lineHeight = fontSize + 6

          console.info(cfg.node)

          group.addShape('text', {
            attrs: {
              text: wrapTextIntoLines(text, compTextAreaTextWidth, fontSize),
              x: padding,
              y: padding,
              width: compTextAreaTextWidth,
              height: compTextAreaTextHeight,
              fontSize: fontSize,
              shadowColor: 'blue',
              textAlign: 'start',
              textBaseline: 'top',
              fontFamily: 'Arial, sans-serif',
              fill: cfg.node.style.fontColor,
              lineHeight: lineHeight
            },
            name: 'compTextAreaText',
            draggable: false
          })

          const lineDash: any = {
            solid: [],
            dashed: [10, 5],
            dotted: [2, 2]
          }

          const shape = group.addShape('rect', {
            draggable: true,
            attrs: {
              x: 0,
              y: 0,
              width: width,
              height: height,
              lineWidth: cfg.node.style.boxLineWidth,
              stroke: cfg.node.style.boxStroke,
              fill: cfg.node.style.boxFill,
              radius: cfg.node.style.boxRadius,
              lineDash: lineDash[cfg.node.style.boxLineType]
            },
            key: 'compTextAreaBox'
          })

          createTextAreaDargPoint(group, cfg, 8, 1.5, '#d98205', '#fff')

          return shape
        },
        afterDraw: (cfg: any, group: any) => {
          createTextAreaShapeEvent(cfg, group, graph, (val: boolean) => {})
        },
        update: undefined,
        setState(name, value, node) {
          if (name) {
            const eventNames = name.split(':')

            if (eventNames.length > 1) {
              const shapeName = eventNames[1]
              //对工具栏处理
              if (eventNames[0] === 'tooblar') {
                if (node) {
                  const group = node.get('group')
                  const model: any = node.getModel()

                  const find = model.toolbar.btns.find((item: any) => {
                    return item.data.name === shapeName
                  })

                  toolbarHoverStyle(group, find, value)
                }
              }
            } else {
              //节点鼠标hover处理
              /*if (eventNames[0] === 'nodeHover') {
                if (node) {
                  const findToolbarShape = findToolbar(node.getContainer())
                  if (value) {
                    findToolbarShape.show()
                  } else {
                    findToolbarShape.hide()
                  }
                }
              }*/
            }
          }
        }
      },
      'single-node'
    )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河马开源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值