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: 4, width: 16, lineWidth: 2, }, moveDot: { radius: 6, step: 0.8, gravity: 0.08 }, ripplesStep: 0.6 }; // 转动轴全局配置 this.rollAxis = { speed: 0.1, start: 0, }; // 显示线条的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.getEventPosition = function (ev) { var x, y; if (ev.layerX || ev.layerX == 0) { x = ev.layerX; y = ev.layerY; } else if (ev.offsetX || ev.offsetX == 0) { // Opera x = ev.offsetX; y = ev.offsetY; } return { x: x, y: y }; } // 启动更新 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._Clear = function () { this.s_ctx.clearRect(0, 0, this.width, this.height); this.f_ctx.clearRect(0, 0, this.width, this.height); }; // 更新整个图表 Diagram.prototype._update = function () { 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 type = option.type ? option.type : 'abeam'; let gnt; if (type == 'abeam') { gnt = ctx.createLinearGradient(points[0][0], points[0][1], points[1][0], points[1][1]); //线性渐变的起止坐标 } else { gnt = ctx.createLinearGradient(points[0][0] + 10, points[0][1], points[0][0] + 10, points[0][1] + ctx.lineWidth); //线性渐变的起止坐标 } 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 = "gradientline"; // 添加配置项 this.addOptions(option); return points; }; // 绘制线 Diagram.prototype.moveGradientline = function (option) { let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文 let points = option.points; let opts = this.opts; let start = option.start ? option.start : 0; ctx.beginPath(); ctx.lineWidth = option.lineWidth ? option.lineWidth : opts.lineWidth; let color = option.gradientColor ? option.gradientColor : ['#ffa500', '#ffff1d']; let type = option.type ? option.type : 'abeam'; let gnt; if (this.getOption(option.id)) { if (type == 'abeam') { gnt = ctx.createLinearGradient(points[0][0], points[0][1], points[1][0], points[1][1]); //线性渐变的起止坐标 } else { if (start + 0.02 >= 1) { start = 0; } else { start = start + 0.02; } gnt = ctx.createLinearGradient(points[0][0], points[0][1] - ctx.lineWidth / 2, points[0][0], points[0][1] + ctx.lineWidth / 2); //线性渐变的起止坐标 gnt.addColorStop(0, color[1]); gnt.addColorStop(start, color[0]); gnt.addColorStop(1, color[1]); this.setOption(option.id, 'start', start); } } else { option.start = start; } ctx.strokeStyle = gnt; 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 = "moveGradientline"; // 添加配置项 this.addOptions(option); }; // 获取线缩放后的具体信息 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 = option.onOffBase ? option.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.left = [point[0], point[1] + option.height / 2]; option.right = [point[0] + option.width, point[1] + option.height / 2]; option.top = [point[0] + option.width / 2, point[1]]; option.bottom = [point[0] + option.width / 2, point[1] + 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'; ctx.padding = option.padding ? option.padding : 8; 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] - ctx.padding break; case 'bottom': radiusRectY = point[1] - ctx.padding - fontHeight break; case 'middle': radiusRectY = point[1] - ctx.padding - (fontHeight / 2) break; } let radiusRectData = { id: option.id, showPanel: option.showPanel, point: [point[0] - ctx.padding * 2, radiusRectY - 1], width: fontWidth + ctx.padding * 4, height: fontHeight * texts.length + ctx.padding * 2, strokeStyle: borderColor, fillStyle: bgColor, r: (fontHeight * texts.length + ctx.padding * 2) / 2, } if (option.type) { radiusRectData.r = 1; } 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.getZoomTextInfo = 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 newObj = {}; newObj.width = option.width * Xzoom; newObj.height = option.height * Yzoom; newObj.point = [points[0] * Xzoom, points[1] * Yzoom]; newObj.r = option.r * Xzoom; return newObj } // 绘制可移动的点 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.ripples = function (option) { let ctx = this.f_ctx; let opts = this.opts; let point = option.point; let start = option.start ? option.start : point; let flush = option.flush ? option.flush : false; let color = option.color ? option.color : "#50cef5"; let maxRadius = option.maxRadius ? option.maxRadius : 50; let minRadius = option.minRadius ? option.minRadius : 1; let radius = option.radius ? option.radius : minRadius; radius += opts.ripplesStep; if (radius >= maxRadius) { radius = minRadius } // 设置值 this.setOption(option.id, 'radius', radius); this.arc({ point: start, flush: flush, fillStyle: color, strokeStyle: color, radius: radius, type: 'stroke' }); // 添加配置项 option.method = "ripples"; 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; } }); }; /** * 绘制转动的轴 * @param option 配置项 * start起始坐标点,end结束坐标点必填项 * start.y=end.y */ Diagram.prototype.drawRollAxis = function (option) { let ctx = option.flush ? this.f_ctx : this.s_ctx; // 获取上下文 let start = option.start; let end = option.end; let height = option.height ? option.height : 16; let width = Math.abs(start[0] - end[0]); let rollAxis = this.rollAxis; let rollNumber = rollAxis.start; // 旋转轴的开始点 let rollSpeed = rollAxis.speed; // 旋转的速度 let color1 = option.color1 ? option.color1 : "#cdcaca"; // 开始颜色 let color2 = option.color2 ? option.color2 : "#FFFFFF"; // 中间颜色 let grd = ctx.createLinearGradient(start[0], start[0], start[0], height + start[0]); // 渐变色 grd.addColorStop(rollNumber - Math.floor(rollNumber), color1); rollNumber = rollNumber + 0.25; grd.addColorStop(rollNumber - Math.floor(rollNumber), color2); rollNumber = rollNumber + 0.25; grd.addColorStop(rollNumber - Math.floor(rollNumber), color1); rollNumber = rollNumber + 0.25; grd.addColorStop(rollNumber - Math.floor(rollNumber), color2); rollNumber = rollNumber + 0.25; grd.addColorStop(rollNumber - Math.floor(rollNumber), color1); ctx.fillStyle = grd; ctx.fillRect(start[0], start[1], width, height); rollAxis.start += rollSpeed; if (rollAxis.start > 1.25) { rollAxis.start = 0; } // 添加配置项 option.method = "drawRollAxis"; this.addOptions(option); return { left: [start[0], start[1] + height / 2], bottom: [end[0], end[1] + height / 2], } } export default Diagram;