PluginProbe
E2Pdf – Export Pdf Tool for WordPress / 1.32.17
E2Pdf – Export Pdf Tool for WordPress v1.32.17
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 / StackedBarTrait.php

StackedBarTrait.php in E2Pdf – Export Pdf Tool for WordPress 1.32.17, at vendors/svggraph/StackedBarTrait.php

255 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Copyright (C) 2019-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 trait StackedBarTrait {
25
26 use MultiGraphTrait;
27
28 private $bar_visibility = [];
29
30 // used to determine where the total label should go
31 protected $last_position_pos = [];
32 protected $last_position_neg = [];
33
34 /**
35 * Draws the bars
36 */
37 protected function drawBars()
38 {
39 $this->barSetup();
40
41 $chunk_count = count($this->multi_graph);
42 $datasets = $this->multi_graph->getEnabledDatasets();
43 $bars = '';
44 $legend_entries = [];
45 foreach($this->multi_graph as $bnum => $itemlist) {
46 $item = $itemlist[0];
47
48 // sort the values from bottom to top, assigning position
49 $yplus = $yminus = 0;
50 $chunk_values = [];
51 for($j = 0; $j < $chunk_count; ++$j) {
52 if(!in_array($j, $datasets))
53 continue;
54 $item = $itemlist[$j];
55 if($item->value !== null) {
56 if($item->value < 0) {
57 array_unshift($chunk_values, [$j, $item, $yminus]);
58 $yminus += $item->value;
59 } else {
60 $chunk_values[] = [$j, $item, $yplus];
61 $yplus += $item->value;
62 }
63 }
64 }
65
66 $bar_count = count($chunk_values);
67 $b = 0;
68 foreach($chunk_values as $chunk) {
69 list($j, $item, $start) = $chunk;
70
71 $top = (++$b == $bar_count);
72 $this->setBarVisibility($j, $item, $top);
73
74 $legend_entries[$j][$bnum] = $item;
75 $bars .= $this->drawBar($item, $bnum, $start, null, $j, ['top' => $top]);
76 }
77
78 $this->barTotals($item, $bnum, $yplus, $yminus, $j);
79 }
80
81 // assign legend entries in order of datasets
82 foreach($legend_entries as $j => $dataset)
83 foreach($dataset as $bnum => $item)
84 $this->setBarLegendEntry($j, $bnum, $item);
85
86 return $bars;
87 }
88
89 /**
90 * Displays the bar totals
91 */
92 public function barTotals(DataItem $item, $bnum, $yplus, $yminus, $dataset)
93 {
94 $bar_x = $this->gridPosition($item, $bnum);
95 if($this->getOption('show_bar_totals') && $bar_x !== null) {
96 $cb = $this->getOption('bar_total_callback');
97 if($yplus) {
98 $bar = $this->barDimensions($item, $bnum, 0, null, $dataset);
99 $this->barY($yplus, $bar);
100 if(is_callable($cb)) {
101 $total = call_user_func($cb, $item->key, $yplus);
102 } else {
103 $total = new Number($yplus);
104 $total = $total->format();
105 }
106 $this->addContentLabel('totalpos-' . $dataset, $bnum,
107 $bar['x'], $bar['y'], $bar['width'], $bar['height'], $total);
108 }
109 if($yminus) {
110 $bar = $this->barDimensions($item, $bnum, 0, null, $dataset);
111 $this->barY($yminus, $bar);
112 if(is_callable($cb)) {
113 $total = call_user_func($cb, $item->key, $yminus);
114 } else {
115 $total = new Number($yminus);
116 $total = $total->format();
117 }
118 $this->addContentLabel('totalneg-' . $dataset, $bnum,
119 $bar['x'], $bar['y'], $bar['width'], $bar['height'], $total);
120 }
121 }
122 }
123
124 /**
125 * Overridden to prevent drawing on other bars
126 */
127 public function dataLabelPosition($dataset, $index, &$item, $x, $y, $w, $h,
128 $label_w, $label_h)
129 {
130 list($pos, $target) = parent::dataLabelPosition($dataset, $index, $item,
131 $x, $y, $w, $h, $label_w, $label_h);
132 if(!is_numeric($dataset)) {
133 // doing this supports stacked grouped bar graph totals too
134 list($d) = explode('-', $dataset);
135 if($d === 'totalpos') {
136 if(isset($this->last_position_pos[$index])) {
137 list($lpos, $l_h) = $this->last_position_pos[$index];
138 list($hpos, $vpos) = Graph::translatePosition($lpos);
139 if($vpos == 'ot') {
140 $num_offset = new Number(-$l_h);
141 return ['above 0 ' . $num_offset, $target];
142 }
143 }
144 return ['above', $target];
145 }
146 if($d === 'totalneg') {
147 if(isset($this->last_position_neg[$index])) {
148 list($lpos, $l_h) = $this->last_position_neg[$index];
149 list($hpos, $vpos) = Graph::translatePosition($lpos);
150 if($vpos == 'ob') {
151 $num_offset = new Number($l_h);
152 return ['below 0 ' . $num_offset, $target];
153 }
154 }
155 return ['below', $target];
156 }
157 }
158 if($label_h > $h && Graph::isPositionInside($pos))
159 $pos = str_replace(['top','bottom','above','below'], 'middle', $pos);
160
161 if($item->value > 0)
162 $this->last_position_pos[$index] = [$pos, $label_h];
163 else
164 $this->last_position_neg[$index] = [$pos, $label_h];
165 return [$pos, $target];
166 }
167
168 /**
169 * Returns the style options for bar labels (and totals)
170 */
171 public function dataLabelStyle($dataset, $index, &$item)
172 {
173 $style = parent::dataLabelStyle($dataset, $index, $item);
174
175 if(strpos($dataset, 'total') === 0) {
176
177 // total settings can override label settings
178 $simple = [
179 'font', 'font_size', 'font_weight', 'space', 'type', 'fill',
180 'font_adjust', 'angle', 'round', 'shadow_opacity',
181 'tail_width', 'tail_length',
182 ];
183 foreach($simple as $opt) {
184 $val = $this->getOption('bar_total_' . $opt);
185 if(!empty($val))
186 $style[$opt] = $val;
187 }
188
189 $colour = new Colour($this, $this->getOption('bar_total_colour'));
190 $back_colour = new Colour($this, $this->getOption('bar_total_back_colour'));
191 if(!$colour->isNone())
192 $style['colour'] = $colour;
193 if(!$back_colour->isNone())
194 $style['back_colour'] = $back_colour;
195 $stroke = $this->getOption('bar_total_outline_colour');
196 $stroke_width = $this->getOption('bar_total_outline_thickness');
197 $pad_x = $this->getOption('bar_total_padding_x', 'bar_total_padding');
198 $pad_y = $this->getOption('bar_total_padding_y', 'bar_total_padding');
199
200 if(!empty($stroke))
201 $style['stroke'] = $stroke;
202 if(!empty($stroke_width))
203 $style['stroke_width'] = $stroke_width;
204 if(!empty($pad_x))
205 $style['pad_x'] = $pad_x;
206 if(!empty($pad_y))
207 $style['pad_y'] = $pad_y;
208 }
209 return $style;
210 }
211
212 /**
213 * Returns the maximum (stacked) value
214 */
215 public function getMaxValue()
216 {
217 return $this->multi_graph->getMaxSumValue();
218 }
219
220 /**
221 * Returns the minimum (stacked) value
222 */
223 public function getMinValue()
224 {
225 return $this->multi_graph->getMinSumValue();
226 }
227
228 /**
229 * Sets whether a bar is visible or not
230 */
231 protected function setBarVisibility($dataset, DataItem $item, $top, $override = null)
232 {
233 $k = serialize([$dataset, $item->key]);
234 $this->bar_visibility[$k] = ($override === null ? $item->value != 0 : $override);
235 }
236
237 /**
238 * Returns TRUE if the item is visible on the graph
239 */
240 public function isVisible($item, $dataset = 0)
241 {
242 $k = serialize([$dataset, $item->key]);
243 return isset($this->bar_visibility[$k]) && $this->bar_visibility[$k];
244 }
245
246 /**
247 * Returns the ordering for legend entries
248 */
249 public function getLegendOrder()
250 {
251 return 'reverse';
252 }
253 }
254
255