TPCCLIB
Loading...
Searching...
No Matches
svg_legend.c File Reference

Functions for drawing legends to SVG plots. More...

#include "libtpcsvg.h"

Go to the source code of this file.

Functions

void svg_init_legends (SVG_LEGENDS *legends)
void svg_legend_empty (SVG_LEGENDS *legends)
int svg_legend_add (SVG_LEGENDS *legends, const int plot_type, const int symbol_type, const svgSymbolFill symbol_fill, const int color, const char *text)
int svg_create_legends (FILE *fp, struct svg_viewports *vp, SVG_LEGENDS *legends, char *errmsg, int verbose)
char * svg_str_encode (const char *s)

Variables

int SVG_INLINE

Detailed Description

Functions for drawing legends to SVG plots.

Author
Vesa Oikonen

Definition in file svg_legend.c.

Function Documentation

◆ svg_create_legends()

int svg_create_legends ( FILE * fp,
struct svg_viewports * vp,
SVG_LEGENDS * legends,
char * errmsg,
int verbose )

Create SVG plot legends.

Returns
Returns 0 if successful, <>0 in case of error.
Parameters
fpSVG graphics file pointer.
vpStruct containing the viewport sizes.
legendsPointer to struct containing legends.
errmsgChar pointer to string (at least of length 128) where possible error description is copied; set to NULL if not necessary.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 76 of file svg_legend.c.

88 {
89 char tmp[1024], line[128], ilc[9];
90 double xpos, ypos, ygap, size=100.0, trgsize=140.0, circsize=120.0;
91 int ti, len, maxlen, text_space;
92 const int defNr=24;
93// const double hrratio=1.80; // average character height/width
94 const double hrratio=1.20; // average character height/width
95
96 if(verbose>0) printf("%s(fp, vp, legends, errmsg, %d)\n", __func__, verbose);
97
98 /* Check the input */
99 if(vp->label_area_viewport.is==0) return(0);
100 if(legends==NULL || legends->n<1) return(0);
101 if(fp==NULL) {
102 if(errmsg!=NULL) sprintf(errmsg, "file was closed too early");
103 return(1);
104 }
105
106 if(SVG_INLINE) strcpy(ilc, "svg:"); else strcpy(ilc, "");
107
108 /* Create a new viewport for plot legends */
109 strcpy(tmp, "\n <!-- Legends viewport -->\n");
110 sprintf(line, " <%ssvg x=\"%dpx\" y=\"%dpx\" width=\"%dpx\" height=\"%d\"",
112 vp->label_area_viewport.w, vp->label_area_viewport.h); strcat(tmp, line);
113 sprintf(line, "\n viewBox=\"0 0 %d %d\"",
114 vp->label_area_viewport.w, vp->label_area_viewport.h); strcat(tmp, line);
115 strcat(tmp, "\n preserveAspectRatio=\"xMidYMid meet\"");
116 strcat(tmp, ">\n");
117 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(4);}
118
119
120#if(0) // during testing show the vieport with background color
121 sprintf(tmp, " <%srect width=\"%dpx\" height=\"%dpx\" stroke=\"none\" fill=\"red\" fill-opacity=\"0.3\" />\n",
123 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(99);}
124#endif
125
126 /* Set the space for legend text */
127 text_space=(8*vp->label_area_viewport.w)/10;
128
129 /* Determine font size for legends */
130 /* first, based on legend nr */
131 ti=legends->n; if(ti<defNr) ti=defNr;
133 (double)vp->label_area_viewport.h/(double)(ti+1);
134 //printf("vp->label_area_viewport.chr_size := %d\n", vp->label_area_viewport.chr_size);
135 /* then, make smaller based on max length, if necessary */
136 ti=0; maxlen=len=strlen(legends->l[ti].text);
137 for(ti=1; ti<legends->n; ti++) {
138 len=strlen(legends->l[ti].text); if(len>maxlen) maxlen=len;}
139 //printf("legend max length := %d\n", maxlen);
140 if(vp->label_area_viewport.chr_size*maxlen>hrratio*(double)text_space)
141 vp->label_area_viewport.chr_size=hrratio*(double)text_space/(double)maxlen;
142 //printf("vp->label_area_viewport.chr_size := %d\n", vp->label_area_viewport.chr_size);
143 /* Set line gap, if there is space for that */
144 ygap=0; if(legends->n<=2*defNr/3) ygap=vp->label_area_viewport.chr_size/3;
145
146 /* Write legend texts as a group */
147 xpos=(double)(vp->label_area_viewport.w - text_space);
148 ypos=1.5*(double)vp->label_area_viewport.chr_size;
149 sprintf(tmp, " <%sg", ilc);
150 sprintf(line, " font-family=\"Sans-serif\""); strcat(tmp, line);
151 sprintf(line, " text-anchor=\"Start\""); strcat(tmp, line);
152 sprintf(line, " font-size=\"%d\"", vp->label_area_viewport.chr_size); strcat(tmp, line);
153 sprintf(line, " fill=\"black\""); strcat(tmp, line);
154 strcat(tmp, ">\n");
155 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(8);}
156 /* Write one legend text at a time */
157 for(ti=0; ti<legends->n; ti++) {
158 //printf("ti=%d text='%s'\n", ti, legends->l[ti].text);
159 sprintf(tmp, " <%s", ilc);
160 sprintf(line, "text x=\"%g\" y=\"%g\"", xpos, ypos); strcat(tmp, line);
161 sprintf(line, ">"); strcat(tmp, line);
162 char *senc=svg_str_encode(legends->l[ti].text);
163 if(senc==NULL) strcat(tmp, legends->l[ti].text); else {strcat(tmp, senc); free(senc);}
164 strcat(tmp, "</"); strcat(tmp, ilc); strcat(tmp, "text>\n");
165 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(9);}
166 ypos+=ygap+(double)vp->label_area_viewport.chr_size;
167 }
168 sprintf(tmp, " </%sg>\n", ilc);
169 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(10);}
170
171 /* Write legend symbols */
172 xpos=0.5*(double)(vp->label_area_viewport.w - text_space);
173 ypos=1.25*(double)vp->label_area_viewport.chr_size;
174 for(ti=0; ti<legends->n; ti++) {
175 sprintf(tmp, " <%sg", ilc);
176 sprintf(line, " stroke=\"%s\"", svgColorName(legends->l[ti].color)); strcat(tmp, line);
177 sprintf(line, " fill=\"%s\"", svgColorName(legends->l[ti].color)); strcat(tmp, line);
178 if(legends->l[ti].symbol_fill==SYMBOLOPEN) sprintf(line, " fill-opacity=\"0.02\"");
179 else sprintf(line, " fill-opacity=\"0.92\"");
180 strcat(tmp, line);
181 sprintf(line, " stroke-width=\"25\""); strcat(tmp, line);
182 strcat(tmp, ">\n");
183 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(8);}
184
185 /* Line */
186 if(legends->l[ti].plot_type==0 || legends->l[ti].plot_type==1) {
187 sprintf(tmp, " <%sline", ilc);
188 sprintf(line, " x1=\"%g\"", 0.25*xpos); strcat(tmp, line);
189 sprintf(line, " y1=\"%g\"", ypos); strcat(tmp, line);
190 sprintf(line, " x2=\"%g\"", 1.75*xpos); strcat(tmp, line);
191 sprintf(line, " y2=\"%g\"", ypos); strcat(tmp, line);
192 strcat(tmp, " />\n");
193 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(18);}
194 }
195
196 /* Symbol */
197 if(legends->l[ti].plot_type==0 || legends->l[ti].plot_type==2) {
198 sprintf(tmp, " <%suse ", ilc);
199 switch(legends->l[ti].symbol_type) {
200 case RECTANGLE:
201 sprintf(line, "xlink:href=\"#sym-rect\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
202 xpos-0.5*size, ypos-0.5*size, size, size);
203 break;
204 case UPTRIANGLE:
205 sprintf(line, "xlink:href=\"#sym-uptr\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
206 xpos-0.5*trgsize, ypos-0.5*trgsize, trgsize, trgsize);
207 break;
208 case DOWNTRIANGLE:
209 sprintf(line, "xlink:href=\"#sym-dotr\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
210 xpos-0.5*trgsize, ypos-0.5*trgsize, trgsize, trgsize);
211 break;
212 case DIAMOND:
213 sprintf(line, "xlink:href=\"#sym-diam\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
214 xpos-0.5*trgsize, ypos-0.5*trgsize, trgsize, trgsize);
215 break;
216 case LEFTTRIANGLE:
217 sprintf(line, "xlink:href=\"#sym-letr\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
218 xpos-0.5*trgsize, ypos-0.5*trgsize, trgsize, trgsize);
219 break;
220 case RIGHTTRIANGLE:
221 sprintf(line, "xlink:href=\"#sym-ritr\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
222 xpos-0.5*trgsize, ypos-0.5*trgsize, trgsize, trgsize);
223 break;
224 case CIRCLE:
225 default:
226 sprintf(line, "xlink:href=\"#sym-circ\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"",
227 xpos-0.5*circsize, ypos-0.5*circsize, circsize, circsize);
228 break;
229 }
230 strcat(tmp, line);
231 strcat(tmp, " />\n");
232 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(18);}
233 }
234
235
236 sprintf(tmp, " </%sg>\n", ilc);
237 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(10);}
238 ypos+=ygap+(double)vp->label_area_viewport.chr_size;
239 } // next legend
240
241 /* Close the view port */
242 sprintf(tmp, " </%ssvg>\n", ilc);
243 if(svg_write(fp, tmp, errmsg, verbose-5)!=0) {return(9);}
244
245 return(0);
246}
char * svgColorName(const svgColor index)
Definition svg_defs.c:38
int svg_write(FILE *fp, const char *svg_string, char *errmsg, int verbose)
Definition svg_file.c:304
int plot_type
Definition libtpcsvg.h:126
svgColor color
Definition libtpcsvg.h:132
svgSymbolType symbol_type
Definition libtpcsvg.h:128
char text[MAX_SVG_LEGEND_LEN+1]
Definition libtpcsvg.h:134
svgSymbolFill symbol_fill
Definition libtpcsvg.h:130
SVG_LEGEND * l
Definition libtpcsvg.h:146
struct svg_viewport_pos label_area_viewport
Definition libtpcsvg.h:112
int SVG_INLINE
Definition svg_file.c:12
char * svg_str_encode(const char *s)
Definition svg_legend.c:256

Referenced by plot_fit_svg(), plot_fitrange_svg(), and plot_svg().

◆ svg_init_legends()

void svg_init_legends ( SVG_LEGENDS * legends)

Initiate SVG plot legends struct contents; call this once before usage

Parameters
legendsPointer to legends struct

Definition at line 14 of file svg_legend.c.

17 {
18 legends->_init=1;
19 legends->n=0;
20 legends->l=NULL;
21}

Referenced by plot_fit_svg(), plot_fitrange_svg(), and plot_svg().

◆ svg_legend_add()

int svg_legend_add ( SVG_LEGENDS * legends,
const int plot_type,
const int symbol_type,
const svgSymbolFill symbol_fill,
const int color,
const char * text )

Add information of one legend item to legends struct.

Memory will be allocated here.

Returns
Returns 0 when successful, otherwise <>0.
Parameters
legendsPointer to legends structure.
plot_typePlot type: 1=line, 2=symbols, 0=both line and symbols.
symbol_typeSymbol type: RECTANGLE, CIRCLE, UPTRIANGLE, DOWNTRIANGLE, DIAMOND, LEFTTRIANGLE, RIGHTTRIANGLE
symbol_fillSymbol filling: SYMBOLOPEN, SYMBOLFILLED
colorSVG color index.
textPointer to Legend text.

Definition at line 43 of file svg_legend.c.

56 {
57 if(legends==NULL || legends->_init!=1) return 1;
58 if(legends->n==0) legends->l=malloc((legends->n+1)*sizeof(SVG_LEGEND));
59 else legends->l=realloc(legends->l, (legends->n+1)*sizeof(SVG_LEGEND));
60 if(legends->l==NULL) {legends->n=0; return 2;}
61 legends->n++;
62 legends->l[legends->n-1].plot_type=plot_type;
63 legends->l[legends->n-1].symbol_type=symbol_type;
64 legends->l[legends->n-1].symbol_fill=symbol_fill;
65 legends->l[legends->n-1].color=color;
66 strncpy(legends->l[legends->n-1].text, text, MAX_SVG_LEGEND_LEN);
67 legends->l[legends->n-1].text[MAX_SVG_LEGEND_LEN]=(char)0;
68 return 0;
69}
#define MAX_SVG_LEGEND_LEN
Definition libtpcsvg.h:29

Referenced by plot_fit_svg(), plot_fitrange_svg(), and plot_svg().

◆ svg_legend_empty()

void svg_legend_empty ( SVG_LEGENDS * legends)

Empty the legends struct contents and free the allocated memory.

Parameters
legendsPointer to legends struct

Definition at line 26 of file svg_legend.c.

29 {
30 if(legends==NULL) return;
31 if(legends->_init==0 || legends->n<1) return;
32 free(legends->l);
33 legends->n=0;
34}

Referenced by plot_fit_svg(), plot_fitrange_svg(), and plot_svg().

◆ svg_str_encode()

char * svg_str_encode ( const char * s)

Encode special characters for XML, including SVG.

Postcondition
Free the memory of returned string pointer.
Returns
Returns pointer to encoded string. NULL is returned in case of an error, or if encoding is not necessary.
See also
strEncodeForXML
Parameters
sPointer to the string to be encoded.

Definition at line 256 of file svg_legend.c.

259 {
260 if(s==NULL) return(NULL);
261 /* Count the characters needing encoding */
262 int n=0;
263 for(size_t i=0; i<strlen(s); i++) {
264 if(s[i]=='&') {n++; continue;}
265 if(s[i]=='\'') {n++; continue;}
266 if(s[i]=='\"') {n++; continue;}
267 if(s[i]=='<') {n++; continue;}
268 if(s[i]=='>') {n++; continue;}
269 }
270 if(n==0) return(NULL);
271 /* Allocate memory for new string (one char to max 6 chars) */
272 n*=5; n+=strlen(s);
273 char *ns=(char*)malloc(n*sizeof(char));
274 if(ns==NULL) return(NULL);
275 /* Process the string */
276 for(int i=0; i<n; i++) ns[i]=(char)0;
277 for(size_t i=0; i<strlen(s); i++) {
278 if(s[i]=='&') {strcat(ns, "&amp;"); continue;}
279 if(s[i]=='\'') {strcat(ns, "&apos;"); continue;}
280 if(s[i]=='\"') {strcat(ns, "&quot;"); continue;}
281 if(s[i]=='<') {strcat(ns, "&lt;"); continue;}
282 if(s[i]=='>') {strcat(ns, "&gt;"); continue;}
283 ns[strlen(ns)]=s[i];
284 }
285 return(ns);
286}

Referenced by svg_create_legends(), and svg_write_tac().

Variable Documentation

◆ SVG_INLINE

int SVG_INLINE
extern

Write inline SVG (1) or separate SVG file (0)

Definition at line 12 of file svg_file.c.