Persist layout settings (#1532)

This commit is contained in:
pa
2025-12-12 07:05:28 +09:00
committed by Natsumi
parent b830311772
commit 43c3ba7be4
2 changed files with 66 additions and 8 deletions

View File

@@ -111,11 +111,13 @@
import { useI18n } from 'vue-i18n';
import { useAppearanceSettingsStore, useChartsStore, useFriendStore, useUserStore } from '../../../stores';
import { computeForceOptions, useMutualGraphChart } from '../composables/useMutualGraphChart';
import { applyForceOverrides, computeForceOptions, useMutualGraphChart } from '../composables/useMutualGraphChart';
import { createRateLimiter, executeWithBackoff } from '../../../shared/utils';
import { database } from '../../../service/database';
import { userRequest } from '../../../api';
import configRepository from '../../../service/config';
import * as echarts from 'echarts';
const { t } = useI18n();
@@ -179,12 +181,14 @@
const isForceDialogVisible = ref(false);
const forceOverrides = ref(null);
const persistedForce = ref(null);
const forceForm = reactive({
repulsion: null,
edgeLengthMin: null,
edgeLengthMax: null,
gravity: null
});
const forceConfigKey = 'VRCX_MutualGraphForce';
const parseForceField = (value, { min = 0, max = Infinity, decimals = 0 } = {}) => {
if (value === '' || value === null || value === undefined) {
@@ -250,11 +254,22 @@
(tab) => {
if (tab === 'mutual') {
loadGraphFromDatabase();
loadForceOverridesFromConfig();
}
},
{ immediate: true }
);
watch(
graphReady,
(ready) => {
if (ready && forceOverrides.value) {
updateChart(graphPayload.value);
}
},
{ immediate: false }
);
function showStatusMessage(message, type = 'info') {
if (!message) {
return;
@@ -530,7 +545,10 @@
if (!chartInstance) {
return;
}
chartInstance.setOption(createChartOption(payload, forceOverrides.value));
const forceOption =
persistedForce.value ||
applyForceOverrides(computeForceOptions(nodes, payload?.links ?? []), forceOverrides.value);
chartInstance.setOption(createChartOption(payload, forceOption));
nextTick(() => chartInstance?.resize());
}
@@ -590,16 +608,59 @@
gravity: gravity.value === null ? defaults.gravity : gravity.value,
layoutAnimation: defaults.layoutAnimation
};
persistedForce.value = applyForceOverrides(defaults, forceOverrides.value);
persistForceOverrides();
updateChart(graphPayload.value);
isForceDialogVisible.value = false;
}
function resetForceSettings() {
forceOverrides.value = null;
persistedForce.value = null;
syncForceForm(forceDefaults.value);
if (hasGraphData.value) {
updateChart(graphPayload.value);
}
clearForceOverrides();
}
async function loadForceOverridesFromConfig() {
try {
const saved = await configRepository.getObject(forceConfigKey, null);
if (!saved || typeof saved !== 'object') {
return;
}
forceOverrides.value = saved.overrides || null;
persistedForce.value = saved.force || null;
if (forceOverrides.value) {
syncForceForm(forceOverrides.value);
}
if (graphReady.value) {
updateChart(graphPayload.value);
}
} catch (err) {
console.warn('[MutualNetworkGraph] Failed to load force settings', err);
}
}
function persistForceOverrides() {
if (!forceOverrides.value) {
clearForceOverrides();
return;
}
const payload = {
overrides: forceOverrides.value,
force: persistedForce.value
};
configRepository.setObject(forceConfigKey, payload).catch((err) => {
console.warn('[MutualNetworkGraph] Failed to save force settings', err);
});
}
function clearForceOverrides() {
configRepository.remove(forceConfigKey).catch((err) => {
console.warn('[MutualNetworkGraph] Failed to clear force settings', err);
});
}
</script>

View File

@@ -55,7 +55,7 @@ export function computeForceOptions(nodes, links) {
};
}
function applyForceOverrides(force, forceOverrides) {
export function applyForceOverrides(force, forceOverrides) {
if (!forceOverrides) {
return force;
}
@@ -181,13 +181,10 @@ export function useMutualGraphChart({ cachedUsers, graphPayload }) {
updateChart?.(graphPayload.value);
}
function createChartOption(payload, forceOverrides) {
function createChartOption(payload, force) {
const nodes = payload?.nodes ?? [];
const links = payload?.links ?? [];
const force = applyForceOverrides(
computeForceOptions(nodes, links),
forceOverrides
);
const resolvedForce = force || computeForceOptions(nodes, links);
const labelMap = Object.create(null);
nodes.forEach((node) => {
if (node?.id) {