Fossil SCM
New algorithm for positioning the labels on a piechart.
Commit
2018ad2cc5c829563ccf452f458745517dcfb814
Parent
732b651afa97258…
1 file changed
+95
-38
+95
-38
| --- src/piechart.c | ||
| +++ src/piechart.c | ||
| @@ -64,10 +64,33 @@ | ||
| 64 | 64 | #if INTERFACE |
| 65 | 65 | #define PIE_OTHER 0x0001 /* No wedge less than 1/60th of the circle */ |
| 66 | 66 | #define PIE_CHROMATIC 0x0002 /* Wedge colors are in chromatic order */ |
| 67 | 67 | #define PIE_PERCENT 0x0004 /* Add "(XX%)" marks on each label */ |
| 68 | 68 | #endif |
| 69 | + | |
| 70 | +/* | |
| 71 | +** A pie-chart wedge label | |
| 72 | +*/ | |
| 73 | +struct WedgeLabel { | |
| 74 | + double rCos, rSin; /* Sine and Cosine of center angle of wedge */ | |
| 75 | + char *z; /* Label to draw on this wedge */ | |
| 76 | +}; | |
| 77 | +typedef struct WedgeLabel WedgeLabel; | |
| 78 | + | |
| 79 | +/* | |
| 80 | +** Comparison callback for qsort() to sort labels in order of increasing | |
| 81 | +** distance above and below the horizontal centerline. | |
| 82 | +*/ | |
| 83 | +static int wedgeCompare(const void *a, const void *b){ | |
| 84 | + const WedgeLabel *pA = (const WedgeLabel*)a; | |
| 85 | + const WedgeLabel *pB = (const WedgeLabel*)b; | |
| 86 | + double rA = fabs(pA->rCos); | |
| 87 | + double rB = fabs(pB->rCos); | |
| 88 | + if( rA<rB ) return -1; | |
| 89 | + if( rA>rB ) return +1; | |
| 90 | + return 0; | |
| 91 | +} | |
| 69 | 92 | |
| 70 | 93 | /* |
| 71 | 94 | ** Output HTML that will render a pie chart using data from |
| 72 | 95 | ** the PIECHART temporary table. |
| 73 | 96 | ** |
| @@ -88,24 +111,32 @@ | ||
| 88 | 111 | const char *zAnc; /* Anchor point for text */ |
| 89 | 112 | double a1 = 0.0; /* Angle for first edge of slice */ |
| 90 | 113 | double a2; /* Angle for second edge */ |
| 91 | 114 | double a3; /* Angle at middle of slice */ |
| 92 | 115 | int rot; /* Text rotation angle */ |
| 93 | - double sina3, cosa3; /* sin(a3) and cos(a3) */ | |
| 94 | 116 | unsigned char h; /* Hue */ |
| 95 | 117 | const char *zClr; /* Color */ |
| 96 | 118 | int l; /* Large arc flag */ |
| 97 | 119 | int j; /* Wedge number */ |
| 98 | 120 | double rTotal; /* Total piechart.amt */ |
| 99 | 121 | double rTooSmall; /* Sum of pieChart.amt entries less than 1/60th */ |
| 100 | 122 | int nTotal; /* Total number of entries in piechart */ |
| 101 | 123 | int nTooSmall; /* Number of pieChart.amt entries less than 1/60th */ |
| 102 | 124 | const char *zFg; /* foreground color for lines and text */ |
| 125 | + int nWedgeAlloc = 0; /* Slots allocated for aWedge[] */ | |
| 126 | + int nWedge = 0; /* Slots used for aWedge[] */ | |
| 127 | + WedgeLabel *aWedge = 0; /* Labels */ | |
| 128 | + double rUprRight; /* Floor for next label in the upper right quadrant */ | |
| 129 | + double rUprLeft; /* Floor for next label in the upper left quadrant */ | |
| 130 | + double rLwrRight; /* Ceiling for label in the lower right quadrant */ | |
| 131 | + double rLwrLeft; /* Ceiling for label in the lower left quadrant */ | |
| 132 | + int i; /* Loop counter looping over wedge labels */ | |
| 103 | 133 | |
| 104 | 134 | # define SATURATION 128 |
| 105 | 135 | # define VALUE 192 |
| 106 | 136 | # define OTHER_CUTOFF 90.0 |
| 137 | +# define TEXT_HEIGHT 15.0 | |
| 107 | 138 | |
| 108 | 139 | cx = 0.5*width; |
| 109 | 140 | cy = 0.5*height; |
| 110 | 141 | r2 = cx<cy ? cx : cy; |
| 111 | 142 | r = r2 - 80.0; |
| @@ -148,35 +179,23 @@ | ||
| 148 | 179 | y1 = cy - cos(a1)*r; |
| 149 | 180 | a2 = a1 + x*2.0*M_PI; |
| 150 | 181 | x2 = cx + sin(a2)*r; |
| 151 | 182 | y2 = cy - cos(a2)*r; |
| 152 | 183 | a3 = 0.5*(a1+a2); |
| 153 | - sina3 = sin(a3); | |
| 154 | - cosa3 = cos(a3); | |
| 155 | - x3 = cx + sina3*r; | |
| 156 | - y3 = cy - cosa3*r; | |
| 157 | - d1 = r*1.1; | |
| 158 | - x4 = cx + sina3*d1; | |
| 159 | - y4 = cy - cosa3*d1; | |
| 160 | - y5 = y4 - 3.0 + 6.0*(1.0 -cosa3); | |
| 161 | - rot = ((int)(a3*180/M_PI))%180; | |
| 162 | - if( a2-a1 > 0.6 ){ | |
| 163 | - rot = 0; /* Never rotate text on fat slices */ | |
| 164 | - }else if( rot<60 ){ | |
| 165 | - rot = (rot - 60)/3; | |
| 166 | - }else if( rot>120 ){ | |
| 167 | - rot = (rot - 120)/3; | |
| 168 | - }else{ | |
| 169 | - rot = 0; | |
| 170 | - } | |
| 171 | - if( x4<=cx ){ | |
| 172 | - x5 = x4 - 5.0; | |
| 173 | - zAnc = "end"; | |
| 174 | - }else{ | |
| 175 | - x5 = x4 + 4.0; | |
| 176 | - zAnc = "start"; | |
| 177 | - } | |
| 184 | + if( nWedge+1>nWedgeAlloc ){ | |
| 185 | + nWedgeAlloc = nWedgeAlloc*2 + 40; | |
| 186 | + aWedge = fossil_realloc(aWedge, sizeof(aWedge[0])*nWedgeAlloc); | |
| 187 | + } | |
| 188 | + if( pieFlags & PIE_PERCENT ){ | |
| 189 | + int pct = (int)(x*100.0 + 0.5); | |
| 190 | + aWedge[nWedge].z = mprintf("%s (%d%%)", zLbl, pct); | |
| 191 | + }else{ | |
| 192 | + aWedge[nWedge].z = fossil_strdup(zLbl); | |
| 193 | + } | |
| 194 | + aWedge[nWedge].rSin = sin(a3); | |
| 195 | + aWedge[nWedge].rCos = cos(a3); | |
| 196 | + nWedge++; | |
| 178 | 197 | if( (j&1)==0 || (pieFlags & PIE_CHROMATIC)!=0 ){ |
| 179 | 198 | h = 256*j/nTotal; |
| 180 | 199 | }else if( j+2<nTotal ){ |
| 181 | 200 | h = 256*(j+2)/nTotal; |
| 182 | 201 | }else{ |
| @@ -185,26 +204,64 @@ | ||
| 185 | 204 | zClr = rgbName(h,SATURATION,VALUE); |
| 186 | 205 | l = x>=0.5; |
| 187 | 206 | a1 = a2; |
| 188 | 207 | @ <path stroke="%s(zFg)" stroke-width="1" fill="%s(zClr)" |
| 189 | 208 | @ d='M%g(cx),%g(cy)L%g(x1),%g(y1)A%g(r),%g(r) 0 %d(l),1 %g(x2),%g(y2)z'/> |
| 209 | + } | |
| 210 | + qsort(aWedge, nWedge, sizeof(aWedge[0]), wedgeCompare); | |
| 211 | + rUprLeft = height; | |
| 212 | + rLwrLeft = 0; | |
| 213 | + rUprRight = height; | |
| 214 | + rLwrRight = 0; | |
| 215 | + d1 = r*1.1; | |
| 216 | + for(i=0; i<nWedge; i++){ | |
| 217 | + WedgeLabel *p = &aWedge[i]; | |
| 218 | + x3 = cx + p->rSin*r; | |
| 219 | + y3 = cy - p->rCos*r; | |
| 220 | + x4 = cx + p->rSin*d1; | |
| 221 | + y4 = cy - p->rCos*d1; | |
| 222 | + if( y4<=cy ){ | |
| 223 | + if( x4>=cx ){ | |
| 224 | + if( y4>rUprRight ){ | |
| 225 | + y4 = rUprRight; | |
| 226 | + } | |
| 227 | + rUprRight = y4 - TEXT_HEIGHT; | |
| 228 | + }else{ | |
| 229 | + if( y4>rUprLeft ){ | |
| 230 | + y4 = rUprLeft; | |
| 231 | + } | |
| 232 | + rUprLeft = y4 - TEXT_HEIGHT; | |
| 233 | + } | |
| 234 | + }else{ | |
| 235 | + if( x4>=cx ){ | |
| 236 | + if( y4<rLwrRight ){ | |
| 237 | + y4 = rLwrRight; | |
| 238 | + } | |
| 239 | + rLwrRight = y4 + TEXT_HEIGHT; | |
| 240 | + }else{ | |
| 241 | + if( y4<rLwrLeft ){ | |
| 242 | + y4 = rLwrLeft; | |
| 243 | + } | |
| 244 | + rLwrLeft = y4 + TEXT_HEIGHT; | |
| 245 | + } | |
| 246 | + } | |
| 247 | + if( x4<=cx ){ | |
| 248 | + x5 = x4 - 1.0; | |
| 249 | + zAnc = "end"; | |
| 250 | + }else{ | |
| 251 | + x5 = x4 + 1.0; | |
| 252 | + zAnc = "start"; | |
| 253 | + } | |
| 254 | + y5 = y4 - 3.0 + 6.0*(1.0 - p->rCos); | |
| 190 | 255 | @ <line stroke='%s(zFg)' stroke-width='1' |
| 191 | 256 | @ x1='%g(x3)' y1='%g(y3)' x2='%g(x4)' y2='%g(y4)''/> |
| 192 | - if( rot!=0 ){ | |
| 193 | - @ <text text-anchor="%s(zAnc)" transform='rotate(%d(rot),%g(x5),%g(y5))' | |
| 194 | - }else{ | |
| 195 | - @ <text text-anchor="%s(zAnc)" transform='rotate(%d(rot),%g(x5),%g(y5))' | |
| 196 | - } | |
| 197 | - if( pieFlags & PIE_PERCENT ){ | |
| 198 | - int p = (int)(x*100.0 + 0.5); | |
| 199 | - @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(zLbl) (%d(p)%%)</text> | |
| 200 | - }else{ | |
| 201 | - @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(zLbl)</text> | |
| 202 | - } | |
| 257 | + @ <text text-anchor="%s(zAnc)" | |
| 258 | + @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(p->z)</text> | |
| 259 | + fossil_free(p->z); | |
| 203 | 260 | } |
| 204 | 261 | db_finalize(&q); |
| 205 | - | |
| 262 | + fossil_free(aWedge); | |
| 206 | 263 | } |
| 207 | 264 | |
| 208 | 265 | /* |
| 209 | 266 | ** WEBPAGE: test-piechart |
| 210 | 267 | ** |
| 211 | 268 |
| --- src/piechart.c | |
| +++ src/piechart.c | |
| @@ -64,10 +64,33 @@ | |
| 64 | #if INTERFACE |
| 65 | #define PIE_OTHER 0x0001 /* No wedge less than 1/60th of the circle */ |
| 66 | #define PIE_CHROMATIC 0x0002 /* Wedge colors are in chromatic order */ |
| 67 | #define PIE_PERCENT 0x0004 /* Add "(XX%)" marks on each label */ |
| 68 | #endif |
| 69 | |
| 70 | /* |
| 71 | ** Output HTML that will render a pie chart using data from |
| 72 | ** the PIECHART temporary table. |
| 73 | ** |
| @@ -88,24 +111,32 @@ | |
| 88 | const char *zAnc; /* Anchor point for text */ |
| 89 | double a1 = 0.0; /* Angle for first edge of slice */ |
| 90 | double a2; /* Angle for second edge */ |
| 91 | double a3; /* Angle at middle of slice */ |
| 92 | int rot; /* Text rotation angle */ |
| 93 | double sina3, cosa3; /* sin(a3) and cos(a3) */ |
| 94 | unsigned char h; /* Hue */ |
| 95 | const char *zClr; /* Color */ |
| 96 | int l; /* Large arc flag */ |
| 97 | int j; /* Wedge number */ |
| 98 | double rTotal; /* Total piechart.amt */ |
| 99 | double rTooSmall; /* Sum of pieChart.amt entries less than 1/60th */ |
| 100 | int nTotal; /* Total number of entries in piechart */ |
| 101 | int nTooSmall; /* Number of pieChart.amt entries less than 1/60th */ |
| 102 | const char *zFg; /* foreground color for lines and text */ |
| 103 | |
| 104 | # define SATURATION 128 |
| 105 | # define VALUE 192 |
| 106 | # define OTHER_CUTOFF 90.0 |
| 107 | |
| 108 | cx = 0.5*width; |
| 109 | cy = 0.5*height; |
| 110 | r2 = cx<cy ? cx : cy; |
| 111 | r = r2 - 80.0; |
| @@ -148,35 +179,23 @@ | |
| 148 | y1 = cy - cos(a1)*r; |
| 149 | a2 = a1 + x*2.0*M_PI; |
| 150 | x2 = cx + sin(a2)*r; |
| 151 | y2 = cy - cos(a2)*r; |
| 152 | a3 = 0.5*(a1+a2); |
| 153 | sina3 = sin(a3); |
| 154 | cosa3 = cos(a3); |
| 155 | x3 = cx + sina3*r; |
| 156 | y3 = cy - cosa3*r; |
| 157 | d1 = r*1.1; |
| 158 | x4 = cx + sina3*d1; |
| 159 | y4 = cy - cosa3*d1; |
| 160 | y5 = y4 - 3.0 + 6.0*(1.0 -cosa3); |
| 161 | rot = ((int)(a3*180/M_PI))%180; |
| 162 | if( a2-a1 > 0.6 ){ |
| 163 | rot = 0; /* Never rotate text on fat slices */ |
| 164 | }else if( rot<60 ){ |
| 165 | rot = (rot - 60)/3; |
| 166 | }else if( rot>120 ){ |
| 167 | rot = (rot - 120)/3; |
| 168 | }else{ |
| 169 | rot = 0; |
| 170 | } |
| 171 | if( x4<=cx ){ |
| 172 | x5 = x4 - 5.0; |
| 173 | zAnc = "end"; |
| 174 | }else{ |
| 175 | x5 = x4 + 4.0; |
| 176 | zAnc = "start"; |
| 177 | } |
| 178 | if( (j&1)==0 || (pieFlags & PIE_CHROMATIC)!=0 ){ |
| 179 | h = 256*j/nTotal; |
| 180 | }else if( j+2<nTotal ){ |
| 181 | h = 256*(j+2)/nTotal; |
| 182 | }else{ |
| @@ -185,26 +204,64 @@ | |
| 185 | zClr = rgbName(h,SATURATION,VALUE); |
| 186 | l = x>=0.5; |
| 187 | a1 = a2; |
| 188 | @ <path stroke="%s(zFg)" stroke-width="1" fill="%s(zClr)" |
| 189 | @ d='M%g(cx),%g(cy)L%g(x1),%g(y1)A%g(r),%g(r) 0 %d(l),1 %g(x2),%g(y2)z'/> |
| 190 | @ <line stroke='%s(zFg)' stroke-width='1' |
| 191 | @ x1='%g(x3)' y1='%g(y3)' x2='%g(x4)' y2='%g(y4)''/> |
| 192 | if( rot!=0 ){ |
| 193 | @ <text text-anchor="%s(zAnc)" transform='rotate(%d(rot),%g(x5),%g(y5))' |
| 194 | }else{ |
| 195 | @ <text text-anchor="%s(zAnc)" transform='rotate(%d(rot),%g(x5),%g(y5))' |
| 196 | } |
| 197 | if( pieFlags & PIE_PERCENT ){ |
| 198 | int p = (int)(x*100.0 + 0.5); |
| 199 | @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(zLbl) (%d(p)%%)</text> |
| 200 | }else{ |
| 201 | @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(zLbl)</text> |
| 202 | } |
| 203 | } |
| 204 | db_finalize(&q); |
| 205 | |
| 206 | } |
| 207 | |
| 208 | /* |
| 209 | ** WEBPAGE: test-piechart |
| 210 | ** |
| 211 |
| --- src/piechart.c | |
| +++ src/piechart.c | |
| @@ -64,10 +64,33 @@ | |
| 64 | #if INTERFACE |
| 65 | #define PIE_OTHER 0x0001 /* No wedge less than 1/60th of the circle */ |
| 66 | #define PIE_CHROMATIC 0x0002 /* Wedge colors are in chromatic order */ |
| 67 | #define PIE_PERCENT 0x0004 /* Add "(XX%)" marks on each label */ |
| 68 | #endif |
| 69 | |
| 70 | /* |
| 71 | ** A pie-chart wedge label |
| 72 | */ |
| 73 | struct WedgeLabel { |
| 74 | double rCos, rSin; /* Sine and Cosine of center angle of wedge */ |
| 75 | char *z; /* Label to draw on this wedge */ |
| 76 | }; |
| 77 | typedef struct WedgeLabel WedgeLabel; |
| 78 | |
| 79 | /* |
| 80 | ** Comparison callback for qsort() to sort labels in order of increasing |
| 81 | ** distance above and below the horizontal centerline. |
| 82 | */ |
| 83 | static int wedgeCompare(const void *a, const void *b){ |
| 84 | const WedgeLabel *pA = (const WedgeLabel*)a; |
| 85 | const WedgeLabel *pB = (const WedgeLabel*)b; |
| 86 | double rA = fabs(pA->rCos); |
| 87 | double rB = fabs(pB->rCos); |
| 88 | if( rA<rB ) return -1; |
| 89 | if( rA>rB ) return +1; |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | /* |
| 94 | ** Output HTML that will render a pie chart using data from |
| 95 | ** the PIECHART temporary table. |
| 96 | ** |
| @@ -88,24 +111,32 @@ | |
| 111 | const char *zAnc; /* Anchor point for text */ |
| 112 | double a1 = 0.0; /* Angle for first edge of slice */ |
| 113 | double a2; /* Angle for second edge */ |
| 114 | double a3; /* Angle at middle of slice */ |
| 115 | int rot; /* Text rotation angle */ |
| 116 | unsigned char h; /* Hue */ |
| 117 | const char *zClr; /* Color */ |
| 118 | int l; /* Large arc flag */ |
| 119 | int j; /* Wedge number */ |
| 120 | double rTotal; /* Total piechart.amt */ |
| 121 | double rTooSmall; /* Sum of pieChart.amt entries less than 1/60th */ |
| 122 | int nTotal; /* Total number of entries in piechart */ |
| 123 | int nTooSmall; /* Number of pieChart.amt entries less than 1/60th */ |
| 124 | const char *zFg; /* foreground color for lines and text */ |
| 125 | int nWedgeAlloc = 0; /* Slots allocated for aWedge[] */ |
| 126 | int nWedge = 0; /* Slots used for aWedge[] */ |
| 127 | WedgeLabel *aWedge = 0; /* Labels */ |
| 128 | double rUprRight; /* Floor for next label in the upper right quadrant */ |
| 129 | double rUprLeft; /* Floor for next label in the upper left quadrant */ |
| 130 | double rLwrRight; /* Ceiling for label in the lower right quadrant */ |
| 131 | double rLwrLeft; /* Ceiling for label in the lower left quadrant */ |
| 132 | int i; /* Loop counter looping over wedge labels */ |
| 133 | |
| 134 | # define SATURATION 128 |
| 135 | # define VALUE 192 |
| 136 | # define OTHER_CUTOFF 90.0 |
| 137 | # define TEXT_HEIGHT 15.0 |
| 138 | |
| 139 | cx = 0.5*width; |
| 140 | cy = 0.5*height; |
| 141 | r2 = cx<cy ? cx : cy; |
| 142 | r = r2 - 80.0; |
| @@ -148,35 +179,23 @@ | |
| 179 | y1 = cy - cos(a1)*r; |
| 180 | a2 = a1 + x*2.0*M_PI; |
| 181 | x2 = cx + sin(a2)*r; |
| 182 | y2 = cy - cos(a2)*r; |
| 183 | a3 = 0.5*(a1+a2); |
| 184 | if( nWedge+1>nWedgeAlloc ){ |
| 185 | nWedgeAlloc = nWedgeAlloc*2 + 40; |
| 186 | aWedge = fossil_realloc(aWedge, sizeof(aWedge[0])*nWedgeAlloc); |
| 187 | } |
| 188 | if( pieFlags & PIE_PERCENT ){ |
| 189 | int pct = (int)(x*100.0 + 0.5); |
| 190 | aWedge[nWedge].z = mprintf("%s (%d%%)", zLbl, pct); |
| 191 | }else{ |
| 192 | aWedge[nWedge].z = fossil_strdup(zLbl); |
| 193 | } |
| 194 | aWedge[nWedge].rSin = sin(a3); |
| 195 | aWedge[nWedge].rCos = cos(a3); |
| 196 | nWedge++; |
| 197 | if( (j&1)==0 || (pieFlags & PIE_CHROMATIC)!=0 ){ |
| 198 | h = 256*j/nTotal; |
| 199 | }else if( j+2<nTotal ){ |
| 200 | h = 256*(j+2)/nTotal; |
| 201 | }else{ |
| @@ -185,26 +204,64 @@ | |
| 204 | zClr = rgbName(h,SATURATION,VALUE); |
| 205 | l = x>=0.5; |
| 206 | a1 = a2; |
| 207 | @ <path stroke="%s(zFg)" stroke-width="1" fill="%s(zClr)" |
| 208 | @ d='M%g(cx),%g(cy)L%g(x1),%g(y1)A%g(r),%g(r) 0 %d(l),1 %g(x2),%g(y2)z'/> |
| 209 | } |
| 210 | qsort(aWedge, nWedge, sizeof(aWedge[0]), wedgeCompare); |
| 211 | rUprLeft = height; |
| 212 | rLwrLeft = 0; |
| 213 | rUprRight = height; |
| 214 | rLwrRight = 0; |
| 215 | d1 = r*1.1; |
| 216 | for(i=0; i<nWedge; i++){ |
| 217 | WedgeLabel *p = &aWedge[i]; |
| 218 | x3 = cx + p->rSin*r; |
| 219 | y3 = cy - p->rCos*r; |
| 220 | x4 = cx + p->rSin*d1; |
| 221 | y4 = cy - p->rCos*d1; |
| 222 | if( y4<=cy ){ |
| 223 | if( x4>=cx ){ |
| 224 | if( y4>rUprRight ){ |
| 225 | y4 = rUprRight; |
| 226 | } |
| 227 | rUprRight = y4 - TEXT_HEIGHT; |
| 228 | }else{ |
| 229 | if( y4>rUprLeft ){ |
| 230 | y4 = rUprLeft; |
| 231 | } |
| 232 | rUprLeft = y4 - TEXT_HEIGHT; |
| 233 | } |
| 234 | }else{ |
| 235 | if( x4>=cx ){ |
| 236 | if( y4<rLwrRight ){ |
| 237 | y4 = rLwrRight; |
| 238 | } |
| 239 | rLwrRight = y4 + TEXT_HEIGHT; |
| 240 | }else{ |
| 241 | if( y4<rLwrLeft ){ |
| 242 | y4 = rLwrLeft; |
| 243 | } |
| 244 | rLwrLeft = y4 + TEXT_HEIGHT; |
| 245 | } |
| 246 | } |
| 247 | if( x4<=cx ){ |
| 248 | x5 = x4 - 1.0; |
| 249 | zAnc = "end"; |
| 250 | }else{ |
| 251 | x5 = x4 + 1.0; |
| 252 | zAnc = "start"; |
| 253 | } |
| 254 | y5 = y4 - 3.0 + 6.0*(1.0 - p->rCos); |
| 255 | @ <line stroke='%s(zFg)' stroke-width='1' |
| 256 | @ x1='%g(x3)' y1='%g(y3)' x2='%g(x4)' y2='%g(y4)''/> |
| 257 | @ <text text-anchor="%s(zAnc)" |
| 258 | @ x='%g(x5)' y='%g(y5)' fill='%s(zFg)'>%h(p->z)</text> |
| 259 | fossil_free(p->z); |
| 260 | } |
| 261 | db_finalize(&q); |
| 262 | fossil_free(aWedge); |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | ** WEBPAGE: test-piechart |
| 267 | ** |
| 268 |