3 * Generates the JavaScripts needed to visualize GIS data.
5 * @package phpMyAdmin-GIS
7 class PMA_GIS_Visualization
10 * @var array Raw data for the visualization
15 * @var array Set of default settigs values are here.
17 private $_settings = array(
19 // Array of colors to be used for GIS visualizations.
40 // The width of the GIS visualization.
43 // The height of the GIS visualization.
48 * @var array Options that the user has specified.
50 private $_userSpecifiedSettings = null;
53 * Returns the settings array
55 * @return the settings array.
57 public function getSettings()
59 return $this->_settings
;
63 * Constructor. Stores user specified options.
65 * @param array $data Data for the visualization
66 * @param array $options Users specified options
68 public function __construct($data, $options)
70 $this->_userSpecifiedSettings
= $options;
75 * All the variable initialization, options handling has to be done here.
79 protected function init()
81 $this->_handleOptions();
85 * A function which handles passed parameters. Useful if desired
86 * chart needs to be a little bit different from the default one.
90 private function _handleOptions()
92 if (! is_null($this->_userSpecifiedSettings
)) {
93 $this->_settings
= array_merge($this->_settings
, $this->_userSpecifiedSettings
);
98 * Sanitizes the file name.
100 * @param string $file_name file name
101 * @param string $ext extension of the file
103 * @return the sanitized file name
105 private function _sanitizeName($file_name, $ext)
107 // convert filename to iso-8859-1, it is safer
108 $file_name = PMA_convert_string('utf-8', 'iso-8859-1', $file_name);
110 // Check if the user already added extension;
111 // get the substring where the extension would be if it was included
112 $extension_start_pos = strlen($file_name) - strlen($ext) - 1;
113 $user_extension = substr($file_name, $extension_start_pos, strlen($file_name));
114 $required_extension = "." . $ext;
115 if (strtolower($user_extension) != $required_extension) {
116 $file_name .= $required_extension;
122 * Handles common tasks of writing the visualization to file for various formats.
124 * @param string $file_name file name
125 * @param string $type mime type
126 * @param string $ext extension of the file
130 private function _toFile($file_name, $type, $ext)
132 $file_name = $this->_sanitizeName($file_name, $ext);
136 PMA_download_header($file_name, $type);
140 * Generate the visualization in SVG format.
142 * @return the generated image resource
144 private function _svg()
148 $output = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
149 $output .= '<svg version="1.1" xmlns:svg="http://www.w3.org/2000/svg"'
150 . ' xmlns="http://www.w3.org/2000/svg" width="' . $this->_settings
['width'] . '"'
151 . ' height="' . $this->_settings
['height'] . '">';
152 $output .= '<g id="groupPanel">';
154 $scale_data = $this->_scaleDataSet($this->_data
);
155 $output .= $this->_prepareDataSet($this->_data
, $scale_data, 'svg', '');
164 * Get the visualization as a SVG.
166 * @return the visualization as a SVG
168 public function asSVG()
170 $output = $this->_svg();
175 * Saves as a SVG image to a file.
177 * @param string $file_name File name
181 public function toFileAsSvg($file_name)
183 $img = $this->_svg();
184 $this->_toFile($file_name, 'image/svg+xml', 'svg');
189 * Generate the visualization in PNG format.
191 * @return the generated image resource
193 private function _png()
198 $image = imagecreatetruecolor($this->_settings
['width'], $this->_settings
['height']);
200 // fill the background
201 $bg = imagecolorallocate($image, 229, 229, 229);
202 imagefilledrectangle(
203 $image, 0, 0, $this->_settings
['width'] - 1,
204 $this->_settings
['height'] - 1, $bg
207 $scale_data = $this->_scaleDataSet($this->_data
);
208 $image = $this->_prepareDataSet($this->_data
, $scale_data, 'png', $image);
214 * Get the visualization as a PNG.
216 * @return the visualization as a PNG
218 public function asPng()
220 $img = $this->_png();
222 // render and save it to variable
224 imagepng($img, null, 9, PNG_ALL_FILTERS
);
226 $output = ob_get_contents();
230 $encoded = base64_encode($output);
231 return '<img src="data:image/png;base64,'. $encoded .'" />';
235 * Saves as a PNG image to a file.
237 * @param string $file_name File name
241 public function toFileAsPng($file_name)
243 $img = $this->_png();
244 $this->_toFile($file_name, 'image/png', 'png');
245 imagepng($img, null, 9, PNG_ALL_FILTERS
);
250 * Get the code for visualization with OpenLayers.
252 * @return the code for visualization with OpenLayers
254 public function asOl()
257 $scale_data = $this->_scaleDataSet($this->_data
);
260 . 'projection: new OpenLayers.Projection("EPSG:900913"),'
261 . 'displayProjection: new OpenLayers.Projection("EPSG:4326"),'
263 . 'numZoomLevels: 18,'
264 . 'maxResolution: 156543.0339,'
265 . 'maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508),'
266 . 'restrictedExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508)'
268 . 'var map = new OpenLayers.Map("openlayersmap", options);'
269 . 'var layerNone = new OpenLayers.Layer.Boxes("None", {isBaseLayer: true});'
270 . 'var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");'
271 . 'var layerOsmarender = new OpenLayers.Layer.OSM.Osmarender("Osmarender");'
272 . 'var layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");'
273 . 'map.addLayers([layerMapnik, layerOsmarender, layerCycleMap, layerNone]);'
274 . 'var vectorLayer = new OpenLayers.Layer.Vector("Data");'
276 $output .= $this->_prepareDataSet($this->_data
, $scale_data, 'ol', '');
278 'map.addLayer(vectorLayer);'
279 . 'map.zoomToExtent(bound);'
280 . 'if (map.getZoom() < 2) {'
283 . 'map.addControl(new OpenLayers.Control.LayerSwitcher());'
284 . 'map.addControl(new OpenLayers.Control.MousePosition());';
289 * Saves as a PDF to a file.
291 * @param string $file_name File name
295 public function toFileAsPdf($file_name)
299 include_once './libraries/tcpdf/tcpdf.php';
302 $pdf = new TCPDF('', 'pt', $GLOBALS['cfg']['PDFDefaultPageSize'], true, 'UTF-8', false);
304 // disable header and footer
305 $pdf->setPrintHeader(false);
306 $pdf->setPrintFooter(false);
308 //set auto page breaks
309 $pdf->SetAutoPageBreak(false);
314 $scale_data = $this->_scaleDataSet($this->_data
);
315 $pdf = $this->_prepareDataSet($this->_data
, $scale_data, 'pdf', $pdf);
317 // sanitize file name
318 $file_name = $this->_sanitizeName($file_name, 'pdf');
321 $pdf->Output($file_name, 'D');
325 * Calculates the scale, horizontal and vertical offset that should be used.
327 * @param array $data Row data
329 * @return an array containing the scale, x and y offsets
331 private function _scaleDataSet($data)
335 // effective width and height of the plot
336 $plot_width = $this->_settings
['width'] - 2 * $border;
337 $plot_height = $this->_settings
['height'] - 2 * $border;
339 foreach ($data as $row) {
341 // Figure out the data type
342 $ref_data = $row[$this->_settings
['spatialColumn']];
343 $type_pos = stripos($ref_data, '(');
344 $type = substr($ref_data, 0, $type_pos);
346 $gis_obj = PMA_GIS_Factory
::factory($type);
350 $scale_data = $gis_obj->scaleRow($row[$this->_settings
['spatialColumn']]);
352 // Upadate minimum/maximum values for x and y cordinates.
353 $c_maxX = (float) $scale_data['maxX'];
354 if (! isset($min_max['maxX']) ||
$c_maxX > $min_max['maxX']) {
355 $min_max['maxX'] = $c_maxX;
358 $c_minX = (float) $scale_data['minX'];
359 if (! isset($min_max['minX']) ||
$c_minX < $min_max['minX']) {
360 $min_max['minX'] = $c_minX;
363 $c_maxY = (float) $scale_data['maxY'];
364 if (! isset($min_max['maxY']) ||
$c_maxY > $min_max['maxY']) {
365 $min_max['maxY'] = $c_maxY;
368 $c_minY = (float) $scale_data['minY'];
369 if (! isset($min_max['minY']) ||
$c_minY < $min_max['minY']) {
370 $min_max['minY'] = $c_minY;
374 // scale the visualization
375 $x_ratio = ($min_max['maxX'] - $min_max['minX']) / $plot_width;
376 $y_ratio = ($min_max['maxY'] - $min_max['minY']) / $plot_height;
377 $ratio = ($x_ratio > $y_ratio) ?
$x_ratio : $y_ratio;
379 $scale = ($ratio != 0) ?
(1 / $ratio) : 1;
381 if ($x_ratio < $y_ratio) {
382 // center horizontally
383 $x = ($min_max['maxX'] +
$min_max['minX'] - $plot_width / $scale) / 2;
385 $y = $min_max['minY'] - ($border / $scale);
388 $x = $min_max['minX'] - ($border / $scale);
390 $y =($min_max['maxY'] +
$min_max['minY'] - $plot_height / $scale) / 2;
397 'minX' => $min_max['minX'],
398 'maxX' => $min_max['maxX'],
399 'minY' => $min_max['minY'],
400 'maxY' => $min_max['maxY'],
401 'height' => $this->_settings
['height'],
406 * Prepares and return the dataset as needed by the visualization.
408 * @param array $data Raw data
409 * @param array $scale_data Data related to scaling
410 * @param string $format Format of the visulaization
411 * @param image $results Image object in the case of png
413 * @return the formatted array of data.
415 private function _prepareDataSet($data, $scale_data, $format, $results)
419 // loop through the rows
420 foreach ($data as $row) {
421 $index = $color_number %
sizeof($this->_settings
['colors']);
423 // Figure out the data type
424 $ref_data = $row[$this->_settings
['spatialColumn']];
425 $type_pos = stripos($ref_data, '(');
426 $type = substr($ref_data, 0, $type_pos);
428 $gis_obj = PMA_GIS_Factory
::factory($type);
433 if (isset($this->_settings
['labelColumn'])
434 && isset($row[$this->_settings
['labelColumn']])
436 $label = $row[$this->_settings
['labelColumn']];
439 if ($format == 'svg') {
440 $results .= $gis_obj->prepareRowAsSvg(
441 $row[$this->_settings
['spatialColumn']], $label,
442 $this->_settings
['colors'][$index], $scale_data
444 } elseif ($format == 'png') {
445 $results = $gis_obj->prepareRowAsPng(
446 $row[$this->_settings
['spatialColumn']], $label,
447 $this->_settings
['colors'][$index], $scale_data, $results
449 } elseif ($format == 'pdf') {
450 $results = $gis_obj->prepareRowAsPdf(
451 $row[$this->_settings
['spatialColumn']], $label,
452 $this->_settings
['colors'][$index], $scale_data, $results
454 } elseif ($format == 'ol') {
455 $results .= $gis_obj->prepareRowAsOl(
456 $row[$this->_settings
['spatialColumn']], $row['srid'],
457 $label, $this->_settings
['colors'][$index], $scale_data