試用 SpatiaLite(五):網上郵筒資料庫

先前試過將香港郵筒的資料輸入資料庫,這一次我就試試將這個資料庫供 PHP 讀取,製成網上郵筒資料庫。

由於預設的地圖範圍只有一小區,所以不用一下子將全港的郵筒位置傳送到瀏覽器,而是利用 Leaflet 這 JavaScript 地圖程式庫的 Bound 功能,當用戶移動地圖範圍時,程式將地圖時的左上角和右下角的經緯度經 Ajax 傳送到另一 PHP 去處理,有結果之後就將各點加到地圖上。

此 PHP 會將這兩組經緯度,向 SpatiaLite 查詢。因為我用了 R* Index,查詢的速度很快。

我亦用了 HTML5 裡的位置功能,用戶可點選「尋找我附近的郵筒」,地圖便自動跳往用戶身在的位置。

效果圖:
hkpost14

點選那些標記可見詳細資料:
hkpost15

供用戶使用的 index.html:
<!DOCTYPE html>
<html>
	<head>
		<title>香港郵筒地圖</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
		<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
		<style>
			#map { height: 500px; width:600px; }
		</style>
		<!--[if lte IE 8]>
			<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
		<![endif]-->
		<script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>
		<script>
		var map = null;
		var currentMarkerLayerGroup = L.layerGroup();
		$(function(){
			$("#lookForMyPos").click(function(){
				if(navigator.geolocation){
					navigator.geolocation.getCurrentPosition(function(position){
						map.setView([position.coords.latitude, position.coords.longitude], 15);
					}, function(){
						alert("未能取得你的位置!");
					});
				}else{
					alert("你的瀏覽器不支援此功能!");
				}
			});
		 
			map = L.map('map', {"minZoom": 10}).setView([22.4518, 114.1689], 14);
			
			L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
				attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
			}).addTo(map);
			
			map.addEventListener("dragend zoomend", function(obj){
				var bound = map.getBounds();
				getAjaxResult(bound.getNorthWest().lat, bound.getNorthWest().lng, bound.getSouthEast().lat,  bound.getSouthEast().lng);
			});
			
			var bound = map.getBounds();
			getAjaxResult(bound.getNorthWest().lat, bound.getNorthWest().lng, bound.getSouthEast().lat,  bound.getSouthEast().lng);
		 
		 });
		 
		function getAjaxResult(bound1Lat, bound1Lon, bound2Lat, bound2Lon){
			var request = $.ajax({
				url: "getdata.php",
				type: "GET",
				data: {bound1Lon: bound1Lon, bound1Lat: bound1Lat, bound2Lon: bound2Lon, bound2Lat: bound2Lat},
				dataType: "json"
			});
 
			request.done(function(msg) {
				plotResult(msg);
			});

		 }
		 
		function plotResult(result){
			currentMarkerLayerGroup.clearLayers();
			currentMarkerLayerGroup = L.layerGroup();
			for(var i = 0; i < result.length; i++){
				var item = result[i];
				var marker = L.marker([item.LAT, item.LON]);
				marker.bindPopup(item.CHI_NAME + "<br />" + item.CHI_DISTRICT + " - " + item.CHI_SUB_DISTRICT + "<br />" + item.CHI_ADDRESS + "<br />" + item.CHI_LAST_COLLECTION_TIME);
				currentMarkerLayerGroup.addLayer(marker);

			}
			
			currentMarkerLayerGroup.addTo(map);
		 }
		</script>
	</head>
	<body>
		<span style="font-size: 25px;">香港郵筒地圖</span> - <a href="javascript: void(0);" id="lookForMyPos">尋找我附近的郵筒</a><br />
		<div id="map"></div>
		<br />
		免責聲明<br />
		本網站/產品/服務載有的一些資料,是複製或摘錄自香港特別行政區政府(下稱「政府」)「地理資訊地圖」的「資料下載」功能(http://www.map.gov.hk)的資料。本網站、產品或服務提供複製、下載或摘錄自「地理資訊地圖」所載的資料或連接至「地理資訊地圖」的連結,並不構成政府與本網站、產品或服務或其所載任何內容有關的任何人士或公司有任何形式的合作或聯繫。本網站、產品或服務並無任何材料構成政府申述、保證或暗示其同意、認可、推薦或批准本網站、產品或服務的任何內容。對於因你使用或不當使用或依據或不能使用本網站、產品或服務的任何內容而引致或所涉及的任何損失、毀壞或損害(包括但不限於相應而生的損失、毀壞或損害),政府概不承擔任何法律責任、義務或責任。
	</body>
</html>

負責向資料庫查詢的 getdata.php
<?php
	$db = new SQLite3('db.sqlite');
	$db->loadExtension('libspatialite.so');
	$db->exec("SELECT InitSpatialMetadata()");

	$bound1Lat = $_GET["bound1Lat"];
	$bound1Lon = $_GET["bound1Lon"];
	$bound2Lat = $_GET["bound2Lat"];
	$bound2Lon = $_GET["bound2Lon"];

	$stmt = $db->prepare('SELECT CHI_NAME, CHI_ADDRESS, CHI_DISTRICT, CHI_SUB_DISTRICT, CHI_LAST_COLLECTION_TIME, X(geometry_wgs84) as lon, Y(geometry_wgs84) as lat FROM hkpost WHERE ROWID IN (SELECT pkid FROM idx_hkpost_geometry_wgs84 WHERE pkid MATCH RTreeIntersects(:bound1Lon, :bound1Lat, :bound2Lon, :bound2Lat));');
	$stmt->bindValue(':bound1Lon', $bound1Lon);
	$stmt->bindValue(':bound1Lat', $bound1Lat);
	$stmt->bindValue(':bound2Lon', $bound2Lon);
	$stmt->bindValue(':bound2Lat', $bound2Lat);
	$result = $stmt->execute();
	$resultArray = array();
	while ($row = $result->fetchArray()){
			$resultArray[] = array("CHI_NAME" => $row["CHI_NAME"], "CHI_ADDRESS" => $row["CHI_ADDRESS"],
				"CHI_DISTRICT" => $row["CHI_DISTRICT"], "CHI_SUB_DISTRICT" => $row["CHI_SUB_DISTRICT"],
				"CHI_LAST_COLLECTION_TIME" => $row["CHI_LAST_COLLECTION_TIME"], "LAT" => $row["lat"], "LON" => $row["lon"]);
	}
	
	print json_encode($resultArray);
?>

內部連結:
【目錄】地理/地理資訊系統/空間資料庫/大地測量內部連結

本文連結