看了Joeshu的 代码贡献:uchart柱状图的扩展(圆角边框,渐变),觉得很受用,马上移植到代码中,但是实际使用中发现存在一些缺陷和不够懒人的做法:
1、圆角边框:
1)如果设置了圆角边框,但是column的高度小于设置的圆角值,则会变成这样
2)如果column的widith不是固定的,那还得根据width值来动态设置参数barBorderRadius
2、渐变:
1)设置了渐变后,如果存在多个series,那么每个series的颜色都是一样的
2)无法自动沿用系统设置的多series默认颜色,如第一个series为蓝色,第二个series为绿色。。。
所以针对上述问题,做了如下优化与扩展:
1、当设置的圆角值大于column条的height或column条的width/2时,动态调整圆角值
2、增加半圆角参数 barBorderCircle(布尔型) ,自动根据每个column条的width调整radius值,且只有column条的上方是半圆角,效果如下图
3、增加透明渐变参数 opacityColor (值范围0到1),自下而上渐变透明显示column条,值越小透明程度越高,以下为值为0.2的效果
4、增加白色渐变参数 linearColor (值范围0到1),自下而上向白色渐变显示column条,值越大白色程度越高,以下为值为1的效果
5、额外增加了多series间距属性 opts.extra.column.seriesGap,当值设置为2时效果如下:
替换源码的方法和原文一样,覆盖原来的if (item !== null && i>leftNum && i<rightNum) { // 原来代码...},
加入下面的代码:
if (item !== null && i>leftNum && i<rightNum) {
var startX = item.x - item.width / 2;
var height = opts.height - item.y - opts.area[2];
context.beginPath();
var fillColor = item.color || eachSeries.color
var strokeColor = item.color || eachSeries.color
// 渐变色
if(columnOption.opacityColor !== undefined && columnOption.opacityColor >= 0 && columnOption.opacityColor <= 1){
//透明渐变
var start = fillColor.length === 4 ? fillColor.substr(1).split('').map(function (s) { return 0x11 * parseInt(s, 16); }) : [fillColor.substr(1, 2), fillColor.substr(3, 2), fillColor.substr(5, 2)].map(function (s) { return parseInt(s, 16); })
//canvas2D才支持该写法
//var color = fillColor+ ('0' + parseInt(columnOption.opacityColor * 255).toString(16)).slice(-2);
var color = "rgba(" + start[0] + "," + start[1] + "," + start[2] + "," + columnOption.opacityColor + ")"
columnOption.color = {type:'linear',colorStops:[{offset:0.9, color:fillColor},{offset:0, color:color}]}
}else if(columnOption.linearColor !== undefined && columnOption.linearColor > 0){
//向白色渐变
var color1 = fillColor, color2 = '#ffffff';
var start = color1.length === 4 ? color1.substr(1).split('').map(function (s) { return 0x11 * parseInt(s, 16); }) : [color1.substr(1, 2), color1.substr(3, 2), color1.substr(5, 2)].map(function (s) { return parseInt(s, 16); })
var end = color2.length === 4 ? color2.substr(1).split('').map(function (s) { return 0x11 * parseInt(s, 16); }) : [color2.substr(1, 2), color2.substr(3, 2), color2.substr(5, 2)].map(function (s) { return parseInt(s, 16); })
var ms = columnOption.linearColor;
var me = 1 - ms, so = [];
for (var j = 0; j < 3; j++){
so[j] = Math.round((start[j] * me + end[j] * ms)).toString(16);
so[j] = (so[j].length === 1) ? '0' + so[j] : so[j];
}
columnOption.color = {type:'linear',colorStops:[{offset:1, color:fillColor},{offset:0, color:'#' + so.join('')}]}
}
if(columnOption.color && columnOption.color.type === 'linear'){
var grd=context.createLinearGradient(startX, item.y, startX, opts.height - opts.area[2]);
grd.addColorStop(columnOption.color.colorStops[0].offset, columnOption.color.colorStops[0].color);
grd.addColorStop(columnOption.color.colorStops[1].offset, columnOption.color.colorStops[1].color);
fillColor = grd
}
// 圆角边框
if((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) || columnOption.barBorderCircle){
const left = startX;
const top = item.y;
const width = item.width;
const height = opts.height - opts.area[2] - item.y;
if(columnOption.barBorderCircle){
columnOption.barBorderRadius = [width / 2,width / 2,0,0];
}
let [r0,r1,r2,r3] = columnOption.barBorderRadius;
if(r0 + r2 > height){r0 = height;r2=0;r1 = height;r3=0;}
if(r0 + r2 > width / 2){r0 = width / 2;r2=0;r1 = width / 2;r3=0;}
context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
}else{
context.moveTo(startX, item.y);
context.lineTo(startX+item.width-2,item.y);
context.lineTo(startX+item.width-2,opts.height - opts.area[2]);
context.lineTo(startX,opts.height - opts.area[2]);
context.lineTo(startX,item.y);
context.setLineWidth(1)
context.setStrokeStyle(strokeColor);
}
context.setFillStyle(fillColor);
context.closePath();
context.stroke();
context.fill();
}
如果需要支持多series间距属性 opts.extra.column.seriesGap 的设置,还需要修改 fixColumeData 函数,替换为下面的代码
function fixColumeData(points, eachSpacing, columnLen, index, config, opts) {
return points.map(function(item) {
if (item === null) {
return null;
}
item.width = Math.ceil((eachSpacing - 2 * config.columePadding - (opts.extra.column.seriesGap || 0) * (columnLen - 1)) / columnLen);
if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
item.width = Math.min(item.width, +opts.extra.column.width);
}
if (item.width <= 0) {
item.width = 1;
}
item.x += (index + 0.5 - columnLen / 2) * (item.width + (opts.extra.column.seriesGap || 0));
return item;
});
}
在 UChart column图表的参数中,添加以下代码即可:
extra: {
column: {
// 颜色支持线性渐变
color: {
type: 'linear',
colorStops: [{
offset: 0, color: '#FC6713' // 0% 处的颜色
}, {
offset: 1, color: '#FFD37B' // 100% 处的颜色
}],
global: false // 缺省为 false
},
// 圆角半径,单位px,必须传入数组分别指定 4 个圆角半径
barBorderRadius: [10, 10, 0, 0],
// 半圆边框
barBorderCircle: true,
// 透明渐变(值范围0到1,自下而上渐变透明显示column条,值越小透明程度越高)
opacityColor : 0.2,
// 白色渐变(值范围0到1,自下而上向白色渐变显示column条,值越大白色程度越高)
linearColor: 0.9,
//多series之间的间距
seriesGap:2
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
登录 后才可以发表评论