diff --git a/simple-mind-map/src/core/render/node/Node.js b/simple-mind-map/src/core/render/node/Node.js index c382b087..7038c21c 100644 --- a/simple-mind-map/src/core/render/node/Node.js +++ b/simple-mind-map/src/core/render/node/Node.js @@ -1,6 +1,6 @@ import Style from './Style' import Shape from './Shape' -import { G, ForeignObject, Rect } from '@svgdotjs/svg.js' +import { G, ForeignObject, Rect, Defs } from '@svgdotjs/svg.js' import nodeGeneralizationMethods from './nodeGeneralization' import nodeExpandBtnMethods from './nodeExpandBtn' import nodeCommandWrapsMethods from './nodeCommandWraps' @@ -63,6 +63,8 @@ class Node { this.userList = [] // 节点内容的容器 this.group = null + this.defsNode = null // 节点静态元素 + this.gradientNode = null // 节点渐变背景 this.shapeNode = null // 节点形状节点 this.hoverNode = null // 节点hover和激活的节点 // 节点内容对象 @@ -299,11 +301,17 @@ class Node { let { paddingY } = this.getPaddingVale() const halfBorderWidth = this.getBorderWidth() / 2 paddingY += this.shapePadding.paddingY + halfBorderWidth + // 节点静态元素 + this.defsNode = new Defs() + // 节点渐变背景 + this.gradientNode = this.style.createGradient() + this.defsNode.add(this.gradientNode) + this.group.add(this.defsNode) // 节点形状 this.shapeNode = this.shapeInstance.createShape() this.shapeNode.addClass('smm-node-shape') this.shapeNode.translate(halfBorderWidth, halfBorderWidth) - this.style.shape(this.shapeNode) + this.style.shape(this.shapeNode, this.gradientNode.id()) this.group.add(this.shapeNode) // 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示 this.renderExpandBtnPlaceholderRect() diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index 0a36e433..2a0daf3a 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -2,6 +2,7 @@ import { checkIsNodeStyleDataKey, generateColorByContent } from '../../../utils/index' +import { Gradient } from '@svgdotjs/svg.js' const rootProp = ['paddingX', 'paddingY'] const backgroundStyleProps = [ @@ -89,6 +90,14 @@ class Style { return this.merge(prop, root) } + createGradient() { + let gradient = new Gradient("linear") + gradient.id() + gradient.stop(0,this.merge('startColor')) + gradient.stop(1, this.merge('endColor')) + return gradient + } + // 获取自身自定义样式 getSelfStyle(prop) { return this.ctx.getData(prop) @@ -101,10 +110,18 @@ class Style { } // 矩形外的其他形状 - shape(node) { - node.fill({ - color: this.merge('fillColor') - }) + shape(node, uid) { + if (this.merge('gradientStyle')) { + node.fill('url(#' + uid + ')' + ) + } else { + node.fill({ + color: this.merge('fillColor') + }) + } + // node.fill({ + // color: this.merge('fillColor') + // }) // 节点使用横线样式,不需要渲染非激活状态的边框样式 // if ( // !this.ctx.isRoot && diff --git a/simple-mind-map/src/themes/default.js b/simple-mind-map/src/themes/default.js index 53185f22..4cf34510 100644 --- a/simple-mind-map/src/themes/default.js +++ b/simple-mind-map/src/themes/default.js @@ -72,7 +72,10 @@ export default { borderWidth: 0, borderDasharray: 'none', borderRadius: 5, - textDecoration: 'none' + textDecoration: 'none', + gradientStyle: false, + startColor: '#549688', + endColor: '#fff', }, // 二级节点样式 second: { @@ -90,7 +93,10 @@ export default { borderWidth: 1, borderDasharray: 'none', borderRadius: 5, - textDecoration: 'none' + textDecoration: 'none', + gradientStyle: false, + startColor: '#549688', + endColor: '#fff', }, // 三级及以下节点样式 node: { @@ -108,7 +114,10 @@ export default { borderWidth: 0, borderRadius: 5, borderDasharray: 'none', - textDecoration: 'none' + textDecoration: 'none', + gradientStyle: false, + startColor: '#549688', + endColor: '#fff', }, // 概要节点样式 generalization: { @@ -126,7 +135,10 @@ export default { borderWidth: 1, borderDasharray: 'none', borderRadius: 5, - textDecoration: 'none' + textDecoration: 'none', + gradientStyle: false, + startColor: '#549688', + endColor: '#fff', } } diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index 5482a1e7..1d748513 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -200,7 +200,10 @@ export default { line: '线条', nodePadding: '节点内边距', horizontal: '水平', - vertical: '垂直' + vertical: '垂直', + gradientStyle: '渐变', + startColor: '起始', + endColor: '结束' }, theme: { title: '主题', diff --git a/web/src/pages/Edit/components/Style.vue b/web/src/pages/Edit/components/Style.vue index 197728e4..483a2b40 100644 --- a/web/src/pages/Edit/components/Style.vue +++ b/web/src/pages/Edit/components/Style.vue @@ -249,6 +249,48 @@ +
+
+ {{ $t('style.gradientStyle') }} +
+ {{style.gradientStyle ? '渐变' : '单一'}} +
+
+
+ {{ $t('style.startColor') }} + + + + +
+
+ {{ $t('style.endColor') }} + + + + +
+
{{ $t('style.shape') }}
@@ -443,7 +485,10 @@ export default { borderRadius: '', lineColor: '', lineDasharray: '', - lineWidth: '' + lineWidth: '', + gradientStyle: false, + startColor: '', + endColor: '' } } }, @@ -518,7 +563,10 @@ export default { 'borderRadius', 'lineColor', 'lineDasharray', - 'lineWidth' + 'lineWidth', + 'gradientStyle', + 'startColor', + 'endColor' ].forEach(item => { this.style[item] = this.activeNodes[0].getStyle(item, false) }) @@ -601,6 +649,40 @@ export default { changeFillColor(color) { this.style.fillColor = color this.update('fillColor') + }, + + /** + * @Author: lxr_cel + * @Date: 2024-01-02 10:28:17 + * @Desc: 切换渐变背景 + */ + toggleGradientStyle() { + if (this.style.gradientStyle === false) { + this.style.gradientStyle = true + } else { + this.style.gradientStyle = false + } + this.update('gradientStyle') + }, + + /** + * @Author: lxr_cel + * @Date: 2024-01-02 11:09:27 + * @Desc: 切换渐变开始颜色 + */ + changeStartColor(color) { + this.style.startColor = color; + this.update('startColor') + }, + + /** + * @Author: lxr_cel + * @Date: 2024-01-02 10:10:34 + * @Desc: 切换渐变结束颜色 + */ + changeEndColor(color) { + this.style.endColor = color; + this.update('endColor') } } }