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