TPCCLIB
Loading...
Searching...
No Matches
svg_legend.c
Go to the documentation of this file.
1
5/*****************************************************************************/
6#include "libtpcsvg.h"
7/*****************************************************************************/
9extern int SVG_INLINE;
10/*****************************************************************************/
11
12/*****************************************************************************/
16 SVG_LEGENDS *legends
17) {
18 legends->_init=1;
19 legends->n=0;
20 legends->l=NULL;
21}
22/*****************************************************************************/
23
24/*****************************************************************************/
28 SVG_LEGENDS *legends
29) {
30 if(legends==NULL) return;
31 if(legends->_init==0 || legends->n<1) return;
32 free(legends->l);
33 legends->n=0;
34}
35/*****************************************************************************/
36
37/*****************************************************************************/
45 SVG_LEGENDS *legends,
47 const int plot_type,
49 const int symbol_type,
51 const svgSymbolFill symbol_fill,
53 const int color,
55 const char *text
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}
70/*****************************************************************************/
71
72/*****************************************************************************/
78 FILE *fp,
80 struct svg_viewports *vp,
82 SVG_LEGENDS *legends,
85 char *errmsg,
87 int verbose
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}
247/*****************************************************************************/
248
249/*****************************************************************************/
258 const char *s
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}
287/*****************************************************************************/
288
289/*****************************************************************************/
Header file for libtpcsvg.
#define MAX_SVG_LEGEND_LEN
Definition libtpcsvg.h:29
char * svgColorName(const svgColor index)
Definition svg_defs.c:38
svgSymbolFill
Definition libtpcsvg.h:47
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
void svg_legend_empty(SVG_LEGENDS *legends)
Definition svg_legend.c:26
int SVG_INLINE
Definition svg_file.c:12
void svg_init_legends(SVG_LEGENDS *legends)
Definition svg_legend.c:14
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)
Definition svg_legend.c:43
int svg_create_legends(FILE *fp, struct svg_viewports *vp, SVG_LEGENDS *legends, char *errmsg, int verbose)
Definition svg_legend.c:76
char * svg_str_encode(const char *s)
Definition svg_legend.c:256