355 lines
13 KiB
JavaScript
355 lines
13 KiB
JavaScript
/**
|
||
* Created by JianJia.Zhou<jianjia.zhou@longmaster.com.cn> on 2017/12/18.
|
||
*/
|
||
var CircleProcess = (function (window) {
|
||
// 版本
|
||
var version = "0.0.1";
|
||
|
||
var CircleProcess = function (selector, options) {
|
||
return new CircleProcess.fn.init(selector, options);
|
||
};
|
||
CircleProcess.fn = CircleProcess.prototype = {
|
||
circleProcess: version,
|
||
context: null,
|
||
option: {},
|
||
interVal: 0,
|
||
constructor: CircleProcess,
|
||
init: function (selector, options) {
|
||
// 如果没有传递实体对象 抛出异常
|
||
if (typeof selector === "undefined") {
|
||
throw new Error("Unable to get canvas object");
|
||
}
|
||
// 获取canvas对象
|
||
this.context = selector.getContext("2d");
|
||
|
||
// 获取配置
|
||
this.option = this._option();
|
||
// 根据canvas获取初始配置
|
||
this._getCanvasOption(selector);
|
||
// 获取全局配置
|
||
this._getOption();
|
||
if (typeof options === 'object') {
|
||
this._setOption(options);
|
||
this._getOption();
|
||
}
|
||
this.interVal = setInterval(function () {
|
||
this.run();
|
||
}.bind(this), 20);
|
||
},
|
||
|
||
/**
|
||
* 执行
|
||
*/
|
||
run: function () {
|
||
var option = this.option;
|
||
var process = option.percent;//从0到刻度:option.process; 立即到刻度:option.percent;
|
||
|
||
if (option.percent > 100 || option.percent < 0) {
|
||
clearInterval(this.interVal);
|
||
alert("Percentage out of range,The correct range of 1 - 100");
|
||
throw new Error("Percentage out of range,The correct range of 1 - 100");
|
||
}
|
||
|
||
if (process >= option.percent) {
|
||
process = option.percent;
|
||
clearInterval(this.interVal);
|
||
}
|
||
this._clear();
|
||
// 设置背景圆是否显示
|
||
if (option.backgroundCircle.show) {
|
||
this._backgroundCircle();
|
||
}
|
||
// 设置梯度是否显示
|
||
if (option.percentCircle.show) {
|
||
this._percentCircle(process);
|
||
}
|
||
// 设置起始圆点是否显示
|
||
if (option.startSmallCircle.show) {
|
||
this._smallCircle(option.startSmallCircle.radius, option.startSmallCircle.color, 0);
|
||
}
|
||
// 设置截止圆点是否显示
|
||
if (option.endSmallCircle.show) {
|
||
this._smallCircle(option.endSmallCircle.borderRadius, option.endSmallCircle.borderColor, process);
|
||
this._smallCircle(option.endSmallCircle.radius, option.endSmallCircle.color, process);
|
||
}
|
||
// 设置文字是否显示
|
||
if (option.processText.show) {
|
||
this._showProcess(process);
|
||
}
|
||
this._speed(option.percentCircle.speed);
|
||
},
|
||
/**
|
||
* 清除上一次画板
|
||
* @private
|
||
*/
|
||
_clear: function () {
|
||
var option = this.option;
|
||
this.context.clearRect(0, 0, option.backgroundCircle.roundX * 2, option.backgroundCircle.roundY * 2);
|
||
},
|
||
/**
|
||
* 背景圆环
|
||
* @private
|
||
*/
|
||
_backgroundCircle: function () {
|
||
var option = this.option;
|
||
// 设置线宽
|
||
this.context.lineWidth = option.lineWidth;
|
||
this.context.beginPath();
|
||
// 绘制圆环
|
||
this.context.arc(option.backgroundCircle.roundX,
|
||
option.backgroundCircle.roundY,
|
||
option.radius,
|
||
option.backgroundCircle.startAngle,
|
||
option.backgroundCircle.endAngle
|
||
);
|
||
this.context.strokeStyle = option.backgroundCircle.color;
|
||
this.context.stroke();
|
||
this.context.closePath();
|
||
},
|
||
/**
|
||
* 前置圆环
|
||
*
|
||
* @param {int|float} process
|
||
* @private
|
||
*/
|
||
_percentCircle: function (process) {
|
||
var option = this.option;
|
||
this.context.beginPath();
|
||
this.context.lineWidth = option.lineWidth;
|
||
|
||
this.context.arc(option.backgroundCircle.roundX,
|
||
option.backgroundCircle.roundY,
|
||
option.radius,
|
||
option.backgroundCircle.startAngle,
|
||
option.backgroundCircle.startAngle + process / 100 * option.cMultiple, // Math.PI * 180 / 180 * 2
|
||
false
|
||
);
|
||
if (option.percentCircle.gradientColorShow) {
|
||
this.context.strokeStyle = this._linearGradient();
|
||
} else {
|
||
this.context.strokeStyle = option.percentCircle.color;
|
||
}
|
||
this.context.lineCap = 'round';
|
||
this.context.stroke();
|
||
this.context.closePath();
|
||
},
|
||
/**
|
||
* 梯度颜色
|
||
*
|
||
* @returns {CanvasGradient}
|
||
* @private
|
||
*/
|
||
_linearGradient: function () {
|
||
var option = this.option;
|
||
// createLinearGradient x起点, y起点, x终点, y终点
|
||
var xStart = option.backgroundCircle.roundX - option.radius - this.option.lineWidth;
|
||
var xEnd = option.backgroundCircle.roundX + option.radius + this.option.lineWidth;
|
||
var yStart = option.backgroundCircle.roundY;
|
||
var yEnd = option.backgroundCircle.roundY;
|
||
|
||
var linGrad = this.context.createLinearGradient(xStart, yStart, xEnd, yEnd);
|
||
|
||
linGrad.addColorStop(0.0, 'rgba(255,0,0,0.1)');
|
||
linGrad.addColorStop(0.2, 'rgba(255,0,0,0.3)');
|
||
linGrad.addColorStop(0.4, 'rgba(255,0,0,0.5)');
|
||
linGrad.addColorStop(0.6, 'rgba(255,0,0,0.7)');
|
||
linGrad.addColorStop(0.8, 'rgba(255,0,0,0.9)');
|
||
linGrad.addColorStop(1.0, 'rgba(255,0,0,1)');
|
||
|
||
return linGrad;
|
||
},
|
||
|
||
/**
|
||
* 开始|结束圆点
|
||
* @param {int|float} radius
|
||
* @param {int|float} process
|
||
* @param {string} color
|
||
* @private
|
||
*/
|
||
_smallCircle: function (radius, color, process) {
|
||
var option = this.option;
|
||
var cx = Math.cos(2 * Math.PI / 360 * (option.angle + process * option.sMultiple / 100)) * option.radius + option.backgroundCircle.roundX;
|
||
var cy = Math.sin(2 * Math.PI / 360 * (option.angle + process * option.sMultiple / 100)) * option.radius + option.backgroundCircle.roundY;
|
||
this.context.beginPath();
|
||
this.context.arc(cx, cy, radius, 0, Math.PI * 2);
|
||
this.context.lineWidth = 1;
|
||
this.context.fillStyle = color;
|
||
this.context.fill();
|
||
},
|
||
/**
|
||
* 显示文字进度
|
||
* @param {int} process
|
||
* @private
|
||
*/
|
||
_showProcess: function (process) {
|
||
var decimal = 0;
|
||
var option = this.option;
|
||
var num = option.percent.toString();
|
||
// 如果当前数字是小数,那么需要保留小数 最大两位
|
||
if (/\./.test(num) && num.split(".")[1].length > 0) {
|
||
decimal = num.split(".")[1].length < 2 ? 1 : 2;
|
||
}
|
||
this.context.font = option.processText.fontSize + 'px April';
|
||
this.context.textAlign = option.processText.textAlign;
|
||
this.context.textBaseline = option.processText.textBaseline;
|
||
this.context.fillStyle = option.processText.color;
|
||
this.context.fillText(parseFloat(process).toFixed(decimal) + '%', option.backgroundCircle.roundX, option.backgroundCircle.roundY);
|
||
},
|
||
_showProcessFollow: function () {
|
||
|
||
},
|
||
/**
|
||
* 梯度速度
|
||
*
|
||
* @param mode
|
||
* @private
|
||
*/
|
||
_speed: function (mode) {
|
||
var option = this.option;
|
||
if (mode === "gradient") {
|
||
if (option.process / option.percent > 0.90) {
|
||
option.process += 0.30;
|
||
} else if (option.process / option.percent > 0.80) {
|
||
this.option.process += 0.55;
|
||
} else if (option.process / option.percent > 0.70) {
|
||
option.process += 0.75;
|
||
} else {
|
||
option.process += 1.0;
|
||
}
|
||
} else if (mode === "normal") {
|
||
option.process += 1.0;
|
||
} else if (mode === "fast") {
|
||
option.process += 2.5;
|
||
}
|
||
|
||
},
|
||
/**
|
||
* 初始化时获取canvas对象参数
|
||
*
|
||
* @param {object} selector
|
||
* @private
|
||
*/
|
||
_getCanvasOption: function (selector) {
|
||
this._extend(this.option, {
|
||
"backgroundCircle": {
|
||
"roundX": selector.width / 2,
|
||
"roundY": selector.height / 2,
|
||
"startAngle": Math.PI / 180 * 180,
|
||
"endAngle": Math.PI / 180 * 180 * 2
|
||
}
|
||
});
|
||
},
|
||
/**
|
||
* 合并对象
|
||
*
|
||
* @param {object} o
|
||
* @param {object} n
|
||
* @private
|
||
*/
|
||
_extend: function (o, n) {
|
||
for (var p in n) {
|
||
if (typeof n[p] === "object") {
|
||
this._extend(o[p], n[p]);
|
||
} else if (n.hasOwnProperty(p) && (!o.hasOwnProperty(p))) {
|
||
o[p] = n[p];
|
||
} else if (n.hasOwnProperty(p) && o.hasOwnProperty(p)) {
|
||
o[p] = n[p];
|
||
}
|
||
}
|
||
},
|
||
/**
|
||
*
|
||
* @returns {*}
|
||
* @private
|
||
*/
|
||
_getOption: function () {
|
||
var option = this.option;
|
||
option.angle = 180;
|
||
option.cMultiple = option.backgroundCircle.startAngle;
|
||
option.sMultiple = 180;
|
||
if (option.size === "complete") {
|
||
option.angle = 120;
|
||
option.cMultiple = option.backgroundCircle.startAngle * 2;
|
||
option.sMultiple = 360;
|
||
this._extend(this.option, {
|
||
"backgroundCircle": {
|
||
"startAngle": Math.PI / 180 * 120,
|
||
"endAngle": Math.PI / 180 * 120 * 4
|
||
}
|
||
});
|
||
} else if (option.size === "incomplete") {
|
||
option.angle = 120;
|
||
option.cMultiple = Math.PI * 5 / 3;
|
||
option.sMultiple = 300;
|
||
|
||
this._extend(this.option, {
|
||
"backgroundCircle": {
|
||
"startAngle": Math.PI / 180 * 120,
|
||
"endAngle": Math.PI / 180 * 420
|
||
}
|
||
});
|
||
}
|
||
},
|
||
_setOption: function (option) {
|
||
this._extend(this.option, option);
|
||
},
|
||
/**
|
||
* 初始参数配置
|
||
*
|
||
* @returns {{size: string, lineWidth: number, radius: number, position: string, percent: number, process: number, backgroundCircle: {show: boolean, color: string, roundX: number, roundY: number, startAngle: number, endAngle: number}, percentCircle: {show: boolean, color: string, speed: string}, startSmallCircle: {show: boolean, color: string, radius: number}, endSmallCircle: {show: boolean, color: string, radius: number}, gradient: {color: string}, processText: {show: boolean, fontSize: number, color: string, follow: boolean, textAlign: string, textBaseline: string}}}
|
||
* @private
|
||
*/
|
||
_option: function () {
|
||
return {
|
||
"size": "half", //complete,half,incomplete or todo-percent
|
||
"lineWidth": 5,
|
||
"radius": 100,
|
||
"percent": 80,
|
||
"process": 0.00,
|
||
"backgroundCircle": {
|
||
"show": true,
|
||
"color": "#eee",
|
||
"roundX": 0,
|
||
"roundY": 0,
|
||
"startAngle": 0,
|
||
"endAngle": 0
|
||
},
|
||
"percentCircle": {
|
||
"show": true,
|
||
"color": "#f00",
|
||
"speed": "gradient",//gradient normal fast
|
||
"gradientColorShow": false,
|
||
"gradientColor": "rgba(255.0.0,0.1)"
|
||
},
|
||
"startSmallCircle": {
|
||
"show": false,
|
||
"color": "#06a8f3",
|
||
"radius": 5
|
||
},
|
||
"endSmallCircle": {
|
||
"show": false,
|
||
"color": "#00f8bb",
|
||
"radius": 5
|
||
},
|
||
"gradient": {
|
||
"color": "rgba(255,0,0,0.1)",// todo 梯度颜色
|
||
"size": 4
|
||
},
|
||
"processText": {
|
||
"show": true,
|
||
"fontSize": 20,
|
||
"color": "#ccc",
|
||
"follow": false,//todo 是否跟随渐变而改变颜色
|
||
"textAlign": "center",
|
||
"textBaseline": "alphabetic"
|
||
}
|
||
};
|
||
}
|
||
|
||
};
|
||
|
||
CircleProcess.fn.init.prototype = CircleProcess.fn;
|
||
|
||
return CircleProcess;
|
||
})();
|