PluginProbe
E2Pdf – Export Pdf Tool for WordPress / 1.32.49
E2Pdf – Export Pdf Tool for WordPress v1.32.49
1.32.49 1.32.48 1.32.43 1.32.40 1.32.34 1.32.32 1.32.31 1.32.26 1.32.22 1.32.23 1.32.18 1.32.17 1.32.15 trunk 1.00.00 1.00.13 1.01.01 1.02.02 1.03.07 1.04.07 1.05.03 1.06.02 1.07.11 1.08.00 1.08.06 All 72 releases
e2pdf / vendors / svggraph / StackedLineGraph.php

StackedLineGraph.php in E2Pdf – Export Pdf Tool for WordPress 1.32.49, at vendors/svggraph/StackedLineGraph.php

196 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Copyright (C) 2012-2022 Graham Breach
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19 * For more information, please contact <graham@goat1000.com>
20 */
21
22 namespace Goat1000\SVGGraph;
23
24 /**
25 * StackedLineGraph - multiple joined lines with values added together
26 */
27 class StackedLineGraph extends MultiLineGraph {
28
29 public function __construct($w, $h, $settings, $fixed_settings = [])
30 {
31 $fixed = [ 'single_axis' => true ];
32 $fixed_settings = array_merge($fixed, $fixed_settings);
33 parent::__construct($w, $h, $settings, $fixed_settings);
34 }
35
36 protected function draw()
37 {
38 if($this->getOption('log_axis_y'))
39 throw new \Exception('log_axis_y not supported by StackedLineGraph');
40
41 $body = $this->grid() . $this->underShapes();
42 $plots = [];
43 $stack = [];
44
45 $datasets = $this->multi_graph->getEnabledDatasets();
46 foreach($datasets as $i) {
47 $bnum = 0;
48 $cmd = 'M';
49 $path = new PathData;
50 $fillpath = new PathData;
51 $attr = ['fill' => 'none'];
52 $fill = $this->getOption(['fill_under', $i]);
53 $dash = $this->getOption(['line_dash', $i]);
54 $stroke_width = $this->getOption(['line_stroke_width', $i]);
55 if(!empty($dash))
56 $attr['stroke-dasharray'] = $dash;
57 $attr['stroke-width'] = $stroke_width <= 0 ? 1 : $stroke_width;
58
59 $bottom = [];
60 $point_count = 0;
61 foreach($this->multi_graph[$i] as $item) {
62 $x = $this->gridPosition($item, $bnum);
63 // key might not be an integer, so convert to string for $stack
64 $strkey = serialize($item->key);
65 if(!isset($stack[$strkey]))
66 $stack[$strkey] = 0;
67 if($x !== null) {
68 $x = new Number($x);
69 $bottom[] = [$x, $stack[$strkey]];
70 $y = new Number($this->gridY($stack[$strkey] + $item->value));
71 $stack[$strkey] += $item->value;
72
73 $path->add($cmd, $x, $y);
74 if($fill && $fillpath->isEmpty())
75 $fillpath->add('M', $x, $y, 'L');
76 else
77 $fillpath->add($x, $y);
78
79 // no need to repeat same L command
80 $cmd = $cmd == 'M' ? 'L' : '';
81 if($item->value !== null)
82 ++$point_count;
83 }
84 ++$bnum;
85 }
86
87 if($point_count > 0) {
88 $attr['d'] = $path;
89 $attr['stroke'] = $this->getColour(null, 0, $i, false, false);
90 if($this->getOption('semantic_classes'))
91 $attr['class'] = 'series' . $i;
92 $graph_line = $this->element('path', $attr);
93 $fill_style = null;
94
95 if($fill) {
96 // complete the fill area with the previous stack total
97 $cmd = 'L';
98 $opacity = $this->getOption(['fill_opacity', $i]);
99 $bpoints = array_reverse($bottom, TRUE);
100 foreach($bpoints as $pos) {
101 list($x, $ypos) = $pos;
102 $y = $this->gridY($ypos);
103 $fillpath->add($x, $y);
104 }
105 $fillpath->add('z');
106 $fill_style = [
107 'fill' => $this->getColour(null, 0, $i),
108 'd' => $fillpath,
109 'stroke' => $attr['fill'],
110 ];
111 if($opacity < 1)
112 $fill_style['opacity'] = $opacity;
113 if($this->getOption('semantic_classes'))
114 $fill_style['class'] = 'series' . $i;
115 $graph_line = $this->element('path', $fill_style) . $graph_line;
116 }
117
118 $plots[] = $graph_line;
119 unset($attr['d'], $attr['class'], $fill_style['class']);
120
121 // add the markers and associated legend entries
122 $this->line_styles[$i] = $attr;
123 $this->fill_styles[$i] = $fill_style;
124 $bnum = 0;
125 foreach($this->multi_graph[$i] as $item) {
126 $x = $this->gridPosition($item, $bnum);
127 // key might not be an integer, so convert to string for $stack
128 $strkey = serialize($item->key);
129 if($x !== null) {
130 $y = $this->gridY($stack[$strkey]);
131
132 if($item->value !== null) {
133 $marker_id = $this->markerLabel($i, $bnum, $item, $x, $y);
134 $extra = empty($marker_id) ? null : ['id' => $marker_id];
135 $this->addMarker($x, $y, $item, $extra, $i);
136 }
137 }
138 ++$bnum;
139 }
140 }
141 }
142
143 $plots = array_reverse($plots);
144 $all_plots = implode($plots);
145
146 $group = [];
147 $this->clipGrid($group);
148 if($this->getOption('semantic_classes'))
149 $group['class'] = 'series';
150 if(!empty($group))
151 $all_plots = $this->element('g', $group, null, $all_plots);
152
153 $group = [];
154 $shadow_id = $this->defs->getShadow();
155 if($shadow_id !== null)
156 $group['filter'] = 'url(#' . $shadow_id . ')';
157 if(!empty($group))
158 $all_plots = $this->element('g', $group, null, $all_plots);
159
160 list($best_fit_above, $best_fit_below) = $this->bestFitLines();
161 $body .= $best_fit_below;
162 $body .= $all_plots;
163 $body .= $this->overShapes();
164 $body .= $this->axes();
165 $body .= $this->drawMarkers();
166 $body .= $best_fit_above;
167 return $body;
168 }
169
170
171 /**
172 * Returns the maximum value
173 */
174 public function getMaxValue()
175 {
176 return $this->multi_graph->getMaxSumValue();
177 }
178
179 /**
180 * Returns the minimum value
181 */
182 public function getMinValue()
183 {
184 return $this->multi_graph->getMinSumValue();
185 }
186
187 /**
188 * Returns the ordering for legend entries
189 */
190 public function getLegendOrder()
191 {
192 return 'reverse';
193 }
194 }
195
196