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'
)