D3 Gauge Chart 如何添加四区段图例、用旋钮代替指针并显示居中数值
D3.js仪表盘自定义修改方案
修改对应需求
- 用旋钮替换原有指针:删除原三角指针逻辑,改为圆形旋钮沿刻度环随数值移动
- 新增颜色区段图例:在仪表盘底部添加4组图例,每个颜色块对应区段说明
- 中心显示分数与等级:仪表盘中心新增两行文本,分别展示当前分数、对应区段等级名称
完整实现代码
HTML
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> <div class="chart-gauge"></div>
CSS
.chart-gauge { width: 400px; margin: 50px auto; } .chart-first { fill: #EA4335; } .chart-second { fill: #FBBC05; } .chart-third { fill: #4285F4; } .chart-fourth { fill: #34A853; } .knob { fill: #222; stroke: #fff; stroke-width: 2; } .center-score { font-size: 32px; font-weight: bold; text-anchor: middle; } .center-level { font-size: 16px; text-anchor: middle; } .legend-item rect { width: 15px; height: 15px; } .legend-item text { font-size: 12px; fill: #333; } svg { font: 10px sans-serif; }
JavaScript
// 配置项 var gaugeConfig = { value: 17, maxValue: 100, levelList: [ { name: "较差", colorClass: "chart-first", min: 0, max: 25 }, { name: "中等", colorClass: "chart-second", min: 25, max: 50 }, { name: "良好", colorClass: "chart-third", min: 50, max: 75 }, { name: "优秀", colorClass: "chart-fourth", min: 75, max: 100 } ] } var percentValue = gaugeConfig.value / gaugeConfig.maxValue; (function () { var barWidth, chart, chartInset, degToRad, repaintGauge, height, margin, numSections, padRad, percToDeg, percToRad, percent, radius, svg, totalPercent, width, knob; percent = percentValue; numSections = 4; padRad = 0.025; chartInset = 10; totalPercent = .75; el = d3.select(".chart-gauge"); margin = { top: 20, right: 20, bottom: 50, left: 20 }; width = el[0][0].offsetWidth - margin.left - margin.right; height = width + 30; radius = Math.min(width, width) / 2; barWidth = 40 * width / 300; // 工具方法 percToDeg = function (perc) { return perc * 360; }; percToRad = function (perc) { return degToRad(percToDeg(perc)); }; degToRad = function (deg) { return deg * Math.PI / 180; }; // 获取当前数值对应的等级 function getCurrentLevel(val) { for(var i=0;i<gaugeConfig.levelList.length;i++) { if(val >= gaugeConfig.levelList[i].min && val <= gaugeConfig.levelList[i].max) { return gaugeConfig.levelList[i]; } } return gaugeConfig.levelList[0]; } // 创建SVG svg = el.append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom); chart = svg.append("g").attr("transform", "translate(" + (width + margin.left) / 2 + ", " + (width + margin.top) / 2 + ")"); // 绘制刻度弧 chart.append("path").attr("class", "arc chart-first"); chart.append("path").attr("class", "arc chart-second"); chart.append("path").attr("class", "arc chart-third"); chart.append("path").attr("class", "arc chart-fourth"); var arc = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth); repaintGauge = function () { var perc = 0.5; var next_start = totalPercent; for(var i=1;i<=4;i++) { var arcStartRad = percToRad(next_start); var arcEndRad = arcStartRad + percToRad(perc / 4); next_start += perc / 4; if(i>1) arcStartRad += padRad; arc.startAngle(arcStartRad).endAngle(arcEndRad); chart.select(".chart-"+["first","second","third","fourth"][i-1]).attr("d", arc); } } repaintGauge(); // 绘制刻度值 svg.append("text").text(0).attr("x", 10).attr("y", (width + margin.top)/2 + 5).attr("font-size", 15).style("fill", "#000"); svg.append("text").text(gaugeConfig.maxValue/2).attr("x", (width + margin.left)/2 - 10).attr("y", 20).attr("font-size", 15).style("fill", "#000"); svg.append("text").text(gaugeConfig.maxValue).attr("x", width + margin.left - 20).attr("y", (width + margin.top)/2 + 5).attr("font-size", 15).style("fill", "#000"); // 绘制旋钮 knob = chart.append("circle") .attr("class", "knob") .attr("r", 8) .attr("cx", 0) .attr("cy", 0); // 旋钮移动逻辑 function moveKnob(perc) { var thetaRad = percToRad(perc / 2); var knobRadius = radius - chartInset - barWidth/2; var x = -knobRadius * Math.cos(thetaRad); var y = -knobRadius * Math.sin(thetaRad); knob.transition().delay(300).ease("bounce").duration(1500) .attr("cx", x) .attr("cy", y); } moveKnob(percent); // 绘制中心文本 var currentLevel = getCurrentLevel(gaugeConfig.value); chart.append("text") .attr("class", "center-score") .attr("x", 0) .attr("y", 0) .text(gaugeConfig.value); chart.append("text") .attr("class", "center-level") .attr("x", 0) .attr("y", 20) .text(currentLevel.name); // 绘制图例 var legend = svg.append("g").attr("transform", "translate("+(margin.left)+"," + (width + margin.top + 10) + ")"); var legendItems = legend.selectAll(".legend-item") .data(gaugeConfig.levelList) .enter().append("g") .attr("class", "legend-item") .attr("transform", function(d,i) { return "translate(" + (i * 80) + ", 0)"; }); legendItems.append("rect") .attr("x", 0) .attr("y", 0) .attr("class", function(d) { return d.colorClass; }); legendItems.append("text") .attr("x", 20) .attr("y", 12) .text(function(d) { return d.min + "-" + d.max + " " + d.name; }); })();
内容的提问来源于stack exchange,提问作者V K
相关产品推荐
相关产品推荐

