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