function Diagram() {
|
this.stc = ""; // 静态层canvas
|
this.flush = ""; // 刷新层canvas
|
this.s_ctx = ""; // 静态层上下文
|
this.f_ctx = ""; // 刷新层上下文
|
this.width = 1500; // 默认宽度
|
this.height = 750; // 默认高度
|
this.options = []; // 所有配置对象
|
this.flushOptions = []; // 需要刷新的对象
|
this.handleObj = []; // 可以触发事件的对象
|
this.opts = { // 默认配置
|
lineWidth: 3, // 线宽
|
onOffBase: { // 开关的基础配置
|
radius: 3,
|
width: 16,
|
lineWidth: 2,
|
},
|
moveDot: {
|
radius: 6,
|
step: 2.2,
|
gravity: 0.08
|
}
|
};
|
// 显示线条的id
|
this.showLineId = false;
|
}
|
|
// 设置canvas
|
Diagram.prototype.setCanvas = function (stc, flush) {
|
// 设置静态canvas
|
this.stc = document.createElement('canvas');
|
stc.appendChild(this.stc);
|
this.stc.width = this.width;
|
this.stc.height = this.height;
|
this.s_ctx = this.stc.getContext('2d');
|
|
// 设置动态canvas
|
this.flush = document.createElement('canvas');
|
flush.appendChild(this.flush);
|
this.flush.width = this.width;
|
this.flush.height = this.height;
|
this.f_ctx = this.flush.getContext('2d');
|
|
this.startState = false;
|
|
// 启动更新
|
this.start(true);
|
};
|
|
|
// 启动更新
|
Diagram.prototype.start = function (start) {
|
if (start) {
|
console.log('已经启动持续更新');
|
this.startState = true;
|
}
|
|
// 停止更新
|
if (!this.startState) {
|
return;
|
}
|
// 更新所有的配置项
|
this._update();
|
// 持续更新函数
|
requestAnimationFrame(() => {
|
this.start();
|
});
|
this.f_ctx.save();
|
this.f_ctx.fillStyle = "rgba(0, 0, 0, 0.9)";
|
this.f_ctx.globalCompositeOperation = 'destination-in';
|
this.f_ctx.fillRect(0, 0, this.width, this.height);
|
this.f_ctx.restore();
|
|
}
|
|
// 停止更新
|
Diagram.prototype.stop = function () {
|
this.startState = false;
|
console.log('已经停止持续更新');
|
};
|
|
// 更新整个图表
|
Diagram.prototype._update = function () {
|
// 清空图表
|
//this.f_ctx.clearRect(0, 0, this.width, this.height);
|
let options = this.flushOptions;
|
options.forEach(option => {
|
this.update(option);
|
});
|
};
|
// 根据配置项更新图表
|
Diagram.prototype.update = function (option) {
|
if (option && option.method && typeof this[option.method] == 'function') {
|
this[option.method](option);
|
}
|
}
|
|
/**
|
* 检测对象是否在数组中
|
*
|
* @param {[object]} option 需要检测的对象
|
*
|
* @param {[Array]} options 对象数组
|
*
|
* @return {[Boolean]} 返回对象是否在对象数组中
|
*/
|
Diagram.prototype.checkObjInArr = function (option, options) {
|
// 如果未设置id
|
if (!option.id) {
|
return true;
|
}
|
|
// 根据id判断
|
let isIn = false;
|
for (let i = 0; i < options.length; i++) {
|
let _option = options[i];
|
if (option.id == _option.id) {
|
isIn = true;
|
break;
|
}
|
}
|
// 返回结果
|
return isIn;
|
}
|
|
// 添加配置项
|
Diagram.prototype.addOptions = function (option) {
|
// 检测配置项是否在配置项中
|
let options = this.options;
|
// 检测对象不在对象中
|
if (!this.checkObjInArr(option, options)) {
|
options.push(option);
|
// 可刷新,添加到刷新配置项
|
if (option.flush) {
|
this.flushOptions.push(option);
|
}
|
}
|
};
|
|
// 修改配置信息
|
Diagram.prototype.changeOption = function (id, attr, value, options) {
|
for (let i = 0; i < options.length; i++) {
|
let _option = options[i];
|
if (id == _option.id) {
|
_option[attr] = value;
|
break;
|
}
|
}
|
};
|
|
// 设置配置的值(仅可以设置刷新层的内容)
|
Diagram.prototype.setOption = function (id, attr, value) {
|
let options = this.flushOptions;
|
this.changeOption(id, attr, value, options);
|
};
|
|
// 获取option
|
Diagram.prototype.getOption = function (id) {
|
let options = this.options;
|
let result = false;
|
for (let i = 0; i < options.length; i++) {
|
let option = options[i];
|
if (option.id == id) {
|
result = option;
|
}
|
}
|
return result;
|
}
|
|
// 绘制线
|
Diagram.prototype.line = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let points = option.points;
|
let opts = this.opts;
|
ctx.beginPath();
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : opts.lineWidth;
|
ctx.strokeStyle = option.strokeStyle ? option.strokeStyle : "#b370fe";
|
points.forEach((point, index) => {
|
if (index != 0) {
|
ctx.lineTo(point[0], point[1]);
|
} else {
|
ctx.moveTo(point[0], point[1]);
|
}
|
});
|
if (!option.hide) {
|
ctx.stroke();
|
}
|
// 控制线条id显示
|
if (this.showLineId) {
|
let point = [];
|
if (points[0][0] == points[1][0]) {
|
// 设置x轴坐标
|
point[0] = points[0][0];
|
// 设置y轴坐标
|
if (points[0][1] > points[1][1]) {
|
point[1] = points[1][1] + (points[0][1] - points[1][1]) / 2;
|
} else {
|
point[1] = points[1][1] + (points[0][1] - points[1][1]) / 2;
|
}
|
} else {
|
// 设置y轴坐标
|
point[1] = points[0][1];
|
// 设置x轴坐标
|
if (points[0][0] > points[1][0]) {
|
point[0] = points[1][0] + (points[0][0] - points[1][0]) / 2;
|
} else {
|
point[0] = points[1][0] + (points[0][0] - points[1][0]) / 2;
|
}
|
|
}
|
this.text({
|
text: option.id ? option.id : '',
|
point: point,
|
hide: option.hide,
|
});
|
}
|
// 设置执行的方法
|
option.method = "line";
|
// 添加配置项
|
this.addOptions(option);
|
return points;
|
};
|
|
// 绘制线
|
Diagram.prototype.gradientline = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let points = option.points;
|
let opts = this.opts;
|
ctx.beginPath();
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : opts.lineWidth;
|
let color = option.gradientColor ? option.gradientColor : ['#ffa500', '#ffff1d'];
|
let gnt = ctx.createLinearGradient(points[0][0], points[0][1], points[1][0], points[1][1]); //线性渐变的起止坐标
|
ctx.strokeStyle = gnt;
|
gnt.addColorStop(0, color[0]);
|
gnt.addColorStop(1, color[1]);
|
points.forEach((point, index) => {
|
if (index != 0) {
|
ctx.lineTo(point[0], point[1]);
|
} else {
|
ctx.moveTo(point[0], point[1]);
|
}
|
});
|
if (!option.hide) {
|
ctx.stroke();
|
}
|
// 控制线条id显示
|
if (this.showLineId) {
|
let point = [];
|
if (points[0][0] == points[1][0]) {
|
// 设置x轴坐标
|
point[0] = points[0][0];
|
// 设置y轴坐标
|
if (points[0][1] > points[1][1]) {
|
point[1] = points[1][1] + (points[0][1] - points[1][1]) / 2;
|
} else {
|
point[1] = points[1][1] + (points[0][1] - points[1][1]) / 2;
|
}
|
} else {
|
// 设置y轴坐标
|
point[1] = points[0][1];
|
// 设置x轴坐标
|
if (points[0][0] > points[1][0]) {
|
point[0] = points[1][0] + (points[0][0] - points[1][0]) / 2;
|
} else {
|
point[0] = points[1][0] + (points[0][0] - points[1][0]) / 2;
|
}
|
|
}
|
this.text({
|
text: option.id ? option.id : '',
|
point: point,
|
hide: option.hide,
|
});
|
}
|
// 设置执行的方法
|
option.method = "line";
|
// 添加配置项
|
this.addOptions(option);
|
return points;
|
};
|
|
// 获取线缩放后的具体信息
|
Diagram.prototype.getZoomLineInfo = function (id) {
|
let option = this.getOption(id)
|
let points = option.points;
|
let Xzoom = this.stc.clientWidth / this.width;
|
let Yzoom = this.stc.clientHeight / this.height;
|
let newPoints = [];
|
points.map((item, index) => {
|
let point = []
|
point.push(item[0] * Xzoom);
|
point.push(item[1] * Yzoom);
|
newPoints.push(point)
|
});
|
return newPoints
|
}
|
|
// 绘制点线
|
Diagram.prototype.dashLine = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let opts = this.opts;
|
let points = option.points;
|
ctx.beginPath();
|
// 设置间距(参数为无限数组,虚线的样式会随数组循环)
|
ctx.setLineDash([2, 4]);
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : opts.lineWidth;
|
ctx.strokeStyle = option.strokeStyle ? option.strokeStyle : "#b370fe";
|
points.forEach((point, index) => {
|
if (index != 0) {
|
ctx.lineTo(point[0], point[1]);
|
} else {
|
ctx.moveTo(point[0], point[1]);
|
}
|
});
|
ctx.stroke();
|
// 切回实线
|
ctx.setLineDash([]);
|
return points;
|
};
|
|
// 绘制充放电单元
|
Diagram.prototype.chargeAndDischarge = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let defaultOption = {
|
width: 120,
|
};
|
let point = option.point;
|
let strokeStyle = '#FFFFFF';
|
let lineWidth = option.lineWidth ? option.lineWidth : 2;
|
// 线条1
|
let line1 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
point,
|
[point[0], point[1] - defaultOption.width / 2]
|
],
|
});
|
|
// 线条2
|
let line2 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line1[1],
|
[line1[1][0] + defaultOption.width, line1[1][1]]
|
],
|
});
|
|
// 线条3
|
let line3 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line2[1],
|
[line2[1][0] + defaultOption.width, line2[1][1]]
|
],
|
});
|
|
// 线条4
|
let line4 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line3[1],
|
[line3[1][0], line3[1][1] + defaultOption.width]
|
],
|
});
|
|
// 线条5
|
let line5 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line4[1],
|
[line1[1][0], line1[1][1] + defaultOption.width]
|
],
|
});
|
|
// 线条6
|
let line6 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line5[1],
|
[line1[0][0], line1[0][1]]
|
],
|
});
|
|
// 线条7
|
let line7 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
[line1[1][0] + defaultOption.width, line1[1][1]],
|
[line1[1][0] + defaultOption.width, line1[1][1] + defaultOption.width]
|
],
|
});
|
|
return [
|
[line1[1][0] + defaultOption.width / 2, line1[1][1]],
|
[line1[1][0] + defaultOption.width * 3 / 2, line1[1][1]],
|
[line1[1][0] + defaultOption.width * 3 / 2, line1[1][1] + defaultOption.width],
|
[line1[1][0] + defaultOption.width / 2, line1[1][1] + defaultOption.width],
|
]
|
};
|
|
// 绘制圆
|
Diagram.prototype.arc = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let point = option.point; //圆心坐标
|
// 不隐藏绘制圆圈
|
if (!option.hide) {
|
ctx.beginPath();
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : 1;
|
ctx.strokeStyle = option.strokeStyle;
|
ctx.fillStyle = option.fillStyle;
|
ctx.arc(point[0], point[1], option.radius, 0, 2 * Math.PI);
|
switch (option.type) {
|
case 'stroke':
|
ctx.stroke();
|
break;
|
case 'fill':
|
ctx.fill();
|
break;
|
default:
|
ctx.stroke();
|
ctx.fill();
|
break;
|
}
|
}
|
|
let info = {
|
center: [point[0], point[1]],
|
left: [point[0] - option.radius, point[1]],
|
right: [point[0] + option.radius, point[1]],
|
top: [point[0], point[1] - option.radius],
|
bottom: [point[0], point[1] + option.radius],
|
tl: [point[0] - option.radius / 2, point[1] - option.radius / 2],
|
tr: [point[0] + option.radius / 2, point[1] - option.radius / 2],
|
bl: [point[0] - option.radius / 2, point[1] + option.radius / 2],
|
br: [point[0] + option.radius / 2, point[1] + option.radius / 2],
|
strokeStyle: option.strokeStyle,
|
fillStyle: option.fillStyle,
|
radius: option.radius
|
};
|
// 添加配置项
|
option.method = "arc";
|
|
this.addOptions(option);
|
return info;
|
};
|
|
// 绘制开关
|
Diagram.prototype.onOff = function (option) {
|
let result;
|
switch (option.direction) {
|
case 'top':
|
case 'bottom':
|
result = this.onOff_h(option);
|
break;
|
default:
|
result = this.onOff_v(option);
|
break;
|
}
|
// 添加配置项
|
option.method = "onOff";
|
this.addOptions(option);
|
// 返回开关的信息
|
return result;
|
};
|
|
// 水平方向
|
Diagram.prototype.onOff_v = function (option) {
|
let point = option.point;
|
let state = option.state ? true : false;
|
let color = option.color ? option.color : '#50cef5';
|
let onOffBase = this.opts.onOffBase;
|
|
// 开关的第一个圆
|
let arc1 = this.arc({
|
point: [point[0] + onOffBase.radius / 2, point[1]],
|
flush: option.flush,
|
fillStyle: color,
|
strokeStyle: color,
|
radius: onOffBase.radius,
|
type: 'stroke'
|
});
|
|
// 开关的第二个圆
|
let arc2 = this.arc({
|
point: [arc1.right[0] + onOffBase.width * 4 / 3, arc1.right[1]],
|
flush: option.flush,
|
fillStyle: arc1.fillStyle,
|
strokeStyle: arc1.fillStyle,
|
radius: arc1.radius,
|
type: 'stroke'
|
});
|
let line1;
|
switch (option.direction) {
|
case 'right':
|
// 绘制线条
|
line1 = this.line({
|
points: [
|
arc2.left,
|
[
|
state ? arc1.top[0] : arc1.center[0],
|
state ? arc1.top[1] : arc1.center[1] - (arc1.radius + onOffBase.width * 3 / 4)
|
],
|
],
|
flush: option.flush,
|
strokeStyle: state ? '#50cef5' : color,
|
lineWidth: onOffBase.lineWidth
|
});
|
break;
|
default:
|
// 绘制线条
|
line1 = this.line({
|
points: [
|
arc1.right,
|
[
|
state ? arc2.top[0] : arc2.center[0],
|
state ? arc2.top[1] : arc2.center[1] - (arc2.radius + onOffBase.width * 3 / 4)
|
],
|
],
|
flush: option.flush,
|
strokeStyle: state ? '#50cef5' : color,
|
lineWidth: onOffBase.lineWidth
|
});
|
break;
|
}
|
return {
|
arc1: arc1,
|
arc2: arc2,
|
line1: line1
|
}
|
};
|
// 竖直方向
|
Diagram.prototype.onOff_h = function (option) {
|
let point = option.point;
|
let state = option.state ? true : false;
|
let color = option.color ? option.color : '#50cef5';
|
let onOffBase = this.opts.onOffBase;
|
|
// 开关的第一个圆
|
let arc1 = this.arc({
|
point: [point[0], point[1] + onOffBase.radius],
|
flush: option.flush,
|
fillStyle: color,
|
strokeStyle: color,
|
radius: onOffBase.radius,
|
type: 'stroke'
|
});
|
|
// 开关的第二个圆
|
let arc2 = this.arc({
|
point: [arc1.bottom[0], arc1.right[1] + onOffBase.width * 4 / 3],
|
flush: option.flush,
|
fillStyle: arc1.fillStyle,
|
strokeStyle: arc1.fillStyle,
|
radius: arc1.radius,
|
type: 'stroke'
|
});
|
|
let line1;
|
switch (option.direction) {
|
case 'top':
|
// 绘制线条
|
line1 = this.line({
|
points: [
|
arc1.bottom,
|
[
|
state ? arc2.right[0] : arc2.center[0] + (arc1.radius + onOffBase.width * 3 / 4),
|
state ? arc2.right[1] : arc2.center[1]
|
],
|
],
|
flush: option.flush,
|
strokeStyle: state ? '#50cef5' : color,
|
lineWidth: onOffBase.lineWidth
|
});
|
break;
|
default:
|
// 绘制线条
|
line1 = this.line({
|
points: [
|
arc2.top,
|
[
|
state ? arc1.right[0] : arc1.center[0] + (arc2.radius + onOffBase.width * 3 / 4),
|
state ? arc1.right[1] : arc1.center[1]
|
],
|
],
|
flush: option.flush,
|
strokeStyle: state ? '#50cef5' : color,
|
lineWidth: onOffBase.lineWidth
|
});
|
break;
|
}
|
return {
|
arc1: arc1,
|
arc2: arc2,
|
line1: line1
|
}
|
};
|
|
// BAT
|
Diagram.prototype.bat = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx;
|
let point = option.point;
|
let bat = {
|
width: 14
|
};
|
ctx.fillStyle = option.fillStyle ? option.fillStyle : "#b370fe";
|
ctx.strokeStyle = option.strokeStyle;
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : 3;
|
|
ctx.fillRect(point[0] - bat.width / 2, point[1] - bat.width / 2, bat.width, bat.width);
|
|
ctx.strokeRect(point[0] - bat.width / 2, point[1] - bat.width / 2, bat.width, bat.width)
|
return {
|
top: [point[0], point[1] - bat.width / 2],
|
bottom: [point[0], point[1] + bat.width / 2],
|
left: [point[0] - bat.width / 2 - ctx.lineWidth / 2, point[1]],
|
right: [point[0] + bat.width / 2 + ctx.lineWidth / 2, point[1]]
|
}
|
};
|
|
// 绘制图片
|
Diagram.prototype.drawImage = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx;
|
let point = option.point;
|
// 绘制内容
|
if (!option.hide) {
|
let img = new Image();
|
img.src = option.url;
|
if (option.flush) {
|
ctx.drawImage(img, point[0], point[1], option.width, option.height);
|
} else {
|
img.onload = function () {
|
ctx.drawImage(img, point[0], point[1], option.width, option.height);
|
}
|
}
|
|
}
|
|
// 返回图片信息
|
let info = {
|
tl: [point[0], point[1]],
|
tr: [point[0] + option.width, point[1]],
|
bl: [point[0], point[1] + option.height],
|
br: [point[0] + option.width, point[1] + option.height],
|
left: [point[0], point[1] + option.height / 2],
|
right: [point[0] + option.width, point[1] + option.height / 2],
|
top: [point[0] + option.width / 2, point[1]],
|
bottom: [point[0] + option.width / 2, point[1] + option.height],
|
width: option.width,
|
height: option.height,
|
};
|
|
// 设置执行的方法
|
option.method = "drawImage";
|
// 添加配置项
|
this.addOptions(option);
|
return info;
|
};
|
|
// 获取图片缩放后自身信息
|
Diagram.prototype.getZoomImageInfo = function (id) {
|
let option = this.getOption(id)
|
let points = option.point;
|
let Xzoom = this.stc.clientWidth / this.width;
|
let Yzoom = this.stc.clientHeight / this.height;
|
let point = [];
|
point[0] = points[0] * Xzoom;
|
point[1] = points[1] * Yzoom;
|
|
// 返回图片信息
|
let info = {
|
tl: [point[0], point[1]], //左上角坐标
|
tr: [point[0] + option.width, point[1]], //右上角坐标
|
bl: [point[0], point[1] + option.height], //左下角坐标
|
br: [point[0] + option.width, point[1] + option.height], //右下角坐标
|
left: [point[0], point[1] + option.height / 2], //左侧中间点坐标
|
right: [point[0] + option.width, point[1] + option.height / 2], //右侧中间点坐标
|
top: [point[0] + option.width / 2, point[1]], //上侧中间点坐标
|
bottom: [point[0] + option.width / 2, point[1] + option.height], //下侧中间点坐标
|
width: option.width * Xzoom, //图片宽度
|
height: option.height * Yzoom, //图片高度
|
};
|
return info;
|
};
|
|
// 绘制字体
|
Diagram.prototype.text = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx;
|
let point = option.point;
|
let fontSize = option.fontSize ? option.fontSize : 12;
|
let texts = option.text.split('&');
|
ctx.beginPath();
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : 1;
|
ctx.font = fontSize + 'px Arial';
|
ctx.textAlign = option.align ? option.align : 'start';
|
ctx.textBaseline = option.baseline ? option.baseline : 'top';
|
let Yzoom = this.stc.clientHeight / this.height;
|
let borderColor = option.borderColor ? option.borderColor : '#5a62c9'; //矩形边框颜色
|
let bgColor = option.bgColor ? option.bgColor : '#191553'; //矩形填充颜色
|
let radiusRectInfo;
|
let fontWidth = 0;
|
ctx.fillStyle = option.fillStyle ? option.fillStyle : '#FFFFFF';
|
if (!option.hide) {
|
texts.forEach((text, index) => { //第一遍画文字获取文字宽度
|
if (index == 0) {
|
ctx.fillText(text, point[0], point[1] + fontSize * index);
|
} else {
|
ctx.fillText(text, point[0], point[1] + fontSize * index + 2);
|
}
|
if (fontWidth < ctx.measureText(text).width) {
|
fontWidth = ctx.measureText(text).width;
|
}
|
});
|
if (option.radBorder) { //画边框
|
let fontHeight = fontSize * Yzoom;
|
let radiusRectY;
|
switch (ctx.textBaseline) {
|
case 'top':
|
radiusRectY = point[1] - 8
|
break;
|
case 'bottom':
|
radiusRectY = point[1] - 8 - fontHeight
|
break;
|
case 'middle':
|
radiusRectY = point[1] - 8 - (fontHeight / 2)
|
break;
|
}
|
let radiusRectData = {
|
point: [point[0] - 16, radiusRectY - 1],
|
width: fontWidth + 32,
|
height: fontHeight * texts.length + 16,
|
strokeStyle: borderColor,
|
fillStyle: bgColor,
|
r: (fontHeight * texts.length + 16) / 2,
|
}
|
radiusRectInfo = this.drawRadiusRect(radiusRectData);
|
ctx.fillStyle = option.fillStyle ? option.fillStyle : '#FFFFFF';
|
texts.forEach((text, index) => { //第二遍画文字覆盖边框
|
if (index == 0) {
|
ctx.fillText(text, point[0], point[1] + fontSize * index);
|
} else {
|
ctx.fillText(text, point[0], point[1] + fontSize * index + 2);
|
}
|
});
|
}
|
}
|
if (option.radBorder) {
|
return radiusRectInfo
|
}
|
|
// 设置执行的方法
|
option.method = "text";
|
// 添加配置项
|
this.addOptions(option);
|
};
|
|
// 绘制可移动的点
|
Diagram.prototype.moveDot = function (option) {
|
let ctx = this.f_ctx;
|
let opts = this.opts.moveDot;
|
let points = option.points;
|
let start = option.start ? option.start : [points[0][0], points[0][1]];
|
let fillStyle = option.fillStyle ? option.fillStyle : "#b370fe";
|
let strokeStyle = option.strokeStyle ? option.strokeStyle : "#b370fe";
|
let radius = option.radius ? option.radius : opts.radius;
|
if (this.getOption(option.id)) {
|
switch (option.type) {
|
case 'up':
|
start[1] -= opts.step;
|
// 约束限制
|
if (start[1] < points[1][1]) {
|
start[1] = points[0][1];
|
}
|
break;
|
case 'down':
|
start[1] += opts.step;
|
// 约束限制
|
if (start[1] > points[1][1]) {
|
start[1] = points[0][1];
|
}
|
break;
|
case 'left':
|
start[0] += opts.step;
|
// 约束限制
|
if (start[0] > points[1][0]) {
|
start[0] = points[0][0];
|
}
|
break;
|
case 'right':
|
start[0] -= opts.step;
|
// 约束限制
|
if (start[0] < points[1][0]) {
|
start[0] = points[0][0];
|
}
|
}
|
// 设置值
|
this.setOption(option.id, 'start', start);
|
} else {
|
// 竖直运动
|
if (points[0][0] == points[1][0]) {
|
// 向上运动
|
if (points[0][1] > points[1][1]) {
|
option.type = 'up';
|
} else {
|
option.type = 'down';
|
}
|
} else {
|
// 向左运动
|
if (points[0][0] < points[1][0]) {
|
option.type = 'left';
|
} else {
|
option.type = 'right';
|
}
|
}
|
option.start = start;
|
}
|
this.arc({
|
flush: true,
|
point: start,
|
fillStyle: fillStyle,
|
strokeStyle: strokeStyle,
|
radius: radius
|
});
|
// 添加配置项
|
option.method = "moveDot";
|
this.addOptions(option);
|
};
|
|
// 绘制二极管
|
Diagram.prototype.diode = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx;
|
let point = option.point;
|
let width = 40;
|
let height = width * 2 / 3;
|
let lineWidth = 2;
|
// line1
|
let line1 = this.line({
|
strokeStyle: "#b370fe",
|
lineWidth: lineWidth,
|
points: [
|
point,
|
[point[0], point[1] + width / 2]
|
]
|
});
|
// line2
|
let line2 = this.line({
|
strokeStyle: "#b370fe",
|
lineWidth: lineWidth,
|
points: [
|
[line1[1][0] - width / 2, line1[1][1]],
|
[line1[1][0] + width / 2, line1[1][1]]
|
]
|
});
|
ctx.beginPath();
|
ctx.moveTo(line1[1][0], line1[1][1]);
|
ctx.lineTo(line2[0][0], line2[0][1] + height);
|
ctx.lineTo(line2[1][0], line2[1][1] + height);
|
ctx.closePath();
|
ctx.fillStyle = "#b370fe";
|
ctx.fill();
|
|
// line3
|
let line3 = this.line({
|
strokeStyle: "#b370fe",
|
lineWidth: lineWidth,
|
points: [
|
[line1[1][0], line1[1][1] + height],
|
[line1[1][0], line1[1][1] + height + width / 2]
|
]
|
});
|
|
// 添加配置项
|
option.method = "diode";
|
this.addOptions(option);
|
return {
|
top: line1[0],
|
bottom: line3[1]
|
}
|
};
|
|
// 绘制矩形
|
Diagram.prototype.drawRect = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let defaultOption = {
|
width: 120,
|
height: 120,
|
};
|
let point = option.point;
|
let strokeStyle = '#FFFFFF';
|
let lineWidth = option.lineWidth ? option.lineWidth : 2;
|
// 线条1
|
let line1 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
point,
|
[point[0], point[1] + defaultOption.height]
|
],
|
});
|
|
// 线条2
|
let line2 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line1[1],
|
[line1[1][0] + defaultOption.width, line1[1][1]]
|
],
|
});
|
|
// 线条3
|
let line3 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line2[1],
|
[line2[1][0], line2[1][1] - defaultOption.height]
|
],
|
});
|
|
// 线条4
|
let line4 = this.line({
|
strokeStyle: strokeStyle,
|
lineWidth: lineWidth,
|
hide: option.hide,
|
points: [
|
line3[1],
|
line1[0]
|
],
|
});
|
|
return {
|
left: [line1[0][0], line1[0][1] + defaultOption.height / 2],
|
bottom: [line2[0][0] + defaultOption.width / 2, line2[0][1]],
|
right: [line3[0][0], line3[0][1] - defaultOption.height / 2],
|
top: [line1[0][0] + defaultOption.width / 2, line1[0][1]]
|
}
|
|
}
|
|
// 绘制圆角矩形
|
Diagram.prototype.drawRadiusRect = function (option) {
|
// (x,y):圆角矩形起始坐标; width: 矩形宽度; height: 矩形高度; r: 矩形圆角;
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let point = option.point;
|
let x = point[0];
|
let y = point[1];
|
let width = option.width ? option.width : 150;
|
let height = option.height ? option.height : 40;
|
let r = option.r ? option.r : 6;
|
ctx.strokeStyle = option.strokeStyle ? option.strokeStyle : '#5a62c9'; //矩形填充颜色
|
ctx.fillStyle = option.fillStyle ? option.fillStyle : '#191553'; //矩形填充颜色
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : 3; //矩形线宽;
|
ctx.beginPath();
|
ctx.moveTo(x + r, y);
|
ctx.lineTo(x + width - r, y);
|
ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
|
ctx.lineTo(x + width, y + height - r);
|
ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5);
|
ctx.lineTo(x + r, y + height);
|
ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI);
|
ctx.lineTo(x, y + r);
|
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
|
switch (option.type) {
|
case 'stroke':
|
ctx.stroke();
|
break;
|
case 'fill':
|
ctx.fill();
|
break;
|
default:
|
ctx.stroke();
|
ctx.fill();
|
break;
|
}
|
// 添加配置项
|
option.method = "drawRadiusRect";
|
this.addOptions(option);
|
return {
|
width: width,
|
height: height,
|
radius: r,
|
point: point,
|
left: [x, y + height / 2],
|
bottom: [x + width / 2, y + height],
|
right: [x + width, y + height / 2],
|
top: [x + width / 2, y],
|
}
|
}
|
|
// 绘制箭头
|
Diagram.prototype.drawArrow = function (option) {
|
let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文
|
let point = option.point;
|
ctx.strokeStyle = option.strokeStyle ? option.strokeStyle : '#5a62c9'; //填充颜色
|
ctx.fillStyle = option.fillStyle ? option.fillStyle : '#5a62c9'; //填充颜色
|
ctx.lineWidth = option.lineWidth ? option.lineWidth : 1; //线宽;
|
let direction = option.direction ? option.direction : 'right' //箭头方向
|
let size = option.size ? option.size : 54;; //箭头大小
|
switch (direction) {
|
case 'right':
|
ctx.moveTo(point[0], point[1]);
|
ctx.lineTo(point[0], point[1] - size / 9);
|
ctx.lineTo(point[0] + size / 1.8, point[1] - size / 9);
|
ctx.lineTo(point[0] + size / 1.8, point[1] - size / 9 - size / 4.5);
|
ctx.lineTo(point[0] + size, point[1]);
|
ctx.lineTo(point[0] + size / 1.8, point[1] + size / 9 + size / 4.5);
|
ctx.lineTo(point[0] + size / 1.8, point[1] + size / 9);
|
ctx.lineTo(point[0], point[1] + size / 9);
|
ctx.lineTo(point[0], point[1]);
|
break;
|
case 'left':
|
ctx.moveTo(point[0], point[1]);
|
ctx.lineTo(point[0], point[1] - size / 9);
|
ctx.lineTo(point[0] - size / 1.8, point[1] - size / 9);
|
ctx.lineTo(point[0] - size / 1.8, point[1] - size / 9 - size / 4.5);
|
ctx.lineTo(point[0] - size, point[1]);
|
ctx.lineTo(point[0] - size / 1.8, point[1] + size / 9 + size / 4.5);
|
ctx.lineTo(point[0] - size / 1.8, point[1] + size / 9);
|
ctx.lineTo(point[0], point[1] + size / 9);
|
ctx.lineTo(point[0], point[1]);
|
break;
|
case 'top':
|
ctx.moveTo(point[0], point[1]);
|
ctx.lineTo(point[0] - size / 9, point[1]);
|
ctx.lineTo(point[0] - size / 9, point[1] - size / 1.8);
|
ctx.lineTo(point[0] - size / 9 - size / 4.5, point[1] - size / 1.8);
|
ctx.lineTo(point[0], point[1] - size);
|
ctx.lineTo(point[0] + size / 9 + size / 4.5, point[1] - size / 1.8);
|
ctx.lineTo(point[0] + size / 9, point[1] - size / 1.8);
|
ctx.lineTo(point[0] + size / 9, point[1]);
|
ctx.lineTo(point[0], point[1]);
|
break;
|
case 'bottom':
|
ctx.moveTo(point[0], point[1]);
|
ctx.lineTo(point[0] - size / 9, point[1]);
|
ctx.lineTo(point[0] - size / 9, point[1] + size / 1.8);
|
ctx.lineTo(point[0] - size / 9 - size / 4.5, point[1] + size / 1.8);
|
ctx.lineTo(point[0], point[1] + size);
|
ctx.lineTo(point[0] + size / 9 + size / 4.5, point[1] + size / 1.8);
|
ctx.lineTo(point[0] + size / 9, point[1] + size / 1.8);
|
ctx.lineTo(point[0] + size / 9, point[1]);
|
ctx.lineTo(point[0], point[1]);
|
break;
|
default:
|
ctx.moveTo(point[0], point[1]);
|
ctx.lineTo(point[0], point[1] - size / 9);
|
ctx.lineTo(point[0] + size / 1.8, point[1] - size / 9);
|
ctx.lineTo(point[0] + size / 1.8, point[1] - size / 9 - size / 4.5);
|
ctx.lineTo(point[0] + size, point[1]);
|
ctx.lineTo(point[0] + size / 1.8, point[1] + size / 9 + size / 4.5);
|
ctx.lineTo(point[0] + size / 1.8, point[1] + size / 9);
|
ctx.lineTo(point[0], point[1] + size / 9);
|
ctx.lineTo(point[0], point[1]);
|
break;
|
}
|
switch (option.type) {
|
case 'stroke':
|
ctx.stroke();
|
break;
|
case 'fill':
|
ctx.fill();
|
break;
|
default:
|
ctx.stroke();
|
ctx.fill();
|
break;
|
}
|
switch (direction) {
|
case 'right':
|
return {
|
right: point,
|
top: [point[0] + size / 1.8, point[1] - size / 9 - size / 4.5],
|
left: [point[0] - size, point[1]],
|
bottom: [point[0] + size / 1.8, point[1] + size / 9 + size / 4.5],
|
}
|
break;
|
case 'left':
|
return {
|
left: point,
|
top: [point[0] - size / 1.8, point[1] - size / 9 - size / 4.5],
|
right: [point[0] + size, point[1]],
|
bottom: [point[0] - size / 1.8, point[1] + size / 9 + size / 4.5],
|
}
|
break;
|
case 'top':
|
return {
|
bottom: point,
|
top: [point[0], point[1] - size],
|
left: [point[0] - size / 9 - size / 4.5, point[1] - size / 1.8],
|
right: [point[0] + size / 9 + size / 4.5, point[1] - size / 1.8],
|
}
|
break;
|
case 'bottom':
|
return {
|
top: point,
|
bottom: [point[0], point[1] + size],
|
left: [point[0] - size / 9 - size / 4.5, point[1] - size / 1.8],
|
right: [point[0] + size / 9 + size / 4.5, point[1] - size / 1.8],
|
}
|
break;
|
default:
|
return {
|
right: point,
|
top: [point[0] + size / 1.8, point[1] - size / 9 - size / 4.5],
|
left: [point[0] - size, point[1]],
|
bottom: [point[0] + size / 1.8, point[1] + size / 9 + size / 4.5],
|
}
|
break;
|
}
|
|
}
|
|
// 根据id正则删除内容
|
Diagram.prototype.del = function (pattern) {
|
// 清空options配置项
|
this.options = this.options.filter(item => {
|
if (!pattern.test(item.id)) {
|
return item;
|
}
|
});
|
|
// 清空刷新对象
|
this.flushOptions = this.flushOptions.filter(item => {
|
if (!pattern.test(item.id)) {
|
return item;
|
}
|
});
|
};
|
|
export default Diagram;
|