1/*------------------------------------------------------------------------------------------------------------------------------------ 2 GNUPLOT - svg.trm 3 4 This file is included by ../term.c. 5 6 This terminal driver supports: 7 W3C Scalable Vector Graphics 8 9 AUTHOR 10 11 Amedeo Farello 12 afarello@libero.it 13 14 HEAVILY MODIFIED by 15 16 Hans-Bernhard Br"oker 17 broeker@physik.rwth-aachen.de 18 19 DomTerm support 20 21 Per Bothner <per@bothner.com> 22 23------------------------------------------------------------------------------------------------------------------------------------*/ 24 25/* PM3D support by Johannes Zellner <johannes@zellner.org>, May-16-2002 */ 26/* set_color fixes by Petr Mikulik <mikulik@physics.muni.cz>, June-10-2002 */ 27/* ISO-Latin encoding, Font selection fixes, option "fixed|dynamic" by 28 * Wilhelm Braunschober <Wilhelm.Braunschober@t-online.de>, Feb-21-2002 */ 29 30/* 31 * Additional code for gnuplot versions 4.2 and 4.3 32 * Ethan Merritt <merritt@u.washington.edu> 33 * 34 * Tweaked code for compatibility with Sodipodi svg viewer/editor. 35 * Added enhanced text support. 36 * Additional line properties. 37 * Increase resolution by adding a coordinate scale factor. 38 * Support dashed lines, TC_* color model. 39 * Change path markup from style='attribute: foo' to attribute='foo' 40 * 41 * Additional code for gnuplot versions 4.5 42 * Ethan Merritt <merritt@u.washington.edu> 43 * 44 * Wrap each plot in a named group <g id="name_plot_%02d"> 45 * Set the name using 'set term svg name "foo"' 46 * Background option 47 * Bitmap image support by creating and linking to external png files 48 * Mouse-tracking with coordinate readout. 49 * Version 4.7 (April 2012) hypertext support 50 * 51 * Contributed by <plotter@piments.com> 52 * Javascript code to toggle plots on/off 53 * 54 * Revised font sizing Oct 2012 55 * specify font-size without "pt" units. 56 * 57 * Inline image data in Base64 encoding 58 * Daniel Sebald May 2016 59 * 60 * Transition to SVG 2.0 61 * remove DTD 62 * remove option "fontfile" and references to SVG fonts 63 */ 64 65/* 66 * Code for gnuplot version 4.5 67 * Bold -> font-weight:bold 68 * Italic -> font-style:italic 69 * Trying to match well with PNG output. 70 * Rich Seymour <rseymour@usc.edu> 71 */ 72 73#include "driver.h" 74 75#ifdef TERM_REGISTER 76register_term(svg) 77#endif 78 79#ifdef TERM_PROTO 80TERM_PUBLIC void SVG_options __PROTO ((void)); 81TERM_PUBLIC void SVG_init __PROTO ((void)); 82TERM_PUBLIC void SVG_graphics __PROTO ((void)); 83TERM_PUBLIC void SVG_text __PROTO ((void)); 84TERM_PUBLIC void SVG_linetype __PROTO ((int linetype)); 85TERM_PUBLIC void SVG_dashtype __PROTO ((int type, t_dashtype *custom_dash_type)); 86TERM_PUBLIC void SVG_move __PROTO ((unsigned int x, unsigned int y)); 87TERM_PUBLIC void SVG_vector __PROTO ((unsigned int x, unsigned int y)); 88TERM_PUBLIC void SVG_put_text __PROTO ((unsigned int x, unsigned int y, const char *str)); 89TERM_PUBLIC void SVG_reset __PROTO ((void)); 90TERM_PUBLIC int SVG_justify_text __PROTO ((enum JUSTIFY mode)); 91TERM_PUBLIC int SVG_text_angle __PROTO ((int ang)); 92TERM_PUBLIC void SVG_point __PROTO ((unsigned int x, unsigned int y, int pointstyle)); 93TERM_PUBLIC int SVG_set_font __PROTO ((const char *font)); 94/* TERM_PUBLIC void SVG_pointsize __PROTO((double pointsize)); */ 95TERM_PUBLIC void SVG_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)); 96TERM_PUBLIC void SVG_linewidth __PROTO ((double linewidth)); 97TERM_PUBLIC int SVG_make_palette __PROTO((t_sm_palette *)); 98TERM_PUBLIC void SVG_previous_palette __PROTO((void)); 99TERM_PUBLIC void SVG_set_color __PROTO((t_colorspec *)); 100TERM_PUBLIC void SVG_filled_polygon __PROTO((int, gpiPoint *)); 101TERM_PUBLIC void SVG_layer __PROTO((t_termlayer syncpoint)); 102 103TERM_PUBLIC void ENHsvg_OPEN __PROTO((char *, double, double, TBOOLEAN, TBOOLEAN, int)); 104TERM_PUBLIC void ENHsvg_FLUSH __PROTO((void)); 105TERM_PUBLIC void ENHsvg_put_text __PROTO((unsigned int, unsigned int, const char *)); 106TERM_PUBLIC void ENHsvg_writec __PROTO((int)); 107 108TERM_PUBLIC void SVG_path __PROTO((int p)); 109TERM_PUBLIC void SVG_hypertext __PROTO((int, const char *)); 110 111#ifdef WRITE_PNG_IMAGE 112TERM_PUBLIC void SVG_image __PROTO((unsigned m, unsigned n, coordval *image, gpiPoint *corner, t_imagecolor color_mode)); 113#endif 114 115#define SVG_SCALE 10. /* Coordinates accuracy is 1/SVG_SCALE pixel */ 116#define PREC 1 /* Decimal places needed for SVG_SCALEd values */ 117#define Y(y) ((float)((int)term->ymax - (int)y) / SVG_SCALE) 118#define X(x) ((float)(x) / SVG_SCALE) 119 120#define SVG_XMAX (600 * SVG_SCALE) 121#define SVG_YMAX (480 * SVG_SCALE) 122 123#endif /* TERM_PROTO */ 124 125#ifndef TERM_PROTO_ONLY 126#ifdef TERM_BODY 127 128static t_sm_palette SVG_palette; 129static unsigned char SVG_red = 0; 130static unsigned char SVG_green = 0; 131static unsigned char SVG_blue = 0; 132static double SVG_alpha = 0.0; 133static unsigned char SVG_color_mode = TC_DEFAULT; 134static char *SVG_linecolor = NULL; 135static char *SVG_name = NULL; 136static char *SVG_scriptdir = NULL; 137static TBOOLEAN SVG_mouseable = FALSE; 138static TBOOLEAN SVG_standalone = FALSE; 139static TBOOLEAN SVG_domterm = FALSE; 140static TBOOLEAN SVG_emit_doctype = TRUE; 141 142static TBOOLEAN SVG_groupFilledIsOpen = FALSE; /* open pm3d group flag*/ 143static TBOOLEAN SVG_inTextBox = FALSE; 144 145struct SVG_PEN 146{ 147 double width; 148 char color[8]; 149}; 150 151static unsigned int SVG_xSize = SVG_XMAX; /* plot horizontal size */ 152static unsigned int SVG_ySize = SVG_YMAX; /* plot vertical size*/ 153static TBOOLEAN SVG_fixed_size = TRUE; /* make SVG viewer size fixed */ 154 155static unsigned int SVG_xLast = UINT_MAX; /* current pen horizontal position*/ 156static unsigned int SVG_yLast = UINT_MAX; /* current pen vertical position*/ 157 158static int SVG_LineType = LT_NODRAW; /* current line type*/ 159static double SVG_LineWidth = 1.0; /* current line width*/ 160static double SVG_linewidth_factor = 1.0; /* Multiplier for linewidths */ 161static double SVG_dashlength = 1.0; /* Multiplier for dash patterns */ 162static t_linecap SVG_linecap = BUTT; /* linejoin and linecap */ 163static int SVG_TextAngle = 0; /* current text orientation*/ 164static enum JUSTIFY SVG_TextJust = LEFT; /* current text justification*/ 165 166/* default text font family: */ 167static char *SVG_fontNameDef = NULL; 168static char *SVG_fontStyleDef = NULL; /* default font style */ 169static char *SVG_fontWeightDef = NULL; /* default font weight */ 170static double SVG_fontSizeDef = 12; /* default text size*/ 171/* current text font family: */ 172static char *SVG_fontNameCur = NULL; 173static char *SVG_fontStyleCur = NULL; /* current font style */ 174static char *SVG_fontWeightCur = NULL; /* current font weight */ 175static double SVG_fontSizeCur = 12; /* current text size*/ 176static double SVG_fontscale = 1.0; /* multiplier for nominal font size */ 177static TBOOLEAN SVG_groupIsOpen = FALSE; /* open group flag*/ 178static TBOOLEAN SVG_pathIsOpen = FALSE; /* open path flag*/ 179static unsigned int SVG_path_count = 0; /* size of current path*/ 180static struct SVG_PEN SVG_pens[16]; /* pen descriptors*/ 181 182static int SVG_fillPattern = -1; /* active fill pattern (-1 == undefined) */ 183static unsigned int SVG_fillPatternIndex = 0; 184static int SVG_background = -1; 185static int SVG_imageno = 0; 186static int SVG_plotno = 0; 187static TBOOLEAN SVG_gridline = FALSE; 188static TBOOLEAN SVG_hasgrid = FALSE; 189 190static double SVG_fontAscent = 0; /* estimated current font ascent*/ 191static double SVG_fontDescent = 0; /* estimated current font descent*/ 192static double SVG_fontLeading = 0; /* estimated current font leading*/ 193static double SVG_fontAvWidth = 0; /* estimated current font char average width*/ 194 195static short SVG_Pen_RealID __PROTO ((int)); 196static void SVG_PathOpen __PROTO ((void)); 197static void SVG_PathClose __PROTO ((void)); 198static void SVG_AddSpaceOrNewline __PROTO ((void)); 199static void SVG_GroupOpen __PROTO ((void)); 200static void SVG_GroupClose __PROTO ((void)); 201static void SVG_SetFont __PROTO ((const char *name, double size)); 202static void SVG_GroupFilledOpen __PROTO ((void)); 203static void SVG_GroupFilledClose __PROTO ((void)); 204static void SVG_StyleColor __PROTO((const char*)); 205static void SVG_StyleFillColor __PROTO((void)); 206static void SVG_local_reset __PROTO((void)); 207static void SVG_DefineFillPattern __PROTO((int fillpat)); 208static void SVG_MoveForced __PROTO((unsigned int x, unsigned int y)); 209static void SVG_write_preamble __PROTO ((void)); 210 211/* Stuff for enhanced text mode */ 212static int ENHsvg_string_state = 0; 213static double ENHsvg_x_offset = 0; 214static TBOOLEAN ENHsvg_preserve_spaces = FALSE; 215 216/* Support for dashed lines */ 217#define SVG_dashtypes 5 218static char *SVG_defaultdashpattern[SVG_dashtypes] = { 219 "", " 5,8", " 2,4", " 8,4,2,4", " 9,4,1,4,1,4" 220}; 221static char *SVG_axis_dashpattern = "2,4"; 222static int SVG_dasharray[SVG_dashtypes][7] = { 223 { 0,0,0,0,0,0,0}, 224 {5,8, 0,0,0,0,0}, 225 {2,4, 0,0,0,0,0}, 226 {8,4,2,4, 0,0,0}, 227 {9,4,1,4,1,4, 0} 228}; 229static char *SVG_dashpattern = NULL; 230static char SVG_custom_dash_pattern[64]; 231 232/* Support for embedded hypertext */ 233static char *SVG_hypertext_text = NULL; 234 235/*------------------------------------------------------------------------------------------------------------------------------------ 236 SVG_Pen_RealID 237------------------------------------------------------------------------------------------------------------------------------------*/ 238static short 239SVG_Pen_RealID (int inPenCode) 240{ 241 if (inPenCode >= 13) 242 inPenCode %= 13; /* normalize pen code*/ 243 inPenCode += 3; 244 if (inPenCode < 0) 245 inPenCode = 0; /* LT_BACKGROUND should use background color */ 246 247 return (inPenCode); 248} 249 250/*------------------------------------------------------------------------------------------------------------------------------------ 251 SVG_GroupOpen 252------------------------------------------------------------------------------------------------------------------------------------*/ 253static void 254SVG_GroupOpen () 255{ 256 SVG_GroupFilledClose(); 257 if (!SVG_groupIsOpen) { 258 259 fprintf (gpoutfile, "<g fill=\"none\" color=\"%s\" stroke=\"", 260 SVG_pens[SVG_Pen_RealID (SVG_LineType)].color); 261 262 if (SVG_color_mode == TC_RGB) 263 fprintf(gpoutfile, "rgb(%3d, %3d, %3d)", SVG_red, SVG_green, SVG_blue); 264 else if (SVG_color_mode == TC_LT) 265 fprintf(gpoutfile, "%s", SVG_linecolor); 266 else 267 fprintf(gpoutfile, "currentColor"); 268 269 fprintf (gpoutfile, "\" "); 270 fprintf (gpoutfile, "stroke-width=\"%.2f\" stroke-linecap=\"%s\" stroke-linejoin=\"%s\"", 271 SVG_pens[SVG_Pen_RealID (SVG_LineType)].width * SVG_linewidth_factor, 272 SVG_linecap == ROUNDED ? "round" : SVG_linecap == SQUARE ? "square" : "butt", 273 SVG_linecap == ROUNDED ? "round" : "miter"); 274 275 fprintf (gpoutfile, ">\n"); 276 277 SVG_groupIsOpen = TRUE; 278 } 279} 280 281/*------------------------------------------------------------------------------------------------------------------------------------ 282 SVG_GroupClose 283------------------------------------------------------------------------------------------------------------------------------------*/ 284static void 285SVG_GroupClose () 286{ 287 SVG_GroupFilledClose(); 288 if (SVG_groupIsOpen) { 289 fputs ("</g>\n", gpoutfile); 290 SVG_groupIsOpen = FALSE; 291 SVG_fillPattern = -1; 292 } 293} 294 295/*------------------------------------------------------------------------------------------------------------------------------------ 296 SVG_PathOpen 297------------------------------------------------------------------------------------------------------------------------------------*/ 298static void 299SVG_PathOpen () 300{ 301 if (!SVG_pathIsOpen) { 302 SVG_GroupFilledClose(); 303 304 fputs ("\t<path ", gpoutfile); 305 306 /* Line color */ 307 if (SVG_LineType == LT_NODRAW) 308 fprintf(gpoutfile, "stroke='none' "); 309 else if (SVG_color_mode == TC_RGB) 310 fprintf(gpoutfile, "stroke='rgb(%3d, %3d, %3d)' ", 311 SVG_red, SVG_green, SVG_blue); 312 else if (SVG_color_mode == TC_LT) 313 fprintf(gpoutfile, "stroke='%s' ", SVG_linecolor); 314 315 /* Axis is always dotted */ 316 if (SVG_LineType == LT_AXIS) 317 fprintf(gpoutfile, "stroke-dasharray='2,4' "); 318 319 /* Other patterns were selected by a previous call to SVG_dashtype */ 320 else if (SVG_dashpattern) 321 fprintf(gpoutfile, "stroke-dasharray='%s' ", SVG_dashpattern); 322 323 /* RGBA */ 324 if (SVG_alpha != 0.0) 325 fprintf(gpoutfile, "opacity='%4.2f' ", 1.0 - SVG_alpha); 326 327 /* Mark grid lines so that we can toggle them on/off */ 328 if (SVG_gridline) 329 fprintf(gpoutfile, "class=\"gridline\" "); 330 331 fputs (" d='", gpoutfile); 332 333 SVG_pathIsOpen = TRUE; 334 } 335} 336 337/*------------------------------------------------------------------------------------------------------------------------------------ 338 SVG_PathClose 339------------------------------------------------------------------------------------------------------------------------------------*/ 340static void 341SVG_PathClose () 342{ 343 if (SVG_pathIsOpen) { 344 SVG_GroupFilledClose(); 345 fprintf(gpoutfile," '/>"); 346 SVG_path_count = 0; 347 SVG_pathIsOpen = FALSE; 348 } 349} 350 351/*------------------------------------------------------------------------------------------------------------------------------------ 352 SVG_AddSpaceOrNewline 353------------------------------------------------------------------------------------------------------------------------------------*/ 354static void 355SVG_AddSpaceOrNewline () 356{ 357 if (SVG_path_count % 8 == 0) /* avoid excessive line length*/ 358 fputs ("\n\t\t", gpoutfile); 359 else 360 fputs (" ", gpoutfile); 361} 362 363/*------------------------------------------------------------------------------------------------------------------------------------ 364 SVG_SetFont 365------------------------------------------------------------------------------------------------------------------------------------*/ 366static void 367SVG_SetFont (const char *name, double size) 368{ 369 if (name != SVG_fontNameCur) { 370 free(SVG_fontNameCur); 371 SVG_fontNameCur = gp_strdup(name); 372 } 373 SVG_fontSizeCur = size; 374 375/* since we cannot interrogate SVG about text properties and according 376 * to SVG 1.0 W3C Candidate Recommendation 2 August 2000 the 377 * "line-height" of the 'text' element is defined to be equal to the 378 * 'font-size' (!), we have to to define font properties in a less 379 * than optimal way */ 380 381 SVG_fontAscent = (SVG_fontSizeCur * 0.90 * SVG_SCALE); 382 SVG_fontDescent = (SVG_fontSizeCur * 0.25 * SVG_SCALE); 383 SVG_fontLeading = (SVG_fontSizeCur * 0.35 * SVG_SCALE); 384 SVG_fontAvWidth = (SVG_fontSizeCur * 0.70 * SVG_SCALE); 385 386 term->h_char = SVG_fontAvWidth; 387 term->v_char = (SVG_fontAscent + SVG_fontDescent + SVG_fontLeading); 388} 389 390static void 391SVG_GroupFilledOpen() 392{ 393 if (!SVG_groupFilledIsOpen) { 394 SVG_PathClose(); 395 fputs("\t<g stroke='none' shape-rendering='crispEdges'>\n", 396 gpoutfile); 397 SVG_groupFilledIsOpen = TRUE; 398 } 399} 400 401static void 402SVG_GroupFilledClose() 403{ 404 if (SVG_groupFilledIsOpen) { 405 fputs("\t</g>\n", gpoutfile); 406 SVG_groupFilledIsOpen = FALSE; 407 } 408} 409 410static void 411SVG_StyleColor(const char* paint) 412{ 413 if (SVG_color_mode == TC_RGB) 414 fprintf(gpoutfile, "%s = 'rgb(%3d, %3d, %3d)'", paint, SVG_red, SVG_green, SVG_blue); 415 else if (SVG_color_mode == TC_LT) 416 fprintf(gpoutfile, "%s = '%s'", paint, SVG_linecolor); 417 else 418 fprintf(gpoutfile, "%s = 'currentColor'", paint); 419} 420 421static void 422SVG_StyleFillColor() 423{ 424 SVG_StyleColor("fill"); 425} 426 427static void 428SVG_DefineFillPattern(int fillpat) 429{ 430 char *path; 431 char *style="stroke"; 432 433 fillpat %= 8; 434 if (fillpat != SVG_fillPattern) { 435 SVG_fillPattern = fillpat; 436 SVG_PathClose(); 437 SVG_fillPatternIndex++; 438 439 fprintf(gpoutfile, 440 "\t<defs>\n" 441 "\t\t<pattern id='gpPat%d' patternUnits='userSpaceOnUse' x='0' y='0' width='8' height='8'>\n", 442 SVG_fillPatternIndex); 443 switch (fillpat) { 444 default: 445 case 0: 446 path=""; 447 break; 448 case 1: 449 path="M0,0 L8,8 M0,8 L8,0"; 450 break; 451 case 2: 452 path="M0,0 L8,8 M0,8 L8,0 M0,4 L4,8 L8,4 L4,0 L0,4"; 453 break; 454 case 3: 455 path="M0,0 L0,8 L8,8 L8,0 L0,0"; 456 style="fill"; 457 break; 458 case 4: 459 path="M-4,0 L8,12 M0,-4 L12,8"; 460 break; 461 case 5: 462 path="M-4,8 L8,-4 M0,12 L12,0"; 463 break; 464 case 6: 465 path="M-2,8 L4,-4 M0,12 L8,-4 M4,12 L10,0"; 466 break; 467 case 7: 468 path="M-2,0 L4,12 M0,-4 L8,12 M4,-4 L10,8"; 469 break; 470 } 471 if (*path) { 472 char *figure = "fill:none;"; 473 if (!strcmp(style,"fill")) figure = "stroke:none;"; 474 if (SVG_color_mode == TC_RGB) 475 fprintf(gpoutfile,"\t\t\t<path style='%s %s:rgb(%d,%d,%d)' d='%s'/>\n", 476 figure, style, SVG_red, SVG_green, SVG_blue, path); 477 else if (SVG_color_mode == TC_LT) 478 fprintf(gpoutfile, "\t\t\t<path style = '%s %s:%s' d= '%s'/>\n", 479 figure, style, SVG_linecolor, path); 480 else 481 fprintf(gpoutfile, "\t\t\t<path style = '%s %s:currentColor' d='%s'/>\n", 482 figure, style, path); 483 } 484 fputs("\t\t</pattern>\n" "\t</defs>\n", gpoutfile); 485 } 486} 487 488static void 489SVG_MoveForced(unsigned int x, unsigned int y) 490{ 491 if (SVG_path_count > 512) 492 SVG_PathClose(); 493 494 SVG_PathOpen (); 495 496 fprintf (gpoutfile, "M%.*f,%.*f", PREC, X(x), PREC, Y(y)); 497 SVG_path_count++; 498 499 SVG_AddSpaceOrNewline (); 500 501 SVG_xLast = x; 502 SVG_yLast = y; 503} 504 505/*------------------------------------------------------------------------------------------------------------------------------------ 506 SVG_options 507------------------------------------------------------------------------------------------------------------------------------------*/ 508TERM_PUBLIC void 509SVG_options () 510{ 511 /* Annoying hack to handle the case of 'set termoption' after */ 512 /* we have already initialized the terminal settings. */ 513 if (!almost_equals(c_token-1, "termopt$ion")) 514 SVG_local_reset(); 515 516 if (strcmp(term->name, "domterm") == 0) { 517 SVG_emit_doctype = FALSE; 518 SVG_domterm = TRUE; 519 } else { 520 SVG_emit_doctype = TRUE; 521 SVG_domterm = FALSE; 522 } 523 524 /* Minimal initialization in case we error out of options parsing */ 525 SVG_set_font(""); 526 527 while (!END_OF_COMMAND) { 528 if (almost_equals(c_token, "s$ize")) { 529 double value; 530 531 c_token++; 532 533 if (END_OF_COMMAND) 534 int_error(c_token,"expecting x size"); 535 value = real_expression(); 536 if (value < 2) 537 int_error(c_token,"x size out of range"); 538 SVG_xSize = value * SVG_SCALE; 539 540 if (equals(c_token,",")) 541 c_token++; 542 if (END_OF_COMMAND) 543 int_error(c_token,"expecting y size"); 544 value = real_expression(); 545 if (value < 2) 546 int_error(c_token,"y size out of range"); 547 SVG_ySize = value * SVG_SCALE; 548 continue; 549 } 550 551 if (equals(c_token, "mouse") || almost_equals(c_token, "mous$ing")) { 552 c_token++; 553 SVG_mouseable = TRUE; 554 continue; 555 } 556 557 if (almost_equals(c_token, "stand$alone")) { 558 c_token++; 559 SVG_standalone = TRUE; 560 continue; 561 } 562 563 if (equals(c_token, "name")) { 564 c_token++; 565 SVG_name = try_to_get_string(); 566 if (!SVG_name) 567 int_error(c_token,"expecting a plot name"); 568 if (SVG_name[strspn(SVG_name, 569 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_1234567890")]) 570 int_error(c_token-1,"name must contain only alphanumerics or _"); 571 continue; 572 } 573 574 if (equals(c_token, "jsdir")) { 575 c_token++; 576 SVG_scriptdir = try_to_get_string(); 577 continue; 578 } 579 580 if (almost_equals(c_token, "d$ynamic")) { 581 c_token++; 582 SVG_fixed_size = FALSE; 583 continue; 584 } 585 586 if (almost_equals(c_token, "fi$xed")){ 587 c_token++; 588 SVG_fixed_size = TRUE; 589 continue; 590 } 591 592 if (almost_equals(c_token, "enh$anced")) { 593 c_token++; 594 term->put_text = ENHsvg_put_text; 595 term->flags |= TERM_ENHANCED_TEXT; 596 continue; 597 } 598 599 if (almost_equals(c_token, "noenh$anced")) { 600 c_token++; 601 term->put_text = SVG_put_text; 602 term->flags &= ~TERM_ENHANCED_TEXT; 603 continue; 604 } 605 606 if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font")) { 607 char *s, *comma; 608 c_token++; 609 610 if (!(s = try_to_get_string())) 611 int_error(c_token,"expecting font name"); 612 comma = strrchr(s,','); 613 if (comma && (1 == sscanf(comma + 1, "%lf", &SVG_fontSizeDef))) 614 *comma = '\0'; 615 616 if (*s) { 617 char *bold, *italic; 618 619 if (!((bold = strstr(s," bold")))) 620 bold = strstr(s," Bold"); 621 622 if (!((italic = strstr(s," italic")))) 623 italic = strstr(s," Italic"); 624 625 free(SVG_fontNameDef); 626 SVG_fontNameDef = s; 627 if (italic) { 628 SVG_fontStyleDef = "italic"; 629 SVG_fontNameDef[strlen(s) - strlen(italic)] = NUL; 630 } else { 631 SVG_fontStyleDef = "normal"; 632 } 633 if (bold) { 634 SVG_fontWeightDef="bold"; 635 SVG_fontNameDef[strlen(s) - strlen(bold)] = NUL; 636 } else { 637 SVG_fontWeightDef = "normal"; 638 } 639 } else 640 free(s); 641 continue; 642 } 643 644 if (equals(c_token, "fontscale")) { 645 c_token++; 646 SVG_fontscale = real_expression(); 647 if (SVG_fontscale <= 0) 648 SVG_fontscale = 1.0; 649 continue; 650 } 651 652 if (almost_equals(c_token, "linew$idth") || equals(c_token, "lw")) { 653 c_token++; 654 SVG_linewidth_factor = real_expression(); 655 if (SVG_linewidth_factor <= 0.0) 656 SVG_linewidth_factor = 1.0; 657 continue; 658 } 659 660 if (almost_equals(c_token, "dashl$ength") || equals(c_token, "dl")) { 661 c_token++; 662 SVG_dashlength = real_expression(); 663 if (SVG_dashlength < 0.5) 664 SVG_dashlength = 1.0; 665 continue; 666 } 667 668 if (almost_equals (c_token, "round$ed")) { 669 c_token++; 670 SVG_linecap = ROUNDED; 671 continue; 672 } 673 674 if (equals (c_token, "square")) { 675 c_token++; 676 SVG_linecap = SQUARE; 677 continue; 678 } 679 680 if (equals (c_token, "butt")) { 681 c_token++; 682 SVG_linecap = BUTT; 683 continue; 684 } 685 686 /* Not used in version 5 */ 687 if (equals(c_token, "solid") || almost_equals(c_token, "dash$ed")) { 688 c_token++; 689 continue; 690 } 691 692 if (almost_equals(c_token, "backg$round")) { 693 c_token++; 694 SVG_background = parse_color_name(); 695 continue; 696 } 697 698 int_error(c_token, "unrecognized terminal option"); 699 } 700 701 /* I don't think any error checks on font name are possible; just set it */ 702 SVG_set_font(""); 703 704 /* Save options back into options string in normalized format */ 705 sprintf(term_options, "size %d,%d%s %s font '%s,%g' ", 706 (int)(SVG_xSize/SVG_SCALE), (int)(SVG_ySize/SVG_SCALE), 707 SVG_fixed_size ? " fixed": " dynamic", 708 term->put_text == ENHsvg_put_text ? "enhanced" : "", 709 SVG_fontNameCur, SVG_fontSizeCur); 710 711 if (SVG_mouseable) { 712 sprintf(term_options + strlen(term_options), 713 "mousing "); 714 } 715 716 if (SVG_standalone) { 717 sprintf(term_options + strlen(term_options), 718 "standalone "); 719 } 720 721 if (SVG_name) { 722 sprintf(term_options + strlen(term_options), 723 "name \"%s\" ", SVG_name); 724 } 725 726 sprintf(term_options + strlen(term_options), 727 SVG_linecap == ROUNDED ? "rounded " : SVG_linecap == SQUARE ? "square " : "butt "); 728 729 sprintf(term_options + strlen(term_options), 730 "dashlength %.1f ", SVG_dashlength); 731 732 if (SVG_linewidth_factor != 1.0) { 733 sprintf(term_options + strlen(term_options), 734 "linewidth %3.1f ", SVG_linewidth_factor); 735 } 736 737 if (SVG_background >= 0) { 738 sprintf(term_options + strlen(term_options), 739 "background \"#%06x\" ", SVG_background); 740 } 741 742} 743 744static void 745SVG_local_reset() 746{ 747 SVG_xSize = SVG_XMAX; 748 SVG_ySize = SVG_YMAX; 749 SVG_fixed_size = TRUE; 750 free(SVG_fontNameDef); 751 SVG_fontNameDef = gp_strdup("Arial"); 752 SVG_fontSizeDef = 12; 753 SVG_mouseable = FALSE; 754 SVG_standalone = FALSE; 755 free(SVG_name); 756 SVG_name = NULL; 757 free(SVG_scriptdir); 758 SVG_scriptdir = NULL; 759 SVG_gridline = FALSE; 760 SVG_hasgrid = FALSE; 761 /* Default to enhanced text */ 762 term->put_text = ENHsvg_put_text; 763 term->flags |= TERM_ENHANCED_TEXT; 764} 765 766/*------------------------------------------------------------------------------------------------------------------------------------ 767 SVG_init 768------------------------------------------------------------------------------------------------------------------------------------*/ 769TERM_PUBLIC void 770SVG_init () 771{ 772 /* setup pens*/ 773 SVG_pens[0].width = SVG_LineWidth; 774 strcpy (SVG_pens[0].color, "white"); /* should really be background */ 775 SVG_pens[1].width = SVG_LineWidth; 776 strcpy(SVG_pens[1].color, "black"); 777 SVG_pens[2].width = SVG_LineWidth; 778 strcpy(SVG_pens[2].color, "gray"); 779 SVG_pens[3].width = SVG_LineWidth; 780 strcpy(SVG_pens[3].color, "red"); 781 SVG_pens[4].width = SVG_LineWidth; 782 strcpy(SVG_pens[4].color, "green"); 783 SVG_pens[5].width = SVG_LineWidth; 784 strcpy(SVG_pens[5].color, "blue"); 785 SVG_pens[6].width = SVG_LineWidth; 786 strcpy(SVG_pens[6].color, "cyan"); 787 SVG_pens[7].width = SVG_LineWidth; 788 sprintf(SVG_pens[7].color, "#%2.2X%2.2X%2.2X", 21, 117, 69); /* pine green*/ 789 SVG_pens[8].width = SVG_LineWidth; 790 sprintf (SVG_pens[8].color, "#%2.2X%2.2X%2.2X", 0, 0, 148); /* navy*/ 791 SVG_pens[9].width = SVG_LineWidth; 792 sprintf (SVG_pens[9].color, "#%2.2X%2.2X%2.2X", 255, 153, 0); /* orange*/ 793 SVG_pens[10].width = SVG_LineWidth; 794 sprintf (SVG_pens[10].color, "#%2.2X%2.2X%2.2X", 0, 153, 161); /* green blue*/ 795 SVG_pens[11].width = SVG_LineWidth; 796 sprintf (SVG_pens[11].color, "#%2.2X%2.2X%2.2X", 214, 214, 69); /* olive*/ 797 SVG_pens[12].width = SVG_LineWidth; 798 sprintf (SVG_pens[12].color, "#%2.2X%2.2X%2.2X", 163, 145, 255); /* cornflower*/ 799 SVG_pens[13].width = SVG_LineWidth; 800 sprintf (SVG_pens[13].color, "#%2.2X%2.2X%2.2X", 255, 204, 0); /* gold*/ 801 SVG_pens[14].width = SVG_LineWidth; 802 sprintf (SVG_pens[14].color, "#%2.2X%2.2X%2.2X", 214, 0, 120); /* mulberry*/ 803 SVG_pens[15].width = SVG_LineWidth; 804 sprintf (SVG_pens[15].color, "#%2.2X%2.2X%2.2X", 171, 214, 0); /* green yellow*/ 805 806 if (SVG_background >= 0) 807 sprintf(SVG_pens[0].color, "#%2.2X%2.2X%2.2X", 808 (SVG_background >> 16)&0xff, 809 (SVG_background >> 8)&0xff, 810 (SVG_background)&0xff); 811 812 SVG_LineType = LT_NODRAW; 813 814/* set xmax, ymax*/ 815 816 term->xmax = SVG_xSize; 817 term->ymax = SVG_ySize; 818 819/* set current font, including h_char and v_char */ 820 821 SVG_SetFont (SVG_fontNameCur, SVG_fontSizeCur); 822 823/* set h_tic, v_tic*/ 824 825 term->h_tic = term->v_char / 2; 826 term->v_tic = term->v_char / 2; 827} 828 829/* write file header*/ 830static void 831SVG_write_preamble () 832{ 833 int len; 834 double stroke_width; 835 char *svg_encoding = ""; 836 837 switch (encoding) { 838 case S_ENC_ISO8859_1: svg_encoding = "encoding=\"iso-8859-1\" "; break; 839 case S_ENC_ISO8859_2: svg_encoding = "encoding=\"iso-8859-2\" "; break; 840 case S_ENC_ISO8859_9: svg_encoding = "encoding=\"iso-8859-9\" "; break; 841 case S_ENC_ISO8859_15: svg_encoding = "encoding=\"iso-8859-15\" "; break; 842 case S_ENC_CP850: svg_encoding = "encoding=\"ibm-850\" "; break; 843 case S_ENC_CP852: svg_encoding = "encoding=\"ibm-852\" "; break; 844 case S_ENC_CP950: svg_encoding = "encoding=\"cp950\" "; break; 845 case S_ENC_CP1250: svg_encoding = "encoding=\"windows-1250\" "; break; 846 case S_ENC_CP1251: svg_encoding = "encoding=\"windows-1251\" "; break; 847 case S_ENC_CP1252: svg_encoding = "encoding=\"windows-1252\" "; break; 848 case S_ENC_KOI8_R: svg_encoding = "encoding=\"koi8-r\" "; break; 849 case S_ENC_KOI8_U: svg_encoding = "encoding=\"koi8-u\" "; break; 850 case S_ENC_SJIS: svg_encoding = "encoding=\"Shift_JIS\" "; break; 851 case S_ENC_CP437: svg_encoding = ""; break; 852 default: /* UTF-8 */ 853 svg_encoding = "encoding=\"utf-8\" "; 854 break; 855 } 856 857 if (SVG_domterm) 858 fprintf(gpoutfile, "\033]72;"); 859 if (SVG_emit_doctype) 860 fprintf (gpoutfile, 861 "<?xml version=\"1.0\" %s standalone=\"no\"?>\n", 862 svg_encoding); 863 fprintf(gpoutfile, "<svg "); 864 865 if (SVG_mouseable) 866 fprintf (gpoutfile, " onload=\"if (typeof(gnuplot_svg)!='undefined') gnuplot_svg.Init(evt)\" "); 867 868 if (SVG_fixed_size) 869 fprintf (gpoutfile, "\n width=\"%u\" height=\"%u\"", 870 (unsigned int) (term->xmax / SVG_SCALE), 871 (unsigned int) (term->ymax / SVG_SCALE)); 872 873 fprintf (gpoutfile, "\n viewBox=\"0 0 %u %u\"\n", 874 (unsigned int) (term->xmax / SVG_SCALE), 875 (unsigned int) (term->ymax / SVG_SCALE)); 876 fprintf (gpoutfile, " xmlns=\"http://www.w3.org/2000/svg\"\n"); 877 fprintf (gpoutfile, " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"); 878#if (0) 879 /* This should be required, but Firefox gets it totally wrong */ 880 fprintf (gpoutfile, " xml:space=\"preserve\"\n"); 881#endif 882 fprintf (gpoutfile, ">\n\n"); 883 884 /* TODO: It would be nice to print the actual plot title here */ 885 fprintf (gpoutfile, "<title>%s</title>\n", SVG_name ? SVG_name : "Gnuplot"); 886 fprintf (gpoutfile, 887 "<desc>Produced by GNUPLOT %s patchlevel %s </desc>\n\n", 888 gnuplot_version, gnuplot_patchlevel); 889 890/* 891 * FIXME: This code could be shared with canvas.trm 892 * Figure out the full URL to use for xlink:href="gnuplot_svg.js" 893 */ 894 if (SVG_scriptdir == NULL) { 895#ifdef GNUPLOT_JS_DIR 896# if defined(_WIN32) 897 SVG_scriptdir = RelativePathToGnuplot(GNUPLOT_JS_DIR); 898# else /* !_WIN32 */ 899 /* use hardcoded _absolute_ path */ 900 SVG_scriptdir = gp_strdup(GNUPLOT_JS_DIR); 901# endif 902#else 903 SVG_scriptdir = gp_strdup(""); 904#endif /* GNUPLOT_JS_DIR */ 905 } 906 907#if !defined(VMS) 908 len = strlen(SVG_scriptdir); 909# if defined(_WIN32) 910 if (*SVG_scriptdir && SVG_scriptdir[len-1] != '\\' && SVG_scriptdir[len-1] != '/') { 911 SVG_scriptdir = gp_realloc(SVG_scriptdir, len+2, "jsdir"); 912 if (SVG_scriptdir[len-1] == '\\') /* use backslash if used in jsdir, otherwise slash */ 913 strcat(SVG_scriptdir,"\\"); 914 else 915 strcat(SVG_scriptdir,"/"); 916 } 917# else 918 if (*SVG_scriptdir && SVG_scriptdir[len-1] != '/') { 919 SVG_scriptdir = gp_realloc(SVG_scriptdir, len+2, "jsdir"); 920 strcat(SVG_scriptdir,"/"); 921 } 922# endif 923#endif 924 925 if (SVG_mouseable) { 926 /* Inclusion of gnuplot_svg.js is sufficient to support toggling plots on/off */ 927 if (!SVG_standalone) { 928 fprintf(gpoutfile, 929 "<script type=\"text/javascript\" xlink:href=\"%sgnuplot_svg.js\"/>\n", 930 SVG_scriptdir); 931 } else { 932 /* "standalone" option includes the mousing code in the file itself */ 933 char *fullname = NULL; 934 char *name ="gnuplot_svg.js"; 935 char buf[256]; 936 FILE *svg_js_fd; 937 938 fullname = gp_alloc(strlen(SVG_scriptdir) + strlen(name) + 4,"javascript name"); 939 strcpy(fullname, SVG_scriptdir); 940 PATH_CONCAT(fullname, name); 941 942 svg_js_fd=fopen(fullname, "r"); 943 if (!svg_js_fd) 944 int_warn(NO_CARET, "Failed to insert javascript file %s\n", fullname); 945 else { 946 fprintf(gpoutfile, 947 "<script type=\"text/javascript\" > <![CDATA[\n"); 948 while (fgets(buf, sizeof(buf), svg_js_fd)) 949 fputs(buf, gpoutfile); 950 fprintf(gpoutfile,"]]>\n</script>\n"); 951 fclose(svg_js_fd); 952 } 953 free(fullname); 954 } 955 } 956 957 if (SVG_mouseable) { /* FIXME: Should only do this for 2D plots */ 958 /* This is extra code to support tracking the mouse coordinates */ 959 fprintf(gpoutfile,"\n<!-- Tie mousing to entire bounding box of the plot -->\n"); 960 fprintf(gpoutfile,"<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"", 961 0, 0, (int)(term->xmax/SVG_SCALE), (int)(term->ymax/SVG_SCALE)); 962 fprintf(gpoutfile," fill=\"#%06x\" stroke=\"black\" stroke-width=\"1\"\n", 963 SVG_background >= 0 ? SVG_background : 0xffffff); 964 fprintf(gpoutfile,"onclick=\"gnuplot_svg.toggleCoordBox(evt)\" onmousemove=\"gnuplot_svg.moveCoordBox(evt)\"/>\n"); 965 fprintf(gpoutfile,"\n<!-- Also track mouse when it is on a plot element -->\n"); 966 fprintf(gpoutfile,"<g id=\"gnuplot_canvas\" onclick=\"gnuplot_svg.toggleCoordBox(evt)\" onmousemove=\"gnuplot_svg.moveCoordBox(evt)\">\n\n"); 967 } else { 968 fprintf(gpoutfile,"<g id=\"gnuplot_canvas\">\n\n"); 969 fprintf(gpoutfile,"<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"", 970 0, 0, (int)(term->xmax/SVG_SCALE), (int)(term->ymax/SVG_SCALE)); 971 if (SVG_background >= 0) 972 fprintf(gpoutfile," fill=\"#%06x\"", SVG_background); 973 else 974 fprintf(gpoutfile," fill=\"none\""); 975 fprintf(gpoutfile,"/>\n"); 976 } 977 978 /* Start prologue section of output file, and load fonts if requested */ 979 980 fprintf(gpoutfile,"<defs>\n"); 981 982 /* definitions of point symbols */ 983 /* FIXME: SVG scales linewidth along with the marker itself, and 984 * there seems to be no way to avoid that without copying the 985 * marker definition into the file, rather than referencing a 986 * defined one :-( That would make for much larger files */ 987 /* "\t<path id='gpPt3' stroke-width='%.3f' d='M-1,-1 h2 v2 h-2 z'/>\n" */ 988 989 stroke_width = 2.0 *SVG_SCALE / term->h_tic; 990 fprintf (gpoutfile, 991 "\n" 992 /* dot: */ 993 "\t<circle id='gpDot' r='0.5' stroke-width='0.5' stroke='currentColor'/>\n" 994 /* 0 plus */ 995 "\t<path id='gpPt0' stroke-width='%.3f' stroke='currentColor' d='M-1,0 h2 M0,-1 v2'/>\n" 996 /* 1 X */ 997 "\t<path id='gpPt1' stroke-width='%.3f' stroke='currentColor' d='M-1,-1 L1,1 M1,-1 L-1,1'/>\n" 998 /* 2 star */ 999 "\t<path id='gpPt2' stroke-width='%.3f' stroke='currentColor' d='M-1,0 L1,0 M0,-1 L0,1 M-1,-1 L1,1 M-1,1 L1,-1'/>\n" 1000 /* 3 box */ 1001 "\t<rect id='gpPt3' stroke-width='%.3f' stroke='currentColor' x='-1' y='-1' width='2' height='2'/>\n" 1002 /* 4 box filled */ 1003 "\t<rect id='gpPt4' stroke-width='%.3f' stroke='currentColor' fill='currentColor' x='-1' y='-1' width='2' height='2'/>\n" 1004 /* 5 circle */ 1005 "\t<circle id='gpPt5' stroke-width='%.3f' stroke='currentColor' cx='0' cy='0' r='1'/>\n" 1006 /* 6 circle (disk) filled */ 1007 "\t<use xlink:href='#gpPt5' id='gpPt6' fill='currentColor' stroke='none'/>\n" 1008 /* 7 triangle */ 1009 "\t<path id='gpPt7' stroke-width='%.3f' stroke='currentColor' d='M0,-1.33 L-1.33,0.67 L1.33,0.67 z'/>\n" 1010 /* 8 triangle filled */ 1011 "\t<use xlink:href='#gpPt7' id='gpPt8' fill='currentColor' stroke='none'/>\n" 1012 /* 9 upside down triangle */ 1013 "\t<use xlink:href='#gpPt7' id='gpPt9' stroke='currentColor' transform='rotate(180)'/>\n" 1014 /* 10 upside down triangle filled */ 1015 "\t<use xlink:href='#gpPt9' id='gpPt10' fill='currentColor' stroke='none'/>\n" 1016 /* 11 diamond */ 1017 "\t<use xlink:href='#gpPt3' id='gpPt11' stroke='currentColor' transform='rotate(45)'/>\n" 1018 /* 12 diamond filled */ 1019 "\t<use xlink:href='#gpPt11' id='gpPt12' fill='currentColor' stroke='none'/>\n" 1020 /* 13 pentagon */ 1021 "\t<path id='gpPt13' stroke-width='%.3f' stroke='currentColor' d='M0,1.330 L1.265,0.411 L0.782,-1.067 L-0.782,-1.076 L-1.265,0.411 z'/>\n" 1022 /* 14 pentagon filled */ 1023 "\t<use xlink:href='#gpPt13' id='gpPt14' fill='currentColor' stroke='none'/>\n" 1024 1025 /* NOTE: Fill patterns must be defined after the stroke color has been 1026 * set to use the correct (current) stroke color. Therefore we can't 1027 * define fill patterns here. */ 1028#ifdef EAM_BOXED_TEXT 1029 "\t<filter id='textbox' filterUnits='objectBoundingBox' x='0' y='0' height='1' width='1'>\n" 1030 "\t <feFlood flood-color='%s' flood-opacity='1' result='bgnd'/>\n" 1031 "\t <feComposite in='SourceGraphic' in2='bgnd' operator='atop'/>\n" 1032 "\t</filter>\n" 1033#endif 1034 "\t<filter id='greybox' filterUnits='objectBoundingBox' x='0' y='0' height='1' width='1'>\n" 1035 "\t <feFlood flood-color='lightgrey' flood-opacity='1' result='grey'/>\n" 1036 "\t <feComposite in='SourceGraphic' in2='grey' operator='atop'/>\n" 1037 "\t</filter>\n" 1038 1039 "</defs>\n" 1040 , stroke_width 1041 , stroke_width 1042 , stroke_width 1043 , stroke_width 1044 , stroke_width 1045 , stroke_width 1046 , stroke_width 1047 , stroke_width 1048#ifdef EAM_BOXED_TEXT 1049 , SVG_pens[0].color 1050#endif 1051 ); 1052} 1053 1054/*------------------------------------------------------------------------------------------------------------------------------------ 1055 SVG_graphics 1056------------------------------------------------------------------------------------------------------------------------------------*/ 1057TERM_PUBLIC void 1058SVG_graphics () 1059{ 1060 SVG_write_preamble(); 1061 1062 /* We must force a new group with fill:none in order for multiple */ 1063 /* plots per page to work. Otherwise new plots are black-filled */ 1064 SVG_GroupOpen(); 1065 1066 SVG_fillPattern = -1; 1067 SVG_fillPatternIndex = 0; 1068 SVG_groupFilledIsOpen = FALSE; 1069 SVG_color_mode = TC_DEFAULT; 1070 SVG_pathIsOpen = FALSE; 1071 1072/* reset position*/ 1073 1074 SVG_xLast = SVG_yLast = UINT_MAX; 1075} 1076 1077/*------------------------------------------------------------------------------------------------------------------------------------ 1078 SVG_text 1079------------------------------------------------------------------------------------------------------------------------------------*/ 1080TERM_PUBLIC void 1081SVG_text () 1082{ 1083 SVG_PathClose (); 1084 SVG_GroupClose (); 1085 1086 if (SVG_mouseable) { 1087 struct udvt_entry *udv; 1088 1089 fprintf(gpoutfile, "\n<script type=\"text/javascript\"><![CDATA[\n"); 1090 fprintf(gpoutfile, "// plot boundaries and axis scaling information for mousing \n"); 1091 fprintf(gpoutfile, "gnuplot_svg.plot_term_xmax = %d;\n", (int)(term->xmax / SVG_SCALE)); 1092 fprintf(gpoutfile, "gnuplot_svg.plot_term_ymax = %d;\n", (int)(term->ymax / SVG_SCALE)); 1093 fprintf(gpoutfile, "gnuplot_svg.plot_xmin = %.1f;\n", (double)plot_bounds.xleft / SVG_SCALE); 1094 fprintf(gpoutfile, "gnuplot_svg.plot_xmax = %.1f;\n", (double)plot_bounds.xright / SVG_SCALE); 1095 fprintf(gpoutfile, "gnuplot_svg.plot_ybot = %.1f;\n", (double)(term->ymax-plot_bounds.ybot) / SVG_SCALE); 1096 fprintf(gpoutfile, "gnuplot_svg.plot_ytop = %.1f;\n", (double)(term->ymax-plot_bounds.ytop) / SVG_SCALE); 1097 fprintf(gpoutfile, "gnuplot_svg.plot_width = %.1f;\n", (double)(plot_bounds.xright - plot_bounds.xleft) / SVG_SCALE); 1098 fprintf(gpoutfile, "gnuplot_svg.plot_height = %.1f;\n", (double)(plot_bounds.ytop - plot_bounds.ybot) / SVG_SCALE); 1099 1100 /* Get true axis ranges as used in the plot */ 1101 update_gpval_variables(1); 1102 1103#define MOUSE_PARAM( GP_NAME, js_NAME ) \ 1104 if ((udv = add_udv_by_name(GP_NAME))) { \ 1105 if (udv->udv_value.type == INTGR) \ 1106 fprintf(gpoutfile, "gnuplot_svg.%s = %d;\n", \ 1107 js_NAME, udv->udv_value.v.int_val); \ 1108 else if (udv->udv_value.type == CMPLX) \ 1109 fprintf(gpoutfile, "gnuplot_svg.%s = %g;\n", \ 1110 js_NAME, udv->udv_value.v.cmplx_val.real); \ 1111 } 1112 if (axis_array[FIRST_X_AXIS].datatype != DT_TIMEDATE) { 1113 MOUSE_PARAM("GPVAL_X_MIN", "plot_axis_xmin"); 1114 MOUSE_PARAM("GPVAL_X_MAX", "plot_axis_xmax"); 1115 } 1116 /* FIXME: Should this inversion be done at a higher level? */ 1117 if (is_3d_plot && splot_map) { 1118 MOUSE_PARAM("GPVAL_Y_MAX", "plot_axis_ymin"); 1119 MOUSE_PARAM("GPVAL_Y_MIN", "plot_axis_ymax"); 1120 } else { 1121 MOUSE_PARAM("GPVAL_Y_MIN", "plot_axis_ymin"); 1122 MOUSE_PARAM("GPVAL_Y_MAX", "plot_axis_ymax"); 1123 } 1124 1125 fprintf(gpoutfile, "gnuplot_svg.polar_mode = %s;\n", 1126 polar ? "true" : "false"); 1127 if (polar) { 1128 fprintf(gpoutfile, "gnuplot_svg.plot_axis_rmin = %g;\n", 1129 (R_AXIS.autoscale & AUTOSCALE_MIN) ? 0.0 : R_AXIS.set_min); 1130 fprintf(gpoutfile, "gnuplot_svg.plot_axis_rmax = %g;\n", R_AXIS.set_max); 1131 fprintf(gpoutfile, "gnuplot_svg.polar_theta0 = %d;\n", (int)theta_origin); 1132 fprintf(gpoutfile, "gnuplot_svg.polar_sense = %d;\n", (int)theta_direction); 1133 } 1134 1135 if ((axis_array[SECOND_X_AXIS].ticmode & TICS_MASK) != NO_TICS) { 1136 MOUSE_PARAM("GPVAL_X2_MIN", "plot_axis_x2min"); 1137 MOUSE_PARAM("GPVAL_X2_MAX", "plot_axis_x2max"); 1138 } else 1139 fprintf(gpoutfile, "gnuplot_svg.plot_axis_x2min = \"none\"\n"); 1140 if ((axis_array[SECOND_Y_AXIS].ticmode & TICS_MASK) != NO_TICS) { 1141 MOUSE_PARAM("GPVAL_Y2_MIN", "plot_axis_y2min"); 1142 MOUSE_PARAM("GPVAL_Y2_MAX", "plot_axis_y2max"); 1143 } else 1144 fprintf(gpoutfile, "gnuplot_svg.plot_axis_y2min = \"none\"\n"); 1145#undef MOUSE_PARAM 1146 1147 fprintf(gpoutfile, "gnuplot_svg.plot_logaxis_x = %d;\n", 1148 axis_array[FIRST_X_AXIS].log ? 1: 0); 1149 fprintf(gpoutfile, "gnuplot_svg.plot_logaxis_y = %d;\n", 1150 axis_array[FIRST_Y_AXIS].log ? 1: 0); 1151 if (polar) 1152 fprintf(gpoutfile, "gnuplot_svg.plot_logaxis_r = %d;\n", 1153 axis_array[POLAR_AXIS].log ? 1: 0); 1154 1155 /* 1156 * Note: mouse_alt_string is set by 'set mouse mouseformat "foo"' 1157 * The only strings currently recognized by gnuplot_svg.js are 1158 * "Time", "Date", and "DateTime" but the user could modify 1159 * gnuplot_svg.js to recognize additional formats. 1160 * FIXME: This all needs to be documented somewhere! 1161 */ 1162 if (axis_array[FIRST_X_AXIS].datatype == DT_TIMEDATE) { 1163 fprintf(gpoutfile, "gnuplot_svg.plot_axis_xmin = %.3f;\n", 1164 axis_array[FIRST_X_AXIS].min); 1165 fprintf(gpoutfile, "gnuplot_svg.plot_axis_xmax = %.3f;\n", 1166 axis_array[FIRST_X_AXIS].max); 1167 fprintf(gpoutfile, "gnuplot_svg.plot_timeaxis_x = \"%s\";\n", 1168 (mouse_alt_string) ? mouse_alt_string 1169 : (mouse_mode == 4) ? "Date" 1170 : (mouse_mode == 5) ? "Time" 1171 : "DateTime" 1172 ); 1173 } else if (axis_array[FIRST_X_AXIS].datatype == DT_DMS) { 1174 fprintf(gpoutfile, "gnuplot_svg.plot_timeaxis_x = \"DMS\";\n"); 1175 } else 1176 fprintf(gpoutfile, "gnuplot_svg.plot_timeaxis_x = \"\";\n"); 1177 1178 if (axis_array[FIRST_Y_AXIS].datatype == DT_DMS) 1179 fprintf(gpoutfile, "gnuplot_svg.plot_timeaxis_y = \"DMS\";\n"); 1180 else 1181 fprintf(gpoutfile, "gnuplot_svg.plot_timeaxis_y = \"\";\n"); 1182 1183 fprintf(gpoutfile,"]]>\n</script>\n"); 1184 } /* End of section writing out variables for mousing */ 1185 1186 /* Close off the group with id=gnuplot_canvas that wraps the entire plot */ 1187 fprintf(gpoutfile,"</g>\n"); 1188 1189 /* Now create a text element to hold the mouse-tracking text. */ 1190 /* It comes _after_ the plot group so that it floats on top. */ 1191 if (SVG_mouseable) { 1192 fprintf(gpoutfile,"\n <text id=\"coord_text\" text-anchor=\"start\" pointer-events=\"none\"\n"); 1193 fprintf(gpoutfile," font-size=\"12\" font-family=\"Arial\"\n"); 1194 fprintf(gpoutfile," visibility=\"hidden\"> </text>\n"); 1195 } 1196 1197 /* Add a box and a text element to hold mouseover hypertext */ 1198 if (SVG_mouseable) { 1199 fprintf(gpoutfile,"\n <rect id=\"hypertextbox\" class=\"hypertextbox\" pointer-events=\"none\"\n"); 1200 fprintf(gpoutfile," fill=\"white\" stroke=\"black\" opacity=\"0.8\"\n"); 1201 fprintf(gpoutfile," height=\"16\" visibility=\"hidden\" />\n"); 1202 fprintf(gpoutfile,"\n <text id=\"hypertext\" class=\"hypertext\" pointer-events=\"none\"\n"); 1203 fprintf(gpoutfile," font-size=\"12\" font-family=\"Arial\"\n"); 1204 fprintf(gpoutfile," visibility=\"hidden\"> </text>\n"); 1205 } 1206 1207 /* Add a placeholder for an image linked to mouseover hypertext */ 1208 if (SVG_mouseable) { 1209 fprintf(gpoutfile,"\n <image id=\"hyperimage\" class=\"hyperimage\" pointer-events=\"none\"\n"); 1210 fprintf(gpoutfile," fill=\"white\" stroke=\"black\" opacity=\"0.8\"\n"); 1211 fprintf(gpoutfile," height=\"200\" width=\"300\" visibility=\"hidden\" />\n"); 1212 } 1213 1214 /* If there were any grid lines in this plot, add a button to toggle them */ 1215 if (SVG_mouseable && SVG_hasgrid) { 1216 fprintf(gpoutfile,"\n <image x='10' y='%d' width='16' height='16' ", 1217 (int)(term->ymax/SVG_SCALE)-26); 1218 fprintf(gpoutfile, "\n xlink:href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABmJLR0QA/wD/AP+gvaeTAAAAM0lEQVQokWP8//8/AymACc5iZGQkyEDRQCwgyUn///9nhGtgZISy8TBGnTSCnMRIavIGAGPTWfVV7DcfAAAAAElFTkSuQmCC'"); 1219 fprintf(gpoutfile, "\n onclick='gnuplot_svg.toggleGrid();'/>\n"); 1220 } 1221 1222 fputs("</svg>\n\n", gpoutfile); 1223 1224 if (SVG_domterm) { 1225 fprintf(gpoutfile, "\007"); 1226 fflush(gpoutfile); 1227 } 1228} 1229 1230/*------------------------------------------------------------------------------------------------------------------------------------ 1231 SVG_reset 1232------------------------------------------------------------------------------------------------------------------------------------*/ 1233TERM_PUBLIC void 1234SVG_reset () 1235{ 1236} 1237 1238/*------------------------------------------------------------------------------------------------------------------------------------ 1239 SVG_linetype 1240------------------------------------------------------------------------------------------------------------------------------------*/ 1241TERM_PUBLIC void 1242SVG_linetype (int linetype) 1243{ 1244 SVG_color_mode = TC_DEFAULT; 1245 if (TRUE || linetype != SVG_LineType) { 1246 SVG_PathClose (); 1247 SVG_GroupClose (); 1248 SVG_LineType = linetype; 1249 SVG_GroupOpen (); 1250 } 1251 if (linetype == LT_AXIS) 1252 SVG_dashpattern = SVG_axis_dashpattern; 1253 if (linetype == LT_SOLID) 1254 SVG_dashpattern = NULL; 1255} 1256 1257/*------------------------------------------------------------------------------------------------------------------------------------ 1258 SVG_dashtype 1259------------------------------------------------------------------------------------------------------------------------------------*/ 1260TERM_PUBLIC void 1261SVG_dashtype (int type, t_dashtype *custom_dash_type) 1262{ 1263 int d, j; 1264 double empirical_scale = 0.50; 1265 /* The dash pattern should depend on the `linewidth` and the terminal options `dashlength` and `linewidth`. */ 1266 double dash_scale = SVG_pens[SVG_Pen_RealID (SVG_LineType)].width * SVG_linewidth_factor * SVG_dashlength * empirical_scale; 1267 1268 SVG_dashpattern = NULL; /* Assume solid line */ 1269 1270 switch(type) { 1271 1272 case DASHTYPE_SOLID: 1273 break; 1274 1275 case DASHTYPE_AXIS: 1276 /* Currently handled elsewhere via LT_AXIS */ 1277 break; 1278 1279 case DASHTYPE_CUSTOM: 1280 if (custom_dash_type) { 1281 SVG_dashpattern = SVG_custom_dash_pattern; 1282 *SVG_dashpattern = '\0'; 1283 for (j = 0; j < 8 && custom_dash_type->pattern[j] > 0; j++) { 1284 char *p = &SVG_dashpattern[strlen(SVG_dashpattern)]; 1285 snprintf(p, 8, "%.1f", custom_dash_type->pattern[j] * dash_scale); 1286 if (j < 7 && custom_dash_type->pattern[j+1]) 1287 strcat(p,","); 1288 } 1289 } 1290 break; 1291 1292 default: 1293 /* Fall back to whatever version 4 would have provided */ 1294 d = type % SVG_dashtypes; 1295 if (d <= 0) 1296 break; 1297 1298 /* Default dash length and sequence */ 1299 if (dash_scale == 1.0) 1300 SVG_dashpattern = SVG_defaultdashpattern[d]; 1301 1302 /* Dash patterns scaled up by dashlength and linewidth */ 1303 else { 1304 SVG_dashpattern = SVG_custom_dash_pattern; 1305 *SVG_dashpattern = '\0'; 1306 j = 0; 1307 do { 1308 char *p = &SVG_dashpattern[strlen(SVG_dashpattern)]; 1309 snprintf(p, 8, "%.1f", SVG_dasharray[d][j] * dash_scale); 1310 if (SVG_dasharray[d][++j]) 1311 strcat(p,","); 1312 } while (SVG_dasharray[d][j] > 0); 1313 } 1314 break; 1315 } 1316} 1317 1318TERM_PUBLIC void 1319SVG_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height) 1320{ 1321 gpiPoint corner[4]; 1322 1323 corner[0].x = x1; corner[0].y = y1; 1324 corner[1].x = x1+width; corner[1].y = y1; 1325 corner[2].x = x1+width; corner[2].y = y1+height; 1326 corner[3].x = x1; corner[3].y = y1+height; 1327 corner->style = style; 1328 1329 SVG_filled_polygon(4, corner); 1330} 1331 1332/*------------------------------------------------------------------------------------------------------------------------------------ 1333 SVG_linewidth - verificare 1334------------------------------------------------------------------------------------------------------------------------------------*/ 1335TERM_PUBLIC void 1336SVG_linewidth (double linewidth) 1337{ 1338 if (linewidth != SVG_LineWidth) { 1339 short k; 1340 1341 SVG_LineWidth = linewidth; 1342 1343 for (k = 0; k < 16; k++) 1344 SVG_pens[k].width = SVG_LineWidth; 1345 1346 SVG_PathClose (); 1347 SVG_GroupClose (); 1348 SVG_GroupOpen (); 1349 } 1350} 1351 1352/*------------------------------------------------------------------------------------------------------------------------------------ 1353 SVG_move 1354------------------------------------------------------------------------------------------------------------------------------------*/ 1355TERM_PUBLIC void 1356SVG_move (unsigned int x, unsigned int y) 1357{ 1358 if (x != SVG_xLast || y != SVG_yLast) { 1359 SVG_MoveForced(x, y); 1360 } 1361} 1362 1363/*------------------------------------------------------------------------------------------------------------------------------------ 1364 SVG_vector 1365------------------------------------------------------------------------------------------------------------------------------------*/ 1366TERM_PUBLIC void 1367SVG_vector (unsigned int x, unsigned int y) 1368{ 1369 if (x != SVG_xLast || y != SVG_yLast) { 1370 1371 if (!SVG_pathIsOpen) { 1372 /* The SVG 'path' MUST have a 'moveto' as first command. */ 1373 SVG_MoveForced(SVG_xLast, SVG_yLast); 1374 } 1375 1376 fprintf (gpoutfile, "L%.*f,%.*f", PREC, X(x), PREC, Y(y)); 1377 SVG_path_count++; 1378 1379 SVG_AddSpaceOrNewline (); 1380 1381 SVG_xLast = x; 1382 SVG_yLast = y; 1383 } 1384} 1385 1386/*------------------------------------------------------------------------------------------------------------------------------------ 1387 SVG_point 1388------------------------------------------------------------------------------------------------------------------------------------*/ 1389TERM_PUBLIC void 1390SVG_point (unsigned int x, unsigned int y, int number) 1391{ 1392 char color_spec[0x40]; 1393 if (SVG_color_mode == TC_RGB) { 1394 sprintf(color_spec, " color='rgb(%3d, %3d, %3d)'", 1395 SVG_red, SVG_green, SVG_blue); 1396 if (SVG_alpha != 0.0) 1397 sprintf(&color_spec[27], " opacity='%4.2f'", 1.0 - SVG_alpha); 1398 } else if (SVG_color_mode == TC_LT) 1399 sprintf(color_spec, " color='%s'", SVG_linecolor); 1400 else 1401 *color_spec = '\0'; 1402 1403 SVG_PathClose (); 1404 1405 if (SVG_hypertext_text) { 1406 fprintf(gpoutfile,"\ 1407\t<g onmousemove=\"gnuplot_svg.showHypertext(evt,'%s')\" \ 1408onmouseout=\"gnuplot_svg.hideHypertext()\"><title> </title>\n", 1409 SVG_hypertext_text); 1410 } 1411 1412 if (number < 0) { /* do dot */ 1413 fprintf (gpoutfile, "\ 1414\t<use xlink:href='#gpDot' x='%.*f' y='%.*f'%s/>\n", 1415 PREC, X(x), PREC, Y(y), color_spec); 1416 } else { /* draw a point symbol */ 1417 fprintf (gpoutfile, "\ 1418\t<use xlink:href='#gpPt%u' transform='translate(%.*f,%.*f) scale(%.2f)'%s/>", 1419 number % 15, PREC, X(x), PREC, Y(y), 1420 term_pointsize * term->h_tic / (2 * SVG_SCALE), 1421 color_spec); 1422 } 1423 SVG_xLast = x; 1424 SVG_yLast = y; 1425 1426 if (SVG_hypertext_text) { 1427 fprintf(gpoutfile,"</g>\n"); 1428 free(SVG_hypertext_text); 1429 SVG_hypertext_text = NULL; 1430 } else { 1431 fprintf(gpoutfile,"\n"); 1432 } 1433} 1434 1435/*------------------------------------------------------------------------------------------------------------------------------------ 1436 SVG_justify_text 1437------------------------------------------------------------------------------------------------------------------------------------*/ 1438TERM_PUBLIC int 1439SVG_justify_text (enum JUSTIFY mode) 1440{ 1441 SVG_TextJust = mode; 1442 return (TRUE); 1443} 1444 1445/*------------------------------------------------------------------------------------------------------------------------------------ 1446 SVG_text_angle 1447------------------------------------------------------------------------------------------------------------------------------------*/ 1448TERM_PUBLIC int 1449SVG_text_angle (int ang) 1450{ 1451 /* Can only do pure horizontal or vertical */ 1452 SVG_TextAngle = ang; 1453 return (TRUE); 1454} 1455 1456/*------------------------------------------------------------------------------------------------------------------------------------ 1457 SVG_put_text 1458------------------------------------------------------------------------------------------------------------------------------------*/ 1459TERM_PUBLIC void 1460SVG_put_text (unsigned int x, unsigned int y, const char *str) 1461{ 1462 char *alignment; 1463 double vertical_offset; 1464 int h = x, v = y; 1465 1466 SVG_PathClose (); 1467 1468/* horizontal justification*/ 1469 1470 switch (SVG_TextJust) { 1471 case LEFT: 1472 alignment = "start"; 1473 break; 1474 case CENTRE: 1475 alignment = "middle"; 1476 break; 1477 case RIGHT: 1478 default: /* can't happen, just to make gcc happy */ 1479 alignment = "end"; 1480 break; 1481 } 1482 1483/* vertical justification*/ 1484 vertical_offset = (SVG_fontAscent - SVG_fontDescent) / 2.; 1485 h += vertical_offset * sin(SVG_TextAngle * DEG2RAD); 1486 v -= vertical_offset * cos(SVG_TextAngle * DEG2RAD); 1487 1488/* define text position and attributes */ 1489 1490 fprintf (gpoutfile, "\t<g transform=\"translate(%.*f,%.*f)", PREC, X(h), PREC, Y(v)); 1491 if (SVG_TextAngle) 1492 fprintf (gpoutfile, " rotate(%i)", -SVG_TextAngle); 1493 fprintf (gpoutfile, "\" stroke=\"none\" fill=\""); 1494 1495 if (SVG_color_mode == TC_RGB) 1496 fprintf (gpoutfile, "rgb(%d,%d,%d)", SVG_red, SVG_green, SVG_blue); 1497 else if (SVG_color_mode == TC_LT) 1498 fprintf (gpoutfile, "%s", SVG_linecolor); 1499 else 1500 fprintf (gpoutfile, "%s", SVG_pens[SVG_Pen_RealID (SVG_LineType)].color); 1501 fprintf (gpoutfile, "\" font-family=\"%s\" font-size=\"%.2f\" ", 1502 SVG_fontNameCur, SVG_fontSizeCur * SVG_fontscale); 1503 if (SVG_fontWeightCur && strcmp(SVG_fontWeightCur,"normal")) 1504 fprintf(gpoutfile, " font-weight=\"%s\" ", SVG_fontWeightCur); 1505 if (SVG_fontStyleCur && strcmp(SVG_fontStyleCur,"normal")) 1506 fprintf(gpoutfile, " font-style=\"%s\" ", SVG_fontStyleCur); 1507 fprintf(gpoutfile, " text-anchor=\"%s\"", alignment); 1508#ifdef EAM_BOXED_TEXT 1509 if (SVG_inTextBox) 1510 fprintf(gpoutfile, " style='filter:url(#textbox)'"); 1511#endif 1512 fprintf(gpoutfile, ">\n"); 1513 1514/* output text (unless the enhanced_text processing is in action) */ 1515 1516 if (strstr(str," ")) 1517 fputs ("\t\t<text xml:space=\"preserve\">", gpoutfile); 1518 else 1519 fputs ("\t\t<text>", gpoutfile); 1520 1521 if (!ENHsvg_string_state) { 1522 1523 while (*str) { 1524 /* Escape SVG reserved characters */ 1525 switch (*str) { 1526 case '<': 1527 fputs("<", gpoutfile); 1528 break; 1529 case '&': 1530 if (str[1] == '#' && str[2] == 'x') 1531 fputc(*str, gpoutfile); 1532 else 1533 fputs("&", gpoutfile); 1534 break; 1535 default: 1536 fputc(*str, gpoutfile); 1537 break; 1538 } 1539 1540 str++; 1541 } 1542 fputs("</text>\n\t</g>\n", gpoutfile); 1543 } 1544} 1545 1546/*------------------------------------------------------------------------------------------------------------------------------------ 1547 SVG_set_font 1548------------------------------------------------------------------------------------------------------------------------------------*/ 1549TERM_PUBLIC int 1550SVG_set_font (const char *font) 1551{ 1552 1553 if (!font || !(*font)) { 1554 free(SVG_fontNameCur); 1555 SVG_fontNameCur = gp_strdup(SVG_fontNameDef); 1556 SVG_fontSizeCur = SVG_fontSizeDef; 1557 SVG_fontStyleCur = SVG_fontStyleDef; 1558 SVG_fontWeightCur = SVG_fontWeightDef; 1559 } else { 1560 char *bold, *italic; 1561 int sep; 1562 1563 if (!((bold = strstr(font," bold")))) 1564 bold = strstr(font," Bold"); 1565 1566 if (!((italic = strstr(font," italic")))) 1567 italic = strstr(font," Italic"); 1568 1569 sep = strcspn(font,","); 1570 if (sep > 0) { 1571 free(SVG_fontNameCur); 1572 SVG_fontNameCur = gp_strdup(font); 1573 if (italic) { 1574 SVG_fontStyleCur="italic"; 1575 SVG_fontNameCur[strlen(font) - strlen(italic)] = NUL; 1576 } else { 1577 SVG_fontStyleCur="normal"; 1578 } 1579 1580 if (bold) { 1581 SVG_fontWeightCur="bold"; 1582 SVG_fontNameCur[strlen(font) - strlen(bold)] = NUL; 1583 } else { 1584 SVG_fontWeightCur="normal"; 1585 } 1586 SVG_fontNameCur[sep] = NUL; 1587 } 1588 1589 if (font[sep] == ',') 1590 sscanf(font + sep + 1, "%lf", &SVG_fontSizeCur); 1591 } 1592 1593 /* Set other font properties */ 1594 SVG_SetFont(SVG_fontNameCur, SVG_fontSizeCur); 1595 1596 return (TRUE); 1597} 1598 1599 1600/*------------------------------------------------------------------------------------------------------------------------------------ 1601 SVG_make_palette 1602------------------------------------------------------------------------------------------------------------------------------------*/ 1603TERM_PUBLIC int 1604SVG_make_palette(t_sm_palette *palette) 1605{ 1606 SVG_GroupFilledClose(); 1607 if (palette == NULL) { 1608 /* svg can do continuous colors */ 1609 return 0; 1610 } 1611 1612 /* save mapping formulae needed if SMPAL_COLOR_MODE_RGB */ 1613 SVG_palette.colorMode = palette->colorMode; 1614 SVG_palette.formulaR = palette->formulaR; 1615 SVG_palette.formulaG = palette->formulaG; 1616 SVG_palette.formulaB = palette->formulaB; 1617 SVG_palette.positive = palette->positive; 1618 1619 return 0; 1620} 1621 1622 1623/*------------------------------------------------------------------------------------------------------------------------------------ 1624 SVG_set_color 1625------------------------------------------------------------------------------------------------------------------------------------*/ 1626TERM_PUBLIC void 1627SVG_set_color(t_colorspec *colorspec) 1628{ 1629 rgb255_color rgb255; 1630 SVG_alpha = 0.0; 1631 1632 if (colorspec->type == TC_LT) { 1633 if (SVG_linecolor != SVG_pens[SVG_Pen_RealID (colorspec->lt)].color) { 1634 SVG_linecolor = SVG_pens[SVG_Pen_RealID (colorspec->lt)].color; 1635 SVG_PathClose(); 1636 } 1637 SVG_color_mode = TC_LT; 1638 return; 1639 } else if (colorspec->type == TC_FRAC) { 1640 rgb255maxcolors_from_gray( colorspec->value, &rgb255 ); 1641 } else if (colorspec->type == TC_RGB) { 1642 rgb255.r = colorspec->lt >> 16 & 0xff; 1643 rgb255.g = colorspec->lt >> 8 & 0xff; 1644 rgb255.b = colorspec->lt & 0xff; 1645 SVG_alpha = (double)(colorspec->lt >> 24 & 0xff) / 255.; 1646 } else { 1647 return; 1648 } 1649 1650 SVG_color_mode = TC_RGB; 1651 1652 if (rgb255.r != SVG_red || rgb255.g != SVG_green || rgb255.b != SVG_blue) { 1653 /* pm3d color has changed. We must start a new path 1654 * with a different line color. This is necessary when 1655 * using "linetype palette". */ 1656 SVG_PathClose(); 1657 SVG_red = rgb255.r; 1658 SVG_green = rgb255.g; 1659 SVG_blue = rgb255.b; 1660 } 1661 1662 return; 1663} 1664 1665/*------------------------------------------------------------------------------------------------------------------------------------ 1666 SVG_previous_palette 1667------------------------------------------------------------------------------------------------------------------------------------*/ 1668TERM_PUBLIC void 1669SVG_previous_palette() 1670{ 1671 SVG_GroupFilledClose(); 1672} 1673 1674 1675/*------------------------------------------------------------------------------------------------------------------------------------ 1676 SVG_filled_polygon 1677------------------------------------------------------------------------------------------------------------------------------------*/ 1678TERM_PUBLIC void 1679SVG_filled_polygon(int points, gpiPoint* corners) 1680{ 1681 int i; 1682 int fillpar = corners->style >> 4; 1683 int style = corners->style &= 0xf; 1684 1685 if (style == FS_PATTERN || style == FS_TRANSPARENT_PATTERN) { 1686 /* make sure the pattern is defined (with the current stroke color) 1687 * must be defined AFTER the current group is opened with the color 1688 * attribute set, as the patterns use 'currentColor' */ 1689 SVG_DefineFillPattern(fillpar); 1690 } 1691 1692 SVG_GroupFilledOpen(); 1693 fputs("\t\t<polygon ", gpoutfile); 1694 1695 switch (style) { 1696 case FS_EMPTY: /* fill with background color */ 1697 fprintf(gpoutfile," fill = '%s'", SVG_pens[0].color); 1698 break; 1699 case FS_SOLID: /* solid fill */ 1700 case FS_TRANSPARENT_SOLID: 1701 SVG_StyleFillColor(); 1702 if (SVG_alpha != 0.0) 1703 fprintf(gpoutfile, " fill-opacity='%4.2f' ", 1.0 - SVG_alpha); 1704 else if (fillpar >= 0 && fillpar < 100) 1705 fprintf(gpoutfile, " fill-opacity = '%f'", fillpar * 0.01); 1706 break; 1707 case FS_PATTERN: /* pattern fill */ 1708 case FS_TRANSPARENT_PATTERN: 1709 fprintf(gpoutfile, " fill = 'url(#gpPat%d)'", 1710 SVG_fillPatternIndex); 1711 break; 1712 default: 1713 SVG_StyleFillColor(); 1714 break; 1715 } 1716 1717 fputs(" points = '", gpoutfile); 1718 for (i = 0; i < points; i++) 1719 fprintf(gpoutfile, "%.*f,%.*f%s", 1720 PREC, X(corners[i].x), PREC, Y(corners[i].y), 1721 i % 16 == 15 ? "\n" : " "); 1722 fputs("'/>\n", gpoutfile); 1723} 1724 1725/*------------------------------------------------------------------------------------------------------------------------------------ 1726 SVG_layer 1727------------------------------------------------------------------------------------------------------------------------------------*/ 1728TERM_PUBLIC void 1729SVG_layer(t_termlayer syncpoint) 1730{ 1731 char *name = NULL; 1732 char panel[2] = {'\0','\0'}; 1733 1734 /* We must ignore all syncpoints that we don't recognize */ 1735 switch (syncpoint) { 1736 1737 default: 1738 break; 1739 1740 case TERM_LAYER_BEFORE_PLOT: 1741 SVG_PathClose(); 1742 SVG_GroupClose(); 1743 ++SVG_plotno; 1744 name = (SVG_name) ? SVG_name : "gnuplot"; 1745 if (multiplot && multiplot_current_panel() < 26) 1746 panel[0] = 'a' + multiplot_current_panel(); 1747 1748 fprintf(gpoutfile, "\t<g id=\"%s_plot_%d%s\" ", name,SVG_plotno,panel); 1749 if (SVG_hypertext_text && *SVG_hypertext_text) 1750 fprintf(gpoutfile, "><title>%s</title>\n", SVG_hypertext_text); 1751 else 1752 fprintf(gpoutfile, "><title>%s_plot_%d%s</title>\n", name,SVG_plotno,panel); 1753 free(SVG_hypertext_text); 1754 SVG_hypertext_text = NULL; 1755 SVG_LineType = LT_UNDEFINED; /* Force a new group on next stroke */ 1756 break; 1757 1758 case TERM_LAYER_AFTER_PLOT: 1759 SVG_PathClose(); 1760 SVG_GroupClose(); 1761 fprintf(gpoutfile, "\t</g>\n"); 1762 SVG_LineType = LT_UNDEFINED; /* Force a new group on next stroke */ 1763 break; 1764 1765 case TERM_LAYER_BEGIN_GRID: 1766 SVG_gridline = TRUE; 1767 SVG_hasgrid = TRUE; 1768 break; 1769 1770 case TERM_LAYER_END_GRID: 1771 SVG_gridline = FALSE; 1772 break; 1773 1774 case TERM_LAYER_BEGIN_KEYSAMPLE: 1775 if (SVG_mouseable) { 1776 SVG_PathClose(); 1777 SVG_GroupFilledClose(); 1778 name = (SVG_name) ? SVG_name : "gnuplot"; 1779 if (multiplot && multiplot_current_panel() < 26) 1780 panel[0] = 'a' + multiplot_current_panel(); 1781 1782 fprintf(gpoutfile, "\t<g id=\"%s_plot_%d%s_keyentry\" visibility=\"visible\" ", 1783 name,SVG_plotno,panel); 1784 fprintf(gpoutfile, 1785 "onclick=\"gnuplot_svg.toggleVisibility(evt,'%s_plot_%d%s')\"", 1786 name,SVG_plotno,panel); 1787 fprintf(gpoutfile, ">\n"); 1788 } 1789 break; 1790 1791 case TERM_LAYER_END_KEYSAMPLE: 1792 if (SVG_mouseable) { 1793 SVG_PathClose(); 1794 SVG_GroupFilledClose(); 1795 fprintf(gpoutfile, "\t</g>\n"); 1796 } 1797 break; 1798 1799 case TERM_LAYER_RESET: 1800 case TERM_LAYER_RESET_PLOTNO: 1801 SVG_plotno = 0; 1802 break; 1803 } 1804} 1805 1806/*------------------------------------------------------------------------------------------------------------------------------------ 1807 SVG_image 1808------------------------------------------------------------------------------------------------------------------------------------*/ 1809#ifdef WRITE_PNG_IMAGE 1810TERM_PUBLIC void 1811SVG_image (unsigned m, unsigned n, coordval *image, gpiPoint *corner, t_imagecolor color_mode) 1812{ 1813 SVG_PathClose(); 1814 1815 /* Map image onto the terminal's coordinate system. */ 1816 fprintf(gpoutfile, "<image x='%.*f' y='%.*f' width='%.*f' height='%.*f' preserveAspectRatio='none' ", 1817 PREC, X(corner[0].x), PREC, Y(corner[0].y), 1818 PREC, X(corner[1].x) - X(corner[0].x), PREC, Y(corner[1].y) - Y(corner[0].y)); 1819 1820 /* Feb 2017 - always embed images */ 1821 if (TRUE || SVG_standalone || SVG_domterm) { 1822 /* Embed the PNG file in SVG by converting to base64 */ 1823 fprintf(gpoutfile, "xlink:href='data:image/png;base64,"); 1824 if (write_png_base64_image(m, n, image, color_mode, gpoutfile)) 1825 os_error(NO_CARET, "SVG_image: could not write to gnuplot output file."); 1826 fprintf(gpoutfile, "'/>\n"); 1827 1828 } else { 1829 /* Write the image to a png file */ 1830 char *image_file; 1831 char *base_name = SVG_name ? SVG_name : "gp"; 1832 int wpiresult; 1833 1834 image_file = gp_alloc(strlen(base_name)+16, "SVG_image"); 1835 sprintf(image_file, "%s_image_%02d.png", base_name, ++SVG_imageno); 1836 wpiresult = write_png_image(m, n, image, color_mode, image_file); 1837 1838 /* Reference the png image file */ 1839 fprintf(gpoutfile, "xlink:href='%s_image_%02d.png'/>\n", 1840 base_name, SVG_imageno); 1841 1842 free(image_file); 1843 1844 if (wpiresult != 0) 1845 os_error(NO_CARET, "SVG_image: could not write to PNG reference file."); 1846 } 1847} 1848#endif 1849 1850 1851/* Enhanced text mode support starts here */ 1852 1853static double ENHsvg_base = 0.0; 1854static TBOOLEAN ENHsvg_opened_string = FALSE; 1855static int ENHsvg_charcount = 0; 1856 1857TERM_PUBLIC void 1858ENHsvg_OPEN( 1859 char *fontname, 1860 double fontsize, double base, 1861 TBOOLEAN widthflag, TBOOLEAN showflag, 1862 int overprint) 1863{ 1864 /* overprint = 1 means print the base text (leave position in center) 1865 * overprint = 2 means print the overlying text 1866 * overprint = 3 means save current position 1867 * overprint = 4 means restore saved position 1868 * EAM FIXME - Unfortunately I can find no way in the svg spec to do this. 1869 * The best I can come up with is to count characters from here and then 1870 * try to back up over them. 1871 */ 1872 switch (overprint) { 1873 case 2: 1874 /* FIXME: If there are multiple overprint characters, 1875 * they all get piled on top of one another. 1876 */ 1877 ENHsvg_FLUSH(); 1878 fprintf(gpoutfile, "<tspan dx=\"-%.1fem\" dy=\"%.1fpx\">", 1879 0.5 * ENHsvg_charcount, ENHsvg_base-base); 1880 ENHsvg_base = base; 1881 ENHsvg_x_offset = 0.0; 1882 enhanced_cur_text = enhanced_text; 1883 ENHsvg_charcount = 0; 1884 ENHsvg_opened_string = TRUE; 1885 break; 1886 case 3: 1887 ENHsvg_charcount = 0; 1888 return; 1889 case 4: 1890 /* Defer setting the offsets until the text arrives */ 1891 ENHsvg_x_offset = -0.5 * ENHsvg_charcount; 1892 ENHsvg_base -= base; 1893 ENHsvg_charcount = 0; 1894 return; 1895 default: 1896 break; 1897 } 1898 1899 if (!ENHsvg_opened_string) { 1900 ENHsvg_opened_string = TRUE; 1901 enhanced_cur_text = enhanced_text; 1902 1903 /* Start a new textspan fragment */ 1904 fputs("<tspan", gpoutfile); 1905 if (!fontname) 1906 fprintf(stderr,"ENHsvg_OPEN: null fontname\n"); 1907 else { 1908 char *family = strdup(fontname); 1909 char *sep = strchr(family, ':'); 1910 if (sep) 1911 *sep = '\0'; 1912 if (strcmp(SVG_fontNameCur, family)) { 1913 free(SVG_fontNameCur); 1914 SVG_fontNameCur = family; 1915 } else { 1916 free(family); 1917 } 1918 fprintf(gpoutfile, " font-family=\"%s\" ", SVG_fontNameCur); 1919 if (strstr(fontname,":Bold")) 1920 fprintf(gpoutfile, " font-weight=\"bold\" "); 1921 if (strstr(fontname,":Italic")) 1922 fprintf(gpoutfile, " font-style=\"italic\" "); 1923 } 1924 if (SVG_fontSizeCur != fontsize) { 1925 SVG_fontSizeCur = fontsize; 1926 fprintf(gpoutfile, " font-size=\"%.1f\"", SVG_fontSizeCur * SVG_fontscale); 1927 } 1928 if (ENHsvg_x_offset != 0) { 1929 fprintf(gpoutfile, " dx=\"%.2fem\"", ENHsvg_x_offset); 1930 ENHsvg_x_offset = 0.0; 1931 } 1932 if (ENHsvg_base != base) { 1933 fprintf(gpoutfile, " dy=\"%.2fpx\"", ENHsvg_base-base); 1934 ENHsvg_base = base; 1935 } 1936 if (!showflag) { 1937 fprintf(gpoutfile, " fill=\"none\""); 1938 } 1939 if (ENHsvg_preserve_spaces) { 1940 fprintf(gpoutfile, " xml:space=\"preserve\""); 1941 } 1942 fputs(">", gpoutfile); 1943 } 1944 1945} 1946 1947TERM_PUBLIC void 1948ENHsvg_FLUSH() 1949{ 1950 if (ENHsvg_opened_string) { 1951 ENHsvg_opened_string = FALSE; 1952 *enhanced_cur_text = '\0'; 1953 fprintf(gpoutfile, "%s</tspan>", enhanced_text); 1954 } 1955} 1956 1957TERM_PUBLIC void 1958ENHsvg_put_text(unsigned int x, unsigned int y, const char *str) 1959{ 1960 1961 /* We need local copies of the starting font properties */ 1962 double fontsize = SVG_fontSizeCur; 1963 static char *fontname = NULL; 1964 1965 free(fontname); 1966 fontname = gp_strdup(SVG_fontNameCur); 1967 1968 /* We need the full set of tags for text, just as normal. But in */ 1969 /* the case of enhanced text ENHsvg_string_state == 1 tells the */ 1970 /* SVG_put_text() to return without actually putting the text. */ 1971 if (ignore_enhanced_text) { 1972 ENHsvg_string_state = 0; 1973 SVG_put_text(x, y, str); 1974 return; 1975 } else { 1976 ENHsvg_string_state = 1; 1977 SVG_put_text(x, y, str); 1978 ENHsvg_string_state = 0; 1979 } 1980 1981 /* EAM FIXME - This is a total hack, to make up for the fact that all */ 1982 /* svg viewers I have tried fail to pick up the xml:space setting from */ 1983 /* the environment. So it has to be set all over again for each text */ 1984 /* fragment. Without this, all whitespace is collapsed to a single ' '.*/ 1985 if (strstr(str," ")) 1986 ENHsvg_preserve_spaces = TRUE; 1987 1988 /* Set up global variables needed by enhanced_recursion() */ 1989 ENHsvg_charcount = 0; 1990 enhanced_fontscale = 1.0; 1991 strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format)); 1992 1993 while (*(str = enhanced_recursion((char *)str, TRUE, 1994 fontname, fontsize, 0.0, TRUE, TRUE, 0))) { 1995 (term->enhanced_flush)(); 1996 enh_err_check(str); 1997 if (!*++str) 1998 break; /* end of string */ 1999 } 2000 2001 /* Make sure we leave with the same font properties as on entry */ 2002 free(SVG_fontNameCur); 2003 SVG_fontNameCur = fontname; 2004 fontname = NULL; 2005 if (SVG_fontSizeCur != fontsize || ENHsvg_base != 0) { 2006 fprintf(gpoutfile, "<tspan font-size=\"%.1f\" dy=\"%.2f\"></tspan>", 2007 fontsize * SVG_fontscale, ENHsvg_base); 2008 SVG_fontSizeCur = fontsize; 2009 ENHsvg_base = 0; 2010 } 2011 ENHsvg_preserve_spaces = FALSE; 2012 2013 /* Close the text section */ 2014 fputs("</text>\n\t</g>\n", gpoutfile); 2015 2016 return; 2017} 2018 2019TERM_PUBLIC void 2020ENHsvg_writec(int c) 2021{ 2022 /* Kludge for phantom box accounting */ 2023 ENHsvg_charcount++; 2024 2025 /* Escape SVG reserved characters. Are there any besides '<' and '&' ? */ 2026 switch (c) { 2027 case '<': 2028 *enhanced_cur_text++ = '&'; 2029 *enhanced_cur_text++ = 'l'; 2030 *enhanced_cur_text++ = 't'; 2031 *enhanced_cur_text++ = ';'; 2032 break; 2033 case '&': 2034 *enhanced_cur_text++ = '&'; 2035 *enhanced_cur_text++ = 'a'; 2036 *enhanced_cur_text++ = 'm'; 2037 *enhanced_cur_text++ = 'p'; 2038 *enhanced_cur_text++ = ';'; 2039 break; 2040 case '\n': 2041 *enhanced_cur_text++ = '\\'; 2042 *enhanced_cur_text++ = 'n'; 2043 break; 2044 case '\376': 2045 /* This is an illegal UTF-8 byte; we use it to escape the reserved '&' */ 2046 if (encoding == S_ENC_DEFAULT) { 2047 *enhanced_cur_text++ = '&'; 2048 break; 2049 } /* else fall through */ 2050 default: 2051 *enhanced_cur_text++ = c; 2052 break; 2053 } 2054 2055 /* Split output stream into chunks rather than overflow the buffer */ 2056 if ((enhanced_cur_text - enhanced_text) >= sizeof(enhanced_text)-1) 2057 ENHsvg_FLUSH(); 2058} 2059 2060TERM_PUBLIC void 2061SVG_path(int p) 2062{ 2063 switch (p) { 2064 case 1: /* Close path */ 2065 fputs("Z ", gpoutfile); 2066 SVG_PathClose(); 2067 break; 2068 case 0: 2069 break; 2070 } 2071} 2072 2073TERM_PUBLIC void 2074SVG_hypertext( int type, const char *text ) 2075{ 2076 if (type != TERM_HYPERTEXT_TOOLTIP && type != TERM_HYPERTEXT_TITLE) 2077 return; 2078 2079 free(SVG_hypertext_text); 2080 if (text) { 2081 char *buffer = gp_alloc(2+5*strlen(text),"escape"); 2082 enhanced_cur_text = buffer; 2083 do { ENHsvg_writec(*text); } 2084 while (*text++); 2085 SVG_hypertext_text = gp_strdup(buffer); 2086 enhanced_cur_text = NULL; 2087 free(buffer); 2088 } else { 2089 SVG_hypertext_text = NULL; 2090 } 2091} 2092 2093#ifdef EAM_BOXED_TEXT 2094TERM_PUBLIC void 2095SVG_boxed_text(unsigned int x, unsigned int y, int option) 2096{ 2097 switch (option) { 2098 case TEXTBOX_INIT: 2099 /* Mark group containing next text item */ 2100 SVG_inTextBox = TRUE; 2101 break; 2102 case TEXTBOX_OUTLINE: 2103 /* Stroke the outline of the bounding box (FIXME: how???) */ 2104 case TEXTBOX_BACKGROUNDFILL: 2105 /* Close the group, which will trigger application of the filter */ 2106 SVG_inTextBox = FALSE; 2107 break; 2108 case TEXTBOX_MARGINS: 2109 /* Adjust the size of the bounding box */ 2110 break; 2111 } 2112} 2113#endif 2114 2115#undef Y 2116#undef X 2117#undef PREC 2118 2119#endif /* TERM_BODY */ 2120 2121#ifdef TERM_TABLE 2122TERM_TABLE_START (svg_driver) 2123 "svg", "W3C Scalable Vector Graphics", 2124 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ , 2125 0 /* vtic */ , 0 /* htic */ , 2126 SVG_options, SVG_init, SVG_reset, SVG_text, null_scale, SVG_graphics, 2127 SVG_move, SVG_vector, SVG_linetype, SVG_put_text, SVG_text_angle, 2128 SVG_justify_text, SVG_point, do_arrow, SVG_set_font, do_pointsize, 2129 TERM_CAN_DASH | TERM_ALPHA_CHANNEL|TERM_LINEWIDTH, 2130 0 /* suspend */, 0 /* resume */ , SVG_fillbox, SVG_linewidth 2131#ifdef USE_MOUSE 2132 , 0, 0, 0, 0, 0 /* no mouse support for svg */ 2133#endif 2134 , SVG_make_palette, 2135 SVG_previous_palette, 2136 SVG_set_color, 2137 SVG_filled_polygon 2138#ifdef WRITE_PNG_IMAGE 2139 , SVG_image 2140#else 2141 , NULL /* image */ 2142#endif 2143 , ENHsvg_OPEN, ENHsvg_FLUSH, ENHsvg_writec 2144 , SVG_layer /* layer */ 2145 , SVG_path /* path */ 2146 , SVG_SCALE /* pixel oversampling scale */ 2147 , SVG_hypertext /* hypertext support */ 2148#ifdef EAM_BOXED_TEXT 2149 , SVG_boxed_text /* boxed text labels */ 2150#endif 2151 , NULL /* modify_plots */ 2152 , SVG_dashtype /* Version 5 dashtype support */ 2153TERM_TABLE_END (svg_driver) 2154 2155#undef LAST_TERM 2156#define LAST_TERM svg_driver 2157 2158TERM_TABLE_START (domterm_driver) 2159 "domterm", "DomTerm terminal emulator with embedded SVG", 2160 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ , 2161 0 /* vtic */ , 0 /* htic */ , 2162 SVG_options, SVG_init, SVG_reset, SVG_text, null_scale, SVG_graphics, 2163 SVG_move, SVG_vector, SVG_linetype, SVG_put_text, SVG_text_angle, 2164 SVG_justify_text, SVG_point, do_arrow, SVG_set_font, do_pointsize, 2165 TERM_CAN_DASH | TERM_ALPHA_CHANNEL|TERM_LINEWIDTH, 2166 0 /* suspend */, 0 /* resume */ , SVG_fillbox, SVG_linewidth 2167#ifdef USE_MOUSE 2168 , 0, 0, 0, 0, 0 /* no mouse support for svg */ 2169#endif 2170 , SVG_make_palette, 2171 SVG_previous_palette, 2172 SVG_set_color, 2173 SVG_filled_polygon 2174#ifdef WRITE_PNG_IMAGE 2175 , SVG_image 2176#else 2177 , NULL /* image */ 2178#endif 2179 , ENHsvg_OPEN, ENHsvg_FLUSH, ENHsvg_writec 2180 , SVG_layer /* layer */ 2181 , SVG_path /* path */ 2182 , SVG_SCALE /* pixel oversampling scale */ 2183 , SVG_hypertext /* hypertext support */ 2184#ifdef EAM_BOXED_TEXT 2185 , SVG_boxed_text /* boxed text labels */ 2186#endif 2187 , NULL /* modify_plots */ 2188 , SVG_dashtype /* Version 5 dashtype support */ 2189TERM_TABLE_END (domterm_driver) 2190 2191#undef LAST_TERM 2192#define LAST_TERM domterm_driver 2193 2194#endif /* TERM_TABLE */ 2195#endif /* TERM_PROTO_ONLY */ 2196 2197#ifdef TERM_HELP 2198START_HELP(svg) 2199"1 svg", 2200"?commands set terminal svg", 2201"?set terminal svg", 2202"?set term svg", 2203"?terminal svg", 2204"?term svg", 2205"?svg", 2206" This terminal produces files in the W3C Scalable Vector Graphics format.", 2207"", 2208" Syntax:", 2209" set terminal svg {size <x>,<y> {|fixed|dynamic}}", 2210" {mouse} {standalone | jsdir <dirname>}", 2211" {name <plotname>}", 2212" {font \"<fontname>{,<fontsize>}\"} {{no}enhanced}", 2213" {fontscale <multiplier>}", 2214" {rounded|butt|square} {solid|dashed} {linewidth <lw>}", 2215" {background <rgb_color>}", 2216"", 2217" where <x> and <y> are the size of the SVG plot to generate,", 2218" `dynamic` allows a svg-viewer to resize plot, whereas the default", 2219" setting, `fixed`, will request an absolute size.", 2220"", 2221" `linewidth <w>` increases the width of all lines used in the figure", 2222" by a factor of <w>.", 2223"", 2224" <font> is the name of the default font to use (default Arial) and", 2225" <fontsize> is the font size (in points, default 12). SVG viewing", 2226" programs may substitute other fonts when the file is displayed.", 2227"", 2228" The enhanced text mode syntax is shared with other gnuplot terminal types.", 2229" See `enhanced` for more details.", 2230"", 2231" The `mouse` option tells gnuplot to add support for mouse tracking and for", 2232" toggling individual plots on/off by clicking on the corresponding key entry.", 2233" By default this is done by including a link that points to a script in a", 2234" local directory, usually /usr/local/share/gnuplot/<version>/js.", 2235" You can change this by using the `jsdir` option to specify either a", 2236" different local directory or a general URL. The latter is usually", 2237" appropriate if you are embedding the svg into a web page.", 2238" Alternatively, the `standalone` option embeds the mousing code in the svg", 2239" document itself rather than linking to an external resource.", 2240"", 2241" When an SVG file will be used in conjunction with external files,", 2242" e.g. if it is referenced by javascript code in a web page or parent document,", 2243" then a unique name is required to avoid potential conflicting references", 2244" to other SVG plots. Use the `name` option to ensure uniqueness.", 2245"" 2246END_HELP(svg) 2247 2248START_HELP(domterm) 2249"1 domterm", 2250"?set terminal domterm", 2251"?terminal domterm", 2252"?set term domterm", 2253"?term domterm", 2254"?domterm", 2255" The `domterm` terminal device runs on the DomTerm terminal emulator", 2256" including the domterm and qtdomterm programs.", 2257" It supports SVG graphics embedded directly in the terminal output.", 2258" See http://domterm.org .", 2259"", 2260" Please read the help for the `svg` terminal.", 2261"" 2262END_HELP(domterm) 2263#endif /* TERM_HELP */ 2264