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