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.EdgeMap;
21  import y.base.Node;
22  import y.util.Maps;
23  import y.view.EdgeRealizer;
24  import y.view.Graph2D;
25  import y.view.Graph2DView;
26  
27  import java.awt.EventQueue;
28  import java.awt.Graphics2D;
29  import java.awt.Point;
30  
31  /** 
32   * Demonstrates how to write SVG that shows rollover effects when the mouse
33   * is over nodes or edges of the graph. When the mouse is over a node the node will
34   * be drawn twice its original size. When the mouse is over an edge the edge
35   * will be drawn as if it were in a selected state.
36   */
37  public class RolloverDemo extends SVGExportDemo
38  {
39  
40    /**
41     * Creates and configures the SVGIOHandlers to be used.
42     * This method will add a specialized SVGDOMEnhancer to
43     * the IOHandler.
44     */
45    protected SVGIOHandler createSVGIOHandler(boolean svgz)
46    {
47      SVGIOHandler ioh = super.createSVGIOHandler(svgz);
48      SVGDOMEnhancer enhancer = new RolloverEnhancer();
49      //draw edges behind nodes so that the node rollover does not get spoiled.
50      enhancer.setDrawEdgesFirst(true); 
51      ioh.setSVGGraph2DRenderer(enhancer);
52      return ioh;
53    }
54    
55    /**
56     * A custom SVGDOMEnhancer. This class will do two thing to the SVG:
57     * First, it will add hyperlink statements around each node, node label, edge and
58     * edge label for which the user has given a URL, and second it will
59     * add code that scales the nodes on mouse over events by a factor of 2.
60     */
61    class RolloverEnhancer extends SVGDOMEnhancer
62    {
63      private double mouseOverScaleFactor = 1.25;
64      private EdgeMap highlightType;
65      double viewZoom;
66      Point viewPoint;
67      
68      /**
69       * Override a callback method. Before the graph will be written to the SVG DOM 
70       * we add an additional javascript node to the definition block of the SVG. 
71       * The script will be used to scale the nodes on mouseover events.
72       */ 
73      protected void initializeDOM()
74      {
75        Graph2DView activeView = getSVGIOHandler().getActiveGraph2DView();
76        Graph2D graph = activeView.getGraph2D();
77        viewZoom = activeView.getZoom();
78        viewPoint = activeView.getViewPoint();
79        
80        highlightType = Maps.createIndexEdgeMap(new boolean[graph.E()]);
81        addToSVGDefinition(createScript());
82      }
83      
84      protected void paint(Graphics2D gfx, EdgeRealizer r, boolean sloppyMode)
85      {
86        Edge e = r.getEdge();
87        boolean isSelected = r.isSelected();
88       
89        highlightType.setBool(e, true);
90        r.setSelected(true);
91        super.paint(gfx, r, sloppyMode);
92        
93        highlightType.setBool(e, false);
94        r.setSelected(false);
95        super.paint(gfx, r, sloppyMode);
96        
97        r.setSelected(isSelected);
98      }
99      
100     protected String createGroupID(Edge e)
101     {
102       if(highlightType.getBool(e))
103       {
104         return "y.edge." + e.index() + ".highlight";
105       }
106       else
107       {
108         return "y.edge." + e.index();
109       }
110     }
111         
112     /**
113      * Override a callback method. 
114      * Adds onmouseover and onmouseout attributes to the element that represents
115      * a given yNode in SVG. These attributes trigger the javascript function defined
116      * above.
117      */
118     protected void nodeAddedToDOM(Node yNode, org.w3c.dom.Element element)
119     {
120       Graph2D graph = (Graph2D)yNode.getGraph();
121       int x = (int)((graph.getCenterX(yNode) - viewPoint.x)*viewZoom);
122       int y = (int)((graph.getCenterY(yNode) - viewPoint.y)*viewZoom);
123       String id = element.getAttribute("id");
124       element.setAttribute(
125         "onmouseover", 
126         "scaleNode(evt,'" + id + "'," + x + "," + y + "," + mouseOverScaleFactor + ")");
127       element.setAttribute(
128         "onmouseout", 
129         "scaleNode(evt,'" + id + "'," + x + "," + y + ",1)");  
130     }
131     
132     /**
133      * Override a callback method. Hyperlink the given edge.
134      */
135     protected void edgeAddedToDOM(Edge yEdge, org.w3c.dom.Element element)
136     {
137       String id = "y.edge." + yEdge.index();
138       if(highlightType.getBool(yEdge))
139       {
140         element.setAttribute("style", "visibility:hidden");
141         element.setAttribute("onmouseover", "selectEdge(evt,'" + id + "')");
142         element.setAttribute("onmouseout", "deselectEdge(evt,'" + id + "')");
143       } 
144       else
145       {
146         element.setAttribute("style", "visibility:visible");
147         element.setAttribute("onmouseover", "selectEdge(evt,'" + id + "')");
148         element.setAttribute("onmouseout", "deselectEdge(evt,'" + id + "')");
149 
150       }
151     }
152     
153     ////////////////////////////////////////////////////////////
154     // stuff needed for the "scale node on mouse over" effect //
155     ////////////////////////////////////////////////////////////
156     
157     /**
158      * Creates a DOM element that defines a ecmascript functions responsible
159      * for scaling named DOM groups by a given factor.
160      * @return the ecmascript function definitions for scaling named DOM groups.
161      */
162     private org.w3c.dom.Element createScript()
163     {
164       org.w3c.dom.Element script = createElement("script");
165       script.setAttribute("type","text/ecmascript");
166       
167       // Javascript code that works with both Adobe SVG Viewer plugin
168       // but also with native SVG support in modern browsers.
169       String selectEdge =
170         "function selectEdge(evt, elementId) { \n" +
171         "var document = evt.target.ownerDocument; \n" +
172         "var element = document.getElementById(elementId); \n" +
173         "element.setAttributeNS(null, 'style', 'visibility:hidden'); \n" +
174         "element = document.getElementById(elementId + '.highlight'); \n" +
175         "element.setAttributeNS(null, 'style', 'visibility:visible'); \n" +
176         "}";
177 
178       String deselectEdge =
179         "function deselectEdge(evt, elementId) { \n" +
180         "var document = evt.target.ownerDocument; \n" +
181         "var element = document.getElementById(elementId); \n" +
182         "element.setAttributeNS(null, 'style', 'visibility:visible'); \n" +
183         "element = document.getElementById(elementId + '.highlight'); \n" +
184         "element.setAttributeNS(null, 'style', 'visibility:hidden'); \n" +
185         "}";
186 
187       String scaleNode =
188         "function scaleNode(evt, elementId, x, y, factor) { \n" +
189         "var document = evt.target.ownerDocument; \n" +
190         "var element = document.getElementById(elementId); \n" +
191         "var newtransform = \"translate(\" + x + \",\" + y + \") scale(\" + factor + \") translate(-\" + x + \",-\" + y + \")\"; \n" +
192         "element.setAttributeNS(null, 'transform', newtransform); \n" +
193         "}";
194       
195       script.appendChild(createCDATASection(
196         selectEdge + '\n' + 
197         deselectEdge + '\n' + 
198         scaleNode
199         ));
200       
201       return script;
202     }
203     
204   }
205 
206   /**
207    * Launches this demo.
208    * @param args ignored.
209    */
210   public static void main(String[] args) {
211     EventQueue.invokeLater(new Runnable() {
212       public void run() {
213         initLnF();
214         (new RolloverDemo()).start();
215       }
216     });
217   }
218 }