Add conflictology map mode and fix graph rendering reliability.

Support conflict types, involvement sizing, and map-type toggles while keeping polar sector layout; improve GraphView init retries and edge matching on network maps.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-25 11:51:06 +03:00
co-authored by Cursor
parent e80d0d0e88
commit 85b8b2e9b8
29 changed files with 744 additions and 132 deletions
+89
View File
@@ -0,0 +1,89 @@
export const CONFLICT_RELATION_TYPES = [
{ value: 'conflict_open', label: 'Открытый конфликт / враждебность' },
{ value: 'conflict_tension', label: 'Напряжение / скрытое недовольство' },
{ value: 'conflict_alliance', label: 'Союз / поддержка' },
{ value: 'conflict_neutral', label: 'Нейтральная / слабая связь' },
]
export const CONFLICT_RELATION_STYLES = {
conflict_open: {
color: '#e74c3c',
highlight: '#ff6b6b',
width: 3.5,
dashes: false,
opacity: 0.95,
},
conflict_tension: {
color: '#f1c40f',
highlight: '#f5d76e',
width: 2.5,
dashes: [8, 5],
opacity: 0.9,
},
conflict_alliance: {
color: '#2ecc71',
highlight: '#58d68d',
width: 2.5,
dashes: false,
opacity: 0.9,
},
conflict_neutral: {
color: '#95a5a6',
highlight: '#b2babb',
width: 1.5,
dashes: [5, 5],
opacity: 0.65,
},
}
export const CONFLICT_CENTER_NODE_ID = '__conflict_center__'
const CONFLICT_TYPE_LABELS = Object.fromEntries(
CONFLICT_RELATION_TYPES.map((t) => [t.value, t.label])
)
export function isConflictRelationType(type) {
return String(type || '').startsWith('conflict_')
}
export function conflictRelationLabel(type) {
return CONFLICT_TYPE_LABELS[type] || type
}
export function conflictRelationToVisEdge(edge) {
const style = CONFLICT_RELATION_STYLES[edge.relation_type] || CONFLICT_RELATION_STYLES.conflict_neutral
return {
id: String(edge.id),
from: String(edge.from),
to: String(edge.to),
relation_type: edge.relation_type,
width: style.width,
dashes: style.dashes,
hoverWidth: style.width + 8,
selectionWidth: style.width + 12,
color: {
color: style.color,
highlight: style.highlight,
opacity: style.opacity,
},
arrows: { to: { enabled: true, scaleFactor: 0.85 } },
smooth: false,
title: edge.title || conflictRelationLabel(edge.relation_type),
}
}
export function involvementNodeSize(involvement) {
const raw = Number(involvement)
const i = Number.isFinite(raw) ? Math.max(1, Math.min(5, raw)) : 3
return 10 + (i - 1) * 4
}
export function involvementFromRadiusRatio(ratio) {
const safe = Math.max(0, Math.min(1, Number(ratio) || 0.5))
return Math.max(1, Math.min(5, Math.round(5 - safe * 4)))
}
export function radiusRatioFromInvolvement(involvement) {
const i = Math.max(1, Math.min(5, Number(involvement) || 3))
return 0.92 - ((i - 1) / 4) * 0.67
}