Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ class _TestScreenState extends State<TestScreen> {
MindMapData(
id: 'node1',
title: '📝 노드1',
borderColor: Colors.green,
children: [
MindMapData(id: 'sub1', title: '서브1'),
MindMapData(id: 'sub1', title: '서브1', borderColor: Colors.purple),
MindMapData(id: 'sub2', title: '서브2'),
],
),
Expand Down Expand Up @@ -94,6 +95,9 @@ class _TestScreenState extends State<TestScreen> {
'🍃 첫리프',
() => _focusToNode(CameraFocus.firstLeaf, null),
),
// Forward/Backward focus buttons
_buildButton('⬅️ 이전', _focusPreviousNode),
_buildButton('다음 ➡️', _focusNextNode),
],
),
),
Expand Down Expand Up @@ -171,7 +175,7 @@ class _TestScreenState extends State<TestScreen> {
levelSpacing: 120,
nodeMargin: 15,
),
cameraFocus: CameraFocus.fitAll,
cameraFocus: currentFocus,
focusNodeId: targetNodeId,
focusAnimation: const Duration(
milliseconds: 1000,
Expand Down Expand Up @@ -256,4 +260,31 @@ class _TestScreenState extends State<TestScreen> {
return '🌳 전체트리';
}
}

void _focusNextNode() {
final flatNodes = mindMapData.flatten();
if (flatNodes.isEmpty) return;
int currentIdx = flatNodes.indexWhere((n) => n.id == targetNodeId);
int nextIdx = (currentIdx + 1) % flatNodes.length;
final nextNode = flatNodes[nextIdx];
setState(() {
currentFocus = CameraFocus.custom;
targetNodeId = nextNode.id;
lastAction = '다음 노드로 이동: ${nextNode.title}';
});
}

void _focusPreviousNode() {
final flatNodes = mindMapData.flatten();
if (flatNodes.isEmpty) return;
int currentIdx = flatNodes.indexWhere((n) => n.id == targetNodeId);
int prevIdx = (currentIdx - 1);
if (prevIdx < 0) prevIdx = flatNodes.length - 1;
final prevNode = flatNodes[prevIdx];
setState(() {
currentFocus = CameraFocus.custom;
targetNodeId = prevNode.id;
lastAction = '이전 노드로 이동: ${prevNode.title}';
});
}
}
11 changes: 10 additions & 1 deletion lib/src/models/mind_map_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ class MindMapData {

@override
String toString() {
return 'MindMapData(id: $id, title: $title, children: ${children.length})';
return 'MindMapData(id: $id, title: $title, children: [36m${children.length} [0m)';
}

/// Returns a flat list of all nodes in pre-order traversal (self, then children)
List<MindMapData> flatten() {
List<MindMapData> result = [this];
for (final child in children) {
result.addAll(child.flatten());
}
return result;
}
}
23 changes: 14 additions & 9 deletions lib/src/widgets/mind_map_widget.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math' as math;

import '../models/mind_map_data.dart';
import '../models/mind_map_style.dart';
import '../models/mind_map_node.dart';
import '../enums/camera_focus.dart';
import '../enums/mind_map_layout.dart';
import '../enums/node_shape.dart';
import '../enums/camera_focus.dart';
import '../models/mind_map_data.dart';
import '../models/mind_map_node.dart';
import '../models/mind_map_style.dart';
// import '../enums/mind_map_type.dart';
import '../painters/mind_map_painter.dart';
import '../painters/node_painter.dart';
Expand Down Expand Up @@ -1647,6 +1648,8 @@ class _MindMapWidgetState extends State<MindMapWidget>
/// 개별 노드 위젯 빌드 / Build individual node widget
Widget _buildNodeWidget(MindMapNode node) {
final isSelected = _selectedNodeId == node.id;
final isFocused =
widget.focusNodeId != null && widget.focusNodeId == node.id;

final actualSize = widget.style.getActualNodeSize(
node.title,
Expand Down Expand Up @@ -1746,8 +1749,11 @@ class _MindMapWidgetState extends State<MindMapWidget>
final nodeColor = node.color;
final textColor = node.textColor ?? widget.style.defaultTextStyle.color;
final borderColor =
node.borderColor ??
(isSelected ? widget.style.selectionBorderColor : Colors.white);
(isFocused || isSelected)
? widget.style.selectionBorderColor
: (node.borderColor ?? Colors.white);
final borderWidth =
(isFocused || isSelected) ? widget.style.selectionBorderWidth : 2.0;

return Positioned(
key: ValueKey('positioned_${node.id}'),
Expand Down Expand Up @@ -1785,8 +1791,7 @@ class _MindMapWidgetState extends State<MindMapWidget>
shape: widget.style.nodeShape,
fillColor: nodeColor,
borderColor: borderColor,
borderWidth:
isSelected ? widget.style.selectionBorderWidth : 2.0,
borderWidth: borderWidth,
shadowEnabled: widget.style.enableNodeShadow,
shadowColor: widget.style.nodeShadowColor,
shadowBlurRadius: widget.style.nodeShadowBlurRadius,
Expand Down