1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package ySVG-2.3.
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2002-2010 by yWorks GmbH, Vor dem Kreuzberg 28,
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.yext.svg;
15  
16  import yext.svg.io.SVGDOMEnhancer;
17  import yext.svg.io.SVGIOHandler;
18  
19  import y.base.Edge;
20  import y.base.EdgeCursor;
21  import y.base.EdgeMap;
22  import y.base.Node;
23  import y.base.NodeCursor;
24  import y.util.Maps;
25  import y.view.EdgeRealizer;
26  import y.view.Graph2D;
27  import y.view.LineType;
28  
29  import java.awt.Color;
30  import java.awt.EventQueue;
31  import java.awt.Graphics2D;
32  
33  
34  /** 
35   * Demonstrates how to write SVG that highlights all incoming and outgoing
36   * edges at a node. The highlight effect gets triggered when the mouse is over
37   * a node.
38   */
39  public class HighlightConnectionsDemo extends SVGExportDemo
40  {
41    /**
42     * Creates and configures the SVGIOHandlers to be used.
43     * This method will add a specialized SVGDOMEnhancer to
44     * the IOHandler.
45     */
46    protected SVGIOHandler createSVGIOHandler(boolean svgz)
47    {
48      SVGIOHandler ioh = super.createSVGIOHandler(svgz);
49      SVGDOMEnhancer enhancer = new HighlightConnections();
50      ioh.setSVGGraph2DRenderer(enhancer);
51      return ioh;
52    }
53    
54   /**
55    * Enhances the SVG DOM. Whenever the mouse is over a node highlight
56    * its incoming and outgoing edges.
57    */
58    class HighlightConnections extends SVGDOMEnhancer
59    {
60      private EdgeMap edgeType;
61  
62      /**
63       * Override a callback method. Before the graph will be written to the SVG DOM 
64       * we add an additional ecmacript node to the definition block of the SVG. 
65       * The script will be used to highlight the edges of a node on mouseover events.
66       */ 
67      protected void initializeDOM()
68      {
69        Graph2D graph = view.getGraph2D();
70        edgeType = Maps.createIndexEdgeMap(new Object[graph.E()]);
71        addToSVGDefinition(createScript());
72      }
73      
74      /**
75       * Paint edges in three differetn variants. The first variant gets
76       * shown if the edge is not highlighted. The second variant
77       * gets shown when the edge gets highlighted as an outgoing edge
78       * of a node. The last variant gets shown when the edge gets highlighted 
79       * as an incoming edge.
80       * The type information of the currently painted will be stored in the 
81       * edgeType map. 
82       */
83      protected void paint(Graphics2D gfx, EdgeRealizer r, boolean sloppyMode)
84      {
85        Edge e = r.getEdge();
86        Color lineColor = r.getLineColor();
87        LineType lineType = r.getLineType();
88  
89        edgeType.set(e, Color.black);
90        super.paint(gfx, r, sloppyMode);  
91       
92        r.setLineColor(Color.red);
93        r.setLineType(LineType.LINE_3);
94        edgeType.set(e, Color.red);
95        super.paint(gfx, r, sloppyMode);
96        
97        
98        r.setLineColor(Color.green);
99        r.setLineType(LineType.LINE_3);
100       edgeType.set(e, Color.green);
101       super.paint(gfx, r, sloppyMode);
102 
103       r.setLineType(lineType);
104       r.setLineColor(lineColor);
105     }
106     
107     /**
108      * Mark each variant of the edge with a different group id.
109      */
110     protected String createGroupID(Edge e)
111     {
112       if(edgeType.get(e) == Color.green)
113       {
114         return "green.y.edge." + e.index();
115       }
116       else if(edgeType.get(e) == Color.red)
117       {
118         return "red.y.edge." + e.index();
119       }
120       else 
121       {
122         return "black.y.edge." + e.index();
123       }
124     }
125     
126     
127     /**
128      * Override a callback method. Add mouseover and mouseout events to
129      * the nodes of the graph. The events trigger the scripts for
130      * activating and deactivating the highlight effects.
131      */
132     protected void nodeAddedToDOM(Node yNode, org.w3c.dom.Element element)
133     {
134       element.setAttribute(
135         "onmouseover", 
136         "highlightEdges(evt,'" + yNode.index() + "')");
137       element.setAttribute(
138         "onmouseout", 
139         "lowlightEdges(evt,'" + yNode.index() + "')");
140     }
141     
142     /**
143      * Override a callback method. Sets the initial visibility state on the
144      * edges. Only the lowlighted edges will be visible in the beginning.
145      */
146     protected void edgeAddedToDOM(Edge yEdge, org.w3c.dom.Element element)
147     {
148       if(edgeType.get(yEdge) != Color.black)
149       {
150         element.setAttribute("visibility", "hidden");
151       }
152     }
153     
154     /**
155      * Creates a DOM element that defines an ecmascript function responsible
156      * for highlighting the adjacent edges. In the script we also
157      * add the static arrays inEdges and outEdges that tell us which
158      * edges belong to which nodes.
159      */
160     private org.w3c.dom.Element createScript()
161     {
162       org.w3c.dom.Element script = createElement("script");
163       script.setAttribute("type","text/ecmascript");
164       
165       Graph2D graph = view.getGraph2D();
166      
167       //construct inEdges and outEdges array. inEdges[i]  will contain 
168       //all incoming edges at the node with index i. outEdges[i] is similar.
169       StringBuffer varInEdges = new StringBuffer("var inEdges = [");
170       StringBuffer varOutEdges = new StringBuffer("var outEdges = [");
171       for(NodeCursor nc = graph.nodes(); nc.ok(); nc.next())
172       {
173         Node v = nc.node();
174         varInEdges.append("[");
175         String del = "";
176         for(EdgeCursor ec = v.inEdges(); ec.ok(); ec.next())
177         {
178           varInEdges.append(del).append(ec.edge().index());
179           del = ",";
180         }
181         varInEdges.append("]");
182         
183         varOutEdges.append("[");
184         del = "";
185         for(EdgeCursor ec = v.outEdges(); ec.ok(); ec.next())
186         {
187           varOutEdges.append(del).append(ec.edge().index());
188           del = ",";
189         }
190         varOutEdges.append("]");
191         
192         if(v.index() < graph.N()-1)
193         {
194           varInEdges.append(",");
195           varOutEdges.append(",");
196         }
197       }
198       varInEdges.append("];");
199       varOutEdges.append("];");
200 
201       // Javascript code that works with both Adobe SVG Viewer Plugin
202       // but also with native SVG support in modern browsers.
203       String highlightEdges =
204       "function highlightEdges(evt, nodeId) { \n" +
205         " var document = evt.target.ownerDocument; \n" +
206         " edgeIds = inEdges[nodeId]; \n" +
207         " for(i = 0; i < edgeIds.length; i++) { \n" +
208         "  var red   = document.getElementById('red.y.edge.' + edgeIds[i]); \n" +
209         "  var green = document.getElementById('green.y.edge.' + edgeIds[i]); \n" +
210         "  var black = document.getElementById('black.y.edge.' + edgeIds[i]); \n" +
211         "  red.setAttributeNS(null, 'style'," + "'visibility:visible'); \n" +
212         "  green.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
213         "  black.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
214         " } \n" +
215         " edgeIds = outEdges[nodeId]; \n" +
216         " for(i = 0; i < edgeIds.length; i++) { \n" +
217         "  var red   = document.getElementById('red.y.edge.' + edgeIds[i]); \n" +
218         "  var green = document.getElementById('green.y.edge.' + edgeIds[i]); \n" +
219         "  var black = document.getElementById('black.y.edge.' + edgeIds[i]); \n" +
220         "  red.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
221         "  green.setAttributeNS(null, 'style'," + "'visibility:visible'); \n" +
222         "  black.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
223         " } \n" +
224         "};";
225 
226       // Javascript code that works with both Adobe SVG Viewer Plugin
227       // but also with native SVG support in modern browsers.
228       String lowlightEdges =
229       "function lowlightEdges(evt, nodeId) { \n" +
230         " var document = evt.target.ownerDocument; \n" +
231         " edgeIds = inEdges[nodeId]; \n" +
232         " for(i = 0; i < edgeIds.length; i++) { \n" +
233         "  var red   = document.getElementById('red.y.edge.' + edgeIds[i]); \n" +
234         "  var green = document.getElementById('green.y.edge.' + edgeIds[i]); \n" +
235         "  var black = document.getElementById('black.y.edge.' + edgeIds[i]); \n" +
236         "  red.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
237         "  green.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
238         "  black.setAttributeNS(null, 'style'," + "'visibility:visible'); \n" +
239         " } \n" +
240         " edgeIds = outEdges[nodeId]; \n" +
241         " for(i = 0; i < edgeIds.length; i++) { \n" +
242         "  var red   = document.getElementById('red.y.edge.' + edgeIds[i]); \n" +
243         "  var green = document.getElementById('green.y.edge.' + edgeIds[i]); \n" +
244         "  var black = document.getElementById('black.y.edge.' + edgeIds[i]); \n" +
245         "  red.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
246         "  green.setAttributeNS(null, 'style'," + "'visibility:hidden'); \n" +
247         "  black.setAttributeNS(null, 'style'," + "'visibility:visible'); \n" +
248         " } \n" +
249         "};";
250 
251       script.appendChild(createCDATASection(
252         varInEdges + "\n" +
253         varOutEdges + "\n" +
254         highlightEdges + "\n" +
255         lowlightEdges
256         ));
257 
258       return script;
259     }
260   }
261 
262   /**
263    * Launches this demo.
264    * @param args ignored.
265    */
266   public static void main(String[] args) {
267     EventQueue.invokeLater(new Runnable() {
268       public void run() {
269         initLnF();
270         (new HighlightConnectionsDemo()).start();
271       }
272     });
273   }
274 }