function Chart_line(e) {
this.ele = e;
this.cav = document.createElement('canvas'); //创建canvas实例
this.ctx = this.cav.getContext('2d'); //创建画笔
this.axis = {}; //定义轴
this.data = [];
this.canStyle = {}; //定义画布样式
this.config = { //定义内部元素样式
axis: { //定义轴样式
width : 2, //轴宽度
color: '#00A6FF', //轴颜色
textColor: '#fff',//轴文字颜色
textSize: '12px', //轴文字大小
},
data: { //定义数据样式
lineColor: '#00A6FF',// 数据曲线颜色
lineWidth: 2, //曲线宽度
lineCap: 'round', //定义线端样式
lineDash: [10, 5], //自定义曲线线形
arcColor: '#fff', //数据点颜色
arcSize: 3,//数据点大小
hoverArcColor: '#f00', //鼠标移入数据点样式
hoverArcSize: 8, //鼠标移入数据点大小
},
tips: {
tipsWidth: 100, //提示框宽度
tipsHeight: 50,//提示框高度
backgroundColor: 'rgba(0,0,255,.3)', // 信息提示框背景颜色
tipsTitleBefore: '', //标题文字前缀
tipsTitleAfter: '', //标题文字后缀
tipsDataBefore: '', //数据文字前缀
tipsDataAfter: '', //数据文字后缀
}
}
this.readConfig = (obj)=>{
for (key in obj) {
if (this.config[key]) {
for (j in obj[key]) {
if (this.config[key][j]==''|| this.config[key][j]) {
this.config[key][j] = obj[key][j];
}
}
}
}
}
this.init = () => { //初始化样式函数
this.ele.style.position = 'relative';
// this.ele.style.cursor = 'none';
if (!('width' in this.canStyle) || this.canStyle['width']!=this.ele.offsetWidth) {
this.canStyle['width'] = this.ele.offsetWidth + 'px';
this.cav.setAttribute('width',this.ele.offsetWidth + 'px');
} else {
this.cav.setAttribute('width',this.canStyle.width);
}
if (!('height' in this.canStyle)|| this.canStyle['height']!=this.ele.offsetHeight) {
this.canStyle['height'] = this.ele.offsetHeight + 'px';
this.cav.setAttribute('height',this.ele.offsetHeight + 'px');
} else {
this.cav.setAttribute('height',this.canStyle.height);
}
for (let key in this.canStyle) {
this.cav.style[key] = this.canStyle[key];
}
}
this.createAxis = (x1, y1, x2, y2) => { //绘制轴
this.ctx.save();
let lin = this.ctx.createLinearGradient(x1, y1, x2, y2);
lin.addColorStop(0, this.config.axis.color);
// lin.addColorStop(1, '#00A6FF');
this.ctx.lineWidth = this.config.axis.width;
this.ctx.strokeStyle = lin;
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
}
this.createText = (text, x, y) => {//绘制文字
this.ctx.save();
this.ctx.moveTo(x,y);
this.ctx.fillStyle = this.config.axis.textColor;
this.ctx.font = this.config.axis.textSize+'"微软雅黑"';
this.ctx.textBaseline = 'bottom';
this.ctx.textAlign = 'left';
this.ctx.fillText(text, x, y);
this.ctx.closePath();
this.ctx.restore();
}
this.SerializationData = (data) => {//数据处理
if (Object.prototype.toString.call(data[0]) == '[object Object]') {
for (i = 0; i < this.data.length; i++){
data[i] = data[i].num;
}
}
for (i = 0; i < this.data.length; i++){
let num = data[i];
data[i] = {}
data[i].x = ((parseInt(this.canStyle.width)-40) / this.axis.axisX.length * i) + 55;
data[i].y = parseInt(this.canStyle.height) - 20 - ((parseInt(this.canStyle.height)-20) / (this.axis.axisY[0] * (this.axis.axisY[1]+1)) * num);
data[i].num = num;
}
return data;
}
this.createArc = (x, y) => {//绘制数据点
this.ctx.save();
this.ctx.beginPath();
this.ctx.fillStyle = this.config.data.arcColor;
this.ctx.arc(x, y, this.config.data.arcSize, 0, Math.PI * 2, false);
this.ctx.closePath();
this.ctx.fill();
this.ctx.restore();
}
this.gradient = (a, b) => (b.y - a.y) / (b.x - a.x);//计算两点间斜率
this.createData = (data) => {//绘制数据曲线
if (data.length < 3) {
let f = 0.6;
let t = 0.1;
let g = 0;
let dx1 = 0;
let dy1 = 0;
let dx2 = 0;
let dy2 = 0;
let predata = data[0];
let nextdata = null;
this.ctx.save()
this.ctx.strokeStyle = this.config.data.lineColor;
this.ctx.lineWidth = this.config.data.lineWidth;
this.ctx.lineCap = this.config.data.lineCap;
this.ctx.lineJoin = this.config.data.lineCap;
this.ctx.setLineDash(this.config.data.lineDash);
this.ctx.beginPath();
this.ctx.moveTo(data[0].x, data[0].y);
for (i = 1; i < data.length; i++){
let curdata = data[i];
nextdata = curdata;
if (nextdata) {
g = this.gradient(predata, nextdata);
dx2 = (nextdata.x - curdata.x) * (-f);
dy2 = dx2 * g * t;
} else {
dx2 = 0;
dy2 = 0;
}
this.ctx.bezierCurveTo(predata.x - dx1, predata.y - dy1, curdata.x + dx2, curdata.y + dy2, curdata.x, curdata.y)
dx1 = dx2;
dy1 = dy2;
predata = curdata;
}
this.ctx.stroke();
this.ctx.closePath();
this.ctx.restore()
} else {
let f = 0.6;
let t = 0.1;
let g = 0;
let dx1 = 0;
let dy1 = 0;
let dx2 = 0;
let dy2 = 0;
let predata = data[0];
let nextdata = null;
this.ctx.save()
this.ctx.strokeStyle = this.config.data.lineColor;
this.ctx.lineWidth = this.config.data.lineWidth;
this.ctx.lineCap = this.config.data.lineCap;
this.ctx.lineJoin = this.config.data.lineCap;
this.ctx.setLineDash(this.config.data.lineDash);
this.ctx.beginPath();
this.ctx.moveTo(data[0].x, data[0].y);
for (i = 1; i < data.length; i++){
let curdata = data[i];
nextdata = data[i + 1];
if (nextdata) {
g = this.gradient(predata, nextdata);
dx2 = (nextdata.x - curdata.x) * (-f);
dy2 = dx2 * g * t;
} else {
dx2 = 0;
dy2 = 0;
}
this.ctx.bezierCurveTo(predata.x - dx1, predata.y - dy1, curdata.x + dx2, curdata.y + dy2, curdata.x, curdata.y)
dx1 = dx2;
dy1 = dy2;
predata = curdata;
}
this.ctx.stroke();
this.ctx.closePath();
this.ctx.restore()
}
}
this.createOnArc = (x, y) => { //设置鼠标移入数据点
this.ctx.save();
this.ctx.beginPath();
this.ctx.fillStyle = this.config.data.hoverArcColor;
this.ctx.arc(x, y, this.config.data.hoverArcSize, 0, Math.PI * 2, false);
this.ctx.closePath();
this.ctx.fill();
this.ctx.restore();
}
// 绘制圆角矩形
this.Point = (x, y) => {
return {x:x, y:y};
};
this.Rect = (x, y, w, h) => {
return {x:x, y:y, width:w, height:h};
}
this.drawRoundedRect = (rect, r, ctx) => {
var ptA = this.Point(rect.x + r, rect.y);
var ptB = this.Point(rect.x + rect.width, rect.y);
var ptC = this.Point(rect.x + rect.width, rect.y + rect.height);
var ptD = this.Point(rect.x, rect.y + rect.height);
var ptE = this.Point(rect.x, rect.y);
ctx.beginPath();
ctx.fillStyle = this.config.tips.backgroundColor;
ctx.moveTo(ptA.x, ptA.y);
ctx.arcTo(ptB.x, ptB.y, ptC.x, ptC.y, r);
ctx.arcTo(ptC.x, ptC.y, ptD.x, ptD.y, r);
ctx.arcTo(ptD.x, ptD.y, ptE.x, ptE.y, r);
ctx.arcTo(ptE.x, ptE.y, ptA.x, ptA.y, r);
ctx.closePath();
ctx.fill();
ctx.restore();
// ctx.stroke();
}
this.createRect = (x,y) => {
let rectwidth = this.config.tips.tipsWidth;
let rectheight = this.config.tips.tipsHeight;
let rectx = x - rectwidth / 2; // 使圆角矩形水平居中与数据点
rectx < 40 ? rectx = 40 : rectx;
let recty = y - rectheight - 10; // 使圆角矩形垂直位置居于数据点上方10像素;
if (recty < 0) {
recty = 20;
rectx = x - rectwidth-10;
rectx < 0 ? rectx = x + 10 : rectx;
}
let rect = this.Rect(rectx, recty, rectwidth, rectheight);
this.drawRoundedRect(rect, 10, this.ctx);
this.createText(this.config.tips.tipsTitleBefore+this.axis.axisX[i]+this.config.tips.tipsTitleAfter, rectx+10, recty + 20);//添加标题文字
this.createText(this.config.tips.tipsDataBefore+this.data[i].num+this.config.tips.tipsDataAfter, rectx+10, recty + 45); //添加数据文字
}
this.mouseMove = (e) => { // 鼠标移动事件监听
this.render();
for (i = 0; i < this.data.length; i++){
if (i == 0 || i == this.data.length - 1) {
if (Math.abs(this.data[i].x - e.x) < 3 && Math.abs(this.data[i].y - e.y) < 3) {
this.createOnArc(this.data[i].x, this.data[i].y);
this.createRect(this.data[i].x, this.data[i].y,i);
break;
}
} else {
if (Math.abs(this.data[i].x - e.x) < 3 && Math.abs(this.data[i].y - e.y) < 3) {
this.createOnArc(this.data[i].x, this.data[i].y);
this.createRect(this.data[i].x, this.data[i].y,i);
break;
}
}
}
}
// 绘画
this.render = () => {
this.init(); //初始化样式
window.addEventListener('resize', this.render, false); //监听窗口大小变化
this.ele.appendChild(this.cav); //添加画布到窗口
this.createAxis(40, parseInt(this.canStyle.height) - 20, parseInt(this.canStyle.width) - 20, parseInt(this.canStyle.height) - 20); //绘制x轴
this.createAxis(40, parseInt(this.canStyle.height) - 20, 40, 20); //绘制y轴
this.axis.axisX.forEach((v, i) => {//绘制x轴文字
this.createText(v, ((parseInt(this.canStyle.width)-40) / this.axis.axisX.length * i) + 40, parseInt(this.canStyle.height) - 2);
});
for (let i = 0; i < this.axis.axisY[1]+1; i++){//绘制y轴文字
this.createText(this.axis.axisY[0]*i, 5, parseInt(this.canStyle.height)-20-((parseInt(this.canStyle.height)-20)/(this.axis.axisY[1]+1))*i);
}
this.data = this.SerializationData(this.data);//数据处理
this.createData(this.data); //绘制数据曲线
this.data.forEach((v,i) => { //绘制数据点
// console.log(v, i);
if (i == 0 || i == this.data.length-1) {
this.createArc(v.x, v.y);
} else {
this.createArc(v.x, v.y);
}
})
this.ele.addEventListener('mousemove', this.mouseMove, false);//监听鼠标移动事件对数据进行处理
}
}