一、肯定纵坐标的范围并绘制javascript
二、根据真实数据绘制折线java
相关阅读:
在微信小程序中绘制图表(part1)
在微信小程序中绘制图表(part3)git
关注个人 github 项目 查看完整代码。 github
为了不纵坐标的刻度出现小数的状况,咱们把纵坐标分为5个区块,咱们取最小单位刻度为例如10(可以被5整除),固然真实状况会比这复杂,待会儿咱们再讨论。canvas
因此咱们的处理输入输出应该是下面的结果小程序
(5, 34.1) => (10, 40) (10, 34) => (10, 40) (-5.1, 40) => (-10, 40)
// 肯定Y轴取值范围 function findRange (num, type, limit) { limit = limit || 10; // upper向上查找,lower向下查找 type = type ? type : 'upper'; // 进行取整操做,避免while时进入死循环 if (type === 'upper') { num = Math.ceil(num); } else { num = Math.floor(num); } while (num % limit !== 0) { if (type === 'upper') { num++; } else { num--; } } return num; }
好了,初步的肯定范围已经完成了,可是细想一下这个范围仍是不是很理想,好比用户传入的数据都是小数级别的,好比 (0.2, 0.8)
,咱们输出的范围是(0, 5)
这个范围偏大,图表展示的效果则会是上面有大部分的留白,一样用户输入的数据很大,好比(10000, 18000)
,咱们获得的范围是(10000, 18010)
,这个范围则没什么意义,因此咱们须要根据传入的数据的范围来分别肯定咱们的最小单位刻度。segmentfault
规定咱们的参数格式是这样的:微信小程序
opts = { ... series: [{ ... data: [15, 20, 45, 37, 4, 80] }, { ... data: [70, 40, 65, 100, 34, 18] } ] }
让咱们继续进行优化数组
// 合并数据,将series中的每项data整合到一个数组当中 function dataCombine(series) { return series.reduce(function(a, b) { return (a.data ? a.data : a).concat(b.data); }, []); } // 根据数据范围肯定最小单位刻度 function getLimit (maxData, minData) var limit = 0; var range = maxData - minData; if (range >= 10000) { limit = 1000; } else if (range >= 1000) { limit = 100; } else if (range >= 100) { limit = 10; } else if (range >= 10) { limit = 5; } else if (range >= 1) { limit = 1; } else if (range >= 0.1) { limit = 0.1; } else { limit = 0.01; } } var dataList = dataCombine(opts.series); // 获取传入数据的最小值 var minData = Math.min.apply(this, dataList); // 获取传入数据的最大值 var maxData = Math.max.apply(this, dataList); var limit = getLimit(maxData, minData); var minRange = findRange(minData, 'lower', limit); var maxRange = findRange(maxData, 'upper', limit);
如今咱们动态的肯定除了合适的最小刻度范围,接下来咱们接着优化一下上面的findRange
方法,主要是增长对小数的支持微信
function findRange (num, type, limit) { limit = limit || 10; type = type ? type : 'upper'; var multiple = 1; while (limit < 1) { limit *= 10; multiple *= 10; } if (type === 'upper') { num = Math.ceil(num * multiple); } else { num = Math.floor(num * multiple); } while (num % limit !== 0) { if (type === 'upper') { num++; } else { num--; } } return num / multiple; }
如今咱们已经肯定好了Y轴的取值范围,关于如何画出Y轴能够参看 part1 中X轴的绘制方法,此处再也不累赘。
Y轴效果图:
opts = { ... series: [{ ... data: [15, 20, 45, 37, 4, 80] }, { ... data: [70, 40, 65, 100, 34, 18] } ] }
opts = { ... series: [{ ... data: [0.15, 0.2, 0.45, 0.37, 0.4, 0.8] }, { ... data: [0.30, 0.37, 0.65, 0.78, 0.69, 0.94] } ] }
效果还不错,咱们接着往下
问题的关键在于肯定每一个数据点的(x, y)
坐标,x
坐标比较好肯定,咱们根据画布的宽度以及opts.categories
便可肯定。
规定咱们的配置为:
config = { xAxisHeight: 30, // X轴高度 yAxisWdith: 30 // Y轴宽度 }
var data = [15, 20, 45, 37, 4, 80]; var xPoints = []; var validWidth = opts.width - config.yAxisWidth; var eachSpace = validWidth / opts.categories.length; var start = config.yAxisWidth; data.forEach(function (item, index) { xPoints.push(start + (index + 0.5) * eachSpace); });
y
坐标稍微会复杂一点,须要根据Y轴的范围已经自己的数值进行计算得出。
因此咱们计算出的y
应该为
y = validHeight * (data - min) / (max - min); // 因为canvas画布是左上角为原点坐标,故咱们变化一下 // 获得最终的y绘制点 y = valideHeight - y;
代码以下:
var data = [15, 20, 45, 37, 4, 80]; var yPoints = []; var validHeight = opts.height - config.xAxisHeight; data.forEach(function(item) { var y = validHeight * (item - min) / (max - min); y = validHeight - y; yPoints.push(y); }
如今咱们已经肯定了数据点在画布上的绘制坐标,关于如何绘制折现请查看 part1 中相关内容,此处再也不累赘。
最终效果图以下:
预告:下一部分咱们一块儿讨论绘制过程当中的一些技巧、动画效果和如何工程化咱们的项目。