165 lines
5.7 KiB
JavaScript
165 lines
5.7 KiB
JavaScript
//自定义绘制节点的方法
|
||
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)
|
||
}
|