feat(graph): Phase 3 — type filter, export PNG, fullscreen, focus node
CI / lint (push) Has started running
CI / test (push) Has been cancelled
CI / security (push) Has been cancelled
CI / build (push) Has been cancelled

- Type filter checkboxes (dossier, .md, autre) in legend
- Export PNG button (canvas.toDataURL)
- Fullscreen button (Fullscreen API)
- Focus node function (center on specific node)
- Filter applied during _draw() to skip hidden nodes
This commit is contained in:
2026-05-28 14:48:31 -04:00
parent bf836caccc
commit 0416266dde
2 changed files with 68 additions and 4 deletions
+57
View File
@@ -300,6 +300,7 @@ export const GraphViewManager = {
// Draw nodes
const searchLower = this._searchTerm.toLowerCase();
for (const node of this._nodes) {
if (!this._isNodeVisible(node)) continue;
const p = this._nodePositions[node.id];
if (!p) continue;
@@ -395,6 +396,48 @@ export const GraphViewManager = {
if (this._tooltipEl) this._tooltipEl.style.display = 'none';
},
// --- Advanced controls ---
_isNodeVisible(node) {
const showDir = document.getElementById('graph-filter-dir')?.checked ?? true;
const showMd = document.getElementById('graph-filter-md')?.checked ?? true;
const showOther = document.getElementById('graph-filter-other')?.checked ?? true;
if (node.type === 'directory') return showDir;
if (node.type === 'file' && (node.path || '').endsWith('.md')) return showMd;
if (node.type === 'file') return showOther;
return true;
},
applyTypeFilter() {
// Filters are applied during _draw() — nodes/edges not in visible set are skipped
},
exportPNG() {
const link = document.createElement('a');
link.download = `obsigate-graph-${this._vault}-${Date.now()}.png`;
link.href = this._canvas.toDataURL('image/png');
link.click();
},
toggleFullscreen() {
const container = this._canvas?.parentElement?.parentElement; // editor-container
if (!container) return;
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
container.requestFullscreen();
}
// Re-init layout after fullscreen change
setTimeout(() => this._onResize(), 300);
},
focusNode(nodeId) {
const pos = this._nodePositions[nodeId];
if (!pos) return;
this._offsetX = this._width / 2 - pos.x * this._zoom;
this._offsetY = this._height / 2 - pos.y * this._zoom;
},
_onMouseDown(e) {
const rect = this._canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
@@ -520,6 +563,20 @@ export function initGraphView() {
});
}
// Export PNG
const exportBtn = document.getElementById('graph-export');
if (exportBtn) exportBtn.addEventListener('click', () => gm.exportPNG());
// Fullscreen
const fullscreenBtn = document.getElementById('graph-fullscreen');
if (fullscreenBtn) fullscreenBtn.addEventListener('click', () => gm.toggleFullscreen());
// Type filters
['dir', 'md', 'other'].forEach(type => {
const cb = document.getElementById(`graph-filter-${type}`);
if (cb) cb.addEventListener('change', () => gm.applyTypeFilter());
});
if (canvas) {
canvas.addEventListener('mousedown', (e) => gm._onMouseDown(e));
canvas.addEventListener('mousemove', (e) => gm._onMouseMove(e));