一个自定义扇形图表,内部嵌套折线,点
设计稿:
最后实现效果图:
话不多说,直接上代码!
<!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请告之。