2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.awt.Graphics;
24 import java.awt.print.PrinterException;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.util.Locale;
29 import java.util.concurrent.Callable;
30 import java.util.concurrent.atomic.AtomicBoolean;
32 import org.jfree.graphics2d.svg.SVGGraphics2D;
33 import org.jfree.graphics2d.svg.SVGHints;
35 import jalview.bin.Cache;
36 import jalview.gui.AlignmentPanel;
37 import jalview.gui.LineartOptions;
38 import jalview.gui.OOMWarning;
39 import jalview.math.AlignmentDimension;
40 import jalview.util.MessageManager;
42 public class HtmlSvgOutput extends HTMLOutput
44 public HtmlSvgOutput(AlignmentPanel ap)
49 public int printUnwrapped(int pwidth, int pheight, int pi,
50 Graphics idGraphics, Graphics alignmentGraphics)
51 throws PrinterException
53 return ap.printUnwrapped(pwidth, pheight, pi, idGraphics,
57 public int printWrapped(int pwidth, int pheight, int pi, Graphics... pg)
58 throws PrinterException
60 return ap.printWrappedAlignment(pwidth, pheight, pi, pg[0]);
63 String getHtml(String titleSvg, String alignmentSvg, String jsonData,
66 StringBuilder htmlSvg = new StringBuilder();
67 htmlSvg.append("<html>\n");
71 "<button onclick=\"javascipt:openJalviewUsingCurrentUrl();\">Launch in Jalview</button> ");
73 "<input type=\"submit\" value=\"View raw BioJSON Data\" onclick=\"jQuery.facebox({ div:'#seqData' }); return false;\" />");
75 "<div style=\"display: none;\" name=\"seqData\" id=\"seqData\" >"
76 + jsonData + "</div>");
77 htmlSvg.append("<br/> ");
79 htmlSvg.append("\n<style type=\"text/css\"> "
80 + "div.parent{ width:100%;<!-- overflow: auto; -->}\n"
81 + "div.titlex{ width:11%; float: left; }\n"
82 + "div.align{ width:89%; float: right; }\n"
83 + "div.main-container{ border: 2px solid blue; border: 2px solid blue; width: 99%; min-height: 99%; }\n"
84 + ".sub-category-container {overflow-y: scroll; overflow-x: hidden; width: 100%; height: 100%;}\n"
85 + "object {pointer-events: none;}");
88 // facebox style sheet for displaying raw BioJSON data
90 "#facebox { position: absolute; top: 0; left: 0; z-index: 100; text-align: left; }\n"
91 + "#facebox .popup{ position:relative; border:3px solid rgba(0,0,0,0); -webkit-border-radius:5px;"
92 + "-moz-border-radius:5px; border-radius:5px; -webkit-box-shadow:0 0 18px rgba(0,0,0,0.4); -moz-box-shadow:0 0 18px rgba(0,0,0,0.4);"
93 + "box-shadow:0 0 18px rgba(0,0,0,0.4); }\n"
94 + "#facebox .content { display:table; width: 98%; padding: 10px; background: #fff; -webkit-border-radius:4px; -moz-border-radius:4px;"
95 + " border-radius:4px; }\n"
96 + "#facebox .content > p:first-child{ margin-top:0; }\n"
97 + "#facebox .content > p:last-child{ margin-bottom:0; }\n"
98 + "#facebox .close{ position:absolute; top:5px; right:5px; padding:2px; background:#fff; }\n"
99 + "#facebox .close img{ opacity:0.3; }\n"
100 + "#facebox .close:hover img{ opacity:1.0; }\n"
101 + "#facebox .loading { text-align: center; }\n"
102 + "#facebox .image { text-align: center;}\n"
103 + "#facebox img { border: 0; margin: 0; }\n"
104 + "#facebox_overlay { position: fixed; top: 0px; left: 0px; height:100%; width:100%; }\n"
105 + ".facebox_hide { z-index:-100; }\n"
106 + ".facebox_overlayBG { background-color: #000; z-index: 99; }");
108 htmlSvg.append("</style>");
111 htmlSvg.append("<div class=\"main-container\" \n>");
112 htmlSvg.append("<div class=\"titlex\">\n");
113 htmlSvg.append("<div class=\"sub-category-container\"> \n");
114 htmlSvg.append(titleSvg);
115 htmlSvg.append("</div>");
117 "</div>\n\n<!-- ========================================================================================== -->\n\n");
118 htmlSvg.append("<div class=\"align\" >");
120 "<div class=\"sub-category-container\"> <div style=\"overflow-x: scroll;\">")
121 .append(alignmentSvg).append("</div></div>").append("</div>");
122 htmlSvg.append("</div>");
125 "<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js\"></script>\n"
126 + "<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js\"></script>\n"
128 + "var subCatContainer = $(\".sub-category-container\");\n"
129 + "subCatContainer.scroll(\nfunction() {\n"
130 + "subCatContainer.scrollTop($(this).scrollTop());\n});\n");
132 htmlSvg.append("</script>\n");
136 htmlSvg.append("<div>\n").append(alignmentSvg).append("</div>");
138 "<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js\"></script>\n"
139 + "<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js\"></script>\n");
142 // javascript for launching file in Jalview
143 htmlSvg.append("<script language=\"JavaScript\">\n");
144 htmlSvg.append("function openJalviewUsingCurrentUrl(){\n");
146 " var json = JSON.parse(document.getElementById(\"seqData\").innerHTML);\n");
148 " var jalviewVersion = json['appSettings'].version;\n");
149 htmlSvg.append(" var url = json['appSettings'].webStartUrl;\n");
151 " var myForm = document.createElement(\"form\");\n\n");
152 htmlSvg.append(" var heap = document.createElement(\"input\");\n");
153 htmlSvg.append(" heap.setAttribute(\"name\", \"jvm-max-heap\") ;\n");
154 htmlSvg.append(" heap.setAttribute(\"value\", \"2G\");\n\n");
155 htmlSvg.append(" var target = document.createElement(\"input\");\n");
156 htmlSvg.append(" target.setAttribute(\"name\", \"open\");\n");
157 htmlSvg.append(" target.setAttribute(\"value\", document.URL);\n\n");
159 " var jvVersion = document.createElement(\"input\");\n");
160 htmlSvg.append(" jvVersion.setAttribute(\"name\", \"version\") ;\n");
162 " jvVersion.setAttribute(\"value\", jalviewVersion);\n\n");
163 htmlSvg.append(" myForm.action = url;\n");
164 htmlSvg.append(" myForm.appendChild(heap);\n");
165 htmlSvg.append(" myForm.appendChild(target);\n");
166 htmlSvg.append(" myForm.appendChild(jvVersion);\n");
167 htmlSvg.append(" document.body.appendChild(myForm);\n");
168 htmlSvg.append(" myForm.submit() ;\n");
169 htmlSvg.append(" document.body.removeChild(myForm);\n");
170 htmlSvg.append("}\n");
172 if (jsonData != null)
174 // JQuery FaceBox for displaying raw BioJSON data");
175 File faceBoxJsFile = new File("examples/javascript/facebox-1.3.js");
178 htmlSvg.append(HTMLOutput.readFileAsString(faceBoxJsFile));
179 } catch (IOException e)
185 htmlSvg.append("</script>\n");
186 htmlSvg.append("</html>");
187 return htmlSvg.toString();
191 public boolean isEmbedData()
194 .valueOf(Cache.getDefault("EXPORT_EMBBED_BIOJSON", "true"));
198 public boolean isLaunchInBrowserAfterExport()
210 public void run(String renderer)
214 String renderStyle = renderer == null
215 ? Cache.getDefault("HTML_RENDERING",
216 LineartOptions.PROMPT_EACH_TIME)
218 AtomicBoolean textOption = new AtomicBoolean(
219 !"lineart".equals(renderStyle.toLowerCase(Locale.ROOT)));
222 * configure the action to run on OK in the dialog
224 Callable<Void> okAction = () -> {
225 doOutput(textOption.get());
230 * Prompt for character rendering style if preference is not set
232 if (renderStyle.equalsIgnoreCase(LineartOptions.PROMPT_EACH_TIME)
235 LineartOptions svgOption = new LineartOptions("HTML", textOption);
236 svgOption.setResponseAction(1, () -> {
237 setProgressMessage(MessageManager.formatMessage(
238 "status.cancelled_image_export_operation",
242 svgOption.setResponseAction(0, okAction);
243 svgOption.showDialog();
244 /* no code here - JalviewJS cannot execute it */
249 * else (if preference set) just do the export action
251 doOutput(textOption.get());
253 } catch (OutOfMemoryError err)
255 System.out.println("########################\n" + "OUT OF MEMORY "
256 + generatedFile + "\n" + "########################");
257 new OOMWarning("Creating Image for " + generatedFile, err);
258 } catch (Exception e)
261 setProgressMessage(MessageManager
262 .formatMessage("info.error_creating_file", getDescription()));
267 * Builds and writes the image to the file specified by field
268 * <code>generatedFile</code>
270 * @param textCharacters
271 * true for Text character rendering, false for Lineart
273 protected void doOutput(boolean textCharacters)
277 AlignmentDimension aDimension = ap.getAlignmentDimension();
278 SVGGraphics2D idPanelGraphics = new SVGGraphics2D(
279 aDimension.getWidth(), aDimension.getHeight());
280 SVGGraphics2D alignPanelGraphics = new SVGGraphics2D(
281 aDimension.getWidth(), aDimension.getHeight());
282 if (!textCharacters) // Lineart selected
284 idPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
285 SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
286 alignPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
287 SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
289 if (ap.av.getWrapAlignment())
291 printWrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
296 printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
297 idPanelGraphics, alignPanelGraphics);
300 String idPanelSvgData = idPanelGraphics.getSVGDocument();
301 String alignPanelSvgData = alignPanelGraphics.getSVGDocument();
302 String jsonData = getBioJSONData();
303 String htmlData = getHtml(idPanelSvgData, alignPanelSvgData, jsonData,
304 ap.av.getWrapAlignment());
305 FileOutputStream out = new FileOutputStream(generatedFile);
306 out.write(htmlData.getBytes());
309 setProgressMessage(MessageManager
310 .formatMessage("status.export_complete", getDescription()));
312 } catch (Exception e)
315 setProgressMessage(MessageManager
316 .formatMessage("info.error_creating_file", getDescription()));