|
@@ -0,0 +1,663 @@
|
|
|
+/**
|
|
|
+ * 发现bug
|
|
|
+ * android app上字体要大于等于20px才能画多个字体,不然要每次调用fillText时都要设置字体
|
|
|
+ * android app上,重绘时会一直闪烁
|
|
|
+ * */
|
|
|
+class canvasDraw {
|
|
|
+ /*
|
|
|
+ * @params{ DOM } canvasEl canvas元素节点
|
|
|
+ * @params{ Object } option 统计图配置信息
|
|
|
+ */
|
|
|
+ constructor(el, option) {
|
|
|
+ // canvas DOM;
|
|
|
+ this.option = option;
|
|
|
+ this.context = el.context;
|
|
|
+ // canvas宽高
|
|
|
+ this.width = el.width;
|
|
|
+ this.height = el.height;
|
|
|
+ // 预留XY文字间距
|
|
|
+ this.reservedSpace = 55;
|
|
|
+ this.textAndDotSpace = 10;
|
|
|
+ // X点之间的间隔 宽高
|
|
|
+ this.spaceX = 1;
|
|
|
+ this.spaceY = 70;
|
|
|
+ this.xWidth = 1;
|
|
|
+ this.xHeight = 1;
|
|
|
+
|
|
|
+ this.XList = [];
|
|
|
+ this.YList = [];
|
|
|
+
|
|
|
+ let yAxis = this.option.yAxis || {};
|
|
|
+
|
|
|
+ this.xAxis = this.option.xAxis.map(e => {
|
|
|
+ let date = new Date(e)
|
|
|
+ return date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日';
|
|
|
+ })
|
|
|
+ let measure = this.context.measureText(this.xAxis[0]).width;
|
|
|
+ this.xAxisLength = measure || (this.width - this.reservedSpace) / 2;
|
|
|
+
|
|
|
+ this.drawDataList = this.option.data || [];
|
|
|
+ this.xScaleListLength = this.drawDataList[0] && this.drawDataList[0].data.length || 0;
|
|
|
+
|
|
|
+ // 刻度数量
|
|
|
+ this.scale = yAxis.subsection ? yAxis.subsection + 1 : 5;
|
|
|
+
|
|
|
+ this.xScaleSizeOriginal = 0;
|
|
|
+
|
|
|
+ // XY文字颜色 X线条点颜色 数据线颜色
|
|
|
+ this.XYTextColor = '#666666';
|
|
|
+ this.XDotColor = '#666666';
|
|
|
+ this.dataLineXColor = this.option.dataLineXColor || [];
|
|
|
+ if (this.dataLineXColor.length < this.xScaleListLength) {
|
|
|
+ this.dataLineXColor = this.dataLineXColor.concat(
|
|
|
+ [...Array(this.xScaleListLength - this.dataLineXColor.length).keys()]
|
|
|
+ .map(e => this.getColor16())
|
|
|
+ )
|
|
|
+ }
|
|
|
+ this.dataDotSize = 5;
|
|
|
+ this.dataLineSize = 0.5;
|
|
|
+
|
|
|
+ let data = this.drawDataList.length > 1 ?
|
|
|
+ this.drawDataList.map(e => e.data).reduce((a,b) => a.concat(b || []))
|
|
|
+ : this.drawDataList[0].data;
|
|
|
+
|
|
|
+ this.max = Math.max.apply(null, data);
|
|
|
+ this.min = Math.min.apply(null, data);
|
|
|
+
|
|
|
+
|
|
|
+ this.yScaleList = [];
|
|
|
+ this.xScaleList = [];
|
|
|
+
|
|
|
+ // 获取鼠标手势事件参数
|
|
|
+ this.touchX = 0;
|
|
|
+ this.touchY = 0;
|
|
|
+
|
|
|
+ // 计数的做优化的值
|
|
|
+ this.timeout = null;
|
|
|
+
|
|
|
+ // 初始化
|
|
|
+ this.init();
|
|
|
+
|
|
|
+ // 绑定事件
|
|
|
+ if(el.addEventListener){
|
|
|
+ this.el.addEventListener('touchstart', touchstart, false);
|
|
|
+ this.el.addEventListener('touchmove', touchmove, false);
|
|
|
+ this.el.addEventListener('touchend', touchend, false);
|
|
|
+ this.el.addEventListener('mouseout', mouseout, false);
|
|
|
+ this.el.addEventListener('mousemove', mousemove, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取刻度数据
|
|
|
+ * @return {Array} kedu
|
|
|
+ */
|
|
|
+ getDatas(){
|
|
|
+ let max = this.max;
|
|
|
+ let keduObject = this.keduObject = this.getMeanInfo();
|
|
|
+
|
|
|
+ let kedu = [];
|
|
|
+ if(keduObject.lose){
|
|
|
+ for (let i = keduObject.lose; i > 0; i--) {
|
|
|
+ if(keduObject.mean < 0){
|
|
|
+ kedu.push(parseFloat((keduObject.mean * i).toFixed(2)));
|
|
|
+ }else{
|
|
|
+ kedu.push(parseFloat('-' + (keduObject.mean * i).toFixed(2)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ kedu.push(0)
|
|
|
+ for (let i = 1, length = keduObject.just; i <= length; i++) {
|
|
|
+ kedu.push(parseFloat((Math.abs(keduObject.mean) * i).toFixed(2)));
|
|
|
+ }
|
|
|
+ return kedu
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 刻度算法
|
|
|
+ * @return {Number} 刻度大小
|
|
|
+ */
|
|
|
+ meanFun(max, num = 4, bool) {
|
|
|
+ if(max == 0 || num == 0){
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ if(max < 0){
|
|
|
+ Math.abs(max)
|
|
|
+ }
|
|
|
+ if (bool) {
|
|
|
+ max = max.toFixed(2) * 100;
|
|
|
+ return ((max + max % num) / num) / 100;
|
|
|
+ }
|
|
|
+ return Math.ceil((max + max % num) / num);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 计算刻度数据
|
|
|
+ * @return {Object} .just 正刻度量 .lose 负刻度量 .mean刻度大小
|
|
|
+ */
|
|
|
+ getMeanInfo() {
|
|
|
+ let max = this.max;
|
|
|
+ let min = this.min;
|
|
|
+ let subsection = this.scale - 1;
|
|
|
+
|
|
|
+ let boolEan = Math.floor(max) === Math.floor(min);
|
|
|
+
|
|
|
+ if (max > 0 && min < 0) {
|
|
|
+ let copyMin = Math.abs(min);
|
|
|
+ let mean = this.meanFun(copyMin + max, subsection, boolEan);
|
|
|
+ let bool = copyMin > max;
|
|
|
+ let num = Math.floor([bool ? copyMin : max][0] / mean);
|
|
|
+ let nMean = this.meanFun([bool ? copyMin : max][0], num, boolEan);
|
|
|
+
|
|
|
+ return {
|
|
|
+ just: bool ? subsection - num : num,
|
|
|
+ mean: nMean,
|
|
|
+ lose: !bool ? subsection - num : num
|
|
|
+ }
|
|
|
+ } else if (max >= 0 && min >= 0) {
|
|
|
+ return {
|
|
|
+ just: subsection,
|
|
|
+ mean: this.meanFun(max, subsection,boolEan),
|
|
|
+ lose: 0
|
|
|
+ }
|
|
|
+ } else if (max <= 0 && min < 0) {
|
|
|
+ this.isLose = true;
|
|
|
+ return {
|
|
|
+ just: 0,
|
|
|
+ mean: this.meanFun(min, subsection,boolEan),
|
|
|
+ lose: subsection
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 初始化统计图
|
|
|
+ */
|
|
|
+ init() {
|
|
|
+ this.YText = this.getDatas().reverse();
|
|
|
+ this.getYAxisList();
|
|
|
+ this.getXAxisList();
|
|
|
+
|
|
|
+ this.drawXYAxis();
|
|
|
+ this.drawYText();
|
|
|
+ this.drawXText();
|
|
|
+ this.initData();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 悬停线
|
|
|
+ */
|
|
|
+ drawMouseTooltipLine() {
|
|
|
+ if (!this.isTouch()) return;
|
|
|
+ this.dataLineSize = 1;
|
|
|
+ // this.redraw();
|
|
|
+ this.drawMouseTooltipLineContext();
|
|
|
+ this.drawMouseTooltip();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制悬停线
|
|
|
+ */
|
|
|
+ drawMouseTooltipLineContext(){
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.strokeStyle = 'rgba(0,0,0,0.3)';
|
|
|
+ this.context.lineTo(this.touchX, this.YList[0]);
|
|
|
+ this.context.lineTo(this.touchX, this.YList[this.YList.length - 1]);
|
|
|
+ this.context.stroke();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 用于判断是否是在图指定区域里
|
|
|
+ * @return {Boolean} true在指定区域里
|
|
|
+ */
|
|
|
+ isTouch() {
|
|
|
+ let XList = this.XList;
|
|
|
+ let YList = this.YList;
|
|
|
+ let touchX = this.touchX;
|
|
|
+ let touchY = this.touchY;
|
|
|
+
|
|
|
+ let maxX = XList[XList.length - 1];
|
|
|
+ let minX = XList[0];
|
|
|
+ let maxY = YList[YList.length - 1];
|
|
|
+ let minY = YList[0];
|
|
|
+
|
|
|
+ return (
|
|
|
+ touchX >= minX && touchX <= maxX &&
|
|
|
+ touchY >= minY && touchY <= maxY
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 绘制悬停圈
|
|
|
+ * 绘制坐标点数据
|
|
|
+ */
|
|
|
+ drawMouseTooltip() {
|
|
|
+ let XList = this.XList;
|
|
|
+ let YList = this.YList;
|
|
|
+ let touchX = this.touchX;
|
|
|
+ let list = this.drawDataList;
|
|
|
+ let fontTxtSize = this.fontTxtSize;
|
|
|
+ let xScaleList = this.xScaleList;
|
|
|
+ let yScaleList = this.yScaleList;
|
|
|
+ let dataLineXColor = this.dataLineXColor;
|
|
|
+ let lineHeight = this.lineHeight;
|
|
|
+ let textIndent = this.textIndent;
|
|
|
+ let minXValue = XList[0];
|
|
|
+ let minYValue = YList[0];
|
|
|
+ let xAxis = this.xAxis;
|
|
|
+
|
|
|
+ let index = this.touchIndex = this.getBigValueMin(xScaleList, touchX);
|
|
|
+
|
|
|
+ this.tooltipHeight = (fontTxtSize + lineHeight) * (list.length + 1) + lineHeight;
|
|
|
+
|
|
|
+ list.forEach((e, i) => {
|
|
|
+
|
|
|
+ this.context.beginPath();
|
|
|
+ if(touchX > xScaleList[index] - 2 && touchX < xScaleList[index] + 2){
|
|
|
+ this.context.fillStyle = dataLineXColor[i];
|
|
|
+ this.context.globalAlpha=0.3;
|
|
|
+ this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 2, 0, 2 * Math.PI);
|
|
|
+ this.context.fill();
|
|
|
+
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.globalAlpha= 1;
|
|
|
+ this.context.fillStyle = '#FFFFFF';
|
|
|
+ this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 4 + 0.5, 0, 2 * Math.PI);
|
|
|
+ this.context.fill();
|
|
|
+
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.globalAlpha= 1;
|
|
|
+ this.context.fillStyle = dataLineXColor[i];
|
|
|
+ this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 4, 0, 2 * Math.PI);
|
|
|
+ this.context.fill();
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ // tip长度
|
|
|
+ this.context.textAlign = 'start';
|
|
|
+ this.context.textBaseline = 'middle';
|
|
|
+ this.context.fillStyle = '#FFFFFF';
|
|
|
+ let measure = this.context.measureText(xAxis[index]).width;
|
|
|
+ this.tooltipWidth = measure ? measure + this.fontTxtSize * 2 : (this.width - this.reservedSpace) / 2;
|
|
|
+ list.forEach((e, i) => {
|
|
|
+ let dataTxt = e.data;
|
|
|
+ let title = (e.title || '') + ':' + dataTxt[index];
|
|
|
+ let measure = this.context.measureText(title).width;
|
|
|
+ let tooltipWidth = measure ? measure + this.fontTxtSize * 2 : (this.width - this.reservedSpace) / 2;
|
|
|
+ if(tooltipWidth > this.tooltipWidth){
|
|
|
+ this.tooltipWidth = tooltipWidth;
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ this.context.beginPath()
|
|
|
+ this.context.fillStyle = 'rgba(255,255,255,1)';
|
|
|
+ this.roundRect(minXValue, minYValue, this.tooltipWidth, this.tooltipHeight, 3);
|
|
|
+ this.context.fill();
|
|
|
+
|
|
|
+ this.context.beginPath()
|
|
|
+ this.context.strokeStyle = 'rgba(220,65,55,1)';
|
|
|
+ this.context.moveTo(minXValue, minYValue);
|
|
|
+ this.context.lineTo(minXValue + this.tooltipWidth, minYValue);
|
|
|
+ this.context.lineTo(minXValue + this.tooltipWidth, minYValue + this.tooltipHeight);
|
|
|
+ this.context.lineTo(minXValue, minYValue + this.tooltipHeight);
|
|
|
+ this.context.closePath()
|
|
|
+ this.context.stroke();
|
|
|
+
|
|
|
+ this.context.beginPath()
|
|
|
+ this.context.fillStyle = '#333333';
|
|
|
+ this.context.font = this.fontTxtSize + this.fontFamily;
|
|
|
+ this.context.fillText(xAxis[index], minXValue + textIndent, minYValue + lineHeight + textIndent / 2, );
|
|
|
+ let x = 0;
|
|
|
+ let y = 0;
|
|
|
+ list.forEach((e, i) => {
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.fillStyle = '#333333';
|
|
|
+ let dataTxt = e.data;
|
|
|
+ let title = (e.title || '') + ':' + dataTxt[index];
|
|
|
+ x = minXValue + textIndent;
|
|
|
+ y = minYValue + (fontTxtSize + lineHeight) * (i + 1) + textIndent / 2;
|
|
|
+ this.context.font = this.fontTxtSize + this.fontFamily;
|
|
|
+ this.context.fillText(title, x + textIndent * 2, y + lineHeight);
|
|
|
+
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.fillStyle = dataLineXColor[i];
|
|
|
+ this.context.arc(x + textIndent / 2, y + lineHeight, fontTxtSize / 4, 0, 2 * Math.PI);
|
|
|
+ this.context.fill();
|
|
|
+ })
|
|
|
+ // #ifdef H5
|
|
|
+ setTimeout(() => {
|
|
|
+ this.context.draw(true);
|
|
|
+ },100)
|
|
|
+ // #endif
|
|
|
+ // #ifndef H5
|
|
|
+ this.context.draw(true);
|
|
|
+ // #endif
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制圆角矩形
|
|
|
+ */
|
|
|
+ roundRect(x, y, w, h, r) {
|
|
|
+ if (w < 2 * r) r = w / 2;
|
|
|
+ if (h < 2 * r) r = h / 2;
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.moveTo(x + r, y);
|
|
|
+ this.context.arcTo(x + w, y, x + w, y + h, r);
|
|
|
+ this.context.arcTo(x + w, y + h, x, y + h, r);
|
|
|
+ this.context.arcTo(x, y + h, x, y, r);
|
|
|
+ this.context.arcTo(x, y, x + w, y, r);
|
|
|
+ this.context.closePath();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取数据点下标
|
|
|
+ */
|
|
|
+ getBigValueMin(array, x) {
|
|
|
+ for (let i = 0, length = array.length; i < length; i++) {
|
|
|
+ if (array[i] >= x) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return array.length - 1;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取数据对应坐标
|
|
|
+ */
|
|
|
+ initData() {
|
|
|
+ let YList = this.YList;
|
|
|
+ let XList = this.XList;
|
|
|
+ let YText = this.YText;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ let xAxisLength = this.xAxisLength;
|
|
|
+ // 刻度最大值最小值
|
|
|
+ let minData = YText[YText.length - 1];
|
|
|
+ let maxScaleList = YText[0];
|
|
|
+ // 0坐标到Y刻度总高度的距离
|
|
|
+ let XYHeight = YList[YList.length - 1];
|
|
|
+ // Y刻度总高度
|
|
|
+ let yHeight = XYHeight - this.spaceY;
|
|
|
+ // x总刻度
|
|
|
+ let xScaleAll = XList[XList.length - 1];
|
|
|
+ // X每刻度大小
|
|
|
+ this.xScaleSizeOriginal = this.xScaleSize = parseFloat(((xScaleAll - reservedSpace) / (this.xScaleListLength - 1)).toFixed(
|
|
|
+ 2));
|
|
|
+ // y刻度每份大小
|
|
|
+ let yScaleSize = this.yScaleSize = 0;
|
|
|
+ // 当刻度最大值是0或者负数的时候
|
|
|
+ if (YText[0] <= 0) {
|
|
|
+ this.yScaleSize = yScaleSize = parseFloat((yHeight / (Math.abs(minData) - Math.abs(maxScaleList))).toFixed(8));
|
|
|
+ this.drawDataList.forEach(data => {
|
|
|
+ let list = data.data;
|
|
|
+ this.yScaleList.push(list.map(e => Math.floor((Math.abs(e)) * yScaleSize + this.spaceY)));
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this.yScaleSize = yScaleSize = parseFloat((yHeight / (maxScaleList - minData)).toFixed(8));
|
|
|
+ this.drawDataList.forEach(data => {
|
|
|
+ let list = data.data;
|
|
|
+ this.yScaleList.push(list.map(e => Math.floor((maxScaleList - e) * yScaleSize + this.spaceY)));
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ this.drawDataLine();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 重绘统计图 xy坐标轴 刻度文字 坐标线 统计线
|
|
|
+ */
|
|
|
+ redraw() {
|
|
|
+ this.context.clearRect(0, 0, this.width, this.height);
|
|
|
+ this.drawXYAxis();
|
|
|
+ this.drawYText();
|
|
|
+ this.drawDataLine();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 调节X坐标间距
|
|
|
+ * @param {String,Number} size = [1-10]
|
|
|
+ */
|
|
|
+ handleXScaleSize(size) {
|
|
|
+ this.xScaleSize = this.xScaleSizeOriginal * size;
|
|
|
+ this.redraw();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制统计线
|
|
|
+ */
|
|
|
+ drawDataLine() {
|
|
|
+ let dataLineSize = this.dataLineSize;
|
|
|
+ let dataDotSize = this.dataDotSize;
|
|
|
+ let dataLineXColor = this.dataLineXColor;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ let xScaleSize = this.xScaleSize;
|
|
|
+
|
|
|
+ let YList = this.YList;
|
|
|
+ let xScaleList = this.xScaleList = [...Array(this.xScaleListLength).keys()].map(i => Math.floor(i * xScaleSize + reservedSpace));
|
|
|
+
|
|
|
+ this.context.lineJoin = 'round';
|
|
|
+
|
|
|
+ let indexOf0 = this.YText.indexOf(0);
|
|
|
+ let index0 = YList[indexOf0];
|
|
|
+ let drawDataList = this.drawDataList;
|
|
|
+
|
|
|
+ let gradient = this.context
|
|
|
+ .createLinearGradient(this.xScaleList[0], YList[0], this.xScaleList[0], YList[YList.length - 1]);
|
|
|
+ drawDataList.forEach((e, i) => {
|
|
|
+ if(e.isBg){
|
|
|
+ let bg = e.bgColor || [{ key:0, value: 'rgba(231, 0, 18, 0.5)' },{ key:1, value: 'rgba(231, 0, 18, 0.1)' }];
|
|
|
+ if(typeof bg === 'string'){
|
|
|
+ gradient = bg;
|
|
|
+ }else{
|
|
|
+ bg.forEach((ee,ii) => {
|
|
|
+ gradient.addColorStop(ee.key, ee.value);
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.context.fillStyle = gradient;
|
|
|
+ this.yScaleList.forEach((yD, yI) => {
|
|
|
+ for (var i = 1, length = xScaleList.length; i < length; i++) {
|
|
|
+ let xx = this.xScaleList[i - 1];
|
|
|
+ let xx1 = this.xScaleList[i];
|
|
|
+ let yy = yD[i - 1];
|
|
|
+ let yy1 = yD[i];
|
|
|
+ let ax = (xx1 - xx) / 3;
|
|
|
+ let bx = xx + ax;
|
|
|
+ let bx1 = xx + ax * 2;
|
|
|
+
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.moveTo(xx, yy);
|
|
|
+ this.context.bezierCurveTo(bx, yy, bx1, yy1, xx1, yy1);
|
|
|
+ if(drawDataList[yI].isBg){
|
|
|
+ this.context.lineTo(xx1, index0)
|
|
|
+ this.context.lineTo(xx, index0)
|
|
|
+ this.context.lineTo(xx, yy)
|
|
|
+ this.context.fill();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.context.lineWidth = this.dataLineSize;
|
|
|
+ this.yScaleList.forEach((yD, yI) => {
|
|
|
+ this.context.beginPath();
|
|
|
+ this.context.strokeStyle = dataLineXColor[yI];
|
|
|
+ for (var i = 1, length = xScaleList.length; i < length; i++) {
|
|
|
+ let xx = this.xScaleList[i - 1];
|
|
|
+ let xx1 = this.xScaleList[i];
|
|
|
+ let yy = yD[i - 1];
|
|
|
+ let yy1 = yD[i];
|
|
|
+ let ax = (xx1 - xx) / 3;
|
|
|
+ let bx = xx + ax;
|
|
|
+ let bx1 = xx + ax * 2;
|
|
|
+
|
|
|
+ this.context.moveTo(xx, yy);
|
|
|
+ this.context.bezierCurveTo(bx, yy, bx1, yy1, xx1, yy1);
|
|
|
+ }
|
|
|
+ this.context.stroke();
|
|
|
+ })
|
|
|
+ // #ifdef H5
|
|
|
+ setTimeout(() => {
|
|
|
+ this.context.draw(true);
|
|
|
+ },100)
|
|
|
+ // #endif
|
|
|
+ // #ifndef H5
|
|
|
+ this.context.draw(true);
|
|
|
+ // #endif
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 随机生成16位字符颜色
|
|
|
+ */
|
|
|
+ getColor16() {
|
|
|
+ return '#' + Math.random().toString(16).slice(-6);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制Y刻度文字
|
|
|
+ */
|
|
|
+ drawYText() {
|
|
|
+ let YText = this.YText;
|
|
|
+ let YList = this.YList;
|
|
|
+ let XYTextColor = this.XYTextColor;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ let textAndDotSpace = this.textAndDotSpace;
|
|
|
+ let x = reservedSpace - textAndDotSpace;
|
|
|
+
|
|
|
+
|
|
|
+ this.context.fillStyle = XYTextColor;
|
|
|
+ this.context.textAlign = 'end';
|
|
|
+ this.context.textBaseline = 'middle';
|
|
|
+ YList.forEach((y, i) => {
|
|
|
+ this.context.font = this.fontTxtSize + this.fontFamily;
|
|
|
+ this.context.fillText(this.YText[i], x, y, x);
|
|
|
+ })
|
|
|
+ this.drawXText();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制X刻度文字,由于时间问题,这里只绘制了起始和结束文字
|
|
|
+ */
|
|
|
+ drawXText() {
|
|
|
+ let xAxis = this.xAxis;
|
|
|
+ let YList = this.YList;
|
|
|
+ let XList = this.XList;
|
|
|
+ let xAxisLength = this.xAxisLength;
|
|
|
+ let XYTextColor = this.XYTextColor;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+
|
|
|
+ this.context.fillStyle = XYTextColor;
|
|
|
+
|
|
|
+ this.context.textAlign = 'start';
|
|
|
+ this.context.textBaseline = 'middle';
|
|
|
+ this.context.font = this.fontTxtSize + this.fontFamily;
|
|
|
+ this.context.fillText(xAxis[0], XList[0],
|
|
|
+ YList[YList.length - 1] + this.fontTxtSize,
|
|
|
+ xAxisLength + this.fontTxtSize * 4);
|
|
|
+ this.context.font = this.fontTxtSize + this.fontFamily;
|
|
|
+ this.context.textAlign = 'end';
|
|
|
+ this.context.fillText(xAxis[xAxis.length - 1],
|
|
|
+ XList[XList.length - 1], YList[YList.length - 1] + this.fontTxtSize,
|
|
|
+ xAxisLength + this.fontTxtSize * 4);
|
|
|
+
|
|
|
+
|
|
|
+ // #ifdef H5
|
|
|
+ setTimeout(() => {
|
|
|
+ this.context.draw(true);
|
|
|
+ },100)
|
|
|
+ // #endif
|
|
|
+ // #ifndef H5
|
|
|
+ this.context.draw(true);
|
|
|
+ // #endif
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 绘制XY统计图雏形
|
|
|
+ */
|
|
|
+ drawXYAxis() {
|
|
|
+ let XList = this.XList;
|
|
|
+ let YList = this.YList;
|
|
|
+ let xWidth = this.xWidth;
|
|
|
+ let xHeight = this.xHeight;
|
|
|
+ let XDotColor = this.XDotColor;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ this.context.fillStyle = XDotColor;
|
|
|
+ YList.forEach((y, i) => {
|
|
|
+ XList.forEach((x, j) => {
|
|
|
+ this.context.fillRect(x, y, xWidth, xHeight);
|
|
|
+ })
|
|
|
+ })
|
|
|
+ // #ifdef H5
|
|
|
+ setTimeout(() => {
|
|
|
+ this.context.draw(true);
|
|
|
+ },100)
|
|
|
+ // #endif
|
|
|
+ // #ifndef H5
|
|
|
+ this.context.draw(true);
|
|
|
+ // #endif
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取X轴对应坐标点
|
|
|
+ */
|
|
|
+ getXAxisList() {
|
|
|
+ let width = this.width;
|
|
|
+ let spaceX = this.spaceX;
|
|
|
+ let xWidth = this.xWidth;
|
|
|
+ let xHeight = this.xHeight;
|
|
|
+
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ let length = (width - reservedSpace - this.fontTxtSize) / (xWidth + spaceX);
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ this.XList.push(i * (spaceX + xWidth) + reservedSpace);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取y轴对应坐标点
|
|
|
+ */
|
|
|
+ getYAxisList() {
|
|
|
+ let height = this.height;
|
|
|
+ let scale = this.scale;
|
|
|
+ let reservedSpace = this.reservedSpace;
|
|
|
+ this.spaceY = Math.floor((height - reservedSpace) / scale);
|
|
|
+ for (let i = 0; i < scale; i++) {
|
|
|
+ this.YList.push(i * this.spaceY + this.spaceY);
|
|
|
+ }
|
|
|
+ this.setTextStyle();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 设置字体类型,行高,字体大小,缩进
|
|
|
+ */
|
|
|
+ setTextStyle() {
|
|
|
+ // 字体
|
|
|
+ this.fontFamily = 'px 宋体';
|
|
|
+ this.lineHeight = 10;
|
|
|
+ this.textIndent = 10;
|
|
|
+ this.fontTxtSize = this.spaceY / 5 < 14 ? 14 : this.spaceY / 5;
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+let touchstart = function (e) {
|
|
|
+ if (!e.touches[0]) return
|
|
|
+ this.ctx.touchX = e.touches[0].x;
|
|
|
+ this.ctx.touchY = e.touches[0].y;
|
|
|
+ this.ctx.drawMouseTooltipLine()
|
|
|
+}
|
|
|
+
|
|
|
+let touchmove = function (e) {
|
|
|
+ if (!e.touches[0]) return
|
|
|
+ this.ctx.touchX = e.touches[0].x;
|
|
|
+ this.ctx.touchY = e.touches[0].y;
|
|
|
+ this.ctx.drawMouseTooltipLine()
|
|
|
+}
|
|
|
+
|
|
|
+let mousemove = function (e){
|
|
|
+ if (e.pageX){
|
|
|
+ this.ctx.touchX = e.x;
|
|
|
+ this.ctx.touchY = e.y;
|
|
|
+ this.ctx.drawMouseTooltipLine()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+let mouseout = function (e) {
|
|
|
+ this.ctx.dataLineSize = 0.5;
|
|
|
+ this.ctx.redraw()
|
|
|
+}
|
|
|
+
|
|
|
+let touchend = function (e) {
|
|
|
+ this.ctx.dataLineSize = 0.5;
|
|
|
+ this.ctx.redraw()
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ canvasDraw,
|
|
|
+ touchstart,
|
|
|
+ touchmove,
|
|
|
+ mousemove,
|
|
|
+ mouseout,
|
|
|
+ touchend
|
|
|
+}
|