export class ColorGenerator { // 生成适合地图显示的区分度高的颜色 static generateDistinctColors(count) { const colors = []; for (let i = 0; i < count; i++) { // 使用黄金角分布算法,确保颜色分布均匀 const hue = (i * 137.5) % 360; // 黄金角约等于 137.5 度 const saturation = 70 + Math.random() * 20; // 70-90% 饱和度 const lightness = 45 + Math.random() * 20; // 45-65% 亮度 const hsl = { h: hue, s: saturation, l: lightness }; colors.push(HSLColorGenerator.toCSS(hsl)); } return colors; } // 生成分类数据颜色(确保相邻类别颜色差异明显) static generateCategoricalColors(count, startHue = 0) { const hueStep = 360 / count; const colors = []; for (let i = 0; i < count; i++) { const hue = (startHue + i * hueStep) % 360; const hsl = { h: hue, s: 80 + Math.random() * 15, // 80-95% 饱和度 l: 50 + Math.random() * 15 // 50-65% 亮度 }; colors.push(HSLColorGenerator.toCSS(hsl)); } return colors; } // 生成连续数据颜色(渐变) static generateSequentialColors( count, startColor = '#f7fbff', endColor = '#08306b' ) { const colors = []; // 解析起始颜色和结束颜色 const startRGB = this.parseHexColor(startColor); const endRGB = this.parseHexColor(endColor); for (let i = 0; i < count; i++) { const ratio = i / (count - 1); const r = Math.round(startRGB.r + (endRGB.r - startRGB.r) * ratio); const g = Math.round(startRGB.g + (endRGB.g - startRGB.g) * ratio); const b = Math.round(startRGB.b + (endRGB.b - startRGB.b) * ratio); colors.push(`#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`); } return colors; } // 生成发散颜色(用于有正负值的数据) static generateDivergingColors( count, negativeColor = '#d73027', neutralColor = '#ffffbf', positiveColor = '#1a9850' ) { const colors = []; const midPoint = Math.floor(count + 1 / 2); // 负值部分 const negRGB = this.parseHexColor(negativeColor); const neutralRGB = this.parseHexColor(neutralColor); for (let i = 0; i < midPoint; i++) { const ratio = i / midPoint; const r = Math.round(negRGB.r + (neutralRGB.r - negRGB.r) * ratio); const g = Math.round(negRGB.g + (neutralRGB.g - negRGB.g) * ratio); const b = Math.round(negRGB.b + (neutralRGB.b - negRGB.b) * ratio); colors.push(`#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`); } // 正值部分 const positiveRGB = this.parseHexColor(positiveColor); for (let i = midPoint; i < count; i++) { const ratio = (i - midPoint) / (count - midPoint - 1); const r = Math.round(neutralRGB.r + (positiveRGB.r - neutralRGB.r) * ratio); const g = Math.round(neutralRGB.g + (positiveRGB.g - neutralRGB.g) * ratio); const b = Math.round(neutralRGB.b + (positiveRGB.b - neutralRGB.b) * ratio); colors.push(`#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`); } return colors; } // 解析十六进制颜色 static parseHexColor(hex) { hex = hex.replace('#', ''); if (hex.length === 3) { hex = hex.split('').map(c => c + c).join(''); } return { r: parseInt(hex.substring(0, 2), 16), g: parseInt(hex.substring(2, 4), 16), b: parseInt(hex.substring(4, 6), 16) }; } } export class HSLColorGenerator { // 随机 HSL 颜色 static randomHSL() { return { h: Math.floor(Math.random() * 360), s: Math.floor(Math.random() * 101), l: Math.floor(Math.random() * 101) }; } // 转换为 CSS 字符串 static toCSS(color) { if (color.alpha !== undefined) { return `hsla(${color.h}, ${color.s}%, ${color.l}%, ${color.alpha})`; } return `hsl(${color.h}, ${color.s}%, ${color.l}%)`; } // 生成鲜艳的颜色(高饱和度) static randomVibrantHSL(minSaturation = 80, minLightness = 40) { return { h: Math.floor(Math.random() * 360), s: minSaturation + Math.floor(Math.random() * (101 - minSaturation)), l: minLightness + Math.floor(Math.random() * (61 - minLightness)) }; } // 生成柔和的颜色(低饱和度) static randomPastelHSL(maxSaturation = 40, minLightness = 70) { return { h: Math.floor(Math.random() * 360), s: Math.floor(Math.random() * (maxSaturation + 1)), l: minLightness + Math.floor(Math.random() * (101 - minLightness)) }; } // 转换为 RGB static toRGB(hsl) { const h = hsl.h / 360; const s = hsl.s / 100; const l = hsl.l / 100; let r, g, b; if (s === 0) { r = g = b = l; } else { const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), alpha: hsl.alpha }; } }