UNPKG

leo-mind-map

Version:

一个简单的web在线思维导图

395 lines (365 loc) 10.7 kB
import { checkIsNodeStyleDataKey } from '../../../utils/index' const backgroundStyleProps = [ 'backgroundColor', 'backgroundImage', 'backgroundRepeat', 'backgroundPosition', 'backgroundSize' ] export const shapeStyleProps = [ 'gradientStyle', 'startColor', 'endColor', 'startDir', 'endDir', 'fillColor', 'borderColor', 'borderWidth', 'borderDasharray' ] // 样式类 class Style { // 设置背景样式 static setBackgroundStyle(el, themeConfig) { if (!el) return // 缓存容器元素原本的样式 if (!Style.cacheStyle) { Style.cacheStyle = {} let style = window.getComputedStyle(el) backgroundStyleProps.forEach(prop => { Style.cacheStyle[prop] = style[prop] }) } // 设置新样式 let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig el.style.backgroundColor = backgroundColor if (backgroundImage && backgroundImage !== 'none') { el.style.backgroundImage = `url(${backgroundImage})` el.style.backgroundRepeat = backgroundRepeat el.style.backgroundPosition = backgroundPosition el.style.backgroundSize = backgroundSize } else { el.style.backgroundImage = 'none' } } // 移除背景样式 static removeBackgroundStyle(el) { if (!Style.cacheStyle) return backgroundStyleProps.forEach(prop => { el.style[prop] = Style.cacheStyle[prop] }) Style.cacheStyle = null } // 添加阴影效果 addShadow(node) { const styles = { boxShadowHorizontal: this.merge('boxShadowHorizontal'), boxShadowVertical: this.merge('boxShadowVertical'), boxShadowBlur: this.merge('boxShadowBlur'), boxShadowColor: this.merge('boxShadowColor') } // 只有当有阴影配置时才添加阴影效果 if (styles.boxShadowColor && (styles.boxShadowHorizontal || styles.boxShadowVertical || styles.boxShadowBlur)) { const offsetX = styles.boxShadowHorizontal || 0 const offsetY = styles.boxShadowVertical || 0 const blurRadius = styles.boxShadowBlur || 0 const color = styles.boxShadowColor // 使用 drop-shadow 滤镜函数 node.attr('filter', `drop-shadow(${offsetX}px ${offsetY}px ${blurRadius}px ${color})`) } } // 构造函数 constructor(ctx) { this.ctx = ctx // 箭头图标 this._markerPath = null this._marker = null // 渐变背景 this._gradient = null } // 合并样式 merge(prop, root) { let themeConfig = this.ctx.mindMap.themeConfig let defaultConfig = null let useRoot = false if (root) { // 使用最外层样式 useRoot = true defaultConfig = themeConfig } else if (this.ctx.isGeneralization) { // 概要节点 defaultConfig = themeConfig.generalization } else if (this.ctx.layerIndex === 0) { // 根节点 defaultConfig = themeConfig.root } else if (this.ctx.layerIndex === 1) { // 二级节点 defaultConfig = themeConfig.second } else { // 三级及以下节点 defaultConfig = themeConfig.node } let value = '' // 优先使用节点本身的样式 if (this.getSelfStyle(prop) !== undefined) { value = this.getSelfStyle(prop) } else if (defaultConfig[prop] !== undefined) { // 否则使用对应层级的样式 value = defaultConfig[prop] } else { // 否则使用最外层样式 value = themeConfig[prop] } if (!useRoot) { this.addToEffectiveStyles({ [prop]: value }) } return value } // 获取某个样式值 getStyle(prop, root) { return this.merge(prop, root) } // 获取自身自定义样式 getSelfStyle(prop) { return this.ctx.getData(prop) } // 更新当前节点生效的样式数据 addToEffectiveStyles(styles) { // effectiveStyles目前只提供给格式刷插件使用,所以如果没有注册该插件,那么不需要保存该数据 if (!this.ctx.mindMap.painter) return this.ctx.effectiveStyles = { ...this.ctx.effectiveStyles, ...styles } } // // 矩形 // rect(node) { // this.shape(node) // node.radius(this.merge('borderRadius') // } // 形状 shape(node) { const styles = {} shapeStyleProps.forEach(key => { styles[key] = this.merge(key) }) if (styles.gradientStyle) { if (!this._gradient) { this._gradient = this.ctx.nodeDraw.gradient('linear') } this._gradient.update(add => { add.stop(0, styles.startColor) add.stop(1, styles.endColor) }) this._gradient.from(...styles.startDir).to(...styles.endDir) node.fill(this._gradient) } else { node.fill({ color: styles.fillColor }) } this.addShadow(node) // 添加阴影 // 节点使用横线样式,不需要渲染非激活状态的边框样式 // if ( // !this.ctx.isRoot && // !this.ctx.isGeneralization && // this.ctx.mindMap.themeConfig.nodeUseLineStyle && // !this.ctx.getData('isActive') // ) { // return // } node.stroke({ color: styles.borderColor, width: styles.borderWidth, dasharray: styles.borderDasharray }) } // 文字 text(node) { const styles = { color: this.merge('color'), fontFamily: this.merge('fontFamily'), fontSize: this.merge('fontSize'), fontWeight: this.merge('fontWeight'), fontStyle: this.merge('fontStyle'), textDecoration: this.merge('textDecoration') } node .fill({ color: styles.color }) .css({ 'font-family': styles.fontFamily, 'font-size': styles.fontSize + 'px', 'font-weight': styles.fontWeight, 'font-style': styles.fontStyle, 'text-decoration': styles.textDecoration }) } // html文字节点 domText(node, fontSizeScale = 1) { const styles = { color: this.merge('color'), fontFamily: this.merge('fontFamily'), fontSize: this.merge('fontSize'), fontWeight: this.merge('fontWeight'), fontStyle: this.merge('fontStyle'), textDecoration: this.merge('textDecoration'), textAlign: this.merge('textAlign') } node.style.color = styles.color node.style.textDecoration = styles.textDecoration node.style.fontFamily = styles.fontFamily node.style.fontSize = styles.fontSize * fontSizeScale + 'px' node.style.fontWeight = styles.fontWeight || 'normal' node.style.fontStyle = styles.fontStyle node.style.textAlign = styles.textAlign } // 标签文字 tagText(node, style) { node .fill({ color: '#fff' }) .css({ 'font-size': style.fontSize + 'px' }) } // 标签矩形 tagRect(node, style) { node.fill({ color: style.fill }) if (style.radius) { node.radius(style.radius) } } // 内置图标 iconNode(node, color) { node.attr({ fill: color || this.merge('color') }) } // 连线 line(line, { width, color, dasharray } = {}, enableMarker, childNode) { const { customHandleLine } = this.ctx.mindMap.opt if (typeof customHandleLine === 'function') { customHandleLine(this.ctx, line, { width, color, dasharray }) } line.stroke({ color, dasharray, width }).fill({ color: 'none' }) // 可以显示箭头 if (enableMarker) { const showMarker = this.merge('showLineMarker', true) const childNodeStyle = childNode.style // 显示箭头 if (showMarker) { // 创建子节点箭头标记 childNodeStyle._marker = childNodeStyle._marker || childNodeStyle.createMarker() // 设置样式 childNodeStyle._markerPath.stroke({ color }).fill({ color }) // 箭头位置可能会发生改变,所以需要先删除 line.attr('marker-start', '') line.attr('marker-end', '') const dir = childNodeStyle.merge('lineMarkerDir') line.marker(dir, childNodeStyle._marker) } else if (childNodeStyle._marker) { // 不显示箭头,则删除该子节点的箭头标记 line.attr('marker-start', '') line.attr('marker-end', '') childNodeStyle._marker.remove() childNodeStyle._marker = null } } } // 创建箭头 createMarker() { return this.ctx.lineDraw.marker(20, 20, add => { add.ref(8, 5) add.size(20, 20) add.attr('markerUnits', 'userSpaceOnUse') add.attr('orient', 'auto-start-reverse') this._markerPath = add.path('M0,0 L2,5 L0,10 L10,5 Z') }) } // 概要连线 generalizationLine(node) { node .stroke({ width: this.merge('generalizationLineWidth', true), color: this.merge('generalizationLineColor', true) }) .fill({ color: 'none' }) } // 展开收起按钮 iconBtn(node, node2, fillNode) { let { color, fill, fontSize, fontColor } = this.ctx.mindMap.opt .expandBtnStyle || { color: '#808080', fill: '#fff', fontSize: 12, strokeColor: '#333333', fontColor: '#333333' } node.fill({ color: color }) node2.fill({ color: color }) fillNode.fill({ color: fill }) if (this.ctx.mindMap.opt.isShowExpandNum) { node.attr({ 'font-size': fontSize + 'px', 'font-color': fontColor }) } } // 是否设置了自定义的样式 hasCustomStyle() { let res = false Object.keys(this.ctx.getData()).forEach(item => { if (checkIsNodeStyleDataKey(item)) { res = true } }) return res } // 获取自定义的样式 getCustomStyle() { const customStyle = {} Object.keys(this.ctx.getData()).forEach(item => { if (checkIsNodeStyleDataKey(item)) { customStyle[item] = this.ctx.getData(item) } }) return customStyle } // hover和激活节点 hoverNode(node) { const hoverRectColor = this.merge('hoverRectColor') || this.ctx.mindMap.opt.hoverRectColor const hoverRectRadius = this.merge('hoverRectRadius') node.radius(hoverRectRadius).fill('none').stroke({ color: hoverRectColor }) } // 所属节点被删除时的操作 onRemove() { if (this._marker) { this._marker.remove() this._marker = null } if (this._markerPath) { this._markerPath.remove() this._markerPath = null } if (this._gradient) { this._gradient.remove() this._gradient = null } } } Style.cacheStyle = null export default Style