Connections can be created and edited on the fly using drag and drop. In this example, computers are sources whereas servers are the targets. Once a connection is created, removed or changed using drag and drop, diagram makes an ajax request to save changes in the backend model. Additionally, optional ajax events are provided as callbacks.
<style>
.ui-diagram-element {
border: 0.1em dotted #E5E4E2;
background-color: #EFEEEC;
width: 10em;
height: 8em;
text-align: center;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.8);
user-select: none;
}
.ui-diagram-element:hover {
background-color: #C7C6C4;
}
</style>
<div class="card">
<h:form id="form">
<p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true"/>
<p:diagram value="#{diagramEditableView.model}" style="height:600px" styleClass="ui-widget-content"
var="el">
<f:facet name="element">
<h:outputText value="#{el.name}" style="display:block;margin-top:1em;"/>
<p:graphicImage name="demo/images/#{el.image}"/>
</f:facet>
<p:ajax event="connect" listener="#{diagramEditableView.onConnect}"/>
<p:ajax event="disconnect" listener="#{diagramEditableView.onDisconnect}"/>
<p:ajax event="connectionChange" listener="#{diagramEditableView.onConnectionChange}"/>
</p:diagram>
</h:form>
</div>
package org.primefaces.showcase.view.data.diagram;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import java.io.Serializable;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.primefaces.PrimeFaces;
import org.primefaces.event.diagram.ConnectEvent;
import org.primefaces.event.diagram.ConnectionChangeEvent;
import org.primefaces.event.diagram.DisconnectEvent;
import org.primefaces.model.diagram.DefaultDiagramModel;
import org.primefaces.model.diagram.DiagramModel;
import org.primefaces.model.diagram.Element;
import org.primefaces.model.diagram.connector.StraightConnector;
import org.primefaces.model.diagram.endpoint.DotEndPoint;
import org.primefaces.model.diagram.endpoint.EndPoint;
import org.primefaces.model.diagram.endpoint.EndPointAnchor;
import org.primefaces.model.diagram.endpoint.RectangleEndPoint;
import org.primefaces.model.diagram.overlay.ArrowOverlay;
@Named("diagramEditableView")
@ViewScoped
@RegisterForReflection(serialization = true)
public class EditableView implements Serializable {
private DefaultDiagramModel model;
private boolean suspendEvent;
@PostConstruct
public void init() {
model = new DefaultDiagramModel();
model.setMaxConnections(-1);
model.setContainment(false);
model.getDefaultConnectionOverlays().add(new ArrowOverlay(20, 20, 1, 1));
StraightConnector connector = new StraightConnector();
connector.setPaintStyle("{stroke:'#98AFC7', strokeWidth:3}");
connector.setHoverPaintStyle("{stroke:'#5C738B'}");
model.setDefaultConnector(connector);
Element computerA = new Element(new NetworkElement("Computer A", "computer-icon.png"), "10em", "6em");
EndPoint endPointCA = createRectangleEndPoint(EndPointAnchor.BOTTOM);
endPointCA.setSource(true);
computerA.addEndPoint(endPointCA);
Element computerB = new Element(new NetworkElement("Computer B", "computer-icon.png"), "25em", "6em");
EndPoint endPointCB = createRectangleEndPoint(EndPointAnchor.BOTTOM);
endPointCB.setSource(true);
computerB.addEndPoint(endPointCB);
Element computerC = new Element(new NetworkElement("Computer C", "computer-icon.png"), "40em", "6em");
EndPoint endPointCC = createRectangleEndPoint(EndPointAnchor.BOTTOM);
endPointCC.setSource(true);
computerC.addEndPoint(endPointCC);
Element serverA = new Element(new NetworkElement("Server A", "server-icon.png"), "15em", "24em");
EndPoint endPointSA = createDotEndPoint(EndPointAnchor.AUTO_DEFAULT);
serverA.setDraggable(false);
endPointSA.setTarget(true);
serverA.addEndPoint(endPointSA);
Element serverB = new Element(new NetworkElement("Server B", "server-icon.png"), "35em", "24em");
EndPoint endPointSB = createDotEndPoint(EndPointAnchor.AUTO_DEFAULT);
serverB.setDraggable(false);
endPointSB.setTarget(true);
serverB.addEndPoint(endPointSB);
model.addElement(computerA);
model.addElement(computerB);
model.addElement(computerC);
model.addElement(serverA);
model.addElement(serverB);
}
public DiagramModel getModel() {
return model;
}
public void onConnect(ConnectEvent event) {
if (!suspendEvent) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Connected",
"From " + event.getSourceElement().getData() + " To " + event.getTargetElement().getData());
FacesContext.getCurrentInstance().addMessage(null, msg);
PrimeFaces.current().ajax().update("form:msgs");
} else {
suspendEvent = false;
}
}
public void onDisconnect(DisconnectEvent event) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Disconnected",
"From " + event.getSourceElement().getData() + " To " + event.getTargetElement().getData());
FacesContext.getCurrentInstance().addMessage(null, msg);
PrimeFaces.current().ajax().update("form:msgs");
}
public void onConnectionChange(ConnectionChangeEvent event) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Connection Changed",
"Original Source:" + event.getOriginalSourceElement().getData()
+ ", New Source: " + event.getNewSourceElement().getData()
+ ", Original Target: " + event.getOriginalTargetElement().getData()
+ ", New Target: " + event.getNewTargetElement().getData());
FacesContext.getCurrentInstance().addMessage(null, msg);
PrimeFaces.current().ajax().update("form:msgs");
suspendEvent = true;
}
private EndPoint createDotEndPoint(EndPointAnchor anchor) {
DotEndPoint endPoint = new DotEndPoint(anchor);
endPoint.setScope("network");
endPoint.setTarget(true);
endPoint.setStyle("{fill:'#98AFC7'}");
endPoint.setHoverStyle("{fill:'#5C738B'}");
return endPoint;
}
private EndPoint createRectangleEndPoint(EndPointAnchor anchor) {
RectangleEndPoint endPoint = new RectangleEndPoint(anchor);
endPoint.setScope("network");
endPoint.setSource(true);
endPoint.setStyle("{fill:'#98AFC7'}");
endPoint.setHoverStyle("{fill:'#5C738B'}");
return endPoint;
}
@RegisterForReflection
public class NetworkElement implements Serializable {
private String name;
private String image;
public NetworkElement() {
}
public NetworkElement(String name, String image) {
this.name = name;
this.image = image;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
@Override
public String toString() {
return name;
}
}
}