These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * A query printer for charts series using the jqPlot JavaScript library. |
||
5 | * |
||
6 | * @since 1.8 |
||
7 | * @licence GNU GPL v2 or later |
||
8 | * |
||
9 | * @author mwjames |
||
10 | */ |
||
11 | class SRFjqPlotSeries extends SMWResultPrinter { |
||
12 | |||
13 | /** |
||
14 | * @see SMWResultPrinter::getName |
||
15 | */ |
||
16 | public function getName() { |
||
17 | return wfMessage( 'srf-printername-jqplotseries' )->text(); |
||
18 | } |
||
19 | |||
20 | /** |
||
21 | * Returns an array with the numerical data in the query result. |
||
22 | * |
||
23 | * |
||
24 | * @param SMWQueryResult $result |
||
25 | * @param $outputMode |
||
26 | * |
||
27 | * @return string |
||
28 | */ |
||
29 | protected function getResultText( SMWQueryResult $result, $outputMode ) { |
||
30 | |||
31 | // Get data set |
||
32 | $data = $this->getResultData( $result, $outputMode ); |
||
33 | |||
34 | // Check data availability |
||
35 | if ( $data['series'] === [] ) { |
||
36 | return $result->addErrors( |
||
37 | [ |
||
38 | wfMessage( 'srf-warn-empy-chart' ) |
||
39 | ->inContentLanguage()->text() ] |
||
40 | ); |
||
41 | } else { |
||
42 | $options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) ); |
||
43 | return $this->getFormatOutput( $this->getFormatSettings( $this->getNumbersTicks( $data ), $options ) ); |
||
44 | } |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Returns an array with the numerical data |
||
49 | * |
||
50 | * @since 1.8 |
||
51 | * |
||
52 | * @param SMWQueryResult $result |
||
0 ignored issues
–
show
|
|||
53 | * @param $outputMode |
||
54 | * |
||
55 | * @return array |
||
56 | */ |
||
57 | protected function getResultData( SMWQueryResult $res, $outputMode ) { |
||
58 | $data = []; |
||
59 | $data['series'] = []; |
||
60 | |||
61 | while ( $row = $res->getNext() ) { |
||
62 | // Loop over their fields (properties) |
||
63 | $label = ''; |
||
64 | $i = 0; |
||
65 | |||
66 | foreach ( $row as /* SMWResultArray */ |
||
67 | $field ) { |
||
68 | $i++; |
||
69 | $rowNumbers = []; |
||
70 | |||
71 | // Grouping by subject (page object) or property |
||
72 | if ( $this->params['group'] === 'subject' ) { |
||
73 | $groupedBy = $field->getResultSubject()->getTitle()->getText(); |
||
74 | } else { |
||
75 | $groupedBy = $field->getPrintRequest()->getLabel(); |
||
76 | } |
||
77 | |||
78 | // Property label |
||
79 | $property = $field->getPrintRequest()->getLabel(); |
||
80 | |||
81 | // First column property typeid |
||
82 | $i == 1 ? $data['fcolumntypeid'] = $field->getPrintRequest()->getTypeID() : ''; |
||
83 | |||
84 | // Loop over all values for the property. |
||
85 | while ( ( /* SMWDataValue */ |
||
86 | $object = $field->getNextDataValue() ) !== false ) { |
||
87 | |||
88 | if ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_NUMBER ) { |
||
89 | $number = $object->getNumber(); |
||
90 | |||
91 | // Checking against the row and in case the first column is a numeric |
||
92 | // value it is handled as label with the remaining steps continue to work |
||
93 | // as it were a text label |
||
94 | // The first column container will not be part of the series container |
||
95 | if ( $i == 1 ) { |
||
96 | $label = $number; |
||
97 | continue; |
||
98 | } |
||
99 | |||
100 | if ( $label !== '' && $number >= $this->params['min'] ) { |
||
101 | |||
102 | // Reference array summarize all items per row |
||
103 | $rowNumbers += [ 'subject' => $label, 'value' => $number, 'property' => $property ]; |
||
104 | |||
105 | // Store plain numbers for simpler handling |
||
106 | $data['series'][$groupedBy][] = $number; |
||
107 | } |
||
108 | } elseif ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_TIME ) { |
||
109 | $label = $object->getShortWikiText(); |
||
110 | } else { |
||
111 | $label = $object->getWikiValue(); |
||
112 | } |
||
113 | } |
||
114 | // Only for array's with numbers |
||
115 | if ( count( $rowNumbers ) > 0 ) { |
||
116 | |||
117 | // For cases where mainlabel=- we assume that the subject should not be |
||
118 | // used as identifier and therefore we try to match the groupby |
||
119 | // with the first available text label |
||
120 | if ( $this->params['mainlabel'] == '-' && $this->params['group'] === 'subject' ) { |
||
121 | $data[$this->params['group']][$label][] = $rowNumbers; |
||
122 | } else { |
||
123 | $data[$this->params['group']][$groupedBy][] = $rowNumbers; |
||
124 | } |
||
125 | } |
||
126 | } |
||
127 | } |
||
128 | return $data; |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * Data set sorting |
||
133 | * |
||
134 | * @since 1.8 |
||
135 | * |
||
136 | * @param array $data label => value |
||
137 | * |
||
138 | * @return array |
||
139 | */ |
||
140 | private function getFormatSettings( $data, $options ) { |
||
141 | |||
142 | // Init |
||
143 | $dataSet = []; |
||
144 | $options['mode'] = 'series'; |
||
145 | $options['autoscale'] = false; |
||
146 | |||
147 | // Available markers |
||
148 | $marker = [ 'circle', 'diamond', 'square', 'filledCircle', 'filledDiamond', 'filledSquare' ]; |
||
149 | |||
150 | // Series colour(has to be null otherwise jqplot runs with a type error) |
||
151 | $seriescolors = $this->params['chartcolor'] !== '' ? array_filter( |
||
152 | explode( ",", $this->params['chartcolor'] ) |
||
153 | ) : null; |
||
154 | |||
155 | // Re-grouping |
||
156 | foreach ( $data[$this->params['group']] as $rowKey => $row ) { |
||
157 | $values = []; |
||
158 | |||
159 | foreach ( $row as $key => $value ) { |
||
160 | // Switch labels according to the group parameter |
||
161 | $label = $this->params['grouplabel'] === 'property' ? $value['property'] : $value['subject']; |
||
162 | $values[] = [ $label, $value['value'] ]; |
||
163 | } |
||
164 | $dataSet[] = $values; |
||
165 | } |
||
166 | |||
167 | // Series plotting parameters |
||
168 | foreach ( $data[$this->params['group']] as $key => $row ) { |
||
169 | $series[] = [ |
||
170 | 'label' => $key, |
||
171 | 'xaxis' => 'xaxis', // xaxis could also be xaxis2 or ... |
||
172 | 'yaxis' => 'yaxis', |
||
173 | 'fill' => $this->params['stackseries'], |
||
174 | 'showLine' => $this->params['charttype'] !== 'scatter', |
||
175 | 'showMarker' => true, |
||
176 | 'trendline' => [ |
||
177 | 'show' => in_array( $this->params['trendline'], [ 'exp', 'linear' ] ), |
||
178 | 'shadow' => $this->params['theme'] !== 'simple', |
||
179 | 'type' => $this->params['trendline'], |
||
180 | ], |
||
181 | 'markerOptions' => [ |
||
182 | 'style' => $marker[array_rand( $marker )], |
||
183 | 'shadow' => $this->params['theme'] !== 'simple' |
||
184 | ], |
||
185 | 'rendererOptions' => [ 'barDirection' => $this->params['direction'] ] |
||
186 | ]; |
||
187 | }; |
||
188 | |||
189 | // Basic parameters |
||
190 | $parameters = [ |
||
191 | 'numbersaxislabel' => $this->params['numbersaxislabel'], |
||
192 | 'labelaxislabel' => $this->params['labelaxislabel'], |
||
193 | 'charttitle' => $this->params['charttitle'], |
||
194 | 'charttext' => $this->params['charttext'], |
||
195 | 'infotext' => $this->params['infotext'], |
||
196 | 'theme' => $this->params['theme'] ? $this->params['theme'] : null, |
||
197 | 'valueformat' => $this->params['datalabels'] === 'label' ? '' : $this->params['valueformat'], |
||
198 | 'ticklabels' => $this->params['ticklabels'], |
||
199 | 'highlighter' => $this->params['highlighter'], |
||
200 | 'autoscale' => $options['autoscale'], |
||
201 | 'gridview' => $this->params['gridview'], |
||
202 | 'direction' => $this->params['direction'], |
||
203 | 'smoothlines' => $this->params['smoothlines'], |
||
204 | 'cursor' => $this->params['cursor'], |
||
205 | 'chartlegend' => $this->params['chartlegend'] !== '' ? $this->params['chartlegend'] : 'none', |
||
206 | 'colorscheme' => $this->params['colorscheme'] !== '' ? $this->params['colorscheme'] : null, |
||
207 | 'pointlabels' => $this->params['datalabels'] === 'none' ? false : $this->params['datalabels'], |
||
208 | 'datalabels' => $this->params['datalabels'], |
||
209 | 'stackseries' => $this->params['stackseries'], |
||
210 | 'grid' => $this->params['theme'] === 'vector' ? [ 'borderColor' => '#a7d7f9' ] : ( $this->params['theme'] === 'simple' ? [ 'borderColor' => '#ddd' ] : null ), |
||
211 | 'seriescolors' => $seriescolors |
||
212 | ]; |
||
213 | |||
214 | return [ |
||
215 | 'data' => $dataSet, |
||
216 | //'rawdata' => $data , // control array |
||
217 | 'series' => $series, |
||
218 | 'ticks' => $data['numbersticks'], |
||
219 | 'total' => $data['total'], |
||
220 | 'fcolumntypeid' => $data['fcolumntypeid'], |
||
221 | 'sask' => $options['sask'], |
||
222 | 'mode' => $options['mode'], |
||
223 | 'renderer' => $this->params['charttype'], |
||
224 | 'parameters' => $parameters |
||
225 | ]; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Fetch numbers ticks |
||
230 | * |
||
231 | * @since 1.8 |
||
232 | * |
||
233 | * @param array $data |
||
234 | */ |
||
235 | protected function getNumbersTicks( array $data ) { |
||
236 | |||
237 | // Only look for numeric values that have been stored |
||
238 | $numerics = array_values( $data['series'] ); |
||
239 | |||
240 | // Find min and max values to determine the graphs axis parameter |
||
241 | $maxValue = count( $numerics ) == 0 ? 0 : max( array_map( "max", $numerics ) ); |
||
242 | |||
243 | if ( $this->params['min'] === false ) { |
||
244 | $minValue = count( $numerics ) == 0 ? 0 : min( array_map( "min", $numerics ) ); |
||
245 | } else { |
||
246 | $minValue = $this->params['min']; |
||
247 | } |
||
248 | |||
249 | // Get ticks info |
||
250 | $data['numbersticks'] = SRFjqPlot::getNumbersTicks( $minValue, $maxValue ); |
||
251 | $data['total'] = array_sum( array_map( "array_sum", $numerics ) ); |
||
252 | |||
253 | return $data; |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * Add resource definitions |
||
258 | * |
||
259 | * @since 1.8 |
||
260 | * |
||
261 | * @param array $data |
||
0 ignored issues
–
show
There is no parameter named
$data . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not.
Loading history...
|
|||
262 | * |
||
263 | * @return string |
||
264 | */ |
||
265 | protected function addResources() { |
||
266 | // RL module |
||
267 | switch ( $this->params['charttype'] ) { |
||
268 | case 'bubble': |
||
269 | SMWOutputs::requireResource( 'ext.srf.jqplot.bubble' ); |
||
270 | break; |
||
271 | case 'donut': |
||
272 | SMWOutputs::requireResource( 'ext.srf.jqplot.donut' ); |
||
273 | break; |
||
274 | case 'scatter': |
||
275 | case 'line': |
||
276 | case 'bar': |
||
277 | SMWOutputs::requireResource( 'ext.srf.jqplot.bar' ); |
||
278 | break; |
||
279 | } |
||
280 | |||
281 | // Trendline plugin |
||
282 | if ( in_array( $this->params['trendline'], [ 'exp', 'linear' ] ) ) { |
||
283 | SMWOutputs::requireResource( 'ext.srf.jqplot.trendline' ); |
||
284 | } |
||
285 | |||
286 | // Cursor plugin |
||
287 | if ( in_array( $this->params['cursor'], [ 'zoom', 'tooltip' ] ) ) { |
||
288 | SMWOutputs::requireResource( 'ext.srf.jqplot.cursor' ); |
||
289 | } |
||
290 | |||
291 | // Highlighter plugin |
||
292 | if ( $this->params['highlighter'] ) { |
||
293 | SMWOutputs::requireResource( 'ext.srf.jqplot.highlighter' ); |
||
294 | } |
||
295 | |||
296 | // Enhancedlegend plugin |
||
297 | if ( $this->params['chartlegend'] ) { |
||
298 | SMWOutputs::requireResource( 'ext.srf.jqplot.enhancedlegend' ); |
||
299 | } |
||
300 | |||
301 | // gridview plugin |
||
302 | if ( in_array( $this->params['gridview'], [ 'tabs' ] ) ) { |
||
303 | SMWOutputs::requireResource( 'ext.srf.util.grid' ); |
||
304 | } |
||
305 | |||
306 | // Pointlabels plugin |
||
307 | if ( in_array( $this->params['datalabels'], [ 'value', 'label', 'percent' ] ) ) { |
||
308 | SMWOutputs::requireResource( 'ext.srf.jqplot.pointlabels' ); |
||
309 | } |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * Prepare data for the output |
||
314 | * |
||
315 | * @since 1.8 |
||
316 | * |
||
317 | * @param array $data |
||
318 | * |
||
319 | * @return string |
||
320 | */ |
||
321 | protected function getFormatOutput( array $data ) { |
||
322 | |||
323 | $this->isHTML = true; |
||
324 | |||
325 | static $statNr = 0; |
||
326 | $chartID = 'jqplot-series-' . ++$statNr; |
||
327 | |||
328 | // Encoding |
||
329 | $requireHeadItem = [ $chartID => FormatJson::encode( $data ) ]; |
||
330 | SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) ); |
||
331 | |||
332 | // Add RL resources |
||
333 | $this->addResources(); |
||
334 | |||
335 | // Processing placeholder |
||
336 | $processing = SRFUtils::htmlProcessingElement( $this->isHTML ); |
||
337 | |||
338 | // Conversion due to a string as value that can contain % |
||
339 | $width = strstr( $this->params['width'], "%" ) ? $this->params['width'] : $this->params['width'] . 'px'; |
||
340 | |||
341 | // Chart/graph placeholder |
||
342 | $chart = Html::rawElement( |
||
343 | 'div', |
||
344 | [ |
||
345 | 'id' => $chartID, |
||
346 | 'class' => 'container', |
||
347 | 'style' => "display:none; width: {$width}; height: {$this->params['height']}px;" |
||
348 | ], |
||
349 | null |
||
350 | ); |
||
351 | |||
352 | // Beautify class selector |
||
353 | $class = $this->params['charttype'] ? '-' . $this->params['charttype'] : ''; |
||
354 | $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class . ' jqplot-common'; |
||
355 | |||
356 | // Chart/graph wrappper |
||
357 | return Html::rawElement( |
||
358 | 'div', |
||
359 | [ |
||
360 | 'class' => 'srf-jqplot' . $class, |
||
361 | ], |
||
362 | $processing . $chart |
||
363 | ); |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * @see SMWResultPrinter::getParamDefinitions |
||
368 | * |
||
369 | * @since 1.8 |
||
370 | * |
||
371 | * @param $definitions array of IParamDefinition |
||
372 | * |
||
373 | * @return array of IParamDefinition|array |
||
374 | */ |
||
375 | public function getParamDefinitions( array $definitions ) { |
||
376 | $params = array_merge( parent::getParamDefinitions( $definitions ), SRFjqPlot::getCommonParams() ); |
||
377 | |||
378 | $params['infotext'] = [ |
||
379 | 'message' => 'srf-paramdesc-infotext', |
||
380 | 'default' => '', |
||
381 | ]; |
||
382 | |||
383 | $params['stackseries'] = [ |
||
384 | 'type' => 'boolean', |
||
385 | 'message' => 'srf-paramdesc-stackseries', |
||
386 | 'default' => false, |
||
387 | ]; |
||
388 | |||
389 | $params['group'] = [ |
||
390 | 'message' => 'srf-paramdesc-group', |
||
391 | 'default' => 'subject', |
||
392 | 'values' => [ 'property', 'subject' ], |
||
393 | ]; |
||
394 | |||
395 | $params['grouplabel'] = [ |
||
396 | 'message' => 'srf-paramdesc-grouplabel', |
||
397 | 'default' => 'subject', |
||
398 | 'values' => [ 'property', 'subject' ], |
||
399 | ]; |
||
400 | |||
401 | $params['charttype'] = [ |
||
402 | 'message' => 'srf-paramdesc-charttype', |
||
403 | 'default' => 'bar', |
||
404 | 'values' => [ 'bar', 'line', 'donut', 'bubble', 'scatter' ], |
||
405 | ]; |
||
406 | |||
407 | $params['trendline'] = [ |
||
408 | 'message' => 'srf-paramdesc-trendline', |
||
409 | 'default' => 'none', |
||
410 | 'values' => [ 'none', 'exp', 'linear' ], |
||
411 | ]; |
||
412 | |||
413 | $params['cursor'] = [ |
||
414 | 'message' => 'srf-paramdesc-chartcursor', |
||
415 | 'default' => 'none', |
||
416 | 'values' => [ 'none', 'zoom', 'tooltip' ], |
||
417 | ]; |
||
418 | |||
419 | $params['gridview'] = [ |
||
420 | 'message' => 'srf-paramdesc-gridview', |
||
421 | 'default' => 'none', |
||
422 | 'values' => [ 'none', 'tabs' ], |
||
423 | ]; |
||
424 | |||
425 | return $params; |
||
426 | } |
||
427 | } |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.