graphstream / gs-ui-swing Goto Github PK
View Code? Open in Web Editor NEWGraphStream Swing user interface
Home Page: http://graphstream-project.org/
License: Other
GraphStream Swing user interface
Home Page: http://graphstream-project.org/
License: Other
I noticed that edges are only found if you click right in the middle of them.
I really would like to be able to click (or mouse over) anywhere on the edge in order to find it.
As a workaround, I would like to set my own custom camera that has my own implementation of edgeContains.
Unfortunately, this does not seem possible because there is not setCamera method on the defaultView, only getCamera.
I would like to be able to do this:
viewer.getDefaultView.setCamera(customCamera)
The documentation for "integrating the viewer into your GUI" is not useful.
https://graphstream-project.org/doc/Tutorials/Graph-Visualisation/
GraphStream 2.0, the following statements do not make any sense.
import org.graphstream.ui.swingViewer.View;
import org.graphstream.ui.swingViewer.Viewer;
What is the right syntax for integrating into my own Swing frame?
I would like to use GraphStream to display a tree where the nodes are images.
None of the commands I found in the tutorials work for me. Colouring the nodes with the same commands is no problem. The Url works without any problems in another context.
Unfortunately, I don't see the error even after trying around for a while.
Graph graph = new SingleGraph("Tutorial 1");
Node tmpNode = graph.addNode("A" );
graph.addNode("B" );
graph.addNode("C" );
graph.addEdge("AB", "A", "B");
graph.addEdge("BC", "B", "C");
graph.addEdge("CA", "C", "A");
System.setProperty("org.graphstream.ui", "swing");
tmpNode.addAttribute("ui.style", "fill-color: rgb(0,100,255);"); //works fine
graph.addAttribute("ui.stylesheet", "node { fill-color: rgb(0,100,255); }"); //works fine
tmpNode.addAttribute("ui.style", "fill-image: url('D:/Studium/Scaffold/scaffoldTest/scaffoldTestOutput/Test11/Tree/TreeTest0Level0.png');"); //does not work
graph.addAttribute("ui.stylesheet", "node { fill-mode: image-scaled; fill-image: url('D:/Studium/Scaffold/scaffoldTest/scaffoldTestOutput/Test11/Tree/TreeTest0Level0.png'); }"); //does not work
graph.display();
Greetings
Julian
I have the following bug when I try to create an image :
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.awt.Graphics2D.getTransform()" because "this.g2" is null
at org.graphstream.ui.swing.BackendJ2D.prepareNewFrame(BackendJ2D.java:107)
at org.graphstream.ui.swing.SwingGraphRenderer.render(SwingGraphRenderer.java:223)
at org.graphstream.ui.swing.util.SwingFileSinkImages.render(SwingFileSinkImages.java:70)
at org.graphstream.stream.file.FileSinkImages.outputNewImage(FileSinkImages.java:548)
at org.graphstream.stream.file.FileSinkImages.outputNewImage(FileSinkImages.java:515)
I think the problem is that the function initImage (that create g2d) is never called in the constructor:
Hello, tried to compile it against the master branch of gs libraries and I have got this error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project gs-ui-swing: Compilation failure [ERROR] /Users/xxx/Development/Tests/GraphStream/gs-ui-swing/src/org/graphstream/ui/swing_viewer/DefaultView.java:[114,8] org.graphstream.ui.swing_viewer.DefaultView is not abstract and does not override abstract method enableMouseOptions() in org.graphstream.ui.view.View
regards
john
Test case: DemoViewerJComponents execution cause:
Dec 12, 2019 1:01:07 PM org.graphstream.ui.swing.util.ImageCache loadImage WARNING: file:///home/hicham/Bureau/b.png javax.imageio.IIOException: Can't get input stream from URL!
Hi,
I posted this issue on StackOverflow a few days ago but did not get a response.
There is a problem with the mouse pointer - even after putting the view into it's own panel as written somewhere in the FAQ (it's written for JavaFX but on StackOverflow someone claimed it was the same issue).
Full details and video in the StackOverflow post.
Regards,
Tal.
Hello,
I created a JFrame composed of one View and two JTextField:
The View displays five nodes: four are just landmarks and are not expected to be moved by the user ("fixed_*"), and one is there to be moved by the user ("unfixed"). The two JTextField show the coordinates of the "unfixed" node. Both the View and the JTextField have to be synchronized with each other. Indeed, when the user moves the "unfixed" node in the View, then the two JTextField have to be updated accordingly :
Reciprocally, when the user modifies the coordinate in one of the JTextField, then the View has to be updated accordingly too:
Here are four test cases:
Test cases 1, 2 and 3 work fine, but test case 4 doesn't work. Actually, in test case 4, once the user moved the "unfixed" node in the View, then the modification of the coordinate in one of the JTextField doesn't update the View.
I tried to analyze what differs between the execution of test cases 3 and 4. To do so, I printed the name of the current thread at different places of the code. I saw that modifications through the JTextField are run on thread "AWT-EventQueue-0" (this is the Event Dispatch Thread of Swing, isn't it?), and that modifications through the View are run on thread "Thread-0". In my implementation, "Thread-0" is the thread on which I run the GraphStream's pumping loop, to wait for events occurred in the GraphStream's Viewer thread and to copy back them inside "Thread-0". From what I understood of GraphStream's documentation:
Did I understand well the documentation?
In my implementation, I chose to access the GraphStream's Graph from another thread than the Swing one. Thus, I deduce from my previous runs of test cases 3 and 4 that:
I have the impression that I'm doing something wrong with all these threads. Could you help me please?
I tried to make a minimum working example (MWE) to reproduce my problem. Here is the content of the Java source file NodeSyncTest.java:
package mwe;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import org.apache.commons.lang3.math.NumberUtils;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.MultiGraph;
import org.graphstream.ui.graphicGraph.GraphicGraph;
import org.graphstream.ui.graphicGraph.GraphicNode;
import org.graphstream.ui.swing_viewer.SwingViewer;
import org.graphstream.ui.view.View;
import org.graphstream.ui.view.Viewer;
import org.graphstream.ui.view.ViewerListener;
import org.graphstream.ui.view.ViewerPipe;
class NodeSyncTest {
public static void main(String[] args) {
System.out.println("NodeSyncTest.main : " + Thread.currentThread().getName());
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("SwingUtilities.invokeLater.Runnable.run : " + Thread.currentThread().getName());
new NodeSyncTest();
}
});
}
NodeSyncTest() {
Map<String, MyNode> myNodes = Map.of(
"fixed_top_left", new MyNode(-2, 2),
"fixed_top_right", new MyNode(2, 2),
"fixed_bottom_left", new MyNode(-2, -2),
"fixed_bottom_right", new MyNode(2, -2),
"unfixed", new MyNode(0, 0)
);
GraphStreamControl graphStreamControl = new GraphStreamControl(myNodes);
JTextFieldsControl jTextFieldsControl = new JTextFieldsControl(myNodes);
graphStreamControl.jTextFieldsControl = jTextFieldsControl;
jTextFieldsControl.graphStreamControl = graphStreamControl;
graphStreamControl.fillGraphStreamGraph();
JFrame mainDialog = new JFrame();
mainDialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainDialog.setSize(300, 300);
mainDialog.getContentPane().add((Component) graphStreamControl.view, BorderLayout.CENTER);
mainDialog.getContentPane().add(jTextFieldsControl.panel, BorderLayout.SOUTH);
mainDialog.setLocationRelativeTo(null);
mainDialog.setVisible(true);
graphStreamControl.startPumpLoop();
}
class GraphStreamControl {
Map<String, MyNode> myNodes;
MyNode myUnfixedNode;
Graph graphStreamGraph;
Viewer viewer;
View view;
ViewerPipe viewerPipe;
JTextFieldsControl jTextFieldsControl;
GraphStreamControl(Map<String, MyNode> myNodes) {
this.myNodes = myNodes;
myUnfixedNode = myNodes.get("unfixed");
System.setProperty("org.graphstream.ui", "swing");
graphStreamGraph = new MultiGraph("");
viewer = new SwingViewer(graphStreamGraph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
viewer.disableAutoLayout();
view = viewer.addDefaultView(false);
viewerPipe = viewer.newViewerPipe();
viewerPipe.addSink(graphStreamGraph);
viewerPipe.addViewerListener(new ViewerListener() {
@Override
public void viewClosed(String viewName) {}
@Override
public void buttonPushed(String id) {}
@Override
public void buttonReleased(String id) {
System.out.println("ViewerListener.buttonReleased : " + Thread.currentThread().getName());
if ("unfixed".equals(id)) {
GraphicGraph graphicGraph = viewer.getGraphicGraph();
GraphicNode unfixedGraphStreamNode = (GraphicNode) graphicGraph.getNode("unfixed");
myUnfixedNode.x = unfixedGraphStreamNode.getX();
myUnfixedNode.y = unfixedGraphStreamNode.getY();
jTextFieldsControl.update();
}
}
@Override
public void mouseOver(String id) {}
@Override
public void mouseLeft(String id) {}
});
}
public void fillGraphStreamGraph() {
for (var entry : myNodes.entrySet()) {
String nodeId = entry.getKey();
MyNode myNode = entry.getValue();
Node graphStreamNode = graphStreamGraph.addNode(nodeId);
graphStreamNode.setAttribute("xy", myNode.x, myNode.y);
graphStreamNode.setAttribute("ui.label", nodeId);
graphStreamNode.setAttribute("ui.style", "text-alignment: under;");
}
}
void startPumpLoop() {
new Thread(() -> {
System.out.println("GraphStreamControl.startPumpLoop : " + Thread.currentThread().getName());
while (true) {
try {
viewerPipe.blockingPump();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
void update() {
GraphicGraph graphicGraph = viewer.getGraphicGraph();
GraphicNode unfixedGraphStreamNode = (GraphicNode) graphicGraph.getNode("unfixed");
unfixedGraphStreamNode.setAttribute("xy", myUnfixedNode.x, myUnfixedNode.y);
}
}
class JTextFieldsControl {
Map<String, MyNode> myNodes;
MyNode myUnfixedNode;
JPanel panel;
JTextField xTextField;
JTextField yTextField;
GraphStreamControl graphStreamControl;
JTextFieldsControl(Map<String, MyNode> myNodes) {
this.myNodes = myNodes;
myUnfixedNode = myNodes.get("unfixed");
panel = new JPanel(new GridLayout(1, 4));
JLabel xLabel = new JLabel("X:", SwingConstants.RIGHT);
xLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(xLabel);
xTextField = new JTextField(3);
xTextField.setHorizontalAlignment(SwingConstants.RIGHT);
xTextField.setText(Double.toString(myUnfixedNode.x));
xTextField.getCaret().setDot(0);
xTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("JTextFieldsControl - actionPerformed on xTextField : " + Thread.currentThread().getName());
String xNodeString = xTextField.getText();
double xNodeDouble = NumberUtils.toDouble(xNodeString);
myUnfixedNode.x = xNodeDouble;
graphStreamControl.update();
}
});
panel.add(xTextField);
JLabel yLabel = new JLabel("Y:", SwingConstants.RIGHT);
yLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(yLabel);
yTextField = new JTextField(3);
yTextField.setHorizontalAlignment(SwingConstants.RIGHT);
yTextField.setText(Double.toString(myUnfixedNode.y));
yTextField.getCaret().setDot(0);
yTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("JTextFieldsControl - actionPerformed on yTextField : " + Thread.currentThread().getName());
String yNodeString = yTextField.getText();
double yNodeDouble = NumberUtils.toDouble(yNodeString);
myUnfixedNode.y = yNodeDouble;
graphStreamControl.update();
}
});
panel.add(yTextField);
}
void update() {
String xNodeString = Double.toString(myUnfixedNode.x);
xTextField.setText(xNodeString);
xTextField.getCaret().setDot(0);
String yNodeString = Double.toString(myUnfixedNode.y);
yTextField.setText(yNodeString);
yTextField.getCaret().setDot(0);
}
}
class MyNode {
double x;
double y;
MyNode(double x, double y) {
this.x = x;
this.y = y;
}
}
}
and here is the one of the the Maven POM file pom.xml to build an executable JAR including all dependencies:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mwe</groupId>
<artifactId>mwe</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MWE</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>org.graphstream</groupId>
<artifactId>gs-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.graphstream</groupId>
<artifactId>gs-ui-swing</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- here we specify that we want to use the main
method within the App class -->
<mainClass>mwe.NodeSyncTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>mwe.NodeSyncTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
To use these two files, just create a folder mwe/, put NodeSyncTest.java into mwe/src/main/java/mwe/ and pom.xml into mwe/, and, in mwe/, run
mvn compile assembly:single
and
java -jar target/mwe-0.0.1-SNAPSHOT-jar-with-dependencies.jar
Here is the full project folder:
MWE.zip
EDIT: I just posted my question on Stack Overflow (https://stackoverflow.com/q/77913500/3890496) to reach more readers. I will update this issue if I get answer from there.
Hello,
I created a JFrame composed of one View and two JTextField:
The View displays five nodes: four are just landmarks and are not expected to be moved by the user ("fixed_*"), and one is there to be moved by the user ("unfixed"). The two JTextField show the coordinates of the "unfixed" node. Both the View and the JTextField have to be synchronized with each other. Indeed, when the user moves the "unfixed" node in the View, then the two JTextField have to be updated accordingly :
Reciprocally, when the user modifies the coordinate in one of the JTextField, then the View has to be updated accordingly too:
Here is the code:
package mwe;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import org.apache.commons.lang3.math.NumberUtils;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.MultiGraph;
import org.graphstream.ui.graphicGraph.GraphicGraph;
import org.graphstream.ui.graphicGraph.GraphicNode;
import org.graphstream.ui.swing_viewer.SwingViewer;
import org.graphstream.ui.view.View;
import org.graphstream.ui.view.Viewer;
import org.graphstream.ui.view.ViewerListener;
import org.graphstream.ui.view.ViewerPipe;
class NodeSyncTest2 {
public static void main(String[] args) {
new NodeSyncTest2();
}
NodeSyncTest2() {
Map<String, MyNode> myNodes = Map.of(
"fixed_top_left", new MyNode(-2, 2),
"fixed_top_right", new MyNode(2, 2),
"fixed_bottom_left", new MyNode(-2, -2),
"fixed_bottom_right", new MyNode(2, -2),
"unfixed", new MyNode(1, 2)
);
GraphStreamControl graphStreamControl = new GraphStreamControl(myNodes);
JTextFieldsControl jTextFieldsControl = new JTextFieldsControl(myNodes);
graphStreamControl.jTextFieldsControl = jTextFieldsControl;
jTextFieldsControl.graphStreamControl = graphStreamControl;
graphStreamControl.fillGraphStreamGraph();
JFrame mainDialog = new JFrame();
mainDialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainDialog.setSize(300, 300);
mainDialog.getContentPane().add((Component) graphStreamControl.view, BorderLayout.CENTER);
mainDialog.getContentPane().add(jTextFieldsControl.panel, BorderLayout.SOUTH);
mainDialog.setLocationRelativeTo(null);
mainDialog.setVisible(true);
graphStreamControl.startPumpLoop();
}
class GraphStreamControl {
Map<String, MyNode> myNodes;
MyNode myUnfixedNode;
Graph graphStreamGraph;
Viewer viewer;
View view;
ViewerPipe viewerPipe;
JTextFieldsControl jTextFieldsControl;
GraphStreamControl(Map<String, MyNode> myNodes) {
this.myNodes = myNodes;
myUnfixedNode = myNodes.get("unfixed");
System.setProperty("org.graphstream.ui", "swing");
graphStreamGraph = new MultiGraph("");
viewer = new SwingViewer(graphStreamGraph, Viewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
viewer.disableAutoLayout();
view = viewer.addDefaultView(false);
viewerPipe = viewer.newViewerPipe();
viewerPipe.addSink(graphStreamGraph);
viewerPipe.addViewerListener(new ViewerListener() {
@Override
public void viewClosed(String viewName) {}
@Override
public void buttonPushed(String id) {}
@Override
public void buttonReleased(String id) {
if ("unfixed".equals(id)) {
GraphicGraph graphicGraph = viewer.getGraphicGraph();
GraphicNode unfixedGraphStreamNode = (GraphicNode) graphicGraph.getNode("unfixed");
myUnfixedNode.x = unfixedGraphStreamNode.getX();
myUnfixedNode.y = unfixedGraphStreamNode.getY();
jTextFieldsControl.update();
}
}
@Override
public void mouseOver(String id) {}
@Override
public void mouseLeft(String id) {}
});
}
public void fillGraphStreamGraph() {
for (var entry : myNodes.entrySet()) {
String nodeId = entry.getKey();
MyNode myNode = entry.getValue();
Node graphStreamNode = graphStreamGraph.addNode(nodeId);
// graphStreamNode.setAttribute("x", myNode.x); // WORKS!
// graphStreamNode.setAttribute("y", myNode.y); // WORKS!
// graphStreamNode.setAttribute("xyz", myNode.x, myNode.y, 0.0); // WORKS!
graphStreamNode.setAttribute("xy", myNode.x, myNode.y); // WORKS!
graphStreamNode.setAttribute("ui.label", nodeId);
graphStreamNode.setAttribute("ui.style", "text-alignment: under;");
}
}
void startPumpLoop() {
SwingWorker<Void, Void> swingWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
while (true) {
try {
viewerPipe.blockingPump();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
}
};
swingWorker.execute();
}
void update() {
Node unfixedGraphStreamNode = graphStreamGraph.getNode("unfixed");
// unfixedGraphStreamNode.setAttribute("x", myUnfixedNode.x); // WORKS!
// unfixedGraphStreamNode.setAttribute("y", myUnfixedNode.y); // WORKS!
// unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0); // WORKS!
unfixedGraphStreamNode.setAttribute("xy", myUnfixedNode.x, myUnfixedNode.y); // DOES NOT WORK!
}
}
class JTextFieldsControl {
Map<String, MyNode> myNodes;
MyNode myUnfixedNode;
JPanel panel;
JTextField xTextField;
JTextField yTextField;
GraphStreamControl graphStreamControl;
JTextFieldsControl(Map<String, MyNode> myNodes) {
this.myNodes = myNodes;
myUnfixedNode = myNodes.get("unfixed");
panel = new JPanel(new GridLayout(1, 4));
JLabel xLabel = new JLabel("X:", SwingConstants.RIGHT);
xLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(xLabel);
xTextField = new JTextField(3);
xTextField.setHorizontalAlignment(SwingConstants.RIGHT);
xTextField.setText(Double.toString(myUnfixedNode.x));
xTextField.getCaret().setDot(0);
xTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String xNodeString = xTextField.getText();
double xNodeDouble = NumberUtils.toDouble(xNodeString);
myUnfixedNode.x = xNodeDouble;
graphStreamControl.update();
}
});
panel.add(xTextField);
JLabel yLabel = new JLabel("Y:", SwingConstants.RIGHT);
yLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(yLabel);
yTextField = new JTextField(3);
yTextField.setHorizontalAlignment(SwingConstants.RIGHT);
yTextField.setText(Double.toString(myUnfixedNode.y));
yTextField.getCaret().setDot(0);
yTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String yNodeString = yTextField.getText();
double yNodeDouble = NumberUtils.toDouble(yNodeString);
myUnfixedNode.y = yNodeDouble;
graphStreamControl.update();
}
});
panel.add(yTextField);
}
void update() {
String xNodeString = Double.toString(myUnfixedNode.x);
xTextField.setText(xNodeString);
xTextField.getCaret().setDot(0);
String yNodeString = Double.toString(myUnfixedNode.y);
yTextField.setText(yNodeString);
yTextField.getCaret().setDot(0);
}
}
class MyNode {
double x;
double y;
MyNode(double x, double y) {
this.x = x;
this.y = y;
}
}
}
and here is the one of the Maven POM file pom.xml to build an executable JAR including all dependencies:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mwe</groupId>
<artifactId>mwe</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MWE</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>org.graphstream</groupId>
<artifactId>gs-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.graphstream</groupId>
<artifactId>gs-ui-swing</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- here we specify that we want to use the main
method within the App class -->
<mainClass>mwe.NodeSyncTest2</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>mwe.NodeSyncTest2</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
(to use these two files, just create a folder mwe/, put NodeSyncTest2.java into mwe/src/main/java/mwe/ and pom.xml into mwe/, and, in mwe/, run
mvn compile assembly:single
and
java -jar target/mwe-0.0.1-SNAPSHOT-jar-with-dependencies.jar
;
here is the full project folder: MWE.zip)
My issue: in the method GraphStreamControl.update(), the use of
unfixedGraphStreamNode.setAttribute("x", myUnfixedNode.x);
unfixedGraphStreamNode.setAttribute("y", myUnfixedNode.y);
or of
unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0);
updates the graph correctly. On the contrary, the use of
unfixedGraphStreamNode.setAttribute("xy", myUnfixedNode.x, myUnfixedNode.y);
doesn't update the graph. Why ?
Also, in the method GraphStreamControl.fillGraphStreamGraph(), each of
unfixedGraphStreamNode.setAttribute("x", myUnfixedNode.x);
unfixedGraphStreamNode.setAttribute("y", myUnfixedNode.y);
,
unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0);
and
unfixedGraphStreamNode.setAttribute("xy", myUnfixedNode.x, myUnfixedNode.y);
perfectly works. Why?
Since The Full renderer is fully functional, basicRenderer
is no longer needed.
Currently, when the edges of a graph are styled with
shape: cubic-curve;
they are curved in a seemingly arbitrary way and it rarely looks how I want.
For example, here is a graph where the edges are styled with cubic-curve
:
Note that there are discontinuities at the nodes because the Bezier control vectors are either horizontal or vertical and determined by the angle between the source and destination vertices.
What I propose is a simple backward compatible change that would allow optionally specifying a control point for an edge that would determine the quadratic Bezier to use for its curvature like this:
If an edge has the "ui.control-point" attribute set, then the edge renderer will draw a quadratic Bezier curve using that control point. The implementation is simple, and will give a lot of extra control. I will make a PR.
After adding the control point, I can get the curved edges to look they way that I want.
When doing something like node.setAttribute("label", "Line 1\nLine2")
I expected to get Line 1
and Line 2
on two separate lines. Instead I got the lines concatenated on the same line (Line1Line2
). This works as expected with the JavaFX renderer but not with the Swing renderer.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.