最近因为工作原因,需要制作一个color bar的图表控件,网上百度了下,没有相关的源码,只能自己开发一个。
设计需求的colorBar样式如下图:
三角箭头所在是临界值,临界值数值使用灰色颜色标识在箭头下方,绿色或黄色或红色箭头表示当前值,数值标识在箭头上方。
使用canvas原生开发了一个
1、首先要创建一个canvas,如下:
2、创建colorBar的代码:
/**
* COLORBAR
* @param {*} id canvas的ID
* @param {*} val 当前值
* @param {*} bValArr [2,5,9,12] 临界值数组,从小到大排序
*/
function drawColorBar(id, val, bValArr) {
let canvas = document.getElementById(id);
let ctx = canvas.getContext('2d');
let x = 100; //colorBar在canvas里位置
let y = 100;
let w = 400; //colorBar宽度
let h = 40; //高度
// 以下代码解决字体模糊问题
const ratio = getPixelRatio(ctx)
canvas.style.width = canvas.width + 'px'
canvas.style.height = canvas.height + 'px'
canvas.width = canvas.width * ratio
canvas.height = canvas.height * ratio
ctx.scale(ratio, ratio)
let num = bValArr.length;//临界值数量
let len0 = Math.max(bValArr[num-1], Math.abs(val)) + bValArr[0];
let len = len0 * 2;
let arrowArr = [];
let newVal = 0;
for(let i = 0; i < num; i++){
arrowArr.push(x + (len0 + bValArr[i]) * w / len);
arrowArr.push(x + (len0 - bValArr[i]) * w / len);
}
if(val > 0){
newVal = x + (len0 + Math.abs(val)) * w / len;
}else{
newVal = x + (len0 - Math.abs(val)) * w / len;
}
//当前值箭头颜色
let color = 'green'; //范围内是绿色
const defaultColor = '#666';
if (Math.abs(val) > bValArr[num-1]) {
color = '#ee6666'; //红色
} else {
if (Math.abs(val) > bValArr[0]) {
color = '#ff9901'; //黄色
}
}
// 渐变色
let my_gradient = ctx.createLinearGradient(x, y, x + w, y)
my_gradient.addColorStop(0, '#ee6666')
my_gradient.addColorStop((arrowArr[1] - x) / w / 2, '#fac858')
my_gradient.addColorStop((arrowArr[1] - x) / w, '#91cc75')
my_gradient.addColorStop(0.5, '#91cc75')
my_gradient.addColorStop((arrowArr[0] - x) / w, '#91cc75')
my_gradient.addColorStop(1 - (arrowArr[1] - x) / w / 2, '#fac858')
my_gradient.addColorStop(1, '#ee6666')
ctx.fillStyle = my_gradient
// 绘制矩形
ctx.fillRect(x, y, w, h)
// 边框
ctx.strokeStyle = defaultColor
ctx.rect(x, y, w, h)
ctx.stroke();
for(let i = 0,l = arrowArr.length; i < l; i++){
// 绘制矩形上面向下箭头
drawColorBarArrow(ctx, arrowArr[i], y, 0, defaultColor)
// 绘制矩形下面向上箭头
let text = bValArr[parseInt(Math.floor(i/2))];
if(arrowArr[i] < x + w / 2){
text = -text;
}
drawColorBarArrow(ctx, arrowArr[i], y + h, 1, defaultColor, text)
}
drawColorBarArrow(ctx, newVal, y, 0, color, val)
}
3、创建箭头的方法:
/**
* 三角箭头
* @param {*} ctx
* @param {*} x 位置
* @param {*} y
* @param {*} up 0=位于上方,1=下方
* @param {*} color 颜色数值
* @param {*} text 显示数字文字
*/
function drawColorBarArrow(ctx, x, y, up, color, text){
ctx.beginPath();
ctx.moveTo(x, y);
let newY, textY, textX;
let fontSize = 12;
if(up){
newY = y + 16;
textY = y + fontSize * 3;
}else{
newY = y - 16;
textY = y - fontSize * 2;
}
ctx.lineTo(x - 8, newY);
ctx.lineTo(x + 8, newY);
ctx.fillStyle = color;
ctx.fill();
if(text){
if(typeof text != 'string'){
text = text.toString();
}
ctx.font = "normal normal 500 " + fontSize + "px sans-serif";
if(color == "#666")ctx.fillStyle = "black";
textX = x - text.length / 4 * fontSize;
ctx.fillText(text, textX, textY);
}
}
4、因为屏幕显示分辨率问题导致字体模糊,需要获取显示器和图像实际分辨率的比率:
function getPixelRatio(ctx) {
let backingStore = ctx.backingStorePixelRatio ||
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
};
5、最后输入参数调用方法后得到的结果图形:
drawColorBar('canvas', 19.86, [4,9.5,15]);
6、DEMO地址访问: