package de.tud.kom.socom.web.client.graphview; import static de.tud.kom.socom.web.client.graphview.GlobalGraphSettings.NODE_WIDTH; import java.util.HashMap; import java.util.Map; import org.sgx.raphael4gwt.raphael.Paper; import org.sgx.raphael4gwt.raphael.Path; import org.sgx.raphael4gwt.raphael.Raphael; import org.sgx.raphael4gwt.raphael.Set; import org.sgx.raphael4gwt.raphael.Shape; import org.sgx.raphael4gwt.raphael.base.Glow; import org.sgx.raphael4gwt.raphael.event.HoverListener; import org.sgx.raphael4gwt.raphael.event.MouseEventListener; import org.sgx.raphael4gwt.raphael.widget.PaperWidget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import de.tud.kom.socom.web.client.GraphPanel; import de.tud.kom.socom.web.client.Helper; public class SubGraph extends AbstractGraph { private Set optionSet; public SubGraph(JSONObject graph, long center) { super(graph, false, true, center); } @Override Map<Long, Integer> getNodeLevel() { if (centralNode == -1) return null; Map<Long, Integer> levels = new HashMap<Long, Integer>(); for (Long n : nodes) { JSONObject context = Helper.findContextData(graph.get("contexts").isArray(), n); JSONArray relationsTo = context.get("relationsTo").isArray(); for (int i = 0; relationsTo != null && i < relationsTo.size(); i++) { Long next = (long)relationsTo.get(i).isObject().get("destination").isNumber().doubleValue(); if (next.equals(centralNode)) { levels.put(n, 0); } } } levels.put(centralNode, 1); JSONObject context = Helper.findContextData(graph.get("contexts").isArray(), centralNode); JSONArray relationsTo = context.get("relationsTo").isArray(); for (int i = 0; relationsTo != null && i < relationsTo.size(); i++) { long next = (long)relationsTo.get(i).isObject().get("destination").isNumber().doubleValue(); levels.put(next, 2); } return levels; } @Override void addGraphSpecificDrawings() { //for each connection to a outside the subgraph draw for (long n : levels.keySet()) { int to = 0, from = 0; int level = levels.get(n); boolean leftNode = level == 0; boolean rightNode = level == 2; if (leftNode || rightNode) { for (long n1 : nodes) { if (n1 == centralNode) continue; JSONObject context = Helper.findContextData(graph.get("contexts").isArray(), n1); JSONArray relationsTo = context.get("relationsTo").isArray(); for (int i = 0; relationsTo != null && i < relationsTo.size(); i++) { long next = (long)relationsTo.get(i).isObject().get("destination").isNumber().doubleValue(); if (next == n && levels.get(n1) == null) from++; } } JSONObject context = Helper.findContextData(graph.get("contexts").isArray(), n); JSONArray relationsTo = context.get("relationsTo").isArray(); for (int i = 0; relationsTo != null && i < relationsTo.size(); i++) { long next = (long)relationsTo.get(i).isObject().get("destination").isNumber().doubleValue(); if (next != centralNode && levels.get(next) == null) to++; } for (int i = 0; i < from; i++) { int s = leftNode ? -1 : 1; int l = (int)3*NODE_WIDTH; long nx = drawables.get(n).getX(); long ny = drawables.get(n).getY(); int x1 = (int) nx + l * s; int y1 = (int) ny - l/4 + i * l/2/from; Path p1 = paper.path("M"+x1+","+y1 + " L"+nx+","+ny); Path p2 = paper.path(p1.getSubpath(0,(int) (p1.getTotalLength()/3))); p2.attr("arrow-end", "open-narrow-long"); Raphael.set(paper, p1,p2).attr("stroke-width",2).attr("stroke-dasharray", "--").attr("stroke", "#aaa").toBack(); } for (int i = 0; i < to; i++) { int s = leftNode ? -1 : 1; int l = (int)3*NODE_WIDTH; long nx = drawables.get(n).getX(); long ny = drawables.get(n).getY(); int x1 = (int) nx + l * s; int y1 = (int) ny + l/4 + i * l/2/to; Path p1 = paper.path("M"+nx+","+ny + " L"+x1+","+y1); Path p2 = paper.path(p1.getSubpath(0, (int) (p1.getTotalLength()*2/3))); p2.attr("arrow-end", "open-narrow-long"); Raphael.set(paper, p1,p2).attr("stroke-width",2).attr("stroke-dasharray", "--").attr("stroke", "#aaa").toBack(); } } } addOverviewButton(); } private void addOverviewButton() { int w = 110; int h = 30; // Paper optionPaper = Raphael.paper(PAPER_OFFSET_X, PAPER_OFFSET_Y, w, h); PaperWidget pW = new PaperWidget(w, h); Paper optionPaper = pW.getPaper(); GraphPanel.get(-1, -1).addPanel(pW); Shape r1 = optionPaper.rect(0,0,w,h,0).attr("stroke-color", "#333").attr("fill","#fff"); //from http://raphaeljs.com/icons Shape p1 = optionPaper.path("M1.999,2.332v26.499H28.5V2.332H1.999zM26.499,26.832H4V12.5h8.167V4.332h14.332V26.832zM15.631,17.649l5.468,5.469l-1.208,1.206l5.482,1.469l-1.47-5.481l-1.195,1.195l-5.467-5.466l1.209-1.208l-5.482-1.469l1.468,5.48L15.631,17.649z"); p1.transform("s0.6t-2,-2"); Shape t1 = optionPaper.text(0, h/2, "Show Overview"); t1.transform("t" + (h+t1.getBBox().getWidth()/2) + ",0"); final Set glowSet = Raphael.set(optionPaper, r1, p1); final Set hoverSet = Raphael.set(paper, paper.rect(0, 0, w, h, 0).attr("fill","#f00").attr("opacity", 0)); final HoverListener hoverL = new HoverListener() { private Set g; @Override public void hoverOut(NativeEvent e) { if (g != null) { g.remove(); g = null; } } @Override public void hoverIn(NativeEvent e) { g = glowSet.glow(new Glow(5, false, 0.7, 0, 0, "#999")); } }; hoverSet.hover(hoverL); hoverSet.click(new MouseEventListener() { public void notifyMouseEvent(NativeEvent e) { hoverSet.unhover(hoverL); hoverL.hoverOut(null); unpaintOptionPaper(); GraphPanel.get(-1,-1).showFullGraph(); } }); } public void unpaintOptionPaper() { if(optionSet != null) optionSet.remove(); } }