项目中有需求为highcharts的分组堆叠柱图配置渐变色,该类柱图原始的实现是随机色的,那么配置为渐变色就需要我们调用highchart的配色api写入我们计算好的渐变色的颜色编码
具体实现可以将问题抽象成 为一个二维数组配置渐变色,初步想想差不多就是颜色代码0~255之间累加就可以了,后来发现不是这么回事。 那我们来仔细看看这个问题。
首先我们来抽象一下问题。
有二维数组a,假设为 m * n 维度:
a = [
[{value:1,color:null}, {value:2,color:null}, ····n个····, {value:3,color:null}],
·
·
m个
·
·
[{value:7,color:null}, {value:8,color:null}, ····n个····, {value:9,color:null}],
]
我们的任务就是把m个一级维度设计为一个大色系,其中每个里面的n个二级维度设计为由浅至深的渐变色。 据此设计需求将相应的颜色代码值填充到每个json对象的color属性中。
ok问题明确,我们来了解一下相关的颜色代码知识。 一般网页设计中颜色代码常用表示方法有:
#667788, #333, RGB(0.2,0.4,0.5), rgb(100%,0%,0%), 文字"红色"
但是这些代码都是RGB颜色模型的,它们是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色 RGB数学模型如下:
直观的就能发现,这个颜色模型没有选项来解决渐变色的问题,深入一下还会发现这个模型不能进行可编程式的颜色划分。 亦即我们不能简单的在RGB三个通道上等值累加来获得不同的颜色红橙黄等等系列或实现指定色系的颜色渐变。 这么做我们获得的仅仅是不同程度的灰色。 如#333,#666,#999是逐渐变浅的灰色, 而这些颜色也是一般前端人员唯一记住的颜色代码 :)
经过一番资料搜寻,终于发现一个HSV模型,
这是一个六角锥体模型,这个模型中颜色的参数分别代表了:色调(H),饱和度(S),亮度(V)。
ok,找到一个合适的模型后,我们就方便编程实现了。 我们可以如下设计: 在H参数的360度范围内步进来实现颜色系的切换,在S参数的0 ~ 100%范围内实现颜色渐变,V参数在0 ~ 100% 范围内我们就取值一个合适的固定值80%吧。 在了解了这些之后,剩下的问题就只剩下数学模型间的转换了,也就是把获得的HSV对象转换为浏览器可识别的RGB对象就完成了。 ok, 针对这个抽象好的问题上代码。
/*************************************/
/**** start to fill in color code ****/
/*************************************/
//raw data without color code, Dimension: m*n
var rawData = [
[{value:1,color:null}, {value:2,color:null}, ····n个····, {value:3,color:null}],
·
·
m个
·
·
[{value:7,color:null}, {value:8,color:null}, ····n个····, {value:9,color:null}],
];
var dataWithColor = [];
var sediaoStep = Math.round(360 / m); //caculate the step value for sediao,
var jianbianStep = Math.round(100 / n); //caculate the step value for jianbian,
var sediao = 0;
rawData.forEach(function(item, index){
var jianbian = 0; //every time we switch the color, we init the jianbian with zero
sediao += sediaoStep; //switch the color
item.forEach(function(one){
jianbian += jianbianStep; //switch the jianbian
var hsv = {
h: sediao,
s: jianbian,
v: 80,
};
var color = HSV_To_RGB(hsv);
dataWithColor[index] || dataWithColor.push( [] ); //judge if the index item is exist in dataWithColor, if not ,push in on empty array
dataWithColor[index].push({
value: one.value,
color: color,
});
});
});
//Convert HSV obj like {h:195, s:70, v:60} to RGB object like {r:220, g:160, b:80}
//@param {object} HSV The param strcture is {h:*, s:*, v:*} H:指定色调 S:指定饱和度,用于颜色渐变 V:指定亮度
//@return {object} The return object strcture is like {r:null, g:null, b:null}
function HSV_To_RGB(HSV){
var result = {
r: 0,
g: 0,
b: 0
};
var h = HSV.h / 360;
var s = HSV.s / 100;
var v = HSV.v / 100;
if (s == 0) {
result.r = v * 255;
result.g = v * 255;
result.v = v * 255;
} else {
var_h = h * 6;
var_i = Math.floor(var_h);
var_1 = v * (1 - s);
var_2 = v * (1 - s * (var_h - var_i));
var_3 = v * (1 - s * (1 - (var_h - var_i)));
if (var_i == 0) {
var_r = v;
var_g = var_3;
var_b = var_1
} else if (var_i == 1) {
var_r = var_2;
var_g = v;
var_b = var_1
} else if (var_i == 2) {
var_r = var_1;
var_g = v;
var_b = var_3
} else if (var_i == 3) {
var_r = var_1;
var_g = var_2;
var_b = v
} else if (var_i == 4) {
var_r = var_3;
var_g = var_1;
var_b = v
} else {
var_r = v;
var_g = var_1;
var_b = var_2
};
result.r = var_r * 255;
result.g = var_g * 255;
result.b = var_b * 255;
result.r = Math.round(result.r);
result.g = Math.round(result.g);
result.b = Math.round(result.b);
}
return RGB_To_Color(result);
},
//Convert the RGB Object like {r:220, g:160, b:80} to "#768844"
//@param {object} obj The RGB object
//@return {string} The return color string
function RGB_To_Color(obj){
obj.r = Math.round(obj.r);
obj.g = Math.round(obj.g);
obj.b = Math.round(obj.b);
var color = '#';
color += (obj.r < 16 ? '0' : '') + obj.r.toString(16);
color += (obj.g < 16 ? '0' : '') + obj.g.toString(16);
color += (obj.b < 16 ? '0' : '') + obj.b.toString(16);
return color;
},
/******************************/
/**** end to fill in color ****/
/******************************/