PageRenderTime 65ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/application/controllers/json.php

https://github.com/fayazv/Taarifa_Web
PHP | 951 lines | 677 code | 143 blank | 131 comment | 46 complexity | a29c8913ed91698a4e719cbcf5d535eb MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-3.0, BSD-3-Clause, LGPL-2.1
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Json Controller
  4. * Generates Map GeoJSON File
  5. *
  6. * PHP version 5
  7. * LICENSE: This source file is subject to LGPL license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.gnu.org/copyleft/lesser.html
  10. * @author Ushahidi Team <team@ushahidi.com>
  11. * @package Ushahidi - http://source.ushahididev.com
  12. * @subpackage Controllers
  13. * @copyright Ushahidi - http://www.ushahidi.com
  14. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License (LGPL)
  15. */
  16. class Json_Controller extends Template_Controller
  17. {
  18. /**
  19. * Automatically render the views
  20. * @var bool
  21. */
  22. public $auto_render = TRUE;
  23. /**
  24. * Name of the view template for this controller
  25. * @var string
  26. */
  27. public $template = 'json';
  28. /**
  29. * Database table prefix
  30. * @var string
  31. */
  32. protected $table_prefix;
  33. public function __construct()
  34. {
  35. parent::__construct();
  36. // Set Table Prefix
  37. $this->table_prefix = Kohana::config('database.default.table_prefix');
  38. // Cacheable JSON Controller
  39. $this->is_cachable = TRUE;
  40. }
  41. /**
  42. * Generate JSON in NON-CLUSTER mode
  43. */
  44. public function index()
  45. {
  46. $json = "";
  47. $json_item = "";
  48. $json_array = array();
  49. $color = Kohana::config('settings.default_map_all');
  50. $icon = "";
  51. $media_type = (isset($_GET['m']) AND intval($_GET['m']) > 0)? intval($_GET['m']) : 0;
  52. // Get the incident and category id
  53. $category_id = (isset($_GET['c']) AND intval($_GET['c']) > 0)? intval($_GET['c']) : 0;
  54. $incident_id = (isset($_GET['i']) AND intval($_GET['i']) > 0)? intval($_GET['i']) : 0;
  55. // Get the category colour
  56. if (Category_Model::is_valid_category($category_id))
  57. {
  58. $color = ORM::factory('category', $category_id)->category_color;
  59. }
  60. // Fetch the incidents
  61. $markers = (isset($_GET['page']) AND intval($_GET['page']) > 0)? reports::fetch_incidents(TRUE) : reports::fetch_incidents();
  62. // Variable to store individual item for report detail page
  63. $json_item_first = "";
  64. foreach ($markers as $marker)
  65. {
  66. $thumb = "";
  67. if ($media_type == 1)
  68. {
  69. $media = ORM::factory('incident', $marker->incident_id)->media;
  70. if ($media->count())
  71. {
  72. foreach ($media as $photo)
  73. {
  74. if ($photo->media_thumb)
  75. {
  76. // Get the first thumb
  77. $prefix = url::base().Kohana::config('upload.relative_directory');
  78. $thumb = $prefix."/".$photo->media_thumb;
  79. break;
  80. }
  81. }
  82. }
  83. }
  84. $json_item = "{";
  85. $json_item .= "\"type\":\"Feature\",";
  86. $json_item .= "\"properties\": {";
  87. $json_item .= "\"id\": \"".$marker->incident_id."\", \n";
  88. $encoded_title = utf8tohtml::convert($marker->incident_title, TRUE);
  89. $encoded_title = str_ireplace('"','&#34;',$encoded_title);
  90. $encoded_title = json_encode($encoded_title);
  91. $encoded_title = str_ireplace('"', '', $encoded_title);
  92. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a "
  93. . "href='".url::base()."reports/view/".$marker->incident_id."'>".$encoded_title)."</a>") . "\","
  94. . "\"link\": \"".url::base()."reports/view/".$marker->incident_id."\", ";
  95. $json_item .= (isset($category))
  96. ? "\"category\":[" . $category_id . "], "
  97. : "\"category\":[0], ";
  98. $json_item .= "\"color\": \"".$color."\", \n";
  99. $json_item .= "\"icon\": \"".$icon."\", \n";
  100. $json_item .= "\"thumb\": \"".$thumb."\", \n";
  101. $json_item .= "\"timestamp\": \"" . strtotime($marker->incident_date) . "\"";
  102. $json_item .= "},";
  103. $json_item .= "\"geometry\": {";
  104. $json_item .= "\"type\":\"Point\", ";
  105. $json_item .= "\"coordinates\":[" . $marker->longitude . ", " . $marker->latitude . "]";
  106. $json_item .= "}";
  107. $json_item .= "}";
  108. if ($marker->incident_id == $incident_id)
  109. {
  110. $json_item_first = $json_item;
  111. }
  112. else
  113. {
  114. array_push($json_array, $json_item);
  115. }
  116. // Get Incident Geometries
  117. $geometry = $this->_get_geometry($marker->incident_id, $marker->incident_title, $marker->incident_date);
  118. if (count($geometry))
  119. {
  120. $json_item = implode(",", $geometry);
  121. array_push($json_array, $json_item);
  122. }
  123. }
  124. if ($json_item_first)
  125. {
  126. // Push individual marker in last so that it is layered on top when pulled into map
  127. array_push($json_array, $json_item_first);
  128. }
  129. $json = implode(",", $json_array);
  130. header('Content-type: application/json; charset=utf-8');
  131. $this->template->json = $json;
  132. }
  133. /**
  134. * Generate JSON in CLUSTER mode
  135. */
  136. public function cluster()
  137. {
  138. // Database
  139. $db = new Database();
  140. $json = "";
  141. $json_item = "";
  142. $json_array = array();
  143. $geometry_array = array();
  144. $color = Kohana::config('settings.default_map_all');
  145. $icon = "";
  146. // Get Zoom Level
  147. $zoomLevel = (isset($_GET['z']) AND !empty($_GET['z'])) ?
  148. (int) $_GET['z'] : 8;
  149. //$distance = 60;
  150. $distance = (10000000 >> $zoomLevel) / 100000;
  151. // Fetch the incidents using the specified parameters
  152. $incidents = reports::fetch_incidents();
  153. // Category ID
  154. $category_id = (isset($_GET['c']) AND intval($_GET['c']) > 0) ? intval($_GET['c']) : 0;
  155. // Start date
  156. $start_date = (isset($_GET['s']) AND intval($_GET['s']) > 0) ? intval($_GET['s']) : NULL;
  157. // End date
  158. $end_date = (isset($_GET['e']) AND intval($_GET['e']) > 0) ? intval($_GET['e']) : NULL;
  159. if (Category_Model::is_valid_category($category_id))
  160. {
  161. // Get the color
  162. $color = ORM::factory('category', $category_id)->category_color;
  163. }
  164. // Create markers by marrying the locations and incidents
  165. $markers = array();
  166. foreach ($incidents as $incident)
  167. {
  168. $markers[] = array(
  169. 'id' => $incident->incident_id,
  170. 'incident_title' => $incident->incident_title,
  171. 'latitude' => $incident->latitude,
  172. 'longitude' => $incident->longitude,
  173. 'thumb' => ''
  174. );
  175. }
  176. $clusters = array(); // Clustered
  177. $singles = array(); // Non Clustered
  178. // Loop until all markers have been compared
  179. while (count($markers))
  180. {
  181. $marker = array_pop($markers);
  182. $cluster = array();
  183. // Compare marker against all remaining markers.
  184. foreach ($markers as $key => $target)
  185. {
  186. // This function returns the distance between two markers, at a defined zoom level.
  187. // $pixels = $this->_pixelDistance($marker['latitude'], $marker['longitude'],
  188. // $target['latitude'], $target['longitude'], $zoomLevel);
  189. $pixels = abs($marker['longitude']-$target['longitude']) +
  190. abs($marker['latitude']-$target['latitude']);
  191. // If two markers are closer than defined distance, remove compareMarker from array and add to cluster.
  192. if ($pixels < $distance)
  193. {
  194. unset($markers[$key]);
  195. $target['distance'] = $pixels;
  196. $cluster[] = $target;
  197. }
  198. }
  199. // If a marker was added to cluster, also add the marker we were comparing to.
  200. if (count($cluster) > 0)
  201. {
  202. $cluster[] = $marker;
  203. $clusters[] = $cluster;
  204. }
  205. else
  206. {
  207. $singles[] = $marker;
  208. }
  209. }
  210. // Create Json
  211. foreach ($clusters as $cluster)
  212. {
  213. // Calculate cluster center
  214. $bounds = $this->_calculateCenter($cluster);
  215. $cluster_center = $bounds['center'];
  216. $southwest = $bounds['sw'];
  217. $northeast = $bounds['ne'];
  218. // Number of Items in Cluster
  219. $cluster_count = count($cluster);
  220. // Get the time filter
  221. $time_filter = ( ! empty($start_date) AND ! empty($end_date))
  222. ? "&s=".$start_date."&e=".$end_date
  223. : "";
  224. // Build out the JSON string
  225. $json_item = "{";
  226. $json_item .= "\"type\":\"Feature\",";
  227. $json_item .= "\"properties\": {";
  228. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href=" . url::base()
  229. . "reports/index/?c=".$category_id."&sw=".$southwest."&ne=".$northeast.$time_filter.">" . $cluster_count . " Reports</a>")) . "\",";
  230. $json_item .= "\"link\": \"".url::base()."reports/index/?c=".$category_id."&sw=".$southwest."&ne=".$northeast.$time_filter."\", ";
  231. $json_item .= "\"category\":[0], ";
  232. $json_item .= "\"color\": \"".$color."\", ";
  233. $json_item .= "\"icon\": \"".$icon."\", ";
  234. $json_item .= "\"thumb\": \"\", ";
  235. $json_item .= "\"timestamp\": \"0\", ";
  236. $json_item .= "\"count\": \"" . $cluster_count . "\"";
  237. $json_item .= "},";
  238. $json_item .= "\"geometry\": {";
  239. $json_item .= "\"type\":\"Point\", ";
  240. $json_item .= "\"coordinates\":[" . $cluster_center . "]";
  241. $json_item .= "}";
  242. $json_item .= "}";
  243. array_push($json_array, $json_item);
  244. }
  245. foreach ($singles as $single)
  246. {
  247. $json_item = "{";
  248. $json_item .= "\"type\":\"Feature\",";
  249. $json_item .= "\"properties\": {";
  250. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href=" . url::base()
  251. . "reports/view/" . $single['id'] . "/>".str_replace('"','\"',$single['incident_title'])."</a>")) . "\",";
  252. $json_item .= "\"link\": \"".url::base()."reports/view/".$single['id']."\", ";
  253. $json_item .= "\"category\":[0], ";
  254. $json_item .= "\"color\": \"".$color."\", ";
  255. $json_item .= "\"icon\": \"".$icon."\", ";
  256. // $json_item .= "\"thumb\": \"".$single['thumb']."\", ";
  257. $json_item .= "\"timestamp\": \"0\", ";
  258. $json_item .= "\"count\": \"" . 1 . "\"";
  259. $json_item .= "},";
  260. $json_item .= "\"geometry\": {";
  261. $json_item .= "\"type\":\"Point\", ";
  262. $json_item .= "\"coordinates\":[" . $single['longitude'] . ", " . $single['latitude'] . "]";
  263. $json_item .= "}";
  264. $json_item .= "}";
  265. array_push($json_array, $json_item);
  266. }
  267. $json = implode(",", $json_array);
  268. //
  269. // E.Kala July 27, 2011
  270. // @todo Parking this geometry business for review
  271. //
  272. // if (count($geometry_array))
  273. // {
  274. // $json = implode(",", $geometry_array).",".$json;
  275. // }
  276. header('Content-type: application/json; charset=utf-8');
  277. $this->template->json = $json;
  278. }
  279. /**
  280. * Retrieve Single Marker
  281. */
  282. public function single($incident_id = 0)
  283. {
  284. $json = "";
  285. $json_item = "";
  286. $json_array = array();
  287. // Get the neigbouring incidents
  288. $neighbours = Incident_Model::get_neighbouring_incidents($incident_id, FALSE, 20, 100);
  289. if ($neighbours)
  290. {
  291. // Load the incident
  292. // @todo Get this fixed
  293. $marker = ORM::factory('incident', $incident_id);
  294. // Get the incident/report date
  295. $incident_date = date('Y-m', strtotime($marker->incident_date));
  296. foreach ($neighbours as $row)
  297. {
  298. $json_item = "{";
  299. $json_item .= "\"type\":\"Feature\",";
  300. $json_item .= "\"properties\": {";
  301. $json_item .= "\"id\": \"".$row->id."\", ";
  302. $encoded_title = utf8tohtml::convert($row->incident_title,TRUE);
  303. $encoded_title = str_ireplace('"','&#34;',$encoded_title);
  304. $encoded_title = json_encode($encoded_title);
  305. $encoded_title = str_ireplace('"','',$encoded_title);
  306. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='" . url::base()
  307. . "reports/view/" . $row->id . "'>".$encoded_title."</a>")) . "\",";
  308. $json_item .= "\"link\": \"".url::base()."reports/view/".$row->id."\", ";
  309. $json_item .= "\"category\":[0], ";
  310. $json_item .= "\"timestamp\": \"" . strtotime($row->incident_date) . "\"";
  311. $json_item .= "},";
  312. $json_item .= "\"geometry\": {";
  313. $json_item .= "\"type\":\"Point\", ";
  314. $json_item .= "\"coordinates\":[" . $row->longitude . ", " . $row->latitude . "]";
  315. $json_item .= "}";
  316. $json_item .= "}";
  317. array_push($json_array, $json_item);
  318. }
  319. // Single Main Incident
  320. $json_single = "{";
  321. $json_single .= "\"type\":\"Feature\",";
  322. $json_single .= "\"properties\": {";
  323. $json_single .= "\"id\": \"".$marker->id."\", ";
  324. $encoded_title = utf8tohtml::convert($marker->incident_title,TRUE);
  325. $json_single .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='" . url::base()
  326. . "reports/view/" . $marker->id . "'>".$encoded_title."</a>")) . "\",";
  327. $json_single .= "\"link\": \"".url::base()."reports/view/".$marker->id."\", ";
  328. $json_single .= "\"category\":[0], ";
  329. $json_single .= "\"timestamp\": \"" . strtotime($marker->incident_date) . "\"";
  330. // Get Incident Geometries
  331. $geometry = $this->_get_geometry($marker->id, $marker->incident_title, $marker->incident_date);
  332. // If there are no geometries, use Single Incident Marker
  333. if ( ! count($geometry))
  334. {
  335. $json_item = "{";
  336. $json_item .= "\"type\":\"Feature\",";
  337. $json_item .= "\"properties\": {";
  338. $json_item .= "\"id\": \"".$marker->id."\", ";
  339. $encoded_title = utf8tohtml::convert($marker->incident_title,TRUE);
  340. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='" . url::base()
  341. . "reports/view/" . $marker->id . "'>".$encoded_title."</a>")) . "\",";
  342. $json_item .= "\"link\": \"".url::base()."reports/view/".$marker->id."\", ";
  343. $json_item .= "\"category\":[0], ";
  344. $json_item .= "\"timestamp\": \"" . strtotime($marker->incident_date) . "\"";
  345. $json_item .= "},\"geometry\":";
  346. $json_item .= "{\"type\":\"Point\", ";
  347. $json_item .= "\"coordinates\":[" . $marker->location->longitude . ", " . $marker->location->latitude . "]";
  348. $json_item .= "}";
  349. $json_item .= "}";
  350. }
  351. else
  352. {
  353. $json_item = implode(",", $geometry);
  354. }
  355. array_push($json_array, $json_item);
  356. }
  357. $json = implode(",", $json_array);
  358. header('Content-type: application/json; charset=utf-8');
  359. $this->template->json = $json;
  360. }
  361. /**
  362. * Retrieve timeline JSON
  363. */
  364. public function timeline( $category_id = 0 )
  365. {
  366. $category_id = (int) $category_id;
  367. $this->auto_render = FALSE;
  368. $db = new Database();
  369. $interval = (isset($_GET["i"]) AND !empty($_GET["i"])) ?
  370. $_GET["i"] : "month";
  371. // Get Category Info
  372. if ($category_id > 0)
  373. {
  374. $category = ORM::factory("category", $category_id);
  375. if ($category->loaded)
  376. {
  377. $category_title = $category->category_title;
  378. $category_color = "#".$category->category_color;
  379. }
  380. else
  381. {
  382. break;
  383. }
  384. }
  385. else
  386. {
  387. $category_title = "All Categories";
  388. $category_color = "#990000";
  389. }
  390. // Get the Counts
  391. $select_date_text = "DATE_FORMAT(incident_date, '%Y-%m-01')";
  392. $groupby_date_text = "DATE_FORMAT(incident_date, '%Y%m')";
  393. if ($interval == 'day')
  394. {
  395. $select_date_text = "DATE_FORMAT(incident_date, '%Y-%m-%d')";
  396. $groupby_date_text = "DATE_FORMAT(incident_date, '%Y%m%d')";
  397. }
  398. elseif ($interval == 'hour')
  399. {
  400. $select_date_text = "DATE_FORMAT(incident_date, '%Y-%m-%d %H:%M')";
  401. $groupby_date_text = "DATE_FORMAT(incident_date, '%Y%m%d%H')";
  402. }
  403. elseif ($interval == 'week')
  404. {
  405. $select_date_text = "STR_TO_DATE(CONCAT(CAST(YEARWEEK(incident_date) AS CHAR), ' Sunday'), '%X%V %W')";
  406. $groupby_date_text = "YEARWEEK(incident_date)";
  407. }
  408. $graph_data = array();
  409. $graph_data[0] = array();
  410. $graph_data[0]['label'] = $category_title;
  411. $graph_data[0]['color'] = $category_color;
  412. $graph_data[0]['data'] = array();
  413. // Gather allowed ids if we are looking at a specific category
  414. $allowed_ids = array();
  415. if($category_id != 0)
  416. {
  417. $query = 'SELECT ic.incident_id AS incident_id FROM '.$this->table_prefix.'incident_category AS ic INNER JOIN '.$this->table_prefix.'category AS c ON (ic.category_id = c.id) WHERE c.id='.$category_id.' OR c.parent_id='.$category_id.';';
  418. $query = $db->query($query);
  419. foreach ( $query as $items )
  420. {
  421. $allowed_ids[] = $items->incident_id;
  422. }
  423. }
  424. // Add aditional filter here to only allow for incidents that are in the requested category
  425. $incident_id_in = '';
  426. if(count($allowed_ids) AND $category_id != 0)
  427. {
  428. $incident_id_in = ' AND id IN ('.implode(',',$allowed_ids).')';
  429. }
  430. elseif(count($allowed_ids) == 0 AND $category_id != 0)
  431. {
  432. $incident_id_in = ' AND 3 = 4';
  433. }
  434. $query = 'SELECT UNIX_TIMESTAMP('.$select_date_text.') AS time, COUNT(id) AS number FROM '.$this->table_prefix.'incident WHERE incident_active = 1 '.$incident_id_in.' GROUP BY '.$groupby_date_text;
  435. $query = $db->query($query);
  436. foreach ( $query as $items )
  437. {
  438. array_push($graph_data[0]['data'],
  439. array($items->time * 1000, $items->number));
  440. }
  441. echo json_encode($graph_data);
  442. }
  443. /**
  444. * Read in new layer KML via file_get_contents
  445. * @param int $layer_id - ID of the new KML Layer
  446. */
  447. public function layer($layer_id = 0)
  448. {
  449. $this->template = "";
  450. $this->auto_render = FALSE;
  451. $layer = ORM::factory('layer')
  452. ->where('layer_visible', 1)
  453. ->find($layer_id);
  454. if ($layer->loaded)
  455. {
  456. $layer_url = $layer->layer_url;
  457. $layer_file = $layer->layer_file;
  458. $layer_link = (!$layer_url) ?
  459. url::base().Kohana::config('upload.relative_directory').'/'.$layer_file :
  460. $layer_url;
  461. $content = file_get_contents($layer_link);
  462. if ($content !== false)
  463. {
  464. echo $content;
  465. }
  466. else
  467. {
  468. echo "";
  469. }
  470. }
  471. else
  472. {
  473. echo "";
  474. }
  475. }
  476. /**
  477. * Read in new layer JSON from shared connection
  478. * @param int $sharing_id - ID of the new Share Layer
  479. */
  480. public function share( $sharing_id = false )
  481. {
  482. $json = "";
  483. $json_item = "";
  484. $json_array = array();
  485. $sharing_data = "";
  486. $clustering = Kohana::config('settings.allow_clustering');
  487. if ($sharing_id)
  488. {
  489. // Get This Sharing ID Color
  490. $sharing = ORM::factory('sharing')
  491. ->find($sharing_id);
  492. if( ! $sharing->loaded )
  493. return;
  494. $sharing_url = $sharing->sharing_url;
  495. $sharing_color = $sharing->sharing_color;
  496. if ($clustering)
  497. {
  498. // Database
  499. $db = new Database();
  500. // Start Date
  501. $start_date = (isset($_GET['s']) && !empty($_GET['s'])) ?
  502. (int) $_GET['s'] : "0";
  503. // End Date
  504. $end_date = (isset($_GET['e']) && !empty($_GET['e'])) ?
  505. (int) $_GET['e'] : "0";
  506. // SouthWest Bound
  507. $southwest = (isset($_GET['sw']) && !empty($_GET['sw'])) ?
  508. $_GET['sw'] : "0";
  509. $northeast = (isset($_GET['ne']) && !empty($_GET['ne'])) ?
  510. $_GET['ne'] : "0";
  511. // Get Zoom Level
  512. $zoomLevel = (isset($_GET['z']) && !empty($_GET['z'])) ?
  513. (int) $_GET['z'] : 8;
  514. //$distance = 60;
  515. $distance = (10000000 >> $zoomLevel) / 100000;
  516. $filter = "";
  517. $filter .= ($start_date) ?
  518. " AND incident_date >= '" . date("Y-m-d H:i:s", $start_date) . "'" : "";
  519. $filter .= ($end_date) ?
  520. " AND incident_date <= '" . date("Y-m-d H:i:s", $end_date) . "'" : "";
  521. if ($southwest && $northeast)
  522. {
  523. list($latitude_min, $longitude_min) = explode(',', $southwest);
  524. list($latitude_max, $longitude_max) = explode(',', $northeast);
  525. $filter .= " AND latitude >=".(float) $latitude_min.
  526. " AND latitude <=".(float) $latitude_max;
  527. $filter .= " AND longitude >=".(float) $longitude_min.
  528. " AND longitude <=".(float) $longitude_max;
  529. }
  530. $filter .= " AND sharing_id = ".(int)$sharing_id;
  531. $query = $db->query("SELECT * FROM `".$this->table_prefix."sharing_incident` WHERE 1=1 $filter ORDER BY incident_id ASC ");
  532. $markers = $query->result_array(FALSE);
  533. $clusters = array(); // Clustered
  534. $singles = array(); // Non Clustered
  535. // Loop until all markers have been compared
  536. while (count($markers))
  537. {
  538. $marker = array_pop($markers);
  539. $cluster = array();
  540. // Compare marker against all remaining markers.
  541. foreach ($markers as $key => $target)
  542. {
  543. // This function returns the distance between two markers, at a defined zoom level.
  544. // $pixels = $this->_pixelDistance($marker['latitude'], $marker['longitude'],
  545. // $target['latitude'], $target['longitude'], $zoomLevel);
  546. $pixels = abs($marker['longitude']-$target['longitude']) +
  547. abs($marker['latitude']-$target['latitude']);
  548. // echo $pixels."<BR>";
  549. // If two markers are closer than defined distance, remove compareMarker from array and add to cluster.
  550. if ($pixels < $distance)
  551. {
  552. unset($markers[$key]);
  553. $target['distance'] = $pixels;
  554. $cluster[] = $target;
  555. }
  556. }
  557. // If a marker was added to cluster, also add the marker we were comparing to.
  558. if (count($cluster) > 0)
  559. {
  560. $cluster[] = $marker;
  561. $clusters[] = $cluster;
  562. }
  563. else
  564. {
  565. $singles[] = $marker;
  566. }
  567. }
  568. // Create Json
  569. foreach ($clusters as $cluster)
  570. {
  571. // Calculate cluster center
  572. $bounds = $this->_calculateCenter($cluster);
  573. $cluster_center = $bounds['center'];
  574. $southwest = $bounds['sw'];
  575. $northeast = $bounds['ne'];
  576. // Number of Items in Cluster
  577. $cluster_count = count($cluster);
  578. $json_item = "{";
  579. $json_item .= "\"type\":\"Feature\",";
  580. $json_item .= "\"properties\": {";
  581. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='http://" . $sharing_url . "/reports/index/?c=0&sw=".$southwest."&ne=".$northeast."'>" . $cluster_count . " Reports</a>")) . "\",";
  582. $json_item .= "\"link\": \"http://".$sharing_url."reports/index/?c=0&sw=".$southwest."&ne=".$northeast."\", ";
  583. $json_item .= "\"category\":[0], ";
  584. $json_item .= "\"icon\": \"\", ";
  585. $json_item .= "\"color\": \"".$sharing_color."\", ";
  586. $json_item .= "\"timestamp\": \"0\", ";
  587. $json_item .= "\"count\": \"" . $cluster_count . "\"";
  588. $json_item .= "},";
  589. $json_item .= "\"geometry\": {";
  590. $json_item .= "\"type\":\"Point\", ";
  591. $json_item .= "\"coordinates\":[" . $cluster_center . "]";
  592. $json_item .= "}";
  593. $json_item .= "}";
  594. array_push($json_array, $json_item);
  595. }
  596. foreach ($singles as $single)
  597. {
  598. $json_item = "{";
  599. $json_item .= "\"type\":\"Feature\",";
  600. $json_item .= "\"properties\": {";
  601. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='http://" . $sharing_url . "/reports/view/" . $single['id'] . "'>".$single['incident_title']."</a>")) . "\",";
  602. $json_item .= "\"link\": \"http://".$sharing_url."reports/view/".$single['id']."\", ";
  603. $json_item .= "\"category\":[0], ";
  604. $json_item .= "\"icon\": \"\", ";
  605. $json_item .= "\"color\": \"".$sharing_color."\", ";
  606. $json_item .= "\"timestamp\": \"0\", ";
  607. $json_item .= "\"count\": \"" . 1 . "\"";
  608. $json_item .= "},";
  609. $json_item .= "\"geometry\": {";
  610. $json_item .= "\"type\":\"Point\", ";
  611. $json_item .= "\"coordinates\":[" . $single['longitude'] . ", " . $single['latitude'] . "]";
  612. $json_item .= "}";
  613. $json_item .= "}";
  614. array_push($json_array, $json_item);
  615. }
  616. $json = implode(",", $json_array);
  617. }
  618. else
  619. {
  620. // Retrieve all markers
  621. $markers = ORM::factory('sharing_incident')
  622. ->where('sharing_id', $sharing_id)
  623. ->find_all();
  624. foreach ($markers as $marker)
  625. {
  626. $json_item = "{";
  627. $json_item .= "\"type\":\"Feature\",";
  628. $json_item .= "\"properties\": {";
  629. $json_item .= "\"id\": \"".$marker->incident_id."\", \n";
  630. $encoded_title = utf8tohtml::convert($marker->incident_title,TRUE);
  631. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='http://" . $sharing_url . "/reports/view/" . $marker->incident_id . "'>".$encoded_title."</a>")) . "\",";
  632. $json_item .= "\"link\": \"http://".$sharing_url."reports/view/".$marker->incident_id."\", ";
  633. $json_item .= "\"icon\": \"\", ";
  634. $json_item .= "\"color\": \"".$sharing_color ."\", \n";
  635. $json_item .= "\"timestamp\": \"" . strtotime($marker->incident_date) . "\"";
  636. $json_item .= "},";
  637. $json_item .= "\"geometry\": {";
  638. $json_item .= "\"type\":\"Point\", ";
  639. $json_item .= "\"coordinates\":[" . $marker->longitude . ", " . $marker->latitude . "]";
  640. $json_item .= "}";
  641. $json_item .= "}";
  642. array_push($json_array, $json_item);
  643. }
  644. $json = implode(",", $json_array);
  645. }
  646. }
  647. header('Content-type: application/json; charset=utf-8');
  648. $this->template->json = $json;
  649. }
  650. /**
  651. * Get Geometry JSON
  652. * @param int $incident_id
  653. * @param string $incident_title
  654. * @param int $incident_date
  655. * @return array $geometry
  656. */
  657. private function _get_geometry($incident_id, $incident_title, $incident_date)
  658. {
  659. $geometry = array();
  660. if ($incident_id)
  661. {
  662. $db = new Database();
  663. // Get Incident Geometries via SQL query as ORM can't handle Spatial Data
  664. $sql = "SELECT id, AsText(geometry) as geometry, geometry_label,
  665. geometry_comment, geometry_color, geometry_strokewidth FROM ".$this->table_prefix."geometry
  666. WHERE incident_id=".$incident_id;
  667. $query = $db->query($sql);
  668. $wkt = new Wkt();
  669. foreach ( $query as $item )
  670. {
  671. $geom = $wkt->read($item->geometry);
  672. $geom_array = $geom->getGeoInterface();
  673. $json_item = "{";
  674. $json_item .= "\"type\":\"Feature\",";
  675. $json_item .= "\"properties\": {";
  676. $json_item .= "\"id\": \"".$incident_id."\", ";
  677. $json_item .= "\"feature_id\": \"".$item->id."\", ";
  678. $title = ($item->geometry_label) ?
  679. utf8tohtml::convert($item->geometry_label,TRUE) :
  680. utf8tohtml::convert($incident_title,TRUE);
  681. $fillcolor = ($item->geometry_color) ?
  682. utf8tohtml::convert($item->geometry_color,TRUE) : "ffcc66";
  683. $strokecolor = ($item->geometry_color) ?
  684. utf8tohtml::convert($item->geometry_color,TRUE) : "CC0000";
  685. $strokewidth = ($item->geometry_strokewidth) ? $item->geometry_strokewidth : "3";
  686. $json_item .= "\"name\":\"" . str_replace(chr(10), ' ', str_replace(chr(13), ' ', "<a href='" . url::base() . "reports/view/" . $incident_id . "'>".$title."</a>")) . "\",";
  687. $json_item .= "\"description\": \"" . utf8tohtml::convert($item->geometry_comment,TRUE) . "\", ";
  688. $json_item .= "\"color\": \"" . $fillcolor . "\", ";
  689. $json_item .= "\"strokecolor\": \"" . $strokecolor . "\", ";
  690. $json_item .= "\"strokewidth\": \"" . $strokewidth . "\", ";
  691. $json_item .= "\"link\": \"".url::base()."reports/view/".$incident_id."\", ";
  692. $json_item .= "\"category\":[0], ";
  693. $json_item .= "\"timestamp\": \"" . strtotime($incident_date) . "\"";
  694. $json_item .= "},\"geometry\":".json_encode($geom_array)."}";
  695. $geometry[] = $json_item;
  696. }
  697. }
  698. return $geometry;
  699. }
  700. /**
  701. * Convert Longitude to Cartesian (Pixels) value
  702. * @param double $lon - Longitude
  703. * @return int
  704. */
  705. private function _lonToX($lon)
  706. {
  707. return round(OFFSET + RADIUS * $lon * pi() / 180);
  708. }
  709. /**
  710. * Convert Latitude to Cartesian (Pixels) value
  711. * @param double $lat - Latitude
  712. * @return int
  713. */
  714. private function _latToY($lat)
  715. {
  716. return round(OFFSET - RADIUS *
  717. log((1 + sin($lat * pi() / 180)) /
  718. (1 - sin($lat * pi() / 180))) / 2);
  719. }
  720. /**
  721. * Calculate distance using Cartesian (pixel) coordinates
  722. * @param int $lat1 - Latitude for point 1
  723. * @param int $lon1 - Longitude for point 1
  724. * @param int $lon2 - Latitude for point 2
  725. * @param int $lon2 - Longitude for point 2
  726. * @return int
  727. */
  728. private function _pixelDistance($lat1, $lon1, $lat2, $lon2, $zoom)
  729. {
  730. $x1 = $this->_lonToX($lon1);
  731. $y1 = $this->_latToY($lat1);
  732. $x2 = $this->_lonToX($lon2);
  733. $y2 = $this->_latToY($lat2);
  734. return sqrt(pow(($x1-$x2),2) + pow(($y1-$y2),2)) >> (21 - $zoom);
  735. }
  736. /**
  737. * Calculate the center of a cluster of markers
  738. * @param array $cluster
  739. * @return array - (center, southwest bound, northeast bound)
  740. */
  741. private function _calculateCenter($cluster)
  742. {
  743. // Calculate average lat and lon of clustered items
  744. $south = 0;
  745. $west = 0;
  746. $north = 0;
  747. $east = 0;
  748. $lat_sum = $lon_sum = 0;
  749. foreach ($cluster as $marker)
  750. {
  751. if (!$south)
  752. {
  753. $south = $marker['latitude'];
  754. }
  755. elseif ($marker['latitude'] < $south)
  756. {
  757. $south = $marker['latitude'];
  758. }
  759. if (!$west)
  760. {
  761. $west = $marker['longitude'];
  762. }
  763. elseif ($marker['longitude'] < $west)
  764. {
  765. $west = $marker['longitude'];
  766. }
  767. if (!$north)
  768. {
  769. $north = $marker['latitude'];
  770. }
  771. elseif ($marker['latitude'] > $north)
  772. {
  773. $north = $marker['latitude'];
  774. }
  775. if (!$east)
  776. {
  777. $east = $marker['longitude'];
  778. }
  779. elseif ($marker['longitude'] > $east)
  780. {
  781. $east = $marker['longitude'];
  782. }
  783. $lat_sum += $marker['latitude'];
  784. $lon_sum += $marker['longitude'];
  785. }
  786. $lat_avg = $lat_sum / count($cluster);
  787. $lon_avg = $lon_sum / count($cluster);
  788. $center = $lon_avg.",".$lat_avg;
  789. $sw = $west.",".$south;
  790. $ne = $east.",".$north;
  791. return array(
  792. "center"=>$center,
  793. "sw"=>$sw,
  794. "ne"=>$ne
  795. );
  796. }
  797. }