001/* Attribute for generating the HTML file with JavaScript to plot simulation 002 results. This base class cannot be instanced. 003 004 Copyright (c) 2012-2014 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029 030package ptolemy.vergil.basic.export.web; 031 032import java.util.HashMap; 033 034import ptolemy.data.BooleanToken; 035import ptolemy.data.IntToken; 036import ptolemy.data.expr.Parameter; 037import ptolemy.data.expr.StringParameter; 038import ptolemy.data.type.BaseType; 039import ptolemy.kernel.util.IllegalActionException; 040import ptolemy.kernel.util.NameDuplicationException; 041import ptolemy.kernel.util.NamedObj; 042 043/////////////////////////////////////////////////////////////////// 044////BasicJSPlotter 045/** 046 * Base class for attributes generating the HTML file with JavaScript to plot 047 * simulation results for "Export to Web". This class provides parameters that 048 * control how the figure should be plot. The generated HTML page consists of 049 * three parts: the head, the body and the JavaScript in the head. Methods are 050 * provided to modify the contents of these parts. 051 * 052 * @author Baobing (Brian) Wang 053 * @version $Id$ 054 * @since Ptolemy II 10.0 055 * @Pt.ProposedRating Red (cxh) 056 * @Pt.AcceptedRating Red (cxh) 057 */ 058public abstract class JSPlotterAttribute extends WebContent 059 implements WebExportable { 060 061 /** Create an instance for each parameter. 062 * @param container The container. 063 * @param name The name. 064 * @exception IllegalActionException If the superclass throws it. 065 * @exception NameDuplicationException If the superclass throws it. 066 */ 067 public JSPlotterAttribute(NamedObj container, String name) 068 throws IllegalActionException, NameDuplicationException { 069 super(container, name); 070 _icon.setIconText("JS"); 071 displayText.setDisplayName("Graph title"); 072 displayText.setExpression("Ptolemy II Simulation Result"); 073 setExpression("Customize by clicking \"Configure\""); 074 setVisibility(NOT_EDITABLE); 075 076 width.setVisibility(NONE); 077 height.setExpression("1"); 078 height.setVisibility(NONE); 079 080 outputHTMLFile = new StringParameter(this, "outputHTMLFile"); 081 outputHTMLFile.setDisplayName("Output HTML file name"); 082 outputHTMLFile.setExpression("JSPlotter.html"); 083 084 linkTarget = new LinkTarget(this, "linkTarget"); 085 linkTarget.setDisplayName("The location to open the HTML page"); 086 linkTarget.setExpression("_blank"); 087 088 dataJSON = new StringParameter(this, "dataJSON"); 089 dataJSON.setDisplayName("Input data series in JSON format"); 090 091 eventsJSON = new StringParameter(this, "eventsJSON"); 092 eventsJSON.setDisplayName("Input event series in JSON format"); 093 094 saveDataToFile = new Parameter(this, "saveDataToFile"); 095 saveDataToFile.setDisplayName( 096 "Save data and event series to a " + "separate file"); 097 saveDataToFile.setExpression("false"); 098 saveDataToFile.setTypeEquals(BaseType.BOOLEAN); 099 100 outputDataFile = new StringParameter(this, "outputDataFile"); 101 outputDataFile.setDisplayName("Output data file name"); 102 outputDataFile.setExpression("simulationResult.txt"); 103 104 graphWidth = new Parameter(this, "graphWidth"); 105 graphWidth.setTypeEquals(BaseType.INT); 106 graphWidth.setDisplayName("Graph min width"); 107 graphWidth.setExpression("400"); 108 109 graphHeight = new Parameter(this, "graphHeight"); 110 graphHeight.setTypeEquals(BaseType.INT); 111 graphHeight.setDisplayName("Graph min height"); 112 graphHeight.setExpression("500"); 113 114 autoResize = new Parameter(this, "autoResize"); 115 autoResize.setDisplayName("Auto-resize the graph"); 116 autoResize.setExpression("true"); 117 autoResize.setTypeEquals(BaseType.BOOLEAN); 118 119 enableLegend = new Parameter(this, "enableLegend"); 120 enableLegend.setDisplayName("Show Legend"); 121 enableLegend.setExpression("true"); 122 enableLegend.setTypeEquals(BaseType.BOOLEAN); 123 124 horizontalAlign = new StringParameter(this, "horizontalAlign"); 125 horizontalAlign.setDisplayName("Legend horizontal align"); 126 horizontalAlign.addChoice("center"); 127 horizontalAlign.addChoice("left"); 128 horizontalAlign.addChoice("right"); 129 horizontalAlign.setExpression("center"); 130 131 verticalAlign = new StringParameter(this, "verticalAlign"); 132 verticalAlign.setDisplayName("Legend vertical align"); 133 verticalAlign.addChoice("top"); 134 verticalAlign.addChoice("middle"); 135 verticalAlign.addChoice("bottom"); 136 verticalAlign.setExpression("bottom"); 137 138 dataConnectWidth = new Parameter(this, "dataConnectWidth"); 139 dataConnectWidth.setDisplayName("Data series connect line width"); 140 dataConnectWidth.setExpression("2"); 141 dataConnectWidth.setTypeEquals(BaseType.INT); 142 143 enableDataMarker = new Parameter(this, "enableDataMarker"); 144 enableDataMarker.setDisplayName("Enable data series point marker"); 145 enableDataMarker.setExpression("false"); 146 enableDataMarker.setTypeEquals(BaseType.BOOLEAN); 147 148 dataMarkerRadius = new Parameter(this, "dataMarkerRadius"); 149 dataMarkerRadius.setDisplayName("Data series marker radius"); 150 dataMarkerRadius.setExpression("3"); 151 dataMarkerRadius.setTypeEquals(BaseType.INT); 152 153 eventsConnectWidth = new Parameter(this, "eventsConnectWidth"); 154 eventsConnectWidth.setDisplayName("Event series connect line width"); 155 eventsConnectWidth.setExpression("0"); 156 eventsConnectWidth.setTypeEquals(BaseType.INT); 157 158 enableEventsMarker = new Parameter(this, "enableEventsMarker"); 159 enableEventsMarker.setDisplayName("Enable event series point marker"); 160 enableEventsMarker.setExpression("true"); 161 enableEventsMarker.setTypeEquals(BaseType.BOOLEAN); 162 163 eventsMarkerRadius = new Parameter(this, "eventsMarkerRadius"); 164 eventsMarkerRadius.setDisplayName("Event series marker radius"); 165 eventsMarkerRadius.setExpression("3"); 166 eventsMarkerRadius.setTypeEquals(BaseType.INT); 167 168 xAxisMode = new StringParameter(this, "xAxisMode"); 169 xAxisMode.setDisplayName("X axis type"); 170 xAxisMode.addChoice("linear"); 171 xAxisMode.addChoice("datetime"); 172 xAxisMode.setExpression("linear"); 173 174 drawVerticalGridLine = new Parameter(this, "drawVerticalGridLine"); 175 drawVerticalGridLine.setDisplayName("Draw vertical grid line"); 176 drawVerticalGridLine.setExpression("false"); 177 drawVerticalGridLine.setTypeEquals(BaseType.BOOLEAN); 178 179 xAxisTitle = new StringParameter(this, "xAxisTitle"); 180 xAxisTitle.setDisplayName("X axis title"); 181 xAxisTitle.setExpression("X Axis"); 182 183 yAxisMode = new StringParameter(this, "yAxisMode"); 184 yAxisMode.setDisplayName("Y axis type"); 185 yAxisMode.addChoice("linear"); 186 yAxisMode.addChoice("logarithmic"); 187 yAxisMode.setExpression("linear"); 188 189 drawHorizontalGridLine = new Parameter(this, "drawHorizontalGridLine"); 190 drawHorizontalGridLine.setDisplayName("Draw horizontal grid line"); 191 drawHorizontalGridLine.setExpression("true"); 192 drawHorizontalGridLine.setTypeEquals(BaseType.BOOLEAN); 193 194 yAxisTitle = new StringParameter(this, "yAxisTitle"); 195 yAxisTitle.setDisplayName("Y axis title"); 196 yAxisTitle.setExpression("Y Axis"); 197 198 customContent = new StringParameter(this, "customContent"); 199 customContent.setDisplayName("Custom content"); 200 customContent.setExpression(""); 201 } 202 203 /////////////////////////////////////////////////////////////////// 204 //// parameters //// 205 206 /** Parameter specifying if the figure should be auto-resized based on the 207 * window size. This is a boolean that defaults to true. 208 */ 209 public Parameter autoResize; 210 211 /** Parameter specifying text to be inserted into dygraph constructor call. 212 * Workaround for specifying complicated options not covered by other 213 * parameters, for example, series-specific parameters. 214 */ 215 public StringParameter customContent; 216 217 /** Parameter specifying the width of the stroke connecting data points 218 * This is an int that defaults to 2. 219 */ 220 public Parameter dataConnectWidth; 221 222 /** Parameter giving the data traces in JSON format to be plot. 223 * This defaults to "" 224 */ 225 public StringParameter dataJSON; 226 227 /** Parameter specifying if the horizontal grid line should be drawn. 228 * This is a boolean that defaults to true. 229 */ 230 public Parameter drawHorizontalGridLine; 231 232 /** Parameter specifying the radius of markers for data points. 233 * This is an int that defaults to 3. 234 */ 235 public Parameter dataMarkerRadius; 236 237 /** Parameter specifying if the vertical grid line should be drawn. 238 * This is a boolean that defaults to false. 239 */ 240 public Parameter drawVerticalGridLine; 241 242 /** Parameter specifying if markers should be drawn for data points. 243 * This is a boolean that defaults to false. 244 */ 245 public Parameter enableDataMarker; 246 247 /** Parameter specifying if markers should be drawn for event points. 248 * This is a boolean that defaults to true. 249 */ 250 public Parameter enableEventsMarker; 251 252 /** Parameter specifying if the legend should be shown on the figure. 253 * This a boolean that defaults to true. 254 */ 255 public Parameter enableLegend; 256 257 /** Parameter specifying the width of the stroke connecting event points 258 * This is an int that defaults to 0. 259 */ 260 public Parameter eventsConnectWidth; 261 262 /** Parameter specifying the radius of markers for event points. 263 * This is an int that defaults to 3. 264 */ 265 public Parameter eventsMarkerRadius; 266 267 /** Parameter giving the event traces in JSON format to be plot. 268 * This defaults to "" 269 */ 270 public StringParameter eventsJSON; 271 272 /** Parameter specifying the width of the figure. 273 * This is an int that defaults to 400px. 274 */ 275 public Parameter graphWidth; 276 277 /** Parameter specifying the height of the figure. 278 * This is an int that defaults to 500px. 279 */ 280 public Parameter graphHeight; 281 282 /** Parameter specifying the horizontal position of the legend on the figure. 283 * This defaults to "center". 284 */ 285 public StringParameter horizontalAlign; 286 287 /** Parameter specifying the target for the link. 288 * The possibilities are: 289 * <ul> 290 * <li><b>_lightbox</b>: Open in a lightbox-style popup frame. 291 * <li><b>_blank</b>: Open in a new window or tab. 292 * <li><b>_self</b>: Open in the same frame as it was clicked. 293 * <li><b>_parent</b>: Open in the parent frameset. 294 * <li><b>_top</b>: Open in the full body of the window. 295 * <li><b><i>framename</i></b>: Open in a named frame. 296 * </ul> 297 * The default is "_lightbox". 298 */ 299 public LinkTarget linkTarget; 300 301 /** Parameter specifying the name of the file to store the data and event traces. 302 * This defaults to "simulationResult.txt". 303 */ 304 public StringParameter outputDataFile; 305 306 /** Parameter specifying the name of the generated HTML file. 307 * This defaults to "JSPlotter.html". 308 */ 309 public StringParameter outputHTMLFile; 310 311 /** Parameter specifying if the data and event traces should be saved in a 312 * separated file. This is a boolean that defaults to false. 313 */ 314 public Parameter saveDataToFile; 315 316 /** Parameter specifying the vertical position of the legend on the figure. 317 * This defaults to "bottom". 318 */ 319 public StringParameter verticalAlign; 320 321 /** Parameter specifying how to parse the X axis value. 322 * This defaults to "linear". 323 */ 324 public StringParameter xAxisMode; 325 326 /** Parameter specifying the title of the X axis. 327 * This defaults to "X Axis". 328 */ 329 public StringParameter xAxisTitle; 330 331 /** Parameter specifying how to parse the Y axis value. 332 * This defaults to "linear". 333 */ 334 public StringParameter yAxisMode; 335 336 /** Parameter specifying the title of the Y axis. 337 * This defaults to "Y Axis". 338 */ 339 public StringParameter yAxisTitle; 340 341 /////////////////////////////////////////////////////////////////// 342 //// public methods //// 343 344 /** BasicJSPlotter is of type text/html. 345 * @return The string "text/html" 346 */ 347 @Override 348 public String getMimeType() { 349 return "text/html"; 350 } 351 352 /** Return true, since new content should overwrite old. 353 * @return true, since new content should overwrite old 354 */ 355 @Override 356 public boolean isOverwriteable() { 357 return true; 358 } 359 360 /** Get the parameter values from the GUI input. 361 * @return The hash map containing the values of all parameters 362 * @exception IllegalActionException 363 */ 364 public HashMap<String, String> getBasicConfig() 365 throws IllegalActionException { 366 _config.put("outputHTMLFile", outputHTMLFile.stringValue().trim()); 367 _config.put("dataJSON", dataJSON.stringValue().trim()); 368 _config.put("eventsJSON", eventsJSON.stringValue().trim()); 369 _config.put("saveDataToFile", 370 ((BooleanToken) saveDataToFile.getToken()).toString().trim()); 371 _config.put("outputDataFile", outputDataFile.stringValue().trim()); 372 373 _config.put("graphTitle", displayText.stringValue().trim()); 374 _config.put("graphWidth", 375 ((IntToken) graphWidth.getToken()).toString().trim()); 376 _config.put("graphHeight", 377 ((IntToken) graphHeight.getToken()).toString().trim()); 378 _config.put("autoResize", 379 ((BooleanToken) autoResize.getToken()).toString().trim()); 380 381 _config.put("enableLegend", 382 ((BooleanToken) enableLegend.getToken()).toString().trim()); 383 _config.put("horizontalAlign", horizontalAlign.stringValue().trim()); 384 _config.put("verticalAlign", verticalAlign.stringValue().trim()); 385 386 _config.put("dataConnectWidth", 387 ((IntToken) dataConnectWidth.getToken()).toString().trim()); 388 _config.put("enableDataMarker", 389 ((BooleanToken) enableDataMarker.getToken()).toString().trim()); 390 _config.put("dataMarkerRadius", 391 ((IntToken) dataMarkerRadius.getToken()).toString().trim()); 392 393 _config.put("eventsConnectWidth", 394 ((IntToken) eventsConnectWidth.getToken()).toString().trim()); 395 _config.put("enableEventsMarker", 396 ((BooleanToken) enableEventsMarker.getToken()).toString() 397 .trim()); 398 _config.put("eventsMarkerRadius", 399 ((IntToken) eventsMarkerRadius.getToken()).toString().trim()); 400 401 _config.put("xAxisMode", xAxisMode.stringValue().trim()); 402 _config.put("drawVerticalGridLine", 403 ((BooleanToken) drawVerticalGridLine.getToken()).toString() 404 .trim()); 405 _config.put("xAxisTitle", xAxisTitle.stringValue().trim()); 406 407 _config.put("yAxisMode", yAxisMode.stringValue().trim()); 408 _config.put("drawHorizontalGridLine", 409 ((BooleanToken) drawHorizontalGridLine.getToken()).toString() 410 .trim()); 411 _config.put("yAxisTitle", yAxisTitle.stringValue().trim()); 412 return _config; 413 } 414 415 /** Get the body content. 416 * @return The string containing the body content 417 */ 418 public String getBodyContent() { 419 return _bodyContent.toString(); 420 } 421 422 /** Get the head content. 423 * @return The string containing the head content 424 */ 425 public String getHeaderContent() { 426 _headerContent.append("\t\t<script>\n"); 427 _headerContent.append(_scriptContent.toString()); 428 _headerContent.append("\t\t</script>\n"); 429 return _headerContent.toString(); 430 } 431 432 /** Get the content of the whole HTML page. 433 * @return The string containing the content of the whole HTML page 434 */ 435 public String getHTMLPageContent() { 436 StringBuffer pageContent = new StringBuffer(); 437 pageContent.append( 438 "<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\">\n"); 439 pageContent.append(getHeaderContent()); 440 pageContent.append("\t</head>\n\n\t<body>\n"); 441 pageContent.append(getBodyContent()); 442 pageContent.append("\t</body>\n</html>"); 443 return pageContent.toString(); 444 } 445 446 /** Insert a string to the body with auto-indent. 447 * @param content The content to be inserted 448 */ 449 public void insertBodyContent(String content) { 450 _bodyContent.append("\t\t" + content); 451 } 452 453 /** Insert a string to the header with auto-indent. 454 * @param isJavaScript Whether the inserted content is JavaScript code 455 * @param autoIndent Whether the content should be auto-indented 456 * @param content the content to be inserted 457 */ 458 public void insertHeaderContent(boolean isJavaScript, boolean autoIndent, 459 String content) { 460 if (isJavaScript && autoIndent) { 461 _scriptContent.append("\t\t\t" + content); 462 } else if (!isJavaScript & autoIndent) { 463 _headerContent.append("\t\t" + content); 464 } else if (isJavaScript && !autoIndent) { 465 _scriptContent.append(content); 466 } else { 467 _headerContent.append(content); 468 } 469 } 470 471 /////////////////////////////////////////////////////////////////// 472 //// protected methods //// 473 474 /** Provide content to the specified web exporter to be 475 * included in a web page for the container of this object. 476 * This class defines an href attribute to associate with 477 * the area of the image map corresponding to its container. 478 * 479 * @param exporter The web exporter to write content to 480 * @exception IllegalActionException If evaluating the value 481 * of this parameter fails, or creating a web attribute fails. 482 */ 483 @Override 484 protected void _provideAttributes(WebExporter exporter) 485 throws IllegalActionException { 486 WebAttribute webAttribute; 487 NamedObj container = getContainer(); 488 _config = new HashMap<String, String>(); 489 _scriptContent = new StringBuffer(); 490 _headerContent = new StringBuffer(); 491 _bodyContent = new StringBuffer(); 492 493 if (container != null) { 494 // Last argument specifies to overwrite any previous value defined. 495 if (!outputHTMLFile.stringValue().trim().equals("")) { 496 // Create link attribute and add to exporter. 497 // Content should only be added once (onceOnly -> true). 498 webAttribute = WebAttribute.createWebAttribute(container, 499 "hrefWebAttribute", "href"); 500 webAttribute.setExpression(outputHTMLFile.stringValue()); 501 exporter.defineAttribute(webAttribute, true); 502 } 503 504 String targetValue = linkTarget.stringValue(); 505 if (!targetValue.trim().equals("")) { 506 if (targetValue.equals("_lightbox")) { 507 // Strangely, the class has to be "iframe". 508 // I don't understand why it can't be "lightbox". 509 510 // Create class attribute and add to exporter. 511 // Content should only be added once (onceOnly -> true). 512 webAttribute = WebAttribute.appendToWebAttribute(container, 513 "classWebAttribute", "class", "iframe"); 514 exporter.defineAttribute(webAttribute, true); 515 } else { 516 517 // Create target attribute and add to exporter. 518 // Content should only be added once (onceOnly -> true). 519 webAttribute = WebAttribute.createWebAttribute( 520 getContainer(), "targetWebAttribute", "target"); 521 webAttribute.setExpression(targetValue); 522 exporter.defineAttribute(webAttribute, true); 523 } 524 } 525 } 526 } 527 528 /////////////////////////////////////////////////////////////////// 529 //// private variables //// 530 531 // String buffer storing the body content 532 private StringBuffer _bodyContent; 533 534 // HashMap storing the values of all parameters 535 private HashMap<String, String> _config; 536 537 // String buff storing the head content 538 private StringBuffer _headerContent; 539 540 // String buffer storing the JavaScript content in the head 541 private StringBuffer _scriptContent; 542}