izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg-graphs-line.h
Go to the documentation of this file.
1// izzi line graphs -*- mode: C++ -*-
2
3// Copyright (c) 2025, Benjamin De Kosnik <b.dekosnik@gmail.com>
4
5// This file is part of the alpha60 library. This library is free
6// software; you can redistribute it and/or modify it under the terms
7// of the GNU General Public License as published by the Free Software
8// Foundation; either version 3, or (at your option) any later
9// version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15
16#ifndef izzi_SVG_GRAPHS_LINE_H
17#define izzi_SVG_GRAPHS_LINE_H 1
18
19#include <set>
20
21#include "izzi-json-basics.h"
24#include "a60-svg-markers.h"
25
26
27namespace svg {
28
29/// Polyline/line options.
30/// 1: use one line with css dasharray and markers mid, end points
31/// 2: use two lines: one with css dasharray and no markerspoints, two
32/// with explicit marker paths and added text tooltips
33/// 3: use two lines and add js + image tooltips: like 2 above
34/// but add image tooltips, with js controlling image visibility.
41
42/**
43 Line Graphs / Line Charts.
44
45 Some Example:
46 https://www.highcharts.com/demo/highcharts/accessible-line
47
48 Outline:
49
50 input has 2 columns: x, y
51 - how many x, what is range, what is delta
52 - how many y, what is range, what is delta
53
54 plot as grid/matrix system given above.
55
56 line: points, linestyle
57
58 x axis: title, tick mark spacing, tick mark style
59 y axis: title, tick mark spacing, tick mark style
60*/
61
62/// Per-graph constants, metadata, configuration, text.
64{
66
67 // visible_mode (render_state_base)
68
69 /// Key data: title, area, mode
70 string title; /// graph title
71 area_type graph_area; /// graph area
72 graph_mode mode; /// chart_line_style_n to use
73
74 /// Margins/Spaces
75 static constexpr uint xmargin = 100;
76 static constexpr uint ymargin = 100;
77 static constexpr uint xticdigits = 1; // sig digits xaxis
78 static constexpr uint yticdigits = 10; // number y tic labelsf
79
80 /// Type sizes.
81 static constexpr uint ttitlesz = 16; // title large bold
82 static constexpr uint th1sz = 12; // h1
83 static constexpr uint tpsz = 10; // text, paragraph,
84 static constexpr uint tticsz = 7; // tic text
85
86 /// Labels, tic units.
87 string xlabel; // x axis label
88 string ylabel;
89 string xticu; // x axis tick mark units postfix
90 string yticu;
91
92 /// Line/Outline/Markers/Tooltip styles
93 style lstyle; /// line style
94 stroke_style sstyle; /// marker stroke style, if any.
95 area_type tooltip_area; /// chart_line_style_3 tooltip size
96 string tooltip_id; /// chart_line_style_3 toolip id prefix
97 string tooltip_images; /// chart_line_style 3 set of image elements
98};
99
100
101/// Simplify sorted vrange by removing interior duplicates.
102vrange
104{
105 // Transform range to the simplest expression, where multiple points
106 // without significant vertical change are coalesed to starting
107 // control point and ending control point.
108 vrange simplevr;
109 point_2t last = { -1.0, -1.0 };
110 double duprangep(false);
111 for (const point_2t& pt : vr)
112 {
113 auto [ x, y] = pt;
114 if (y != get<1>(last))
115 {
116 if (duprangep == true)
117 {
118 simplevr.push_back(last);
119 duprangep = false;
120 }
121 simplevr.push_back(pt);
122 }
123 else
124 duprangep = true;
125 last = pt;
126 }
127 return simplevr;
128}
129
130
131/// Tramsform change points to points where the y-axis (% visual complete) changes
132/// @param points already simplified change points
133vrange
135{
136 vrange simplest;
137 point_2t last = { -1.0, -1.0 };
138 for (const point_2t& pt : points)
139 {
140 auto [ x, y] = pt;
141 if (y != get<1>(last))
142 simplest.push_back(pt);
143 last = pt;
144 }
145 return simplest;
146}
147
148
149/// Tramsform change points to points where the x-axis (time) matches a value in onlypoints.
150/// @param points already simplified change points
151vrange
152find_tooltip_points(const vrange& points, const vspace& onlypoints)
153{
154 vrange edited;
155 for (const space_type& matchx : onlypoints)
156 {
157 for (const auto& pt : points)
158 {
159 auto [ x, y ] = pt;
160 if (x == matchx)
161 {
162 edited.push_back(pt);
163 break;
164 }
165 }
166 }
167 return edited;
168}
169
170
171/// Map data points to cartestian points on graph area.
172/// @param data points
173vrange
175 const graph_rstate& gstate,
176 const point_2t xrange, const point_2t yrange)
177{
178 auto [ minx, maxx ] = xrange;
179 auto [ miny, maxy ] = yrange;
180
181 // Locate graph area on plate area.
182 // aplate is total plate area with margins, aka
183 // pwidth = xmargin + gwidth + xmargin
184 // pheight = ymargin + gheight + ymargin
185 auto [ pwidth, pheight ] = gstate.graph_area;
186 double gwidth = pwidth - (2 * gstate.xmargin);
187 double gheight = pheight - (2 * gstate.ymargin);
188 const double chartyo = pheight - gstate.ymargin;
189
190 // Transform data points to scaled cartasian points in graph area.
191 vrange cpoints;
192 for (uint i = 0; i < points.size(); i++)
193 {
194 const point_2t& pt = points[i];
195 auto [ vx, vy ] = pt;
196
197 // At bottom of graph.
198 const double xlen = scale_value_on_range(vx, minx, maxx, 0, gwidth);
199 double x = gstate.xmargin + xlen;
200
201 // Y axis grows up from chartyo.
202 const double ylen = scale_value_on_range(vy, miny, maxy, 0, gheight);
203 double y = chartyo - ylen;
204
205 cpoints.push_back(std::make_tuple(x, y));
206 }
207 return cpoints;
208}
209
210
211/// Return set of images for image tooltips, one for each point.
212/// @param aimg is size of image embedded inside svg element.
213/// @pathprefix is the path to the directory with the store of images
214/// @idimgbase is the root name for what will be document level unique names of
215/// sequentially numbered images (say fximage-, for fximage-101 et al)
216/// Expected, zero filled imageid.
217/// 2025-06-26-android-15-ptablet-talkback-4usted-firefox_13188.webp
218group_element
219make_line_graph_images(const vrange& points, const graph_rstate& gstate,
220 const string imgprefix,
221 const string imgpath = "../filmstrip/",
222 const string imgext = ".webp")
223{
225 g.start_element(gstate.title + "-tooltip-images");
226 for (const point_2t p : points)
227 {
228 std::ostringstream oss;
229 oss << std::setfill('0') << std::setw(5);
230 oss << static_cast<uint>(std::get<0>(p));
231 const string xms = oss.str();
232
233 const string isrc = imgpath + imgprefix + xms + imgext;
234 const string imgid = gstate.tooltip_id + xms;
235 auto [ width, height ] = gstate.tooltip_area;
236
238 image_element::data di = { isrc, 0, 0, width, height };
239 i.start_element(imgid);
240 i.add_data(di, "anonymous", "hidden", "");
241 //i.add_data(di, "anonymous", "", "none");
242 i.finish_element();
243 g.add_element(i);
244 }
245 g.finish_element();
246 return g;
247}
248
249
250/// Return set of paths of marker shapes with text tooltips.
251string
252make_line_graph_markers(const vrange& points, const vrange& cpoints,
253 const graph_rstate& gstate, const double radius,
254 const string imgidbase = "")
255{
256 string ret;
257 for (uint i = 0; i < points.size(); i++)
258 {
259 auto [ vx, vy ] = points[i];
260 auto [ cx, cy ] = cpoints[i];
261
262 std::ostringstream oss;
263 oss << std::setfill('0') << std::setw(5);
264 oss << static_cast<uint>(vx);
265 const string xms = oss.str();
266 const string imgid = imgidbase + xms;
267
268 // Generate displayed tooltip text....
269 string tipstr(gstate.title);
270 tipstr += k::newline;
271 tipstr += std::to_string(static_cast<uint>(vy));
272 tipstr += '%';
273 tipstr += k::comma;
274 tipstr += k::space;
275 tipstr += std::to_string(static_cast<uint>(vx));
276 tipstr += "ms";
277
278 const string& linecap = gstate.sstyle.linecap;
279 const bool roundp = linecap == "round" || linecap == "circle";
280 const bool squarep = linecap == "square";
281 const bool trianglep = linecap == "triangle";
282
283 // Markers default to closed paths that are filled with no stroke.
284 // Setting visible to vector | echo induces outline behavior.
285 style styl = gstate.lstyle;
286 styl._M_fill_opacity = 1;
287 if (gstate.is_visible(select::echo))
289
290
291 // Circle Centered.
292 // svg::circle_element c = make_circle(cpoints[i], gstate.lstyle, r);
293 if (roundp)
294 {
296 circle_element::data dc = { cx, cy, radius };
297 c.start_element();
298 c.add_data(dc);
299 c.add_style(styl);
300 if (!imgidbase.empty())
303 c.add_title(tipstr);
304 c.add_raw(string { circle_element::pair_finish_tag } + k::newline);
305 ret += c.str();
306 }
307
308 // Square Centered.
309 // svg::rect_element r = (cpoints[i], gstate.lstyle, {2 * r, 2 * r});
310 if (squarep)
311 {
312 rect_element r;
313 rect_element::data dr = { cx - radius, cy - radius,
314 2 * radius, 2 * radius };
315 r.start_element();
316 r.add_data(dr);
317 r.add_style(styl);
318 if (!imgidbase.empty())
321 r.add_title(tipstr);
322 r.add_raw(string { rect_element::pair_finish_tag } + k::newline);
323 ret += r.str();
324 }
325
326 // Triangle Centered.
327 if (trianglep)
328 {
329 string xattr;
330 if (!imgidbase.empty())
332
333 // Visual weight of triangle is smaller, so enlarge slightly.
334 const double tradius = radius * 1.3;
335 path_element p = make_path_triangle(cpoints[i], styl, tradius, 120,
336 false, xattr);
337 p.add_title(tipstr);
338 p.add_raw(string { path_element::pair_finish_tag } + k::newline);
339 ret += p.str();
340 }
341
342 // Throw if marker style not supported.
343 if (!roundp && !squarep && !trianglep)
344 {
345 string m("make_line_graph_markers:: ");
346 m += "linecap value invalid or missing, currently set to: ";
347 m += linecap;
348 m += k::newline;
349 throw std::runtime_error(m);
350 }
351 }
352 return ret;
353}
354
355
356/// Axis Labels
357/// Axis X/Y Ticmarks
358/// X line increments
359///
360/// @param aplate = total size of graph area
361/// @param points = vector of {x,y} points to graph
362/// @param gstate = graph render state
363/// @param xscale = scale x axis by this ammount (1000 if converting ms to s)
364/// @param yscale = scale y axis by this ammount
365/// @param typo = typography to use for labels
366svg_element
368 const graph_rstate& gstate,
369 const double xscale = 1, const double yscale = 1,
370 const typography typo = k::apercu_typo)
371{
372 using namespace std;
373 svg_element lanno(gstate.title, "line graph annotation", gstate.graph_area, false);
374
375 // Locate graph area on plate area.
376 auto [ pwidth, pheight ] = gstate.graph_area;
377 double gwidth = pwidth - (2 * gstate.xmargin);
378 double gheight = pheight - (2 * gstate.ymargin);
379 const double chartyo = pheight - gstate.ymargin;
380 const double chartxo = gstate.xmargin;
381 const double chartxe = pwidth - gstate.xmargin;
382
383 // Base typo for annotations.
384 typography anntypo = typo;
385 anntypo._M_style = k::wcagg_style;
387
388 // Axes and Labels
389 if (gstate.is_visible(select::axis))
390 {
391 lanno.add_raw(group_element::start_group("axes-" + gstate.title));
392
393 // Add axis labels.
394 point_2t xlabelp = make_tuple(pwidth / 2, chartyo + (gstate.ymargin / 2));
395 styled_text(lanno, gstate.xlabel, xlabelp, anntypo);
396
397 point_2t ylabelp = make_tuple(chartxo / 2, pheight / 2);
398 styled_text(lanno, gstate.ylabel, ylabelp, anntypo);
399
400 // Add axis lines.
401 line_element lx = make_line({chartxo, chartyo}, {chartxe, chartyo},
402 gstate.lstyle);
403 line_element ly = make_line({chartxo, chartyo}, {chartxo, gstate.ymargin},
404 gstate.lstyle);
405 lanno.add_element(lx);
406 lanno.add_element(ly);
407
409 }
410
411 // Base typo for tic labels.
412 // NB: Assume pointsx/pointsy are monotonically increasing.
415
416 // Separate tic label values for each (x, y) axis, find ranges for each.
417 auto [ maxx, maxy ] = max_vrange(points, gstate.xticdigits, xscale, yscale);
418 auto minx = 0;
419 auto miny = 0;
420
421 const double xrange(maxx - minx);
422 const double gxscale(gwidth / xrange);
423 const double yrange(maxy - miny);
424 const double gyscale(gheight / yrange);
425
426 // Derive the number of tick marks.
427
428 // Use a multiple of 5 to make natural counting easier.
429 // Start with an assumption of 20 tic marks for the x axis.
430 double xtickn(xrange * 2); // .5 sec
431 if (xtickn < 10)
432 xtickn = 10;
433 if (xtickn > 26)
434 xtickn = xrange;
435
436 // X axis is seconds, xtickn minimum delta is 0.1 sec.
437 double xdelta = std::max(xrange / xtickn, 0.1);
438
439 // Round up to significant digits, so if xdelta is 0.18 round to 0.2.
440 xdelta = std::round(xdelta * gstate.xticdigits * 10) / (gstate.xticdigits * 10);
441
442 // Y axis is simpler, 0, 10, 20, ..., 80, 90, 100 in percent.
443 const double ydelta = yrange / gstate.yticdigits;
444
445 // Generate tic marks
446 const double ygo = gstate.ymargin + gheight + graph_rstate::th1sz;
447 if (gstate.is_visible(select::ticks))
448 {
449 // X tic labels
450 lanno.add_raw(group_element::start_group("tic-x-" + gstate.title));
451 for (double x = minx; x < maxx; x += xdelta)
452 {
453 const double xto = chartxo + (x * gxscale);
454 ostringstream oss;
455 oss << fixed << setprecision(gstate.xticdigits) << x;
456 const string sxui = oss.str() + gstate.xticu;
457 styled_text(lanno, sxui, {xto, ygo}, anntypo);
458 }
460
461 // Y tic labels
462 // Positions for left and right y-axis tic labels.
463 lanno.add_raw(group_element::start_group("tic-y-" + gstate.title));
464 const double yticspacer = graph_rstate::th1sz * 2;
465 const double xgol = gstate.xmargin - yticspacer; // left
466 const double xgor = gstate.xmargin + gwidth + yticspacer; // right
467 const double starty = miny != 0 ? miny : miny + ydelta; // skip zero label
468 for (double y = starty; y < maxy + ydelta; y += ydelta)
469 {
470 const double yto = chartyo - (y * gyscale);
471 const string syui = std::to_string(static_cast<uint>(y)) + gstate.yticu;
472 styled_text(lanno, syui, {xgol, yto}, anntypo);
473 styled_text(lanno, syui, {xgor, yto}, anntypo);
474 }
476 }
477
478 // Horizontal lines linking left and right y-axis tic label value to each other,
479 // perhaps with magnification-ready micro text.
480 if (gstate.is_visible(select::linex))
481 {
482 lanno.add_raw(group_element::start_group("tic-y-lines-" + gstate.title));
483
484 style hlstyl = gstate.lstyle;
486
487 anntypo._M_size = 3;
488 //anntypo._M_style.set_colors(color::gray20);
489 for (double y = miny + ydelta; y < maxy + ydelta; y += ydelta)
490 {
491 // Base line layer.
492 const double yto = chartyo - (y * gyscale);
493 line_element lxe = make_line({chartxo + graph_rstate::th1sz, yto},
494 {chartxe - graph_rstate::th1sz, yto}, hlstyl);
495 lanno.add_element(lxe);
496
497 // Add y-axis tic numbers along line for use when magnified.
498 if (gstate.is_visible(select::alt))
499 {
500 // Skip first and last as covered by either Y-axes tic marks.
501 for (double x = minx + xdelta; x < maxx - xdelta; x += xdelta)
502 {
503 const double xto = chartxo + (x * gxscale);
504 const string syui = std::to_string(static_cast<uint>(y)) + gstate.yticu;
505 styled_text(lanno, syui, {xto, yto}, anntypo);
506 }
507 }
508 }
509
511 }
512
513 return lanno;
514}
515
516
517/// Returns a svg_element with the rendered line graph (char).
518/// Assumptions:
519/// vgrange x axis is monotonically increasing
520///
521/// NB1: Axes and labels drawn in a separate pass (make_line_graph_annotations).
522/// NB2: Output file of x-axis point values for image tooltips if strategy = 3.
523///
524/// @param aplate = total size of graph area
525/// @param points = vector of {x,y} points to graph
526/// @param gstate = graph render state
527/// @param xrange = unified x-axis range for all graphs if multiplot
528/// @param yrange = unified y-axis range for all graphs if multiplot
529/// @param metadata = image filename prefix for tooltips if present
530svg_element
531make_line_graph(const vrange& points, const graph_rstate& gstate,
532 const point_2t xrange, const point_2t yrange)
533{
534 using namespace std;
535 const vrange cpoints = transform_to_graph_points(points, gstate,
536 xrange, yrange);
537
538 // Plot path of points on cartesian plane.
539 const string gname = gstate.title + "_line_graph";
540 svg_element lgraph(gname, "line graph", gstate.graph_area, false);
541 if (gstate.is_visible(select::vector))
542 {
543 if (gstate.mode == chart_line_style_1)
544 {
545 // Use polyline and CSS-based markerspoints all in one line on layer 1.
546 lgraph.add_raw(group_element::start_group("polyline-" + gstate.title));
547 polyline_element pl1 = make_polyline(cpoints, gstate.lstyle, gstate.sstyle);
548 lgraph.add_element(pl1);
550 }
551 if (gstate.mode == chart_line_style_2)
552 {
553 // Use polyline base line on layer 1.
554 // Use set of marker points paths with value as text tooltips on layer 2.
555 lgraph.add_raw(group_element::start_group("polyline-" + gstate.title));
556 stroke_style no_markerstyle = gstate.sstyle;
557 no_markerstyle.markerspoints = "";
558 polyline_element pl1 = make_polyline(cpoints, gstate.lstyle, no_markerstyle);
559 lgraph.add_element(pl1);
561
562 // Markers + text tooltips.
563 lgraph.add_raw(group_element::start_group("markers-" + gstate.title));
564 string markers = make_line_graph_markers(points, cpoints, gstate, 3);
565 lgraph.add_raw(markers);
567 }
568 if (gstate.mode == chart_line_style_3)
569 {
570 string m("requested mode requires use of different overloaded function");
571 throw std::runtime_error(m);
572 }
573 }
574
575 return lgraph;
576}
577
578
579/// Line graph 3 needs more parameters.
580svg_element
581make_line_graph(const vrange& points, const vrange& tpoints, graph_rstate& gstate,
582 const point_2t xrange, const point_2t yrange,
583 const string metadata, script_element::scope scontext)
584{
585 using namespace std;
586 const vrange cpoints = transform_to_graph_points(points, gstate,
587 xrange, yrange);
588
589 // Plot path of points on cartesian plane.
590 const string gname = gstate.title + "_line_graph";
591 svg_element lgraph(gname, "line graph", gstate.graph_area, false);
592 if (gstate.is_visible(select::vector))
593 {
594 if (gstate.mode == chart_line_style_3)
595 {
596 // Use polyline base line on layer 1 of control points (subset points).
597 // Use set of control points marker paths with value as text tooltips on layer 2.
598 // Use set of image points (subset control points) image elements on layer 3.
599 lgraph.add_raw(group_element::start_group("polyline-" + gstate.title));
600 stroke_style no_markerstyle = gstate.sstyle;
601 no_markerstyle.markerspoints = "";
602 polyline_element pl1 = make_polyline(cpoints, gstate.lstyle, no_markerstyle);
603 lgraph.add_element(pl1);
605
606 // Markers + text tooltips, add image id + js to make image visible.
607 // Use simplified points, aka only the visual change points.
608 const vrange& ctpoints = transform_to_graph_points(tpoints, gstate,
609 xrange, yrange);
610
611 lgraph.add_raw(group_element::start_group("markers-" + gstate.title));
612 string markers = make_line_graph_markers(tpoints, ctpoints, gstate, 3,
613 gstate.tooltip_id);
614 lgraph.add_raw(markers);
616
617 // Add tool images to graph_rstate.
618 // Add this plus script at the same layer of the DOM, which varies.
619 const string imgprefix = metadata + k::hyphen + gstate.title + "_";
620 group_element ttips = make_line_graph_images(tpoints, gstate, imgprefix);
621
622 if (scontext == script_element::scope::element)
623 {
624 lgraph.add_element(ttips);
625 lgraph.add_raw(script_element::tooltip_script(scontext).str());
626 }
627 else
628 gstate.tooltip_images = ttips.str();
629 }
630 }
631
632 return lgraph;
633}
634
635} // namepace svg
636
637#endif
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
static const script_element tooltip_script(const scope context)
void add_style(const style &sty)
void add_data(const data &d, string trans="")
static constexpr const char * pair_finish_tag
static string finish_group()
void add_title(const string &t)
static const string tooltip_attribute(const string &id)
static string start_group(const string name="")
static constexpr const char * pair_finish_tag
static constexpr const char * pair_finish_tag
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void add_raw(const string &raw)
scope
Where is the script element placed? On/within the element itself, or at the document (global)?...
string str() const
void add_element(const element_base &e)
void start_element(const string &id)
static constexpr string finish_tag_hard
line_element make_line(const point_2t origin, const point_2t end, style s, const string dasharray="")
Line primitive.
group_element make_line_graph_images(const vrange &points, const graph_rstate &gstate, const string imgprefix, const string imgpath="../filmstrip/", const string imgext=".webp")
Return set of images for image tooltips, one for each point.
@ pt
Point where 1 pixel x 1/72 dpi x 96 PPI = .26 mm.
unsigned short ushort
Base integer type: positive and negative, signed integral value.
Definition a60-svg.h:56
double scale_value_on_range(const ssize_type value, const ssize_type min, const ssize_type max, const ssize_type nfloor, const ssize_type nceil)
Scale value from min to max on range (nfloor, nceil).
Definition a60-svg.h:186
double space_type
Base floating point type.
Definition a60-svg.h:62
@ alt
alternate use specified in situ
@ ticks
ticks, markers
@ vector
svg path, circle, rectangle, etc.
@ linex
horizontal lines
@ echo
b & w outline version of vector
vrange find_tooltip_points(const vrange &points, const vspace &onlypoints)
Tramsform change points to points where the x-axis (time) matches a value in onlypoints.
graph_mode
Polyline/line options. 1: use one line with css dasharray and markers mid, end points 2: use two line...
path_element make_path_triangle(const point_2t origin, const style styl, const double r=4, const double angle=120, const bool selfclosingtagp=true, const string xattr="")
Center a triangle at this point.
void styled_text(element_base &obj, const string text, const point_2t origin, const typography typo)
Text at.
svg_element make_line_graph(const vrange &points, const graph_rstate &gstate, const point_2t xrange, const point_2t yrange)
Returns a svg_element with the rendered line graph (char). Assumptions: vgrange x axis is monotonical...
svg_element make_line_graph_annotations(const vrange &points, const graph_rstate &gstate, const double xscale=1, const double yscale=1, const typography typo=k::apercu_typo)
Axis Labels Axis X/Y Ticmarks X line increments.
std::vector< point_2t > vrange
Definition a60-svg.h:86
point_2t max_vrange(vspace &xpoints, vspace &ypoints, const uint pown)
For each dimension of vrnage, find min/max and return (xmax, ymax) NB: Assumes zero is min.
Definition a60-svg.h:117
std::vector< double > vspace
Split range, so one dimension of (x,y) cartesian plane.
Definition a60-svg.h:82
vrange transform_to_graph_points(const vrange &points, const graph_rstate &gstate, const point_2t xrange, const point_2t yrange)
Map data points to cartestian points on graph area.
string make_line_graph_markers(const vrange &points, const vrange &cpoints, const graph_rstate &gstate, const double radius, const string imgidbase="")
Return set of paths of marker shapes with text tooltips.
vrange find_change_points(const vrange &vr)
Simplify sorted vrange by removing interior duplicates.
vrange find_visual_change_points(const vrange &points)
Tramsform change points to points where the y-axis (% visual complete) changes.
unsigned int uint
Definition a60-svg.h:57
polyline_element make_polyline(const vrange &points, const style s, const stroke_style sstyle={ })
Polyline primitive.
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space.
Definition a60-svg.h:65
Per-graph constants, metadata, configuration, text.
string title
Key data: title, area, mode.
static constexpr uint yticdigits
area< space_type > area_type
static constexpr uint xticdigits
string tooltip_id
chart_line_style_3 tooltip size
static constexpr uint th1sz
area_type tooltip_area
marker stroke style, if any.
area_type graph_area
graph title
string xlabel
Labels, tic units.
stroke_style sstyle
line style
graph_mode mode
graph area
static constexpr uint tticsz
static constexpr uint ymargin
static constexpr uint xmargin
chart_line_style_n to use
static constexpr uint ttitlesz
Type sizes.
static constexpr uint tpsz
style lstyle
Line/Outline/Markers/Tooltip styles.
string tooltip_images
chart_line_style_3 toolip id prefix
render_state_base(const select m=select::none)
bool is_visible(const select v) const
Additional path/line/polyline stroke styles.
Datum consolidating style preferences.
color_qi _M_fill_color
color_qi _M_stroke_color