I am little bit stuck on how to export graphs to svg or graphml. Neither the api, examples or threads on forum.jgraph.com did help me until now.
I need to export graphs to both svg and graphml. I got svg to display the nodes and edges even with the correct layout, but I'm missing information like names of nodes and assigned colors.
With graphml I have no clue yet how to get the correct xml code to even display a functioning graph.
Is there any guideline/workflow somewhere which might help me with export in JGraphX?
Thanks in advance for any help,
Chris
In order to save your graph you have to call mxCellRendered to render your graph to a mxicanvas from which you get your Document (dom document).
From the Renderer it goes like this:
mxGraph.drawCell() -> mxGraph.drawState() -> mxICanvas.drawCell() -> mxICanvas.drawShape()
mxICanvas knows only the cell's geometry and style.
I wanted the cell id attribute added in the svg file as well, so I did the following
extended the mxGraph to override the drawCell() in order to add the cell id in the style of the cell, and
extended the mxSvgCanvas for adding the id attribute for the shapes that interested me
The function to save as svg graph goes like:
// use the extended svg canvas, where the cell id is added as attribute
public void createSVG(mxGraphExtended g) {
String filename = "\home\koula\graph.svg";
mxSvgCanvasExtended canvas = (mxSvgCanvasExtended) mxCellRenderer.drawCells(
g, null, 1, null, new CanvasFactory() {
public mxICanvas createCanvas(int width, int height) {
mxSvgCanvasExtended canvas = new mxSvgCanvasExtended(mxDomUtils
.createSvgDocument(width, height));
canvas.setEmbedded(true);
return canvas;
}
});
try {
mxUtils.writeFile(mxXmlUtils.getXml(canvas.getDocument()), filename);
} catch (IOException e) {
e.printStackTrace();
}
}
The overriden drawCell():
public class mxGraphExtended extends mxGraph {
#Override
public void drawCell(mxICanvas canvas, Object cell) {
// add the cell's id as a style attribute
// cause canvas only get the style and geometry
mxCellState state = this.getView().getState(cell);
state.getStyle().put("cellid", ((mxCell)cell).getId());
super.drawCell(canvas, cell);
}
}
The overridden drawShape() goes like:
public class mxSvgCanvasExtended extends mxSvgCanvas {
//... have coppied only the related code
#Override
public Element drawShape(int x, int y, int w, int h,
Map<String, Object> style)
{
//...
// Draws the shape
String shape = mxUtils.getString(style, mxConstants.STYLE_SHAPE, "");
String cellid = mxUtils.getString(style, "cellid", "");
Element elem = null;
// ...
// e.g. if image, add the cell id
if (shape.equals(mxConstants.SHAPE_IMAGE)) {
String img = getImageForStyle(style);
if (img != null) {
// Vertical and horizontal image flipping
boolean flipH = mxUtils.isTrue(style,
mxConstants.STYLE_IMAGE_FLIPH, false);
boolean flipV = mxUtils.isTrue(style,
mxConstants.STYLE_IMAGE_FLIPV, false);
elem = createImageElement(x, y, w, h, img,
PRESERVE_IMAGE_ASPECT, flipH, flipV, isEmbedded());
/* so here we are */
// add the cell id atribute
if(!cellid.equals("")) {
elem.setAttribute("id", cellid);
}
}
} else if (shape.equals(mxConstants.SHAPE_LINE))
// ...
}// end drawShape
} // end class
Hope this help.
Related
i am learning to write code in java and recently started to write a game as per my assignment.
i have completed almost entire game but stuck with the animation part of the game.
here is what i have done so far,
this is the class that load the image ti display,
public class dpmImage {
private BufferedImage dpm1;
private BufferedImage setDpm1;
public dpmImage() { //this is a constructor
try {
dpm1= ImageIO.read(new File("dpm1Load.png"));
} catch (IOException e) {
e.printStackTrace();
}
setDpm1 = dpm1;
}
private BufferedImage dpm1ImageGet() {
return setDpm1;
}
}
the following code is from main class (Main.java)
private Graphics cGraphcs;
cGraphcs.drawImage(dpmImageInstance.dpm1ImageGet(), 0, 0, null);
The code is working fine and displays the image.
Now, I am allowed to modify anything in dpmImage class but not allowed to modify anything in Main.java and still make this image animate. So I create an array of BufferedImage in dpmImage class and add a second image in the array as follows,
public class dpmImage {
private BufferedImage [] dpm1 = new BufferedImage[2];
private BufferedImage setDpm1;
public dpmImage() { //this is a constructor
try {
dpm1[0]= ImageIO.read(new File("dpm1Load.png"));
dpm1[1]= ImageIO.read(new File("dpm1Load1.png"));
} catch (IOException e) {
e.printStackTrace();
}
setDpm1 = dpm1[0];
setDpm1 = dpm1[1];
}
private BufferedImage dpm1ImageGet() {
return setDpm1;
}
}
But i couldn't get to animate it from first image to 2nd. Can someone please give me any hints on that ? i am not allowed to change the Main.java class
You always return the same BufferedImage from the dpm1ImageGet method. You need to get the instance from the array. Based on the frequency of the update, you can simply use an index like
private int indexImage = 0;
private BufferedImage dpm1ImageGet() {
indexImage = ( indexImage + 1 ) % dpm1.length; //increment and use % to prevent any ArrayOutOfBoundsException
return dpm1[indexImage];
}
Each call will return the next image. Of course, this depends on when you want to get the other image. It could be anything.
I'm currently developing a plugin which only renders an image to a map like this:
public class MapRendererTest extends MapRenderer {
private Image image;
public MapRendererTest(File file) {
try {
this.image = ImageIO.read(file);
}
catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void render(MapView mapView, MapCanvas mapCanvas, Player player) {
mapCanvas.drawImage(0, 0, image);
}
}
everything works fine, but there is this little thing in the red circle that I want to remove but I don't know how.
Things I already tried
Setting an emtpy MapCursorCollection
MapView.setWorld to a world where no-one is playing.
Creating MapCursorCollection with a invisible cursor
It would be amazing if someone could help me with that.
Thanks in advance
To get rid of the cursor, you have to remove all the other map renderers or at least the CraftMapRanderer.
In order to do this, you have to do the following:
#EventHandler
public void onMapInitialized(MapInitializeEvent e) {
e.getMap().removeRenderer(e.getMap().getRenderers().get(0));
e.getMap().addRenderer(new MapRendererTest(new File(Main.getInstance().getDataFolder() + "/image.png")));
}
This only works of course if there is no other custom map renderer assigned to this map, so the only registered is the CraftMapRenderer.
If you have multiple MapRenderers you could loop through the list and remove them.
I make an fxml file in javafx2.
I have a List of Person objects. The name of this List, is Entries. I have an ObservableList, myObservableList. Inside of this I want to put labels. Each label must contains a pair of image person and text of his name.
I write this code:
for (int i=0; i<numberOfEntries; i++){
currentEntry = Entries.get(i);
name=currentEntry.getName();
image1 = new Image("file:"+currentEntry.getIcon());
imageView1= new ImageView();
imageView1.setFitHeight(50);
imageView1.setFitWidth(70);
imageView1.setImage(image1);
label = new Label(name, imageView1);
label.setFont(new Font("serif", 32));
myObservableList.add(label);
}
It works ok, but after a few puts of images the JVM gives me the below error message:
Caused by: java.lang.OutOfMemoryError: Java heap space.
This error comes from the code line image1 = new Image("file:"+currentEntry.getIcon());
Finally, I want to put all elements of myObservableList into a ComboBox items. For this reason in Initialize method of java controller I write:
myComboBox.setItems(myObservableList);
ListCell<Label> buttonCell = new ListCell<Label>() {
#Override protected void updateItem(Label item, boolean isEmpty) {
super.updateItem(item, isEmpty);
setText(item==null ? "" : item.getText());
}
};
myComboBox.setButtonCell(buttonCell);
I am sure that I have not enough experience in javafx, and I do not know how must I handle for I have a combobox with pairs of icon and text in the same cell for all items.
I want to express my lot of thanks to Peter Duniho and PakkuDon for their help for improve English in my text.
It is almost always a mistake to use a Node class as the data type for a ComboBox (or for any other control). You should use a class that represents the data only, and register a cell factory to configure how the data are displayed.
In your case, if you include the image in the data, you are likely to run into memory problems. Each image is likely to be represented in memory by a few megabytes. So your data class should hold the image name, and then you can use the cell in the combo box to create an image.
Here's some sample code to give you the idea:
Data class (Person.java):
public class Person {
private final String name ;
private final String imageFileName ;
public Person(String name, String imageFileName) {
this.name = name ;
this.imageFileName = imageFileName ;
}
public String getName() {
return name ;
}
public String getImageFileName() {
return imageFileName ;
}
}
UI code to create ComboBox from a List<Person>:
List<Person> entries = ... ; // populated from DB
ComboBox<Person> comboBox = new ComboBox<>();
comboBox.getItems().addAll(entries);
comboBox.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {
#Override
public ListCell<Person> call(ListView<Person> listCell) {
return new ListCell<Person>() {
private final ImageView = new ImageView();
#Override
public void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
File imageFile = new File(person.getImageFileName());
String imageUrl = imageFile.toURI().toURL().toExternalForm();
Image image = new Image(imageUrl, 70, 50,
// preserve ratio
true,
// smooth resizing
true,
// load in background
true);
imageView.setImage(image);
setText(person.getName());
setGraphic(imageView);
}
}
};
}
});
You can use the same ListCell implementation for the ComboBox's buttonCell.
The point here is that cells are only created for the visible cells, so the images are loaded "on demand" as the cells are displayed. Using the Image constructor that takes the width and height parameters also reduces the memory footprint, as the Image object can resize as it loads.
Finally, note that it's important to use the flag to load images in the background, which keeps the UI responsive. If you scroll quickly, you'll likely see some images not loaded for a brief while; the cells will repaint appropriately once the image becomes available.
I am working on a rummikub game, I have a board which have tiles on it, and all positions on board are defined as TileActor. Some tile actors have actual tiles on them, some are empty. Problem is: when I drag a tile and drop it on an empty TileActor, it works fine but when I drop it on empty space, the actor is getting lost. How can I prevent the actors from getting lost?
This is my drag&drop code:
dragAndDrop.addSource(new Source(actor) {
#Override
public Payload dragStart(InputEvent event, float x, float y, int pointer) {
Payload payload = new Payload();
payload.setObject("Some payload!");
payload.setDragActor(getActor());
Label validLabel = new Label("Valid move!", skin);
validLabel.setColor(0, 1, 0, 1);
payload.setValidDragActor(validLabel);
Label invalidLabel = new Label("Invalid!", skin);
invalidLabel.setColor(1, 0, 0, 1);
payload.setInvalidDragActor(invalidLabel);
return payload;
}
dragAndDrop.addTarget(new Target(actor) {
public boolean drag (Source source, Payload payload, float x, float y, int pointer) {
getActor().setColor(Color.GREEN);
return true;
}
public void reset (Source source, Payload payload) {
getActor().setColor(Color.WHITE);
}
public void drop (Source source, Payload payload, float x, float y, int pointer) {
int movingTile =((TileActor)source.getActor()).getPosition();
if(movingTile!=-1){
int newPosition=player.moveTileOnBoard(movingTile, ((TileActor)getActor()).getPosition());
}
}
});
The problem is that you provide your own Actor to the Payload (so DragAndDrop take care about removing this actor):
payload.setDragActor(getActor());
Try to create the copy of the Actor instead:
Actor newActor = /* clone your actor from getActor() to newActor */;
payload.setDragActor(newActor);
I'm using the GWT google maps V3 API and I need to display custom shapes over the map.
For simple elements I used Polygon, Circle and InfoWidnow classes, but I want to display some other widgets like button or custom panels.
Is there any way to do that using OverlayView class ? I tried a simple solution: an AbsolutePanel that contains the MapWidget and my custom widgets, placed on top, but I would like to use the gwt google maps classes as much as I can. I've read the documentation and also searched for an answer but I could't figure it out so a code example would be great.
Thanx!
Just make use of standard GWT API alongside with your maps V3 API. They will interconnect well enough.
I found what i needed here (the javascript v3 api):
https://developers.google.com/maps/documentation/javascript/overlays#CustomOverlays
the method names and classes are very similar so it isn't so difficult to figure out how the GWT classes should be used (like OverlayView).
Here is an example with custom widgets (containing SVG elements and animation) rendered on the map:
private class TargettingOverlay extends OverlayView {
protected Element div ;
protected PanelWrapper panelWrapper;
private TargettingEffect targetEffect;
TargettingOverlay(){
targetEffect = new TargettingEffect();
targetEffect.setLinedDimension(10500);
targetEffect.setLinesOffset(-5000);
}
void positionTarget(LatLng loc, boolean withoutLines){
if (targetEffect == null )
return;
if (loc == null) {
targetEffect.setElementsVisible(false);
return;
}
targetEffect.setElementsVisible(true);
Point p = null;
Point sw = null;
Point ne = null;
LatLng locSW = (LatLng)this.getMap().getBounds().getSouthWest();
LatLng locNE = (LatLng)this.getMap().getBounds().getNorthEast();
//
p = (Point)getProjection().fromLatLngToDivPixel(loc);
sw = (Point)getProjection().fromLatLngToDivPixel(locSW);
ne = (Point)getProjection().fromLatLngToDivPixel(locNE);
targetEffect.setWithoutLinles(withoutLines);
targetEffect.target((int)ne.getY(), (int)p.getY(), (int)sw.getX(), (int)p.getX());
}
#Override
public void draw() {
Point ne = (Point)getProjection().fromLatLngToDivPixel((LatLng)
this.getMap().getBounds().getNorthEast());
Point sw = (Point)getProjection().fromLatLngToDivPixel((LatLng)
this.getMap().getBounds().getSouthWest());
div.getStyle().setTop(ne.getY(), Unit.PX);
div.getStyle().setLeft(sw.getX(), Unit.PX);
}
#Override
public void onAdd() {
div = DOM.createDiv();
getPanes().getOverlayLayer().appendChild(div);
panelWrapper = new PanelWrapper(div);
panelWrapper.attach();
targetEffect.setContainer(panelWrapper);
}
#Override
public void onRemove() {
div.removeFromParent();
panelWrapper.removeFromParent();
div = null;
panelWrapper = null;
}
}