//自定义绘制节点的方法 export const paintNodeFunction = (storeId) => { return function (ctx, onlyShape) { //默认绘制数据类型图片 if (this.properties.typeIcon) { if (this.selected || this.showSelected) { this.drawShape(ctx, onlyShape) } if (this.alpha < 1) { ctx.save() ctx.globalAlpha = this.alpha ctx.drawImage( this.properties.typeIcon, -this.width / 2, -this.height / 2, this.width, this.height ) ctx.restore() } else { ctx.drawImage( this.properties.typeIcon, -this.width / 2, -this.height / 2, this.width, this.height ) } } else { this.drawShape(ctx, onlyShape) } if (storeId == "anomalousGroup") { // 半径 & 样式参数(按需调整) // ===== 三层:实心圆 + 半透明边框 + 外圈虚线 ===== const rFill = this.radius // 实心圆半径 const ringWidth = 15 // 半透明边框的宽度 const ringGap = 0 // 实心与半透明边框之间的间隙(需要留缝就调大) const outerGap = 0 // 半透明边框与虚线之间的间隙 const dashWidth = 2 // 虚线线宽 const dash = 2, gap = 4 // 虚线样式 const ringAlphaFactor = 0.5 // 半透明边框的相对透明度(相对于 this.alpha) // 1) 中间实心圆(填充) ctx.save() ctx.beginPath() ctx.arc(0, 0, rFill, 0, Math.PI * 2) ctx.fillStyle = `rgba(${this.fillColor}, ${this.alpha})` ctx.fill() ctx.restore() // 2) 同色半透明边框(描边,不是挖空) const rRing = rFill + ringGap + ringWidth / 2 ctx.save(); const rInner = rFill + ringGap; const rOuter = rInner + ringWidth; // 一个小工具函数,复用甜甜圈路径 const ringPath = () => { ctx.beginPath(); ctx.arc(0, 0, rOuter, 0, Math.PI * 2, false); ctx.arc(0, 0, rInner, 0, Math.PI * 2, true); }; // 选择配色方案 const fc = (this.fillColor || "").replace(/\s+/g, ""); const isMint = fc === "75,241,184"; const isBlue = fc === "69,192,242"; const isRed = fc === "255,50,60"; const isYellow = fc === "250,222,37"; // 默认都按照 SVG:每层 0.24 透明度(再乘整体 alpha) const layerAlpha = 0.24 * (this.alpha ?? 1); // --- 第 2-1 层:线性渐变 (#0FE9BE -> #91FFB2), fill-opacity=0.24 --- ringPath(); let lg = ctx.createLinearGradient(-rOuter, 0, rOuter, 0); if(isMint){ lg.addColorStop(0, '#0FE9BE'); lg.addColorStop(1, '#91FFB2'); }else if(isBlue){ lg.addColorStop(0, "#009DFF"); lg.addColorStop(1, "#00FFF2"); }else if(isRed){ lg.addColorStop(0, '#FF0000'); lg.addColorStop(1, '#FF0909'); }else if(isYellow){ lg.addColorStop(0, '#FFDA09'); lg.addColorStop(1, '#FFDA09'); } ctx.globalAlpha = 0.24 * (this.alpha ?? 1); // 与节点整体透明度相乘 ctx.fillStyle = lg; ctx.fill(); // --- 第 2-2 层:径向渐变 (E6F9FF -> BEFFDB(0.5) -> 透明), fill-opacity=0.24 --- // 参照 SVG 的 gradientTransform(translate(35.15,12.16) 相对圆心(20,16)): // 约等于中心点在右上方 (≈ 0.95R, -0.24R),半径≈1.52R ringPath(); const cx = 0.95 * rOuter; const cy = -0.24 * rOuter; let rg = ctx.createRadialGradient(cx, cy, 0, cx, cy, 1.52 * rOuter); if(isMint){ rg.addColorStop(0.0, 'rgba(230,249,255,1)'); // #E6F9FF rg.addColorStop(0.3693,'rgba(190,255,219,0.5)'); // #BEFFDB @ 0.5 rg.addColorStop(1.0, 'rgba(0,0,0,0)'); }else if(isBlue){ rg.addColorStop(0.0, 'rgba(229,249,255,1)'); rg.addColorStop(0.3693,'rgba(141,255,253,0.5)'); rg.addColorStop(1.0, 'rgba(0, 0, 0, 0)'); }else if(isRed){ rg.addColorStop(0.0, 'rgba(255,255,255,1)'); rg.addColorStop(0.3693,'rgba(255,200,200,0.5)'); rg.addColorStop(1.0, 'rgba(0, 0, 0, 0)'); }else if(isYellow){ rg.addColorStop(0.0, 'rgba(229,249,255,1)'); rg.addColorStop(0.3693,'rgba(254,255,200,0.5)'); rg.addColorStop(1.0, 'rgba(0, 0, 0, 0)'); } ctx.globalAlpha = 0.24 * (this.alpha ?? 1); ctx.fillStyle = rg; ctx.fill(); ctx.restore(); // 3) 外圈虚线(同色) ctx.save() ctx.beginPath() const rDash = rRing + ringWidth / 2 + outerGap + dashWidth / 2 ctx.arc(0, 0, rDash, 0, Math.PI * 2) ctx.lineWidth = dashWidth ctx.setLineDash([dash, gap]) ctx.lineCap = "round" ctx.strokeStyle = `rgba(${this.fillColor}, ${this.alpha})` ctx.stroke() ctx.setLineDash([]) // 清理,避免影响后续绘制 ctx.restore() } else { ctx.beginPath() ctx.arc(0, 0, this.radius + 6, 0, Math.PI * 2) ctx.lineWidth = 5 ctx.strokeStyle = `rgba(${this.fillColor},${this.alpha * 0.4})` ctx.stroke() } this.paintText(ctx) //调用内部方法绘制文字 } } //自定义连线的方法 export const paintLineFunction = function (ctx, needHideText) { this.drawOriginalLine(ctx, needHideText) //内置默认的绘制方法 //指定路径,用于鼠标检测选中 this.path = [ { x: this.source.cx, y: this.source.cy }, { x: this.target.cx, y: this.target.cy } ] // //绘制路径 ctx.beginPath() ctx.moveTo(this.source.cx, this.source.cy) ctx.lineTo(this.target.cx, this.target.cy) this.setLineStyle(ctx) ctx.stroke() // //绘制连线上文字(内部方法) this.paintTextOnLineWithAngle(ctx, this.source, this.target) }