echart 使用

    xiaoxiao2021-03-25  223

    1.左右y轴零点不对应,分段数不对应 从github上找到的根据传入最大值,最小值,段数,重新生成最大值,最小值,段数。原文地址 https://github.com/ecomfe/echarts/pull/846/commits/f73d6fe154671ac7e73da8decc35696cf9395002 做了一些修改,根据传入左边y轴的分段坐标和零点的位置,强制设置右边y轴零点的位置,分段数,没有零点强制设0 直接调用smartSteps传入最大值,最小值,分段数,根据返回新的最大值最小值,分段数 只有左边y轴 chart.setOption({yAxis:[{max:newMax,min:newMin,interval:newStep}]}); 左右y轴 chart.setOption({yAxis:[{max:leftY.max,min:leftY.min,interval:leftY.step},{max:rightY.max,min:rightY.min,interval:rightY.step}]});

    /** * echarts 值轴刻度线计算方法 * * @author xieshiwei (谢世威, xieshiwei@baidu.com) */ /** * 最值、跨度、步长取近似值 * @function smartSteps * @param {Number} min 最小值 * @param {Number} max 最大值 * @param {Number} [sections] 段数只能是 [0, 99] 的整数,段数为 0 或者不指定段数时,将自动调整段数 * @param {Object} [opts] 其它扩展参数 * @param {Array} opts.steps 自定义步长备选值,如 [10, 12, 15, 20, 25, 30, 40, 50, 60, 80] ,但必须 => [10, 99] * @return {Object} {min: 新最小值, max: 新最大值, secs: 分段数, step: 每段长, fix: 小数保留位数, pnts: [分段结果]} */ var mySections = [5, 6]; var mySteps = [10,20,40,50]; var custSteps = 0; var Mt = Math; var Math_round = Mt.round;//四舍五入 var Math_floor = Mt.floor;//向下取整 var Math_ceil = Mt.ceil;//向上取整 function Math_log(n) {return Mt.log(n) / Mt.LN10;} function Math_pow(n) {return Mt.pow(10, n);}//返回10的n次幂 function smartSteps(min, max,sections, pntData, opts) { // 拿公共变量来接收 opts.steps 这个参数,就不用带着参数层层传递了,注意在函数的最终出口处释放这个值 custSteps = (opts || {}).steps || mySteps; //如果opts.steps是(undefined,0,null,""),就是mySteps sections = Math_round(+sections || 0) % 99; // 段数限定在 [0, 99] min = +min || 0; max = +max || 0; if (min > max) {max = [min, min = max][0];} // 最值交换 if(min<0&&max==0){ //如果最小值<0&&最大值=0,设定最大值 = -最小值 max = -min; } if((min=="-"||min==""||min==null||min>0)&&max>0){ //如果最小值不明确,最大值>0,让最小值=0 min = 0; } //设置从0开始 if(min>0){ min=0; } var span = max - min; if (span === 0) { // 跨度为零,即最大值等于最小值的情况 return forSpan0(min, max, sections); } else if (span < (sections || 5)) { // 跨度值小于要分的段数,步长必定要小于 1 if (min === Math_round(min) && max === Math_round(max)) { // 步长小于 1 同时两个最值都是整数,特别处理 return forInteger(min, max, sections); } } return coreCalc(min, max, sections,pntData); }; /** * 最值、跨度、步长取近似值 * @function smartSteps.coreCalc * @description 参数及返回值均同 smartSteps */ function coreCalc(min, max, sections,pntData, opts) { custSteps = custSteps || (opts || {}).steps || mySteps; var step, newMin, newMax; var tmpSection = sections || mySections[mySections.length - 1]; var span = getCeil(max - min); // 求 span 的近似值,返回结果是 量级 计数法,c * 10 ^ n ,其中 c => [10, 99] var expon = span.n; // 为了让后面的计算都以整数进行,设置一个基准量级 span = span.c; // 可以认为,这是跨度的最小近似值,为了满足后继条件,这个值可能会被多次延展 step = getCeil(span / tmpSection, custSteps); // 跨度最小值 / 段数最大值 是步长最小值 if (step.n < 0) { // 如果跨度小而段数多,步长出现小数时,再次放大有关值,保持整数计算 expon += step.n; // 各种计算的基准量级,保证 步长(最容易出现小数的量) 是整数 span *= Math_pow(-step.n); step.n = 0; } step = step.c * Math_pow(step.n); var zoom = Math_pow(expon); var params = { min: min, zmin: min / zoom, max: max, zmax: max / zoom, span: span, step: step, secs: tmpSection, exp: expon }; if (!sections) { // 不指定 段数 的情况 look4sections(params); } else { look4step(params); } // 如果原始值都是整数,让输出值也保持整数 if ((min === Math_round(min)) && (max === Math_round(max))) { step = params.step * zoom; if (params.exp < 0 && step !== Math_round(step)) { step = Math_floor(step); span = step * params.secs; if (span < max - min) { step += 1; span = step * params.secs; } if (span >= max - min) { var deltaSpan = span - (max - min); params.max = Math_round(max + deltaSpan / 2); params.min = Math_round(min - deltaSpan / 2); params.step = step; params.span = span; params.exp = 0; } } } var arrMM = cross0(min, max, params.min, params.max); // 避免跨 0 return makeResult(arrMM[0], arrMM[1], params.secs, params.exp,pntData,min,max); } function look4sections(params) { var sections = params.secs; var newMin, newMax, tmpSpan, tmpStep; var minStep = params.step; var minSpan = params.step * sections; // 上面计算了在最大段数下的最小步长,希望这对整体跨度的影响较小,但其它段数也要尝试一遍 for (var i = mySections.length - 1; i--;) { // 有点像二元一次方程,段数 和 步长 两个未知数 // 下面遍历可选的段数,各找一个匹配的步长,然后以 跨度最小 作为最优解的依据 sections = mySections[i]; tmpStep = getCeil(params.span / sections, custSteps).d; newMin = Math_floor(params.zmin / tmpStep) * tmpStep; newMax = Math_ceil(params.zmax / tmpStep) * tmpStep; tmpSpan = newMax - newMin; // 步长的误差被 段数 成倍放大,可能会给跨度造成更大的误差,使最后的段数大于预期的最大值 if (tmpSpan < minSpan) { minSpan = tmpSpan; minStep = tmpStep; } } newMin = Math_floor(params.zmin / minStep) * minStep; newMax = Math_ceil(params.zmax / minStep) * minStep; sections = (newMax - newMin) / minStep; if (sections < 3) {sections *= 2;} // 如果查表所得步长比最小步长大得多,那么段数就可能变得很小 params.min = newMin; params.max = newMax; params.step = minStep; params.secs = sections; } function look4step(params) { var newMax, span; var newMin = params.zmax; // 主要是找一找个步长,能在指定的段数下,覆盖到原始最值 var step = params.step; while (newMin > params.zmin) { span = step * params.secs; newMax = Math_ceil(params.zmax / step) * step; // 优先保证 max 端的误差最小,试看 min 值能否被覆盖到 newMin = newMax - span; step = getCeil(step * 1.01, custSteps).d; // 让 step 的增长允许进入更高一个量级 } step = span / params.secs; var deltaMin = params.zmin - newMin; // 上面的计算可能会让 min 端的误差更大,下面尝试均衡误差 var deltaMax = newMax - params.zmax; var deltaDelta = deltaMin - deltaMax; if (deltaDelta >= 20) { // 当 min 端的误差比 max 端大很多时,考虑将 newMin newMax 同时上移 deltaDelta = getCeil(deltaDelta / 2, custSteps, true); if (params.exp - deltaDelta.n < 1) { // 前面对 span 做了放大,所以还要看 误差修正值 与 span 的量级关系 newMin += deltaDelta.d; newMax += deltaDelta.d; } } params.min = newMin; params.max = newMax; params.step = step; } /** * 构造返回值,主要是小数计算精度处理 * @param {Number} newMin 最小值 * @param {Number} newMax 最大值 * @param {Number} sections 分段数 * @param {Number} [expon] 放大率指数,用于避免小数计算的精度问题 * @return {Object} 同 smartSteps */ function makeResult(newMin, newMax, sections, expon,pntData,min,max) { expon = expon || 0; var zoom = Math_pow(expon); //10的expon次幂 var step = (newMax - newMin) / sections; var fixTo = 0; var points = []; for (var i = sections + 1; i--;) { // 因为点数比段数多 1 points[i] = (newMin + step * i) * zoom; // 如果不涉及小数问题,这里就直接使用数值型 } if (expon < 0) { fixTo = decimals(zoom); // 前面的计算使得 zoom 的小数位数多于 step 的真实小数位,decimal返回小数点后的位数 step = +(step * zoom).toFixed(fixTo); // toFixed() number 四舍五入为指定小数位数的数字 fixTo = decimals(step); // 经过上面的处理,可以得到 step 的真实小数位数了 newMin = +(newMin * zoom).toFixed(fixTo); newMax = +(newMax * zoom).toFixed(fixTo); for (var i = points.length; i--;) { points[i] = points[i].toFixed(fixTo); // 为保证小数点对齐,统一转为字符型 +points[i] === 0 && (points[i] = 0); // 0.000 不好看 } } else { newMin *= zoom; newMax *= zoom; step *= zoom; } var oldStep=step; custSteps = 0; //划分的阶段没有0值 if(points.indexOf(0)==-1){ var inc =1; var poi = parseInt(points.length/2); do{ var stepone = oldStep*inc; for(var po = 0;po<points.length;po++){ points[po]=0; if(po<poi){ points[po]=-(poi-po)*stepone; }else if (po==poi){ points[po]=0; }else{ points[po]=(po-poi)*stepone; } } inc++; newMin = points[0]; newMax = points[points.length-1]; }while((max>newMax)||(min<newMin)) } // custSteps 这个公共变量可能持用了对用户参数的引用 // 这里是函数的最终出口,释放引用 //如果y轴零点不对应,根据传入的做左y轴零点的位置来确定右y轴零点的位置 if(pntData!=null&&pntData!=undefined){ var result= $.inArray(0, pntData); //确认左y轴零点位置 var result1 = $.inArray(0,points); //确认右y轴零点位置 if((result!=result1)){ //位置不相等 var intc =1; do{ step = oldStep*intc; intc++; for(var i=0;i<points.length;i++){ points[i]=0; if(i<result){ points[i]=-(result-i)*step; }else if (i==result){ points[result]=0; }else{ points[i]=(i-result)*step; } } newMin = points[0]; newMax = points[points.length-1]; }while((max>newMax)||(min<newMin)) } } return { min: newMin, // 新最小值 max: newMax, // 新最大值 secs: sections, // 分段数 step: step, // 每段长 fix: fixTo, // 小数保留位数,0 则为整数 pnts: points // 分段结果,整数都是数值型,小数时为了对齐小数点,都是字符型,但其中 0 不带小数点,即没有 "0.000" }; } /** * 求不小于原数的近似数,结果用 量级 计数法表示:c * 10 ^ n ,其中 c n 都是整数,且 c => [10, 99] * @param {Number} num 原数值,不适用于高精度需求 * @param {Array} [rounds] 在取近似时,提供预置选项,让 c 近似到 rounds 中的某项 * @param {Boolean} [butFloor] 为 true 时不用 Math.ceil 反而用 Math.floor 取近似,原始值 >= c * 10 ^ n * @return {Object} {c: c, n: n, d: d} 其中 c n 都是整数,且 c => [10, 99] ,原始值 <= c * 10 ^ n */ function getCeil(num, rounds, butFloor) { var n_10 = Math_floor(Math_log(num)) - 1; // 类似科学记数法,姑且称为 量级 记数法,故意将指数减 1,于是小数部分被放大 10 倍,以避免小数计算的精度问题 var c_10 = +(num * Math_pow(-n_10)).toFixed(9); // 此时的 c_10 => [10, 100),下面取近似之后是 [10, 100],toFixed 处理小数精度问题,所以不适用于高精度需求 if (!rounds) { c_10 = butFloor ? Math_floor(c_10) : Math_ceil(c_10); } else { var i; if (butFloor) { i = rounds.length; while (c_10 < rounds[--i]) {} // 在预置的近似数中,挑一个最接近但不大于目标值的项,如果挑不出来,则下标溢出 while 结束 } else { i = -1; while (c_10 > rounds[++i]) {} // 按 接近但不小于目标值 的标准挑数 } c_10 = custSteps[i]; // 如果预置数都小于目标值,则下标溢出,c_10 = undefined } if (!c_10 || c_10 > 99 || c_10 < 10) { c_10 = 10; n_10 += butFloor ? -1 : 1; // 如果是向下取近似,则 c_10 一定是向下超出区间 [10, 99] ,所以 n_10 - 1 ,反之亦然 } return { c: c_10, n: n_10, d: c_10 * Math_pow(n_10) }; } /** * 取一个数的小数位数 * @param {Number} num 原数值 * @return {Number} decimals 整数则返回 0 ,小数则返回小数点后的位数 */ function decimals(num) { num = String(+num).split('.'); return num.length > 1 ? num.pop().length : 0; } /** * 最大值与最小值相等的情况 * @param min 最小值 * @param max 最大值 * @param sections 步数 */ function forSpan0(min, max, sections) { sections = sections || 5; // 当最大值等于最小值时,就可以随便分几段了 if (max == 0) { return makeResult(0, sections, sections); // 如果全部值都是 0 ,则以 0 为起点,步长按 1 分段 } var delta = Mt.abs(max / sections); // 以最值为中心,上下各延展一小段 return coreCalc(min - delta, max + delta, sections); } /** * 最大值减去最小值小于要分的段数的情况 */ function forInteger(min, max, sections) { // 都是整数,且跨度小于段数,特别处理 sections = sections || 5; var span_2 = (sections - max + min) / 2; // 向上下延展跨度 var newMax = Math_round(max + span_2); var newMin = Math_round(min - span_2); var arrMM = cross0(min, max, newMin, newMax); // 避免跨 0 return makeResult(arrMM[0], arrMM[1], sections); } function cross0(min, max, newMin, newMax) { if (newMin < 0 && min >= 0) { // 当原始值都在 0 以上时,让新值也都在 0 以上 newMax -= newMin; newMin = 0; } else if (newMax > 0 && max <= 0) { // 尽量不让调整后的最值横跨 0 线 newMin -= newMax; newMax = 0; } return [newMin, newMax]; }
    转载请注明原文地址: https://ju.6miu.com/read-421.html

    最新回复(0)