一个自定义扇形图表,内部嵌套折线,点

smallStone

设计稿:
图片描述

最后实现效果图:
图片描述

话不多说,直接上代码!

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="./css/bodyExam.css">
  <title>体测报告</title>
</head>
<body>
<div class="body_tu" id="drawing">
    
  </div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.5/svg.js"></script>
<script>
var text_l = ['体重', 'BMI', '脂肪', '肌肉', '水分', '蛋白质', '皮下脂肪', '内脏脂肪', '骨量', '基础代谢', '身体年龄', '静态心率']
  function pieer(text_list, source) {
    var winwidth = window.innerWidth
    var d_width = winwidth < 375 ? winwidth : 375    // 画布大小
    var viewboxwid = winwidth / 375
    var trasx = (winwidth - 375) / 2
    var d_hlaf = d_width / 2 // 一半
    var circle_r = 103
    var line_color = "#F0F0F0"
    var line_num = text_list.length
    var rotate_one = 360 / line_num
    var source = source
    var sourcelength = String(source).length
    var sourcetext = '综合评分'
    var text_list = text_list
    function fontalign(basefontsize, num) {
      var font_item = basefontsize, font_left = 0, num_length = String(num).length
      if (String(num).indexOf('.') > -1) {
        font_left = (((num_length - 1) * font_item) + 6.67) / 2
      } else {
        font_left = (num_length * font_item) / 2
      }
      return font_left
    }
    function rad(params) {
      return params * Math.PI / 180
    }
    var draw = SVG('drawing').size(d_width, d_width) // 定一画布
    draw.transform({ scale: viewboxwid > 1.2 ? 1.2 : viewboxwid })
    document.getElementById('drawing').style.width = d_width
    var gradient = draw.gradient('linear', function (stop) { // 线性渐变
      stop.at(0, '#27867B', 0.5)
      stop.at(1, '#97E7BB', 0.5)
    })
    gradient.from(0, 1).to(0.5, 0) // 渐变位置更改

    var panel = draw.gradient('linear', function (stop) { // 线性渐变
      stop.at(0, '#69CAB7', 0.4)
      stop.at(1, '#0C4691', 0.05)
    })
    panel.from(0, 1).to(0.5, 0) // 渐变位置更改

    var group = draw.group() // 建立分组
    var circle = group.circle(circle_r * 2).attr({ // 外部线条大圆环
      cx: d_hlaf,
      cy: d_hlaf,
      fill: '#FFFFFF',
      stroke: line_color,
      'stroke-width': 1
    })
    console.log(line_num)
    for (var i = 0; i < line_num; i++) { // 外部文字和蜘蛛网线
      group.line(d_hlaf, d_hlaf - circle_r, d_hlaf, d_hlaf + circle_r).stroke({ width: 1, color: line_color }).transform({ rotation: rotate_one * i })
      // group.text('体重').rotate(rotate_one * i, d_hlaf, d_hlaf)
      var fontitem = text_list[i]
      var xi = d_hlaf + (circle_r + 30) * Math.cos(rad(i * rotate_one - 90)) // 计算每个文字的坐标x
      var yi = d_hlaf + (circle_r + 30) * Math.sin(rad(i * rotate_one - 90)) // 计算每个文字的坐标y
      group.text(fontitem).transform({
        x: xi - fontalign(12, fontitem),
        y: yi - 9
      }).font({
        size: 12,
        anchor: 'start',
      })
    }
    var group1 = draw.group()
    group1.circle((circle_r - 28) * 2).attr({ // 中间圆环
      cx: d_hlaf,
      cy: d_hlaf,
      fill: 'transparent',
      stroke: gradient,
      'stroke-width': 20,
    })
    var linec = ''
    var linearr = []
    for (var i = 0; i < line_num; i++) { // 描点
      // circle_r = 100% , ((circle_r - 10) / 2) = 0%
      var min = ((circle_r - 10) / 2) // 最小值
      var r = Math.floor(Math.random() * (circle_r - min + 1) + min)
      var mindleMin = (circle_r - min) / 3 // 正常最小值  = mindleMin + min
      var mindleMax = (mindleMin * 2) + min // 正常最大值
      var color = '#1AB394'
      if (r < (mindleMin + min)) {
        color = '#7AB8CF'
      } else if (r <= mindleMax) {
        color = '#1AB394'
      } else {
        color = '#F8AC59'
      }
      var xi = d_hlaf + (r) * Math.cos(rad(i * rotate_one - 90)) // 计算每个点的坐标x
      var yi = d_hlaf + (r) * Math.sin(rad(i * rotate_one - 90)) // 计算每个点的坐标y
      var x = d_hlaf + min * Math.cos(rad(i * rotate_one - 90)) // 计算每个点的起始坐标x
      var y = d_hlaf + min * Math.sin(rad(i * rotate_one - 90)) // 计算每个点的起始坐标y
      group.circle(5).attr({ // 外部线条大圆环
        cx: xi,
        cy: yi,
        fill: color
      })
      linec = linec + x + ',' + y + ' '
      linearr.push([xi, yi])
    }
    var polygon = group.polygon(linec).fill(panel) // 绘制折线
    polygon.animate(800).plot(linearr)
    var group3 = draw.group()
    group3.circle(circle_r - 10).attr({
      cx: d_hlaf,
      cy: d_hlaf,
      fill: '#ffffff',
      stroke: line_color,
      'stroke-width': 1,
    })

    var _left = fontalign(13.39, source)
    var soure = group3.text(function (add) {
      add.tspan(source).newLine().dx(0).fill('#1AB394')
    }).transform({
      x: d_hlaf - _left,
      y: d_hlaf - 44
    })
    soure.font({
      family: 'dincondensed-bold',
      size: 36,
      anchor: 'start',
      // leading: '1.5em'
    })

    var font_left = fontalign(11, sourcetext)
    var font = group3.text(function (add) {
      add.tspan(sourcetext).newLine().dx(0).fill('#333333')
    }).transform({
      x: d_hlaf - font_left,
      y: d_hlaf + 10
    })
    font.font({
      size: 12,
      anchor: 'start',
      // leading: '1.5em'
    })
  }
  pieer(text_l, 23.6)
</script>
</html>

直接复制粘贴就能看到效果。
此图考察了svg的各种使用;其中包含了,绘制圆形、圆环,点,折线,多边形,水平居中文字,三角函数计算坐标。关于手机端适配方面,直接使用svg的viewbox来实现。因为svg是矢量图形,无论放大缩小都不失真,所以可以用适用各种设备且效果显示出众。
公司给的设计稿是375宽度,我就用了375.你们也可以将d_width这个值直接设置为屏幕宽度。
如果有bug请告之。

阅读 1.9k

smallhuifei的技术博客
每天积累一点,多了就发现简单了!

前端一枚^_-

164 声望
27 粉丝
0 条评论

前端一枚^_-

164 声望
27 粉丝
文章目录
宣传栏