如何用D3.js生成指定范围的二维数组并绘制平滑曲线?
解决D3.js生成平滑曲线数据的问题
嗨,别担心,新手刚开始摸D3.js总会有点懵,这太正常啦!我来帮你一步步搞定曲线数据生成的部分,再把它和你现有的绘图代码结合起来~
第一步:整理参数+编写数据生成函数
首先咱们把你的参数表转成JavaScript数组,再写个函数,根据每个对象的alpha、beta、spend生成对应的[x,y]二维数组。
注意公式里的2.71828是自然常数e的近似值,直接用JS内置的Math.exp()计算会更准确,所以公式可以写成:y = alpha * (1 - Math.exp(-beta * x))
另外BAN3的alpha是-,你得确认这个值应该填啥(比如0或者其他有效数值),我在代码里加了判断,遇到缺失的alpha会跳过这条数据并给你提示。
// 把参数表转换成JS数组 const curveParams = [ { name: "BAN1", alpha: 140.3, beta: 3.86e-5, max_x_val: 28675.00, spend: 29919.00 }, { name: "BAN2", alpha: 115.31, beta: 2.08e-5, max_x_val: 32302.00, spend: 28367.00 }, { name: "BAN3", alpha: "-", beta: 5.07e-5, max_x_val: 19740.00, spend: 16972.00 }, { name: "ADJ4", alpha: 91.8, beta: 0.000029119, max_x_val: 25855.00, spend: 27112.00 }, { name: "ADJ5", alpha: 90.3, beta: 2.81e-5, max_x_val: 25793.00, spend: 23883.00 } ]; // 生成单条曲线的[x,y]数据函数 function generateCurveData(params) { // 处理alpha缺失/无效的情况 if (params.alpha === "-" || typeof params.alpha !== "number") { console.warn(`跳过${params.name}:alpha值缺失或无效,请确认参数`); return null; } // 生成x序列:从0到spend,步长100(包含spend本身) const xValues = d3.range(0, params.spend + 100, 100); // 计算对应y值,生成二维数组 return xValues.map(x => { const y = params.alpha * (1 - Math.exp(-params.beta * x)); return [x, y]; }); } // 为每个参数对象生成曲线数据,过滤掉无效条目 const allCurveData = curveParams.map(params => ({ name: params.name, data: generateCurveData(params) })).filter(item => item.data !== null);
第二步:结合现有D3代码绘制多条平滑曲线
接下来把生成的数据和你原有的绘图代码结合,修改后可以绘制多条曲线,每条用不同颜色,同时保留你想要的动画效果:
$( document ).ready(function() { // 定义平滑曲线生成器 var bezierLine = d3.svg.line() .x(function(d) { // 把x数据映射到SVG宽度范围内(留20px边距) const maxX = d3.max(allCurveData.flatMap(item => item.data.map(d => d[0]))); return d3.scale.linear().domain([0, maxX]).range([20, 280])(d[0]); }) .y(function(d) { // 把y数据映射到SVG高度范围内(SVG的y轴是从上到下,所以反转range) const maxY = d3.max(allCurveData.flatMap(item => item.data.map(d => d[1]))); return d3.scale.linear().domain([0, maxY]).range([130, 20])(d[1]); }) .interpolate("basis"); var svg = d3.select("#bezier-demo") .append("svg") .attr("width", 300) .attr("height", 150); // 绘制每条曲线并添加动画 svg.selectAll("path") .data(allCurveData) .enter() .append('path') .attr("d", function(d) { return bezierLine(d.data); }) .attr("stroke", function(d, i) { // 用D3内置颜色比例尺生成不同颜色 return d3.scale.category10()(i); }) .attr("stroke-width", 1) .attr("fill", "none") .transition() .duration(2000) .attrTween("stroke-dasharray", function() { var len = this.getTotalLength(); return function(t) { return (d3.interpolateString("0," + len, len + ",0"))(t); }; }); });
几个关键细节说明:
- 比例尺转换:你的x值(比如29919)远大于SVG宽度(300),必须用
d3.scale.linear()把数据值映射到画布像素范围内,不然曲线会超出画布看不到。 - alpha缺失处理:代码里加了警告提示,你替换掉BAN3的
"-"为有效数值后,就能正常生成它的曲线。 - 多曲线区分:用
d3.scale.category10()自动生成不同颜色,方便区分每条曲线对应的对象。
这样你就能得到和Excel里一样的平滑曲线啦!如果要调整比例尺范围、动画时长这类细节,直接修改对应参数就行~
内容的提问来源于stack exchange,提问作者Gerle Batde
相关产品推荐
相关产品推荐

