2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Handles visualization of GIS data
6 * @package PhpMyAdmin-GIS
9 if (! defined('PHPMYADMIN')) {
14 * Handles visualization of GIS data
16 * @package PhpMyAdmin-GIS
18 class PMA_GIS_Visualization
21 * @var array Raw data for the visualization
26 * @var array Set of default settigs values are here.
28 private $_settings = array(
30 // Array of colors to be used for GIS visualizations.
51 // The width of the GIS visualization.
54 // The height of the GIS visualization.
59 * @var array Options that the user has specified.
61 private $_userSpecifiedSettings = null;
64 * Returns the settings array
66 * @return array the settings array
69 public function getSettings()
71 return $this->_settings
;
75 * Constructor. Stores user specified options.
77 * @param array $data Data for the visualization
78 * @param array $options Users specified options
82 public function __construct($data, $options)
84 $this->_userSpecifiedSettings
= $options;
89 * All the variable initialization, options handling has to be done here.
94 protected function init()
96 $this->_handleOptions();
100 * A function which handles passed parameters. Useful if desired
101 * chart needs to be a little bit different from the default one.
106 private function _handleOptions()
108 if (! is_null($this->_userSpecifiedSettings
)) {
109 $this->_settings
= array_merge(
111 $this->_userSpecifiedSettings
117 * Sanitizes the file name.
119 * @param string $file_name file name
120 * @param string $ext extension of the file
122 * @return string the sanitized file name
125 private function _sanitizeName($file_name, $ext)
127 $file_name = PMA_sanitizeFilename($file_name);
129 // Check if the user already added extension;
130 // get the substring where the extension would be if it was included
131 $extension_start_pos = strlen($file_name) - strlen($ext) - 1;
132 $user_extension = substr(
133 $file_name, $extension_start_pos, strlen($file_name)
135 $required_extension = "." . $ext;
136 if (strtolower($user_extension) != $required_extension) {
137 $file_name .= $required_extension;
143 * Handles common tasks of writing the visualization to file for various formats.
145 * @param string $file_name file name
146 * @param string $type mime type
147 * @param string $ext extension of the file
152 private function _toFile($file_name, $type, $ext)
154 $file_name = $this->_sanitizeName($file_name, $ext);
155 PMA_downloadHeader($file_name, $type);
159 * Generate the visualization in SVG format.
161 * @return string the generated image resource
164 private function _svg()
168 $output = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
169 $output .= '<svg version="1.1" xmlns:svg="http://www.w3.org/2000/svg"'
170 . ' xmlns="http://www.w3.org/2000/svg"'
171 . ' width="' . $this->_settings
['width'] . '"'
172 . ' height="' . $this->_settings
['height'] . '">';
173 $output .= '<g id="groupPanel">';
175 $scale_data = $this->_scaleDataSet($this->_data
);
176 $output .= $this->_prepareDataSet($this->_data
, $scale_data, 'svg', '');
185 * Get the visualization as a SVG.
187 * @return string the visualization as a SVG
190 public function asSVG()
192 $output = $this->_svg();
197 * Saves as a SVG image to a file.
199 * @param string $file_name File name
204 public function toFileAsSvg($file_name)
206 $img = $this->_svg();
207 $this->_toFile($file_name, 'image/svg+xml', 'svg');
212 * Generate the visualization in PNG format.
214 * @return object the generated image resource
217 private function _png()
222 $image = imagecreatetruecolor(
223 $this->_settings
['width'],
224 $this->_settings
['height']
227 // fill the background
228 $bg = imagecolorallocate($image, 229, 229, 229);
229 imagefilledrectangle(
230 $image, 0, 0, $this->_settings
['width'] - 1,
231 $this->_settings
['height'] - 1, $bg
234 $scale_data = $this->_scaleDataSet($this->_data
);
235 $image = $this->_prepareDataSet($this->_data
, $scale_data, 'png', $image);
241 * Get the visualization as a PNG.
243 * @return string the visualization as a PNG
246 public function asPng()
248 $img = $this->_png();
250 // render and save it to variable
252 imagepng($img, null, 9, PNG_ALL_FILTERS
);
254 $output = ob_get_contents();
258 $encoded = base64_encode($output);
259 return '<img src="data:image/png;base64,'. $encoded .'" />';
263 * Saves as a PNG image to a file.
265 * @param string $file_name File name
270 public function toFileAsPng($file_name)
272 $img = $this->_png();
273 $this->_toFile($file_name, 'image/png', 'png');
274 imagepng($img, null, 9, PNG_ALL_FILTERS
);
279 * Get the code for visualization with OpenLayers.
281 * @return string the code for visualization with OpenLayers
284 public function asOl()
287 $scale_data = $this->_scaleDataSet($this->_data
);
290 . 'projection: new OpenLayers.Projection("EPSG:900913"),'
291 . 'displayProjection: new OpenLayers.Projection("EPSG:4326"),'
293 . 'numZoomLevels: 18,'
294 . 'maxResolution: 156543.0339,'
295 . 'maxExtent: new OpenLayers.Bounds('
296 . '-20037508, -20037508, 20037508, 20037508),'
297 . 'restrictedExtent: new OpenLayers.Bounds('
298 . '-20037508, -20037508, 20037508, 20037508)'
300 . 'var map = new OpenLayers.Map("openlayersmap", options);'
301 . 'var layerNone = new OpenLayers.Layer.Boxes('
302 . '"None", {isBaseLayer: true});'
303 . 'var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");'
304 . 'var layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");'
305 . 'map.addLayers([layerMapnik,layerCycleMap,layerNone]);'
306 . 'var vectorLayer = new OpenLayers.Layer.Vector("Data");'
308 $output .= $this->_prepareDataSet($this->_data
, $scale_data, 'ol', '');
310 'map.addLayer(vectorLayer);'
311 . 'map.zoomToExtent(bound);'
312 . 'if (map.getZoom() < 2) {'
315 . 'map.addControl(new OpenLayers.Control.LayerSwitcher());'
316 . 'map.addControl(new OpenLayers.Control.MousePosition());';
321 * Saves as a PDF to a file.
323 * @param string $file_name File name
328 public function toFileAsPdf($file_name)
332 include_once './libraries/tcpdf/tcpdf.php';
336 '', 'pt', $GLOBALS['cfg']['PDFDefaultPageSize'], true, 'UTF-8', false
339 // disable header and footer
340 $pdf->setPrintHeader(false);
341 $pdf->setPrintFooter(false);
343 //set auto page breaks
344 $pdf->SetAutoPageBreak(false);
349 $scale_data = $this->_scaleDataSet($this->_data
);
350 $pdf = $this->_prepareDataSet($this->_data
, $scale_data, 'pdf', $pdf);
352 // sanitize file name
353 $file_name = $this->_sanitizeName($file_name, 'pdf');
354 $pdf->Output($file_name, 'D');
358 * Calculates the scale, horizontal and vertical offset that should be used.
360 * @param array $data Row data
362 * @return array an array containing the scale, x and y offsets
365 private function _scaleDataSet($data)
369 // effective width and height of the plot
370 $plot_width = $this->_settings
['width'] - 2 * $border;
371 $plot_height = $this->_settings
['height'] - 2 * $border;
373 foreach ($data as $row) {
375 // Figure out the data type
376 $ref_data = $row[$this->_settings
['spatialColumn']];
377 $type_pos = stripos($ref_data, '(');
378 $type = substr($ref_data, 0, $type_pos);
380 $gis_obj = PMA_GIS_Factory
::factory($type);
384 $scale_data = $gis_obj->scaleRow(
385 $row[$this->_settings
['spatialColumn']]
388 // Upadate minimum/maximum values for x and y cordinates.
389 $c_maxX = (float) $scale_data['maxX'];
390 if (! isset($min_max['maxX']) ||
$c_maxX > $min_max['maxX']) {
391 $min_max['maxX'] = $c_maxX;
394 $c_minX = (float) $scale_data['minX'];
395 if (! isset($min_max['minX']) ||
$c_minX < $min_max['minX']) {
396 $min_max['minX'] = $c_minX;
399 $c_maxY = (float) $scale_data['maxY'];
400 if (! isset($min_max['maxY']) ||
$c_maxY > $min_max['maxY']) {
401 $min_max['maxY'] = $c_maxY;
404 $c_minY = (float) $scale_data['minY'];
405 if (! isset($min_max['minY']) ||
$c_minY < $min_max['minY']) {
406 $min_max['minY'] = $c_minY;
410 // scale the visualization
411 $x_ratio = ($min_max['maxX'] - $min_max['minX']) / $plot_width;
412 $y_ratio = ($min_max['maxY'] - $min_max['minY']) / $plot_height;
413 $ratio = ($x_ratio > $y_ratio) ?
$x_ratio : $y_ratio;
415 $scale = ($ratio != 0) ?
(1 / $ratio) : 1;
417 if ($x_ratio < $y_ratio) {
418 // center horizontally
419 $x = ($min_max['maxX'] +
$min_max['minX'] - $plot_width / $scale) / 2;
421 $y = $min_max['minY'] - ($border / $scale);
424 $x = $min_max['minX'] - ($border / $scale);
426 $y =($min_max['maxY'] +
$min_max['minY'] - $plot_height / $scale) / 2;
433 'minX' => $min_max['minX'],
434 'maxX' => $min_max['maxX'],
435 'minY' => $min_max['minY'],
436 'maxY' => $min_max['maxY'],
437 'height' => $this->_settings
['height'],
442 * Prepares and return the dataset as needed by the visualization.
444 * @param array $data Raw data
445 * @param array $scale_data Data related to scaling
446 * @param string $format Format of the visulaization
447 * @param object $results Image object in the case of png
448 * TCPDF object in the case of pdf
450 * @return mixed the formatted array of data
453 private function _prepareDataSet($data, $scale_data, $format, $results)
457 // loop through the rows
458 foreach ($data as $row) {
459 $index = $color_number %
sizeof($this->_settings
['colors']);
461 // Figure out the data type
462 $ref_data = $row[$this->_settings
['spatialColumn']];
463 $type_pos = stripos($ref_data, '(');
464 $type = substr($ref_data, 0, $type_pos);
466 $gis_obj = PMA_GIS_Factory
::factory($type);
471 if (isset($this->_settings
['labelColumn'])
472 && isset($row[$this->_settings
['labelColumn']])
474 $label = $row[$this->_settings
['labelColumn']];
477 if ($format == 'svg') {
478 $results .= $gis_obj->prepareRowAsSvg(
479 $row[$this->_settings
['spatialColumn']], $label,
480 $this->_settings
['colors'][$index], $scale_data
482 } elseif ($format == 'png') {
483 $results = $gis_obj->prepareRowAsPng(
484 $row[$this->_settings
['spatialColumn']], $label,
485 $this->_settings
['colors'][$index], $scale_data, $results
487 } elseif ($format == 'pdf') {
488 $results = $gis_obj->prepareRowAsPdf(
489 $row[$this->_settings
['spatialColumn']], $label,
490 $this->_settings
['colors'][$index], $scale_data, $results
492 } elseif ($format == 'ol') {
493 $results .= $gis_obj->prepareRowAsOl(
494 $row[$this->_settings
['spatialColumn']], $row['srid'],
495 $label, $this->_settings
['colors'][$index], $scale_data