You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I see this behavior when I use Diagram Editor for one of my projects. When the form re-renders, the data of the diagram is lost. Can someone help me with the same? I have used the pub.dev example and added a simple Floating button that increments the counter.
import 'dart:math' as math;
import 'package:diagram_editor/diagram_editor.dart';
import 'package:flutter/material.dart';
void main() => runApp(const DiagramApp());
class DiagramApp extends StatefulWidget {
const DiagramApp({Key? key}) : super(key: key);
@override
_DiagramAppState createState() => _DiagramAppState();
}
class _DiagramAppState extends State<DiagramApp> {
MyPolicySet myPolicySet = MyPolicySet();
int _counter = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Stack(
children: [
Container(color: Colors.grey),
Padding(
padding: const EdgeInsets.all(16),
child: DiagramEditor(
diagramEditorContext:
DiagramEditorContext(policySet: myPolicySet),
),
),
Padding(
padding: const EdgeInsets.all(0),
child: Row(
children: [
ElevatedButton(
onPressed: () => myPolicySet.deleteAllComponents(),
style: ElevatedButton.styleFrom(primary: Colors.red),
child: const Text('delete all')),
const Spacer(),
ElevatedButton(
onPressed: () => myPolicySet.serialize(),
child: const Text('serialize')),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => myPolicySet.deserialize(),
child: const Text('deserialize')),
],
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() {
_counter = _counter + 1;
}),
child: Text(
_counter.toString(),
),
),
),
),
);
}
}
// Custom component Data which you can assign to a component to dynamic data property.
class MyComponentData {
MyComponentData();
bool isHighlightVisible = false;
Color color =
Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
showHighlight() {
isHighlightVisible = true;
}
hideHighlight() {
isHighlightVisible = false;
}
// Function used to deserialize the diagram. Must be passed to `canvasWriter.model.deserializeDiagram` for proper deserialization.
MyComponentData.fromJson(Map<String, dynamic> json)
: isHighlightVisible = json['highlight'],
color = Color(int.parse(json['color'], radix: 16));
// Function used to serialization of the diagram. E.g. to save to a file.
Map<String, dynamic> toJson() => {
'highlight': isHighlightVisible,
'color': color.toString().split('(0x')[1].split(')')[0],
};
}
// A set of policies compound of mixins. There are some custom policy implementations and some policies defined by diagram_editor library.
class MyPolicySet extends PolicySet
with
MyInitPolicy,
MyComponentDesignPolicy,
MyCanvasPolicy,
MyComponentPolicy,
CustomPolicy,
//
CanvasControlPolicy,
LinkControlPolicy,
LinkJointControlPolicy,
LinkAttachmentRectPolicy {}
// A place where you can init the canvas or your diagram (eg. load an existing diagram).
mixin MyInitPolicy implements InitPolicy {
@override
initializeDiagramEditor() {
canvasWriter.state.setCanvasColor(Colors.grey[300]!);
}
}
// This is the place where you can design a component.
// Use switch on componentData.type or componentData.data to define different component designs.
mixin MyComponentDesignPolicy implements ComponentDesignPolicy {
@override
Widget showComponentBody(ComponentData componentData) {
return Container(
decoration: BoxDecoration(
color: (componentData.data as MyComponentData).color,
border: Border.all(
width: 2,
color: (componentData.data as MyComponentData).isHighlightVisible
? Colors.pink
: Colors.black,
),
),
child: const Center(child: Text('component')),
);
}
}
// You can override the behavior of any gesture on canvas here.
// Note that it also implements CustomPolicy where own variables and functions can be defined and used here.
mixin MyCanvasPolicy implements CanvasPolicy, CustomPolicy {
@override
onCanvasTapUp(TapUpDetails details) {
canvasWriter.model.hideAllLinkJoints();
if (selectedComponentId != null) {
hideComponentHighlight(selectedComponentId);
} else {
canvasWriter.model.addComponent(
ComponentData(
size: const Size(96, 72),
position:
canvasReader.state.fromCanvasCoordinates(details.localPosition),
data: MyComponentData(),
),
);
}
}
}
// Mixin where component behaviour is defined. In this example it is the movement, highlight and connecting two components.
mixin MyComponentPolicy implements ComponentPolicy, CustomPolicy {
// variable used to calculate delta offset to move the component.
late Offset lastFocalPoint;
@override
onComponentTap(String componentId) {
canvasWriter.model.hideAllLinkJoints();
bool connected = connectComponents(selectedComponentId, componentId);
hideComponentHighlight(selectedComponentId);
if (!connected) {
highlightComponent(componentId);
}
}
@override
onComponentLongPress(String componentId) {
hideComponentHighlight(selectedComponentId);
canvasWriter.model.hideAllLinkJoints();
canvasWriter.model.removeComponent(componentId);
}
@override
onComponentScaleStart(componentId, details) {
lastFocalPoint = details.localFocalPoint;
}
@override
onComponentScaleUpdate(componentId, details) {
Offset positionDelta = details.localFocalPoint - lastFocalPoint;
canvasWriter.model.moveComponent(componentId, positionDelta);
lastFocalPoint = details.localFocalPoint;
}
// This function tests if it's possible to connect the components and if yes, connects them
bool connectComponents(String? sourceComponentId, String? targetComponentId) {
if (sourceComponentId == null || targetComponentId == null) {
return false;
}
// tests if the ids are not same (the same component)
if (sourceComponentId == targetComponentId) {
return false;
}
// tests if the connection between two components already exists (one way)
if (canvasReader.model.getComponent(sourceComponentId).connections.any(
(connection) =>
(connection is ConnectionOut) &&
(connection.otherComponentId == targetComponentId))) {
return false;
}
// This connects two components (creates a link between), you can define the design of the link with LinkStyle.
canvasWriter.model.connectTwoComponents(
sourceComponentId: sourceComponentId,
targetComponentId: targetComponentId,
linkStyle: LinkStyle(
arrowType: ArrowType.pointedArrow,
lineWidth: 1.5,
backArrowType: ArrowType.centerCircle,
),
);
return true;
}
}
// You can create your own Policy to define own variables and functions with canvasReader and canvasWriter.
mixin CustomPolicy implements PolicySet {
String? selectedComponentId;
String serializedDiagram = '{"components": [], "links": []}';
highlightComponent(String componentId) {
canvasReader.model.getComponent(componentId).data.showHighlight();
canvasReader.model.getComponent(componentId).updateComponent();
selectedComponentId = componentId;
}
hideComponentHighlight(String? componentId) {
if (componentId != null) {
canvasReader.model.getComponent(componentId).data.hideHighlight();
canvasReader.model.getComponent(componentId).updateComponent();
selectedComponentId = null;
}
}
deleteAllComponents() {
selectedComponentId = null;
canvasWriter.model.removeAllComponents();
}
// Save the diagram to String in json format.
serialize() {
serializedDiagram = canvasReader.model.serializeDiagram();
}
// Load the diagram from json format. Do it cautiously, to prevent unstable state remove the previous diagram (id collision can happen).
deserialize() {
canvasWriter.model.removeAllComponents();
canvasWriter.model.deserializeDiagram(
serializedDiagram,
decodeCustomComponentData: (json) => MyComponentData.fromJson(json),
decodeCustomLinkData: null,
);
}
}
Regards,
Nirmal
The text was updated successfully, but these errors were encountered:
gowda-nirmal
changed the title
Grid Editor data lost on re-render of the form, when a state change in another component occurs.
Diagram Editor : Data lost on re-render of the form.
Jun 23, 2023
DiagramEditor is a widget as all other widgets in Flutter. If you call setState, it calls the build function and rebuilds the content. So the DiagramEditor is build as fresh widget with no data.
Do not rebuild the widget and the data won't be lost.
You can try passing key (GlobalKey) to the DiagramEditor to let the engine to know that it's still the same widget and it's not necessary to rebuild it. I haven't tried this in this particular situation but it may fix the issue in your code. Or just do not rebuild it.
Hello @Arokip,
I'm facing the same issue, and adding a global key doesn't work for me.
I have to open the keyboard in Canvas so it rebuilds the widget.
Hi,
I see this behavior when I use Diagram Editor for one of my projects. When the form re-renders, the data of the diagram is lost. Can someone help me with the same? I have used the pub.dev example and added a simple Floating button that increments the counter.
Regards,
Nirmal
The text was updated successfully, but these errors were encountered: