395 Star 3.4K Fork 660

GVPuCharts / uCharts

 / 详情

代码贡献: uchart圆弧进度图arcbar的扩展(在现有线性渐变基础上,增加弧线渐变、增加进度多颜色渐变)

待办的
任务
创建于  
2021-03-11 12:21

uchart升级到2.0后,加入了很多渐变,但是所有渐变都是基于线性渐变和径向渐变的,对于弧线进度条而言,这种渐变显得不是那么合理。
当颜色从#f04864(红色) 渐变 到 #2fc25b(绿色)时
现有的渐变效果如下(从左到右的线性渐变):
输入图片说明

扩展的 弧线渐变 效果如下:
输入图片说明

扩展的 进度多颜色渐变 效果如下:
输入图片说明
如果进度颜色由2种颜色,增加为3种颜色 '#f04864','#ffaa00','#2fc25b' ,效果如下:
输入图片说明
如果进度颜色由3种颜色,增加为4种颜色 '#f04864','#ffaa00','#1890ff','#2fc25b' ,效果如下:
输入图片说明
其中进度颜色数组可以支持无限添加

输入图片说明

代码中需要做如下修改:
1、增加部分处理函数

function clearArc(opts, context, x,y,radius){
  //context清除圆形区域。圆心(x,y),半径radius
  var calcWidth=radius-opts.stepClear;
  var calcHeight=Math.sqrt(radius*radius-calcWidth*calcWidth);  
  var posX=x-calcWidth;
  var posY=y-calcHeight;  
  var widthX=2*calcWidth;
  var heightY=2*calcHeight;  
  if(opts.stepClear<=radius){
    context.clearRect(posX,posY,widthX,heightY);
    opts.stepClear+=1;
    clearArc(opts, context, x,y,radius);
  }
}
function getMixColor(color1, color2, blv){
  //获取2种颜色按blv混合后的颜色,blv必须介于0与1,blv接近0则颜色接近color1, blv接近1则颜色接近color2
  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 zs = Math.abs(parseInt(blv) % 2);
  var ms = Math.abs(zs - Math.abs(blv == 1 ? 1 : blv % 1));
  ms = ms < 0 ? 1 + ms : ms;
  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];
  }
  return '#' + so.join('');
}
function drawArcbarLinear(opts, config, context, x, y, radius, rs,re, borderW, color1, color2){
  //弧形渐变
  re = rs > re ? re+2 : re;
  rs -= 0.5;
  re -= 0.5;
  rs *= Math.PI;
  re *= Math.PI;
  var ms, me, so = [], color;
  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); })
  for (var n=rs;n<=re;n+=0.03){
    ms = (n - rs) / (re - rs);
    me = 1 - ms;
    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];
    }
    color = '#' + so.join('');
    var s = -Math.sin(n);
    var c = Math.cos(n);
    context.save();
    context.globalAlpha = 1;    
    context.beginPath();
    context.fillStyle = color;
    context.arc(x+(s*radius),y+(c*radius),borderW / 2,0,2*Math.PI, false);
    context.fill();
    context.restore();
  }
}

2、修改drawArcbarDataPoints函数

function drawArcbarDataPoints(series, opts, config, context) {
  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  var arcbarOption = assign({}, {
    startAngle: 0.75,
    endAngle: 0.25,
    type: 'default',
    width: 12 * opts.pix,
    gap: 2 * opts.pix,
    linearType: 'none',
    customColor: [],
  }, opts.extra.arcbar);
  series = getArcbarDataPoints(series, arcbarOption, process);
  var centerPosition;
  if (arcbarOption.centerX || arcbarOption.centerY) {
    centerPosition = {
      x: arcbarOption.centerX ? arcbarOption.centerX : opts.width / 2,
      y: arcbarOption.centerY ? arcbarOption.centerY : opts.height / 2
    };
  } else {
    centerPosition = {
      x: opts.width / 2,
      y: opts.height / 2
    };
  }
  var radius;
  if (arcbarOption.radius) {
    radius = arcbarOption.radius;
  } else {
    radius = Math.min(centerPosition.x, centerPosition.y);
    radius -= 5 * opts.pix;
    radius -= arcbarOption.width / 2;
  }
  arcbarOption.customColor = fillCustomColor(arcbarOption.linearType, arcbarOption.customColor, series, config);
  for (let i = 0; i < series.length; i++) {
    let eachSeries = series[i];
    //背景颜色
    if(process == 0){ //仅第1次画背景颜色
      context.setLineWidth(arcbarOption.width);
      context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9');
      context.setLineCap('round');
      context.beginPath();
      if (arcbarOption.type == 'default') {
        context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width + arcbarOption.gap) * i, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, false);
      } else {
        context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width + arcbarOption.gap) * i, 0, 2 * Math.PI, false);
      }
      context.stroke();
    }
    //进度条
    var fillColor = eachSeries.color
    var colorPercentage = eachSeries.colorPercentage || [];
    if(colorPercentage.length > 1){ 
      //渐变色处理(按照实际百分比展示颜色),起始百分比为上一次结束的进度, 结束百分比为当前process
      var perColorLen = (eachSeries.percentageMax || 1) / (colorPercentage.length - 1);
      //开始颜色
      var curPer = eachSeries.data * eachSeries._process_last;
      var idxS = parseInt(curPer / perColorLen);
      var idxE = idxS + 1;
      idxS = idxS >= colorPercentage.length ? colorPercentage.length - 1 : idxS;
      idxE = idxE >= colorPercentage.length ? colorPercentage.length - 1 : idxE;      
      var color1 = getMixColor(colorPercentage[idxS], colorPercentage[idxE], (curPer - idxS * perColorLen) / perColorLen);
      console.log('color1', color1)
      //结束颜色
      curPer = eachSeries.data * process;
      idxS = parseInt(curPer / perColorLen);
      idxE = idxS + 1;
      idxS = idxS >= colorPercentage.length ? colorPercentage.length - 1 : idxS;
      idxE = idxE >= colorPercentage.length ? colorPercentage.length - 1 : idxE;   
      console.log('color2', curPer + "," + idxS + "," + idxE + "," + perColorLen)   
      var color2 = getMixColor(colorPercentage[idxS], colorPercentage[idxE], (curPer - idxS * perColorLen) / perColorLen);
      drawArcbarLinear(opts,config,context,centerPosition.x, centerPosition.y,radius - (arcbarOption.width + arcbarOption.gap) * i,eachSeries._proportion_last, eachSeries._proportion_ , arcbarOption.width, color1,color2)
      //同步改变主标题字体颜色
      opts.title.color = color2;
    }else if(arcbarOption.linearType == 'arc'){
      //渐变色处理(无论进度多长,都是从对应series设置的color颜色,到customColor中对应series的结束颜色)
      //根据加载的百分比计算渐变开始颜色和结束颜色
      var color1 = getMixColor(eachSeries.color, arcbarOption.customColor[eachSeries.linearIndex], eachSeries._process_last)
      var color2 = getMixColor(eachSeries.color, arcbarOption.customColor[eachSeries.linearIndex], eachSeries._process_)
      drawArcbarLinear(opts,config,context,centerPosition.x, centerPosition.y,radius - (arcbarOption.width + arcbarOption.gap) * i,eachSeries._proportion_last, eachSeries._proportion_ , arcbarOption.width, color1,color2)
    }else{
      if(arcbarOption.linearType == 'custom'){
        var grd = context.createLinearGradient(centerPosition.x - radius, centerPosition.y, centerPosition.x + radius, centerPosition.y);
        grd.addColorStop(1, hexToRgb(arcbarOption.customColor[eachSeries.linearIndex], 1))
        grd.addColorStop(0, hexToRgb(eachSeries.color, 1))
        fillColor = grd;
      }
      context.setLineWidth(arcbarOption.width);
      context.setStrokeStyle(fillColor);
      context.setLineCap('round');
      context.beginPath();
      context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width + arcbarOption.gap) * i, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * Math.PI, false);
      context.stroke();
    }
  }
  //只有1个序列,且主标题包含%时,动态显示百分比
  var oriName = opts.title.oriName || opts.title.name;
  if(series.length == 1 && oriName.slice(-1) == '%'){
    var dotN = oriName.match(/\.\d{1,}/)
    dotN = !dotN ? 0 : dotN[0].length - 1;
    opts.title.oriName = oriName;//记录原始标题,保证process=1时完美还原展示
    opts.title.name = process === 1 ? opts.title.oriName : (((series[0].data * process) * 100).toFixed(dotN) + '%')
    opts.stepClear=1;//别忘记这一步
    clearArc(opts, context, centerPosition.x, centerPosition.y, radius - (arcbarOption.width + arcbarOption.gap)-2);
  }
  drawRingTitle(opts, config, context, centerPosition);
  return {
    center: centerPosition,
    radius: radius,
    series: series
  };
}

3、修改drawCharts函数中对于arcbar的处理

//将 case 'arcbar':
//中 onProcess 函数里面,clearRect的调用,改为只在process == 0 时才处理
process == 0 && context.clearRect(0, 0, opts.width, opts.height);

4、修改函数getArcbarDataPoints
将函数中,如下语句

item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;

修改为

item._process_last = item._process_ || 0;
item._process_ = process || 0;
item._proportion_last = item._proportion_ || arcbarOption.startAngle;
item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;

5、弧形渐变调用方法

...
//arcbar中的linearType传入arc即可,其中customColor不传,则默认使用uchart的config中的默认颜色方案
{arcbar: {...,linearType:'arc',customColor:['#2fc25b']}}
...

6、进度渐变调用方法

...
//不同series支持使用不同的颜色方案,只需要为序列传入 colorPercentage 参数即可,
//需要多少中颜色就传入几个颜色值,其中第一个颜色值表示 0% 时的颜色, 
//最后一个颜色值表示 100% * percentageMax  时的颜色,
//中间的按照颜色个数等分,超过 100% * percentageMax  时超过部分使用最后一个颜色值
//(percentageMax 表示颜色百分比终止位置,1为100%,2为200%...默认为1)
series: [{name: "完成率", data: 0.89, color: '这里可以不传入值', colorPercentage:['#f04864','#ffaa00','#2fc25b'], percentageMax:1}]
...

评论 (3)

yyoinge 创建了任务
yyoinge 关联仓库设置为uCharts/uCharts
yyoinge 修改了描述
yyoinge 修改了描述
yyoinge 修改了描述
yyoinge 修改了描述
yyoinge 修改了描述
16cheng 置顶等级设置为
展开全部操作日志

刚好也要修复这个线性渐变的问题,测试后发现有一个小问题
drawArcbarDataPoints 方法需要修改
if(series.length == 1 && oriName.slice(-1) == '%'){

if(series.length == 1 && oriName.toString().slice(-1) == '%'){

否则会因为数字类型找不到slice方法报错

报错 非法颜色: #NaNNaNNaN;
这是什么原因!
输入图片说明
不显示进度,只显示了一个圆点

大佬有解决吗

登录 后才可以发表评论

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

搜索帮助

14c37bed 8189591 565d56ea 8189591