diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index a4040487..cdf76ede 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -201,5 +201,10 @@ export const defaultOpt = { dragOpacityConfig: { cloneNodeOpacity: 0.5, // 跟随鼠标移动的克隆节点或矩形的透明度 beingDragNodeOpacity: 0.3 // 被拖拽节点的透明度 + }, + // 自定义标签的颜色 + // {pass: 'green, unpass: 'red'} + tagsColorMap: { + pass: 'green' } } diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index 55dc9b22..f638775b 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -1,5 +1,8 @@ import { tagColorList } from '../../../constants/constant' -import { checkIsNodeStyleDataKey } from '../../../utils/index' +import { + checkIsNodeStyleDataKey, + generateColorByContent +} from '../../../utils/index' const rootProp = ['paddingX', 'paddingY'] const backgroundStyleProps = [ @@ -163,10 +166,10 @@ class Style { } // 标签文字 - tagText(node, index) { + tagText(node) { node .fill({ - color: tagColorList[index].color + color: '#fff' }) .css({ 'font-size': '12px' @@ -174,9 +177,9 @@ class Style { } // 标签矩形 - tagRect(node, index) { + tagRect(node, text, color) { node.fill({ - color: tagColorList[index].background + color: color || generateColorByContent(text.node.textContent) }) } diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index 69fefae8..73359791 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -258,7 +258,13 @@ function createTagNode() { let { width } = text.bbox() // 标签矩形 let rect = new Rect().size(width + 16, 20) - this.style.tagRect(rect, index) + // 先从自定义的颜色中获取颜色,没有的话就按照内容生成 + + const tagsColorList = this.mindMap.opt.tagsColorMap || {} + + const color = tagsColorList[text.node.textContent] + + this.style.tagRect(rect, text, color) tag.add(rect).add(text) nodes.push({ node: tag, diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 3096e28b..3659df89 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -1,6 +1,6 @@ import { v4 as uuidv4 } from 'uuid' import { nodeDataNoStylePropList } from '../constants/constant' - +import MersenneTwister from './mersenneTwister' // 深度优先遍历树 export const walk = ( root, @@ -797,3 +797,17 @@ export const getNodeIndex = node => { }) : 0 } + +// 根据内容生成颜色 +export const generateColorByContent = str => { + let hash = 0 + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash) + } + // 这里使用伪随机数的原因是因为 + // 1. 如果字符串的内容差不多,根据hash生产的颜色就比较相近,不好区分,比如v1.1 v1.2,所以需要加入随机数来使得颜色能够区分开 + // 2. 普通的随机数每次数值不一样,就会导致每次新增标签原来的标签颜色就会发生改变,所以加入了这个方法,使得内容不变随机数也不变 + const rng = new MersenneTwister(hash) + const h = rng.genrand_int32() % 360 + return 'hsla(' + h + ', 50%, 50%, 1)' +} diff --git a/simple-mind-map/src/utils/mersenneTwister.js b/simple-mind-map/src/utils/mersenneTwister.js new file mode 100644 index 00000000..6d0cd275 --- /dev/null +++ b/simple-mind-map/src/utils/mersenneTwister.js @@ -0,0 +1,65 @@ +/** + * @description 为了保证相同的内容每次生成的随机数都是一样的,我们可以使用一个伪随机数生成器(PRNG),并使用内容的哈希值作为种子。以下是一个使用Mersenne Twister算法的PRNG的实现: + * + * @param {*} seed + */ + +export default function MersenneTwister(seed) { + this.N = 624 + this.M = 397 + this.MATRIX_A = 0x9908b0df + this.UPPER_MASK = 0x80000000 + this.LOWER_MASK = 0x7fffffff + + this.mt = new Array(this.N) + this.mti = this.N + 1 + + this.init_genrand(seed) +} + +MersenneTwister.prototype.init_genrand = function (s) { + this.mt[0] = s >>> 0 + for (this.mti = 1; this.mti < this.N; this.mti++) { + s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30) + this.mt[this.mti] = + ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + + (s & 0x0000ffff) * 1812433253 + + this.mti + this.mt[this.mti] >>>= 0 + } +} + +MersenneTwister.prototype.genrand_int32 = function () { + var y + var mag01 = new Array(0x0, this.MATRIX_A) + + if (this.mti >= this.N) { + var kk + + if (this.mti == this.N + 1) this.init_genrand(5489) + + for (kk = 0; kk < this.N - this.M; kk++) { + y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) + this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1] + } + + for (; kk < this.N - 1; kk++) { + y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) + this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1] + } + + y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK) + this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1] + + this.mti = 0 + } + + y = this.mt[this.mti++] + + y ^= y >>> 11 + y ^= (y << 7) & 0x9d2c5680 + y ^= (y << 15) & 0xefc60000 + y ^= y >>> 18 + + return y >>> 0 +}