PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/phpmyadmin/libraries/gis/pma_gis_visualization.php

https://bitbucket.org/graaaf/garant
PHP | 464 lines | 267 code | 57 blank | 140 comment | 23 complexity | 1f216f4fbb38ed3168adb75da187d2fd MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0
  1. <?php
  2. /**
  3. * Generates the JavaScripts needed to visualize GIS data.
  4. *
  5. * @package PhpMyAdmin-GIS
  6. */
  7. class PMA_GIS_Visualization
  8. {
  9. /**
  10. * @var array Raw data for the visualization
  11. */
  12. private $_data;
  13. /**
  14. * @var array Set of default settigs values are here.
  15. */
  16. private $_settings = array(
  17. // Array of colors to be used for GIS visualizations.
  18. 'colors' => array(
  19. '#B02EE0',
  20. '#E0642E',
  21. '#E0D62E',
  22. '#2E97E0',
  23. '#BCE02E',
  24. '#E02E75',
  25. '#5CE02E',
  26. '#E0B02E',
  27. '#0022E0',
  28. '#726CB1',
  29. '#481A36',
  30. '#BAC658',
  31. '#127224',
  32. '#825119',
  33. '#238C74',
  34. '#4C489B',
  35. '#87C9BF',
  36. ),
  37. // The width of the GIS visualization.
  38. 'width' => 600,
  39. // The height of the GIS visualization.
  40. 'height' => 450,
  41. );
  42. /**
  43. * @var array Options that the user has specified.
  44. */
  45. private $_userSpecifiedSettings = null;
  46. /**
  47. * Returns the settings array
  48. *
  49. * @return the settings array.
  50. */
  51. public function getSettings()
  52. {
  53. return $this->_settings;
  54. }
  55. /**
  56. * Constructor. Stores user specified options.
  57. *
  58. * @param array $data Data for the visualization
  59. * @param array $options Users specified options
  60. */
  61. public function __construct($data, $options)
  62. {
  63. $this->_userSpecifiedSettings = $options;
  64. $this->_data = $data;
  65. }
  66. /**
  67. * All the variable initialization, options handling has to be done here.
  68. *
  69. * @return nothing
  70. */
  71. protected function init()
  72. {
  73. $this->_handleOptions();
  74. }
  75. /**
  76. * A function which handles passed parameters. Useful if desired
  77. * chart needs to be a little bit different from the default one.
  78. *
  79. * @return nothing
  80. */
  81. private function _handleOptions()
  82. {
  83. if (! is_null($this->_userSpecifiedSettings)) {
  84. $this->_settings = array_merge($this->_settings, $this->_userSpecifiedSettings);
  85. }
  86. }
  87. /**
  88. * Sanitizes the file name.
  89. *
  90. * @param string $file_name file name
  91. * @param string $ext extension of the file
  92. *
  93. * @return the sanitized file name
  94. */
  95. private function _sanitizeName($file_name, $ext)
  96. {
  97. $file_name = PMA_sanitize_filename($file_name);
  98. // Check if the user already added extension;
  99. // get the substring where the extension would be if it was included
  100. $extension_start_pos = strlen($file_name) - strlen($ext) - 1;
  101. $user_extension = substr($file_name, $extension_start_pos, strlen($file_name));
  102. $required_extension = "." . $ext;
  103. if (strtolower($user_extension) != $required_extension) {
  104. $file_name .= $required_extension;
  105. }
  106. return $file_name;
  107. }
  108. /**
  109. * Handles common tasks of writing the visualization to file for various formats.
  110. *
  111. * @param string $file_name file name
  112. * @param string $type mime type
  113. * @param string $ext extension of the file
  114. *
  115. * @return nothing
  116. */
  117. private function _toFile($file_name, $type, $ext)
  118. {
  119. $file_name = $this->_sanitizeName($file_name, $ext);
  120. ob_clean();
  121. PMA_download_header($file_name, $type);
  122. }
  123. /**
  124. * Generate the visualization in SVG format.
  125. *
  126. * @return the generated image resource
  127. */
  128. private function _svg()
  129. {
  130. $this->init();
  131. $output = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
  132. $output .= '<svg version="1.1" xmlns:svg="http://www.w3.org/2000/svg"'
  133. . ' xmlns="http://www.w3.org/2000/svg" width="' . $this->_settings['width'] . '"'
  134. . ' height="' . $this->_settings['height'] . '">';
  135. $output .= '<g id="groupPanel">';
  136. $scale_data = $this->_scaleDataSet($this->_data);
  137. $output .= $this->_prepareDataSet($this->_data, $scale_data, 'svg', '');
  138. $output .= '</g>';
  139. $output .= '</svg>';
  140. return $output;
  141. }
  142. /**
  143. * Get the visualization as a SVG.
  144. *
  145. * @return the visualization as a SVG
  146. */
  147. public function asSVG()
  148. {
  149. $output = $this->_svg();
  150. return $output;
  151. }
  152. /**
  153. * Saves as a SVG image to a file.
  154. *
  155. * @param string $file_name File name
  156. *
  157. * @return nothing
  158. */
  159. public function toFileAsSvg($file_name)
  160. {
  161. $img = $this->_svg();
  162. $this->_toFile($file_name, 'image/svg+xml', 'svg');
  163. echo($img);
  164. }
  165. /**
  166. * Generate the visualization in PNG format.
  167. *
  168. * @return the generated image resource
  169. */
  170. private function _png()
  171. {
  172. $this->init();
  173. // create image
  174. $image = imagecreatetruecolor($this->_settings['width'], $this->_settings['height']);
  175. // fill the background
  176. $bg = imagecolorallocate($image, 229, 229, 229);
  177. imagefilledrectangle(
  178. $image, 0, 0, $this->_settings['width'] - 1,
  179. $this->_settings['height'] - 1, $bg
  180. );
  181. $scale_data = $this->_scaleDataSet($this->_data);
  182. $image = $this->_prepareDataSet($this->_data, $scale_data, 'png', $image);
  183. return $image;
  184. }
  185. /**
  186. * Get the visualization as a PNG.
  187. *
  188. * @return the visualization as a PNG
  189. */
  190. public function asPng()
  191. {
  192. $img = $this->_png();
  193. // render and save it to variable
  194. ob_start();
  195. imagepng($img, null, 9, PNG_ALL_FILTERS);
  196. imagedestroy($img);
  197. $output = ob_get_contents();
  198. ob_end_clean();
  199. // base64 encode
  200. $encoded = base64_encode($output);
  201. return '<img src="data:image/png;base64,'. $encoded .'" />';
  202. }
  203. /**
  204. * Saves as a PNG image to a file.
  205. *
  206. * @param string $file_name File name
  207. *
  208. * @return nothing
  209. */
  210. public function toFileAsPng($file_name)
  211. {
  212. $img = $this->_png();
  213. $this->_toFile($file_name, 'image/png', 'png');
  214. imagepng($img, null, 9, PNG_ALL_FILTERS);
  215. imagedestroy($img);
  216. }
  217. /**
  218. * Get the code for visualization with OpenLayers.
  219. *
  220. * @return the code for visualization with OpenLayers
  221. */
  222. public function asOl()
  223. {
  224. $this->init();
  225. $scale_data = $this->_scaleDataSet($this->_data);
  226. $output
  227. = 'var options = {'
  228. . 'projection: new OpenLayers.Projection("EPSG:900913"),'
  229. . 'displayProjection: new OpenLayers.Projection("EPSG:4326"),'
  230. . 'units: "m",'
  231. . 'numZoomLevels: 18,'
  232. . 'maxResolution: 156543.0339,'
  233. . 'maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508),'
  234. . 'restrictedExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508)'
  235. . '};'
  236. . 'var map = new OpenLayers.Map("openlayersmap", options);'
  237. . 'var layerNone = new OpenLayers.Layer.Boxes("None", {isBaseLayer: true});'
  238. . 'var layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");'
  239. . 'var layerOsmarender = new OpenLayers.Layer.OSM.Osmarender("Osmarender");'
  240. . 'var layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");'
  241. . 'map.addLayers([layerMapnik, layerOsmarender, layerCycleMap, layerNone]);'
  242. . 'var vectorLayer = new OpenLayers.Layer.Vector("Data");'
  243. . 'var bound;';
  244. $output .= $this->_prepareDataSet($this->_data, $scale_data, 'ol', '');
  245. $output .=
  246. 'map.addLayer(vectorLayer);'
  247. . 'map.zoomToExtent(bound);'
  248. . 'if (map.getZoom() < 2) {'
  249. . 'map.zoomTo(2);'
  250. . '}'
  251. . 'map.addControl(new OpenLayers.Control.LayerSwitcher());'
  252. . 'map.addControl(new OpenLayers.Control.MousePosition());';
  253. return $output;
  254. }
  255. /**
  256. * Saves as a PDF to a file.
  257. *
  258. * @param string $file_name File name
  259. *
  260. * @return nothing
  261. */
  262. public function toFileAsPdf($file_name)
  263. {
  264. $this->init();
  265. include_once './libraries/tcpdf/tcpdf.php';
  266. // create pdf
  267. $pdf = new TCPDF('', 'pt', $GLOBALS['cfg']['PDFDefaultPageSize'], true, 'UTF-8', false);
  268. // disable header and footer
  269. $pdf->setPrintHeader(false);
  270. $pdf->setPrintFooter(false);
  271. //set auto page breaks
  272. $pdf->SetAutoPageBreak(false);
  273. // add a page
  274. $pdf->AddPage();
  275. $scale_data = $this->_scaleDataSet($this->_data);
  276. $pdf = $this->_prepareDataSet($this->_data, $scale_data, 'pdf', $pdf);
  277. // sanitize file name
  278. $file_name = $this->_sanitizeName($file_name, 'pdf');
  279. ob_clean();
  280. $pdf->Output($file_name, 'D');
  281. }
  282. /**
  283. * Calculates the scale, horizontal and vertical offset that should be used.
  284. *
  285. * @param array $data Row data
  286. *
  287. * @return an array containing the scale, x and y offsets
  288. */
  289. private function _scaleDataSet($data)
  290. {
  291. $min_max = array();
  292. $border = 15;
  293. // effective width and height of the plot
  294. $plot_width = $this->_settings['width'] - 2 * $border;
  295. $plot_height = $this->_settings['height'] - 2 * $border;
  296. foreach ($data as $row) {
  297. // Figure out the data type
  298. $ref_data = $row[$this->_settings['spatialColumn']];
  299. $type_pos = stripos($ref_data, '(');
  300. $type = substr($ref_data, 0, $type_pos);
  301. $gis_obj = PMA_GIS_Factory::factory($type);
  302. if (! $gis_obj) {
  303. continue;
  304. }
  305. $scale_data = $gis_obj->scaleRow($row[$this->_settings['spatialColumn']]);
  306. // Upadate minimum/maximum values for x and y cordinates.
  307. $c_maxX = (float) $scale_data['maxX'];
  308. if (! isset($min_max['maxX']) || $c_maxX > $min_max['maxX']) {
  309. $min_max['maxX'] = $c_maxX;
  310. }
  311. $c_minX = (float) $scale_data['minX'];
  312. if (! isset($min_max['minX']) || $c_minX < $min_max['minX']) {
  313. $min_max['minX'] = $c_minX;
  314. }
  315. $c_maxY = (float) $scale_data['maxY'];
  316. if (! isset($min_max['maxY']) || $c_maxY > $min_max['maxY']) {
  317. $min_max['maxY'] = $c_maxY;
  318. }
  319. $c_minY = (float) $scale_data['minY'];
  320. if (! isset($min_max['minY']) || $c_minY < $min_max['minY']) {
  321. $min_max['minY'] = $c_minY;
  322. }
  323. }
  324. // scale the visualization
  325. $x_ratio = ($min_max['maxX'] - $min_max['minX']) / $plot_width;
  326. $y_ratio = ($min_max['maxY'] - $min_max['minY']) / $plot_height;
  327. $ratio = ($x_ratio > $y_ratio) ? $x_ratio : $y_ratio;
  328. $scale = ($ratio != 0) ? (1 / $ratio) : 1;
  329. if ($x_ratio < $y_ratio) {
  330. // center horizontally
  331. $x = ($min_max['maxX'] + $min_max['minX'] - $plot_width / $scale) / 2;
  332. // fit vertically
  333. $y = $min_max['minY'] - ($border / $scale);
  334. } else {
  335. // fit horizontally
  336. $x = $min_max['minX'] - ($border / $scale);
  337. // center vertically
  338. $y =($min_max['maxY'] + $min_max['minY'] - $plot_height / $scale) / 2;
  339. }
  340. return array(
  341. 'scale' => $scale,
  342. 'x' => $x,
  343. 'y' => $y,
  344. 'minX' => $min_max['minX'],
  345. 'maxX' => $min_max['maxX'],
  346. 'minY' => $min_max['minY'],
  347. 'maxY' => $min_max['maxY'],
  348. 'height' => $this->_settings['height'],
  349. );
  350. }
  351. /**
  352. * Prepares and return the dataset as needed by the visualization.
  353. *
  354. * @param array $data Raw data
  355. * @param array $scale_data Data related to scaling
  356. * @param string $format Format of the visulaization
  357. * @param image $results Image object in the case of png
  358. *
  359. * @return the formatted array of data.
  360. */
  361. private function _prepareDataSet($data, $scale_data, $format, $results)
  362. {
  363. $color_number = 0;
  364. // loop through the rows
  365. foreach ($data as $row) {
  366. $index = $color_number % sizeof($this->_settings['colors']);
  367. // Figure out the data type
  368. $ref_data = $row[$this->_settings['spatialColumn']];
  369. $type_pos = stripos($ref_data, '(');
  370. $type = substr($ref_data, 0, $type_pos);
  371. $gis_obj = PMA_GIS_Factory::factory($type);
  372. if (! $gis_obj) {
  373. continue;
  374. }
  375. $label = '';
  376. if (isset($this->_settings['labelColumn'])
  377. && isset($row[$this->_settings['labelColumn']])
  378. ) {
  379. $label = $row[$this->_settings['labelColumn']];
  380. }
  381. if ($format == 'svg') {
  382. $results .= $gis_obj->prepareRowAsSvg(
  383. $row[$this->_settings['spatialColumn']], $label,
  384. $this->_settings['colors'][$index], $scale_data
  385. );
  386. } elseif ($format == 'png') {
  387. $results = $gis_obj->prepareRowAsPng(
  388. $row[$this->_settings['spatialColumn']], $label,
  389. $this->_settings['colors'][$index], $scale_data, $results
  390. );
  391. } elseif ($format == 'pdf') {
  392. $results = $gis_obj->prepareRowAsPdf(
  393. $row[$this->_settings['spatialColumn']], $label,
  394. $this->_settings['colors'][$index], $scale_data, $results
  395. );
  396. } elseif ($format == 'ol') {
  397. $results .= $gis_obj->prepareRowAsOl(
  398. $row[$this->_settings['spatialColumn']], $row['srid'],
  399. $label, $this->_settings['colors'][$index], $scale_data
  400. );
  401. }
  402. $color_number++;
  403. }
  404. return $results;
  405. }
  406. }
  407. ?>