395 Star 3.4K Fork 667

GVPuCharts / uCharts

 / 详情

代码贡献: uchart柱状图的扩展(圆角边框,渐变) 之再扩展(半圆边框、透明渐变、白色渐变、多series间距)

已完成
任务
创建于  
2020-11-28 10:24

为什么要写这个

看了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时效果如下:
输入图片说明

在源文件的第2330行的case 'group':内替换代码

替换源码的方法和原文一样,覆盖原来的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
        
    }
}

点击下载修改后的源码

评论 (4)

yyoinge 创建了任务
yyoinge 关联仓库设置为uCharts/uCharts
yyoinge 修改了描述
yyoinge 修改了描述
yyoinge 修改了描述
yyoinge 修改了标题
yyoinge 修改了描述
yyoinge 修改了描述
展开全部操作日志

感谢付出,后续有时间我会参考更新, :thumbsup:

if(r0 + r2 > width / 2){r0 = width / 2;r2=0;r1 = width / 2;r3=0;}
这个判断影响了原本的圆角边框

麻烦问下 混合图里的柱状图用不了这个设置圆角的属性么

2.0已加入,感谢付出

16cheng 任务状态待办的 修改为已完成

登录 后才可以发表评论

状态
负责人
项目
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(4)
1316944 cc qiun 1578948788 7926951 c  xiner 1598840939
JavaScript
1
https://gitee.com/uCharts/uCharts.git
git@gitee.com:uCharts/uCharts.git
uCharts
uCharts
uCharts

搜索帮助