优化社交图展示并为通讯录接入本地头像缓存

This commit is contained in:
liuwei
2026-04-27 09:13:01 +08:00
parent 0636e0453f
commit e573fd9c37
4 changed files with 274 additions and 37 deletions

View File

@@ -1394,8 +1394,8 @@ class ValueRankPlugin(MessagePluginInterface):
cm = ContactManager.get_instance()
edge_svg_parts: List[str] = []
# 双向@标签层:
# 1. 每条边中点标注“a->b / b->a”
# 2. 使用白底半透明标签提升可读性,避免与连线重叠难辨识
# 1. 每条边只保留双向次数数字,避免标签信息量过大把图面压得太满
# 2. 仍保留白底半透明标签,确保在密集连线里也能看清数值
edge_label_parts: List[str] = []
for edge_idx, (a, b, mention_count, score, a_to_b_count, b_to_a_count) in enumerate(selected_edges, start=1):
ax, ay = pos_map[a]
@@ -1408,8 +1408,7 @@ class ValueRankPlugin(MessagePluginInterface):
f'stroke="rgba(33, 150, 243, {opacity:.3f})" stroke-width="{stroke_width:.2f}" />'
)
# 通过字典序固定方向,确保同一条边每次渲染文案方向一致。
# 标签文案改为“昵称 + 双向次数 + 恶搞关系标签”,不再展示 wxid
# 为避免标签压在线条上,这里把标签放到“线段法线方向”的偏移位置。
# 当前标签只保留双向互动数字,同时继续沿法线方向偏移,避免数字压在线条上
mx, my = (ax + bx) / 2.0, (ay + by) / 2.0
dx, dy = (bx - ax), (by - ay)
edge_len = max(math.hypot(dx, dy), 1.0)
@@ -1426,25 +1425,9 @@ class ValueRankPlugin(MessagePluginInterface):
angle_deg = math.degrees(math.atan2(dy, dx))
if angle_deg > 90 or angle_deg < -90:
angle_deg += 180
nick_a = cm.get_group_name(group_id, a) or a
nick_b = cm.get_group_name(group_id, b) or b
total_count = int(a_to_b_count) + int(b_to_a_count)
diff_count = abs(int(a_to_b_count) - int(b_to_a_count))
if total_count >= 12 and diff_count <= 2:
relation_tag = "双向奔赴"
elif diff_count >= 8 and max(int(a_to_b_count), int(b_to_a_count)) >= 10:
relation_tag = "下头互动"
elif total_count <= 2:
relation_tag = "点头之交"
elif int(a_to_b_count) == 0 or int(b_to_a_count) == 0:
relation_tag = "疯狂舔狗"
else:
relation_tag = "互相捧场"
label_text = f"{nick_a}{nick_b} {a_to_b_count}/{b_to_a_count} {relation_tag}"
label_text = f"{int(a_to_b_count)}/{int(b_to_a_count)}"
safe_label = html.escape(label_text)
label_width = max(140.0, min(360.0, 8.0 * len(label_text) + 34.0))
label_width = max(52.0, min(92.0, 10.0 * len(label_text) + 24.0))
edge_label_parts.append(
f'<g transform="translate({label_x:.1f},{label_y:.1f}) rotate({angle_deg:.1f})">'
f'<rect x="-{label_width / 2:.1f}" y="-11" width="{label_width:.1f}" height="22" '
@@ -1503,17 +1486,17 @@ class ValueRankPlugin(MessagePluginInterface):
f'{html.escape(str(nick)[:1] or "?")}</text>'
)
# 节点文案放到节点外侧
# 1. 外圈节点文本沿“从中心指向外部”的方向偏移,减少互相压住
# 2. 内圈节点仍保持较近距离,保证中心区域不会炸开
# 3. 文本锚点根据左右半区自动切换,让阅读方向更自然
# 节点文案继续放在头像外侧,但整体收紧一圈
# 1. 用户反馈昵称和头像分得太开,这里缩短外偏移距离
# 2. 昵称字号调小,减少节点一多时的横向挤压
# 3. 统计行与昵称保持较近距离,让“头像-昵称-数据”看起来是一组
outward_dx = math.cos(angle)
outward_dy = math.sin(angle)
label_gap = node_radius + (18.0 if ring_idx == 0 else 28.0 + ring_idx * 4.0)
label_gap = node_radius + (11.0 if ring_idx == 0 else 17.0 + ring_idx * 2.0)
title_x = x + outward_dx * label_gap
title_y = y + outward_dy * label_gap
info_x = x + outward_dx * (label_gap + 22.0)
info_y = y + outward_dy * (label_gap + 22.0)
info_x = x + outward_dx * (label_gap + 12.0)
info_y = y + outward_dy * (label_gap + 12.0) + 1.5
if abs(outward_dx) < 0.20:
anchor = "middle"
elif outward_dx > 0:
@@ -1522,11 +1505,11 @@ class ValueRankPlugin(MessagePluginInterface):
anchor = "end"
node_svg_parts.append(
f'<text x="{title_x:.1f}" y="{title_y:.1f}" text-anchor="{anchor}" '
f'font-size="19" fill="#2F3B52" font-weight="700">{safe_nick}</text>'
f'font-size="16" fill="#2F3B52" font-weight="700">{safe_nick}</text>'
)
node_svg_parts.append(
f'<text x="{info_x:.1f}" y="{info_y:.1f}" text-anchor="{anchor}" '
f'font-size="14" fill="#6C7A96">连接{partner_count} · 互动{score:.1f}</text>'
f'font-size="12" fill="#6C7A96">连接{partner_count} · {score:.1f}</text>'
)
group_title = html.escape(ContactManager.get_instance().get_nickname(group_id) or group_id)