leo-mind-map
Version:
一个简单的web在线思维导图
317 lines (299 loc) • 8.8 kB
JavaScript
import { Polygon, Path, SVG } from '@svgdotjs/svg.js'
import { CONSTANTS } from '../../../constants/constant'
// 节点形状类
export default class Shape {
constructor(node) {
this.node = node
this.mindMap = node.mindMap
}
// 形状需要的padding
getShapePadding(width, height, paddingX, paddingY) {
const shape = this.node.getShape()
const defaultPaddingX = 15
const defaultPaddingY = 5
const actWidth = width + paddingX * 2
const actHeight = height + paddingY * 2
const actOffset = Math.abs(actWidth - actHeight)
switch (shape) {
case CONSTANTS.SHAPE.ROUNDED_RECTANGLE:
return {
paddingX: height > width ? (height - width) / 2 : 0,
paddingY: 0
}
case CONSTANTS.SHAPE.DIAMOND:
return {
paddingX: width / 2,
paddingY: height / 2
}
case CONSTANTS.SHAPE.PARALLELOGRAM:
return {
paddingX: paddingX <= 0 ? defaultPaddingX : 0,
paddingY: 0
}
case CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE:
return {
paddingX: paddingX <= 0 ? defaultPaddingX : 0,
paddingY: 0
}
case CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE:
return {
paddingX: paddingX <= 0 ? defaultPaddingX : 0,
paddingY: 0
}
case CONSTANTS.SHAPE.ELLIPSE:
return {
paddingX: paddingX <= 0 ? defaultPaddingX : 0,
paddingY: paddingY <= 0 ? defaultPaddingY : 0
}
case CONSTANTS.SHAPE.CIRCLE:
return {
paddingX: actHeight > actWidth ? actOffset / 2 : 0,
paddingY: actHeight < actWidth ? actOffset / 2 : 0
}
}
const extendShape = this.getShapeFromExtendList(shape)
if (extendShape) {
return (
extendShape.getPadding({
node: this.node,
width,
height,
paddingX,
paddingY
}) || {
paddingX: 0,
paddingY: 0
}
)
} else {
return {
paddingX: 0,
paddingY: 0
}
}
}
// 从形状扩展列表里获取指定名称的形状
getShapeFromExtendList(shape) {
return this.mindMap.extendShapeList.find(item => {
return item.name === shape
})
}
// 创建形状节点
createShape() {
const shape = this.node.getShape()
let node = null
// 矩形
if (shape === CONSTANTS.SHAPE.RECTANGLE) {
node = this.createRect()
} else if (shape === CONSTANTS.SHAPE.DIAMOND) {
// 菱形
node = this.createDiamond()
} else if (shape === CONSTANTS.SHAPE.PARALLELOGRAM) {
// 平行四边形
node = this.createParallelogram()
} else if (shape === CONSTANTS.SHAPE.ROUNDED_RECTANGLE) {
// 圆角矩形
node = this.createRoundedRectangle()
} else if (shape === CONSTANTS.SHAPE.OCTAGONAL_RECTANGLE) {
// 八角矩形
node = this.createOctagonalRectangle()
} else if (shape === CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE) {
// 外三角矩形
node = this.createOuterTriangularRectangle()
} else if (shape === CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE) {
// 内三角矩形
node = this.createInnerTriangularRectangle()
} else if (shape === CONSTANTS.SHAPE.ELLIPSE) {
// 椭圆
node = this.createEllipse()
} else if (shape === CONSTANTS.SHAPE.CIRCLE) {
// 圆
node = this.createCircle()
}
if (!node) {
const extendShape = this.getShapeFromExtendList(shape)
if (extendShape) {
node = extendShape.createShape(this.node)
}
}
return node || this.createRect()
}
// 获取节点减去节点边框宽度、hover节点边框宽度后的尺寸
getNodeSize() {
const borderWidth = this.node.getBorderWidth()
let { width, height } = this.node
width -= borderWidth
height -= borderWidth
return {
width,
height
}
}
// 创建路径节点
createPath(pathStr) {
const { customCreateNodePath } = this.mindMap.opt
if (customCreateNodePath) {
return SVG(customCreateNodePath(pathStr))
}
return new Path().plot(pathStr)
}
// 创建多边形节点
createPolygon(points) {
const { customCreateNodePolygon } = this.mindMap.opt
if (customCreateNodePolygon) {
return SVG(customCreateNodePolygon(points))
}
return new Polygon().plot(points)
}
// 创建矩形
createRect() {
let { width, height } = this.getNodeSize()
let borderRadius = this.node.style.merge('borderRadius')
const pathStr = `
M${borderRadius},0
L${width - borderRadius},0
C${width - borderRadius},0 ${width},${0} ${width},${borderRadius}
L${width},${height - borderRadius}
C${width},${height - borderRadius} ${width},${height} ${
width - borderRadius
},${height}
L${borderRadius},${height}
C${borderRadius},${height} ${0},${height} ${0},${height - borderRadius}
L${0},${borderRadius}
C${0},${borderRadius} ${0},${0} ${borderRadius},${0}
Z
`
return this.createPath(pathStr)
}
// 创建菱形
createDiamond() {
let { width, height } = this.getNodeSize()
let halfWidth = width / 2
let halfHeight = height / 2
let topX = halfWidth
let topY = 0
let rightX = width
let rightY = halfHeight
let bottomX = halfWidth
let bottomY = height
let leftX = 0
let leftY = halfHeight
const points = [
[topX, topY],
[rightX, rightY],
[bottomX, bottomY],
[leftX, leftY]
]
return this.createPolygon(points)
}
// 创建平行四边形
createParallelogram() {
let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX
let { width, height } = this.getNodeSize()
const points = [
[paddingX, 0],
[width, 0],
[width - paddingX, height],
[0, height]
]
return this.createPolygon(points)
}
// 创建圆角矩形
createRoundedRectangle() {
let { width, height } = this.getNodeSize()
let halfHeight = height / 2
const pathStr = `
M${halfHeight},0
L${width - halfHeight},0
A${height / 2},${height / 2} 0 0,1 ${width - halfHeight},${height}
L${halfHeight},${height}
A${height / 2},${height / 2} 0 0,1 ${halfHeight},${0}
`
return this.createPath(pathStr)
}
// 创建八角矩形
createOctagonalRectangle() {
let w = 5
let { width, height } = this.getNodeSize()
const points = [
[0, w],
[w, 0],
[width - w, 0],
[width, w],
[width, height - w],
[width - w, height],
[w, height],
[0, height - w]
]
return this.createPolygon(points)
}
// 创建外三角矩形
createOuterTriangularRectangle() {
let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX
let { width, height } = this.getNodeSize()
const points = [
[paddingX, 0],
[width - paddingX, 0],
[width, height / 2],
[width - paddingX, height],
[paddingX, height],
[0, height / 2]
]
return this.createPolygon(points)
}
// 创建内三角矩形
createInnerTriangularRectangle() {
let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX
let { width, height } = this.getNodeSize()
const points = [
[0, 0],
[width, 0],
[width - paddingX / 2, height / 2],
[width, height],
[0, height],
[paddingX / 2, height / 2]
]
return this.createPolygon(points)
}
// 创建椭圆
createEllipse() {
let { width, height } = this.getNodeSize()
let halfWidth = width / 2
let halfHeight = height / 2
const pathStr = `
M${halfWidth},0
A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${height}
M${halfWidth},${height}
A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${0}
`
return this.createPath(pathStr)
}
// 创建圆
createCircle() {
let { width, height } = this.getNodeSize()
let halfWidth = width / 2
let halfHeight = height / 2
const pathStr = `
M${halfWidth},0
A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${height}
M${halfWidth},${height}
A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${0}
`
return this.createPath(pathStr)
}
}
// 形状列表
export const shapeList = [
CONSTANTS.SHAPE.RECTANGLE,
CONSTANTS.SHAPE.DIAMOND,
CONSTANTS.SHAPE.PARALLELOGRAM,
CONSTANTS.SHAPE.ROUNDED_RECTANGLE,
CONSTANTS.SHAPE.OCTAGONAL_RECTANGLE,
CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE,
CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE,
CONSTANTS.SHAPE.ELLIPSE,
CONSTANTS.SHAPE.CIRCLE
]