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 org.w3c.dom.Document;
18  import org.w3c.dom.Element;
19  import y.base.Node;
20  import y.view.NodeRealizer;
21  import y.view.ViewMode;
22  import yext.svg.io.SVGDOMEnhancer;
23  import yext.svg.io.SVGIOHandler;
24  
25  import javax.swing.JPanel;
26  import javax.swing.JToolTip;
27  import javax.swing.SwingUtilities;
28  import java.awt.Dimension;
29  import java.awt.Graphics2D;
30  import java.awt.geom.AffineTransform;
31  
32  /**
33   * Demo that shows how to add HTML formatted tooltips for nodes to a
34   * generated SVG file.
35   */
36  public class HtmlTooltipDemo extends SVGExportDemo
37  {
38  
39    /**
40     * Add a view mode that displays a tooltip for each node
41     */
42    public HtmlTooltipDemo() {
43      view.addViewMode(new TooltipViewMode());
44    }
45  
46    /**
47     * Creates and configures the SVGIOHandlers to be used.
48     * This method will add a specialized SVGDOMEnhancer to
49     * the IOHandler.
50     */
51    protected SVGIOHandler createSVGIOHandler(boolean svgz)
52    {
53      SVGIOHandler ioh = super.createSVGIOHandler(svgz);
54      SVGDOMEnhancer enhancer = new HtmlTooltipDemo.TooltipEnhancer();
55      //draw edges behind nodes so that the node rollover does not get spoiled.
56      enhancer.setDrawEdgesFirst(true);
57      ioh.setSVGGraph2DRenderer(enhancer);
58      ioh.setCanvasSizeAssigned(false); //do not assign canvas size to avoid tooltop clipping
59      return ioh;
60    }
61  
62    /**
63     * Creates the HTML formatted tooltip to be displayed for an object
64     */
65    String createHTMLDescription(Object obj) {
66      return "<html><head>" +
67      "<style><!--\n" +
68      ".tooltip {\n" +
69      "  font-size: 10pt;\n" +
70      "  position: absolute;\n" +
71      "  display: none;\n" +
72      "  background-color: #EDECF4;\n" +
73      "  border-width: 1px;\n" +
74      "  border-style: solid;\n" +
75      "  border-color: #E2860E; }\n" +
76      "\n" +
77      ".tooltip .head {\n" +
78      "  font-weight: bold;\n" +
79      "  background-color: #E2860E;\n" +
80      "  color: #EDECF4;\n" +
81      "  padding: 2px; }\n" +
82      "\n" +
83      ".tooltip .content {\n" +
84      "  color: #666666;\n" +
85      "  font-weight: bold;\n" +
86      "  padding: 4px; }\n" +
87      "--></style>\n" +
88      "</head>\n" +
89      "<div class=\"tooltip\">\n" +
90        "<div class=\"head\">Description</div>\n" +
91        "<div class=\"content\">Node " + obj + "</div>\n" +
92      "</div>";
93    }
94  
95    /**
96     * Viewmode that displays a HTML formatted tooltip for each node
97     */
98    class TooltipViewMode extends ViewMode {
99  
100     public void mouseMoved(double x, double y) {
101       Node hitNode = getHitInfo(x,y).getHitNode();
102       if(hitNode != null) {
103         String tipText = createHTMLDescription(hitNode);
104         if(tipText != null) {
105           view.setToolTipText(tipText);
106         }
107       }
108     }
109   }
110 
111   /**
112    * Specialized SVGDOMEnhancer that adds the necessary data and functionality to
113    * display tooltips from within an SVG file.
114    */
115   class TooltipEnhancer extends SVGDOMEnhancer
116   {
117     JPanel labelContainer = new JPanel();
118 
119     /**
120      * Override a callback method. Before the graph will be written to the SVG DOM
121      * we add an additional javascript node to the definition block of the SVG.
122      * The script will be used to show and hide tooltip elements
123      */
124     protected void initializeDOM()
125     {
126       addToSVGDefinition(createScript());
127     }
128 
129     /**
130      * Creates a DOM element that defines a ecmascript function responsible
131      * for showing and hiding appropriate tooltips at the right position
132      */
133     private Element createScript() {
134       Element script = createElement("script");
135       script.setAttribute("type", "text/ecmascript");
136 
137       String sourceCode =
138               "      var SVGDocument = null;\n" +
139               "      var SVGRoot = null;\n" +
140               "      var toolTip = null;\n" +
141               "      var TrueCoords = null;\n" +
142               "      var lastElement = null;\n" +
143               "      var initialized = null;\n" +
144               "      var tipGroup;\n" +
145               "      function Init(evt)\n" +
146               "      {\n" +
147               "         SVGDocument = evt.target.ownerDocument;\n" +
148               "         SVGRoot = SVGDocument.documentElement;\n" +
149               "         TrueCoords = SVGRoot.createSVGPoint();\n" +
150               "         initialized = evt;\n" +
151               "      };\n" +
152               "      function GetTrueCoords(evt)\n" +
153               "      {\n" +
154               "         var newScale = SVGRoot.currentScale;\n" +
155               "         var translation = SVGRoot.currentTranslate;\n" +
156               "         TrueCoords.x = (evt.clientX - translation.x)/newScale;\n" +
157               "         TrueCoords.y = (evt.clientY - translation.y)/newScale;\n" +
158               "      };\n" +
159               "      function HideTooltip( evt )\n" +
160               "      {\n" +
161               "         if(initialized == null) {\n" +
162               "           Init(evt);\n" +
163               "         }\n" +
164               "         if(tipGroup != null) {\n" +
165               "           tipGroup.setAttributeNS(null, 'visibility', 'hidden');\n" +
166               "         }\n" +
167               "      };\n" +
168               "      function ShowTooltip( evt )\n" +
169               "      {\n" +
170               "         if(initialized == null) {\n" +
171               "           Init(evt);\n" +
172               "         }\n" +
173               "         GetTrueCoords( evt );\n" +
174               "         var tipScale = 1/SVGRoot.currentScale;\n" +
175               "         var textWidth = 0;\n" +
176               "         var tspanWidth = 0;\n" +
177               "         var boxHeight = 20;\n" +
178               "         var targetElement = evt.currentTarget;\n" +
179               "         if ( lastElement != targetElement )\n" +
180               "         {\n" +
181               "            var targetId = targetElement.getAttributeNS(null, 'id');\n" +
182               "            var tipId = 'tooltip.' + targetId;\n" +
183               "            tipGroup = SVGDocument.getElementById(tipId);\n" +
184               "            var xPos = TrueCoords.x + (10 * tipScale);\n" +
185               "            var yPos = TrueCoords.y + (10 * tipScale);\n" +
186               "            tipGroup.setAttributeNS(null, 'transform', 'translate(' + xPos + ',' + yPos + ') scale(' + tipScale + ')');\n" +
187               "            tipGroup.setAttributeNS(null, 'visibility', 'visible');\n" +
188               "         }\n" +
189               "      };\n";
190 
191 
192       script.appendChild(createCDATASection(sourceCode));
193 
194       return script;
195     }
196 
197     protected void paint(Graphics2D gfx, NodeRealizer r, boolean sloppyMode) {
198       super.paint(gfx,r,sloppyMode);
199       paintDescription(gfx, r.getNode(), createGroupID(r.getNode()));
200     }
201 
202     /**
203      * Override a callback method.
204      * Adds onmouseover and onmouseout attributes to the element that represents
205      * a given yNode in SVG. These attributes trigger the javascript function defined
206      * above.
207      */
208     protected void nodeAddedToDOM(Node yNode, Element element) {
209       String desc = createHTMLDescription(yNode);
210       if(desc != null && !desc.equals("")) {
211         element.setAttribute(
212             "onmousemove",
213             "ShowTooltip(evt)");
214         element.setAttribute(
215             "onmouseout",
216             "HideTooltip(evt)");
217       }
218     }
219 
220     private void paintDescription(Graphics2D gfx, Object obj, String objectId) {
221       String desc = createHTMLDescription(obj);
222       if (desc != null && desc.trim().length() > 0) {
223         Document doc = getSVGDocument();
224         Element topLevelGroup = getTopLevelGroup();
225         Element tipGroup = doc.createElement("g");
226         tipGroup.setAttribute("visibility", "hidden");
227         tipGroup.setAttribute("pointer-events", "none");
228         tipGroup.setAttribute("id", "tooltip." + objectId);
229         topLevelGroup.appendChild(tipGroup);
230 
231         setTopLevelGroup(tipGroup);
232 
233         JToolTip label = new JToolTip();
234         label.setTipText(desc);
235         Dimension dim = label.getPreferredSize();
236         label.setSize(dim.width, dim.height);
237 
238         AffineTransform origTrans = gfx.getTransform();
239         gfx.setTransform(new AffineTransform());
240         SwingUtilities.paintComponent(gfx, label, labelContainer, 0, 0, dim.width, dim.height);
241         gfx.setTransform(origTrans);
242         setTopLevelGroup(topLevelGroup);
243       }
244     }
245   }
246 
247   /**
248    * Launches this demo.
249    */
250   public static void main(String args[])
251   {
252     initLnF();
253     HtmlTooltipDemo demo = new HtmlTooltipDemo();
254     demo.start();
255   }
256 
257 }
258