在项目开发中需要实现以下效果:元素之间两两相关
这种实际上是一种热力图,在基础的热力图上做修改,达到此效果。
- 要点1:去除图表底色
visualMap: {
show: false,
pieces: [
{
min: 0,
max: 100,
color: "none",
},
],
},
- 要点2:根据数据动态渲染底色
图例如下
这里使用颜色渐变算法 颜色渐变算法
const gerColorOfWeight = (minNum, maxNum, colorStart, colorend, number) => {
const colorR =
((colorend.red - colorStart.red) * (number - minNum)) / (maxNum - minNum) +
colorStart.red;
const colorG =
((colorend.green - colorStart.green) * (number - minNum)) /
(maxNum - minNum) +
colorStart.green;
const colorB =
((colorend.blue - colorStart.blue) * (number - minNum)) /
(maxNum - minNum) +
colorStart.blue;
const color = `rgb(${parseInt(colorR).toString()},${parseInt(
colorG
).toString()},${parseInt(colorB).toString()})`;
// #color=getColorstr((int(colorR),int(colorG),int(colorB)))#转换为16进制颜色
return color;
};
- 要点3:动态绘制形状
给不同范围的值规定不同的宽度以及圆角
const handleDataColor = (val) => {
// 取绝对值
let value = Math.abs(val);
let color = "";
let startColor = null;
let endColor = null;
// 形状配置
let opt = {};
switch (true) {
case value >= 0 && value < 25:
if (val >= 0) {
startColor = { red: 246, green: 255, blue: 148 };
endColor = { red: 255, green: 228, blue: 119 };
} else {
startColor = { red: 177, green: 250, blue: 156 };
endColor = { red: 246, green: 255, blue: 148 };
}
color = gerColorOfWeight(0, 25, startColor, endColor, value);
opt = {
width: 25,
height: 25,
borderRadius: 15,
};
break;
case value >= 25 && value < 50:
if (val >= 0) {
startColor = { red: 255, green: 228, blue: 119 };
endColor = { red: 253, green: 173, blue: 89 };
} else {
startColor = { red: 102, green: 220, blue: 159 };
endColor = { red: 177, green: 250, blue: 156 };
}
color = gerColorOfWeight(25, 50, startColor, endColor, value);
opt = {
width: 20,
height: 30,
rotate: val < 0 ? 15 : -15,
borderRadius: 60,
};
break;
case value >= 50 && value < 75:
if (val >= 0) {
startColor = { red: 253, green: 173, blue: 89 };
endColor = { red: 204, green: 82, blue: 72 };
} else {
startColor = { red: 85, green: 151, blue: 174 };
endColor = { red: 102, green: 220, blue: 159 };
}
color = gerColorOfWeight(50, 75, startColor, endColor, value);
opt = {
width: 15,
height: 30,
rotate: val < 0 ? 30 : -30,
borderRadius: 30,
};
break;
case value >= 75 && value < 100:
if (val >= 0) {
startColor = { red: 204, green: 82, blue: 72 };
endColor = { red: 153, green: 1, blue: 62 };
} else {
startColor = { red: 86, green: 80, blue: 188 };
endColor = { red: 85, green: 151, blue: 174 };
}
color = gerColorOfWeight(75, 100, startColor, endColor, value);
opt = {
width: 10,
height: 30,
rotate: val < 0 ? 45 : -45,
borderRadius: 35,
};
break;
}
return {
color,
opt,
};
};
以下是完整代码
// 数据源
const dataOrigin = {
xAxisData: [
"SO₂",
"NO₂",
"CO",
"O₃",
"PM₁₀",
"PM₂.₅",
"T",
"P",
"RH",
"WS",
"WD",
"RAIN",
],
yAxisData: [
"SO₂",
"NO₂",
"CO",
"O₃",
"PM₁₀",
"PM₂.₅",
"T",
"P",
"RH",
"WS",
"WD",
"RAIN",
],
seriesDatas: [],
};
const handleDataColor = (val) => {
let value = Math.abs(val);
let color = "";
let startColor = null;
let endColor = null;
let opt = {};
switch (true) {
case value >= 0 && value < 25:
if (val >= 0) {
startColor = { red: 246, green: 255, blue: 148 };
endColor = { red: 255, green: 228, blue: 119 };
} else {
startColor = { red: 177, green: 250, blue: 156 };
endColor = { red: 246, green: 255, blue: 148 };
}
color = gerColorOfWeight(0, 25, startColor, endColor, value);
opt = {
width: 25,
height: 25,
borderRadius: 15,
};
break;
case value >= 25 && value < 50:
if (val >= 0) {
startColor = { red: 255, green: 228, blue: 119 };
endColor = { red: 253, green: 173, blue: 89 };
} else {
startColor = { red: 102, green: 220, blue: 159 };
endColor = { red: 177, green: 250, blue: 156 };
}
color = gerColorOfWeight(25, 50, startColor, endColor, value);
opt = {
width: 20,
height: 30,
rotate: val < 0 ? 15 : -15,
borderRadius: 60,
};
break;
case value >= 50 && value < 75:
if (val >= 0) {
startColor = { red: 253, green: 173, blue: 89 };
endColor = { red: 204, green: 82, blue: 72 };
} else {
startColor = { red: 85, green: 151, blue: 174 };
endColor = { red: 102, green: 220, blue: 159 };
}
color = gerColorOfWeight(50, 75, startColor, endColor, value);
opt = {
width: 15,
height: 30,
rotate: val < 0 ? 30 : -30,
borderRadius: 30,
};
break;
case value >= 75 && value < 100:
if (val >= 0) {
startColor = { red: 204, green: 82, blue: 72 };
endColor = { red: 153, green: 1, blue: 62 };
} else {
startColor = { red: 86, green: 80, blue: 188 };
endColor = { red: 85, green: 151, blue: 174 };
}
color = gerColorOfWeight(75, 100, startColor, endColor, value);
opt = {
width: 10,
height: 30,
rotate: val < 0 ? 45 : -45,
borderRadius: 35,
};
break;
}
return {
color,
opt,
};
};
const gerColorOfWeight = (minNum, maxNum, colorStart, colorend, number) => {
const colorR =
((colorend.red - colorStart.red) * (number - minNum)) / (maxNum - minNum) +
colorStart.red;
const colorG =
((colorend.green - colorStart.green) * (number - minNum)) /
(maxNum - minNum) +
colorStart.green;
const colorB =
((colorend.blue - colorStart.blue) * (number - minNum)) /
(maxNum - minNum) +
colorStart.blue;
const color = `rgb(${parseInt(colorR).toString()},${parseInt(
colorG
).toString()},${parseInt(colorB).toString()})`;
// #color=getColorstr((int(colorR),int(colorG),int(colorB)))#转换为16进制颜色
return color;
};
dataOrigin.xAxisData.forEach((item, index) => {
dataOrigin.yAxisData.forEach((itm, idx) => {
let list = [];
let value = Math.floor(Math.random() * 100);
list.push(item);
list.push(itm);
if (item == itm) {
list.push(100);
} else if (index % 2 !== 0 || idx % 2 === 0) {
list.push(-value);
} else {
list.push(value);
}
dataOrigin.seriesDatas.push({
name: "",
data: [list],
color: list[2] == 100 ? "none" : handleDataColor(list[2]).color,
labelOpt: list[2] == 100 ? {} : handleDataColor(list[2]).opt,
});
});
});
option = {
grid: {
top: 40,
left: 65,
right: 15,
bottom: 65,
show: true,
width: 421,
height: 421,
borderColor: "#061A19",
borderWidth: 2,
},
visualMap: {
show: false,
pieces: [
{
min: 0,
max: 100,
color: "none",
},
],
},
xAxis: {
type: "category",
data: dataOrigin.xAxisData,
nameGap: 18,
nameRotate: 90,
axisLine: {
show: false,
},
axisTick: {
show: true,
alignWithLabel: true,
lineStyle: {
color: "#061A19",
width: 2,
},
},
splitArea: {
show: false,
},
axisLabel: {
interval: 0,
fontSize: 14,
fontFamily: "Source Han Sans CN",
fontWeight: 500,
color: "#061A19",
},
},
yAxis: {
type: "category",
data: dataOrigin.yAxisData,
nameGap: 18,
axisLine: {
show: false,
},
axisTick: {
show: true,
alignWithLabel: true,
lineStyle: {
color: "#061A19",
width: 2,
},
},
splitArea: {
show: false,
},
axisLabel: {
fontSize: 14,
fontFamily: "Source Han Sans CN",
fontWeight: 500,
color: "#061A19",
},
},
series: dataOrigin.seriesDatas.map(({ name, data, color, labelOpt }) => ({
name,
data,
type: "heatmap",
label: {
show: true,
backgroundColor: color,
...labelOpt,
lineheight: 30,
verticalAlign: "middle",
fontSize: 14,
fontFamily: "Source Han Sans CN",
fontWeight: 500,
color: "#061A19",
},
itemStyle: {
color: "none",
borderCap: "round",
},
markLine: {
lineStyle: {
type: "dashed",
color: "#14C3BA",
width: 2,
},
data: [
[
{
xAxis: "SO₂",
yAxis: "SO₂",
symbol: "none",
},
{
xAxis: "RAIN",
yAxis: "RAIN",
symbol: "none",
},
],
],
},
})),
};