分類
Javascript

實做使用Google Maps API進行指定位置是否在指定區域內

有個需求是要檢查某地址是否在某特定區域內, 於是思考使用 Google Maps API 來實做, 判斷的部分可以不需要 Google Maps 顯示, 但在測試或開發時, 若有可視的地圖會比較容易理解狀況, 也比較明白指定區域與指定位置的關係, 以下分為幾個部分來進行.

首先需要能繪製指定區域, 這個和程式沒有直接關係, 但透過 Google 的 MyMaps 比較好進行:

http://mymaps.google.com/

進入後, 建立新地圖, 出現 Google Maps 之後, 使用”畫一條線”的”新增內容或形狀”工具來進行區域的繪製:

一點一點地把區域點好後, 點回起點, 就可以產生一個封閉區域了, 再給予命名, 如以下範例:

這個部分可以隨時再進行區域的調整, 到自己滿意為止, 之後我們需要的其實是這個區域的多邊形座標點, 如何取得呢? 點擊新增圖層邊的三個點, 出現選單後, 選匯出成 KML:

就可以取得對應的 KML 檔案了, 打開 KML 檔中, 最重要的是找到座標點, 內容會是這樣的文字:
<coordinates>121.5437222,25.0416515,0.0 …… </coordinates>
這些座標點就是用來做這個指定區域的座標位置了, 接下來才真正要準備實作程式.

寫了一個小程式, 把這些座標點輸出成一串之後 Google Maps API Geometry 會用到的格式:

http://sample.diary.tw/36/tools.htm

我們將上面的 <coordinates> 中的字串, 填入上面小程式的 textarea 之後, 按下”產生區域多邊形座標”, 就可以得到像是這樣的內容:

{lat: 25.0416515, lng:121.5437222},
{lat: 25.0333111, lng:121.543529},
.....

先準備好到這裡, 之後參考這個部分可以進行多邊形繪製:

https://developers.google.com/maps/documentation/javascript/examples/polygon-simple

可以看到其中會需要的陣列就由上面小程式產生的內容填入即可, 記得, 在參考 google maps 的範例程式時, 在 initMap 中, 有個 center 參數和 zoom 參數, 要填入實際上你地圖的位置附近, 不然不會出現在地圖上, 如 google maps 範例內, 是百幕達三角洲地帶, 而且 zoom 是 5, 若是以台北市來看, 大約 zomm 是在 15或16 左右.

如範例: http://sample.diary.tw/36/map1.htm

主要程式碼為:

map = new google.maps.Map(document.getElementById('map'), {
  center: {lat: 25.037828, lng: 121.547204},
  zoom: 16,
});

var testAreaCoords = [
    {lat: 25.0416515, lng:121.5437222},
    {lat: 25.0333111, lng:121.543529},
    {lat: 25.033116700000004, lng:121.5526271},
    {lat: 25.036052399999996, lng:121.55267000000002},
    {lat: 25.0374716, lng:121.55146840000002},
    {lat: 25.038016, lng:121.5513396},
    {lat: 25.0415348, lng:121.5474987},
    {lat: 25.0416515, lng:121.5437222}, 
];

testArea = new google.maps.Polygon({
    paths: testAreaCoords,
    strokeColor: '#FF0000',
    strokeOpacity: 0.8,
    strokeWeight: 3,
    fillColor: '#FF0000',
    fillOpacity: 0.05
    
});
testArea.setMap(map);

接下來就是由指定的地址查找座標, 這個部分會用到 Google Maps API 中的 geocoder, 只需要將地址傳入, 就可以取得對應的座標了, 參考資料:

https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingStatusCodes

程式碼不多, 參考範例:

http://sample.diary.tw/36/map2.htm

輸入地址就可以取得座標(經緯度)

主要程式碼如下(注意, geocoder 是用 callback 方式回傳):

function initMap() {
    geocoder = new google.maps.Geocoder();
}

function codeAddress() {
    var address = document.getElementById("address").value;
    geocoder.geocode({
        'address': address
    }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            alert("lat=" + results[0].geometry.location.lat() + ",lng=" + results[0].geometry.location.lng());
        } else {
            alert("Geocode was not successful for the following reason: " + status);
        }
    });
}

最後就是利用一個很重要的判斷式來判斷某地址(已取得座標)是否在指定區域內, containsLocation() 參考:

https://developers.google.com/maps/documentation/javascript/examples/poly-containsLocation

上面的範例是用點擊地圖的方式, 看點擊的位置是否在百幕達三角洲內, 是的話就是紅色 marker, 不是的話, 就用綠色 marker.

來改寫一下程式碼, 就可以達成判斷指定的地址是否在指定的區域內了, 如範例:

http://sample.diary.tw/36/map3.htm

主要程式碼:

// check if position in polygon
if(google.maps.geometry.poly.containsLocation(results[0].geometry.location, testArea)){
    alert("在指定區域內");
}else{
    alert("不在指定區域內");
}

總結一下:

  1. 先製作指定區域座標陣列(多邊形用)
  2. 使用 geocoder 取得指定的地址轉換為座標
  3. 使用 google.maps.geometry.poly.containsLocation 來判斷2.是否在1.裡面

PS. 記得要先到 https://console.developers.google.com/ 建立一個可以使用 Google Maps API 的應用程式, 並建立對應的 browser key 放到上面的程式碼中, 以順利執行你的 web 應用程式.

分類
PHP

實作讀取twitter內容的方式

今天有個需求, 是要讀取某 twitter 帳號的內容, 該帳號內容原本也就是公開的, 所以也就不用 follow 就可以讀取. 以下簡單介紹程式讀取的方式:

1. 先需要有個 twitter 帳號, 而已必須提供手機號碼並驗證
2. 到 https://apps.twitter.com/ 建立一個應用程式, 建立的時候也會通知你的帳號必須滿足上面 1. 的條件
3. 在建立好的應用程式中, 取得兩個重要的參數, key 與 secret (會在 Keys and Access Tokens 頁籤上)
4. 開始實作程式, 先參考這裡:
https://dev.twitter.com/oauth/reference/post/oauth2/token
https://dev.twitter.com/oauth/application-only
使用 oauth 取得 access token, 程式碼如下:

$key = "[your application key]";
$secret = "[your application secret]";
$access_token = "";

$b64 = base64_encode($key . ":" . $secret);

$url = 'https://api.twitter.com/oauth2/token';
$data = array('grant_type' => 'client_credentials');

$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\nAuthorization: Basic " . $b64 . "\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data),
    ),
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);

if ($result === FALSE) { 
    /* Handle error */ 
}else{
    $json = json_decode($result);
    $access_token = $json->{"access_token"};
}

5. 取到 access_token 後, 就可以利用這個 user_timeline API 進行取得對應帳號的 tweeter 內容:
https://dev.twitter.com/rest/reference/get/statuses/user_timeline
程式碼如下:

$url = "https://api.twitter.com/1.1/statuses/user_timeline.json?count=[筆數]&screen_name=[twitter account]";

$options = array(
    'http' => array(
        'header' => "Authorization: Bearer " . $access_token . "\r\n",
        'method' => "GET",
    ),
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);

if ($result === FALSE) { 
    /* Handle error */ 
}else{
    $json = json_decode($result);
    for($i=0;$i<count($json);$i++){
        echo $json[$i]->{"text"} . "<br>";
    }
}

這樣就可以順利取得對應的 twitter 帳號發表的內容了.

這篇使用了 PHP5 不使用 curl 方式的程式內容, 參考這篇(CURL-less method with PHP5):
http://stackoverflow.com/questions/5647461/how-do-i-send-a-post-request-with-php

分類
WebTrend

有趣的Google Vision API

什麼是 Google Vision API, 先來看看影片吧:

(影片引用自: https://www.youtube.com/watch?v=eve8DkkVdhI)

功能是用 Google 的 Cloud API 來進行視覺辨識的功能, 影片中使用了 GoPiGo (http://www.dexterindustries.com/gopigo/) 來進行影像視覺辨識, 十分有趣而實用的功能, 好厲害呢.

這樣未來的應用就愈來愈多可能了.

繼續閱讀:

分類
程式技術

如何取得Google Plus的user avatar(大頭圖)

繼上次 facebook 取得大頭圖 (link)後, 這次來說明取得 Google Plus大頭圖的方式.

需要先取得一個 Google Plus API 的 key (目前共有4種, server、browser、android、ios), 依實際需求來使用, 若要方便測試, 可以建立 server api key, 並設限 ip 0.0.0.0/0 全開放, 或是 browser api key 並設限為不限網域全開放.

接下來我們將使用的 Google Plus Api 是這個: plus.people.get, 參考以下網址:
http://developers.google.com/apis-explorer/?hl=zh_TW#p/plus/v1/plus.people.get

由於我們要取得大頭圖, 所以 fields 是使用 image, 可以獲得 api 存取需要以下網址:
https://www.googleapis.com/plus/v1/people/{user_google_plus_id}?fields=image&key={YOUR_API_KEY}

接下來訪問這個 url:
https://www.googleapis.com/plus/v1/people/106189723444098348646?fields=image&key={YOUR_API_KEY}

就可以取得如下回應:

{
 "image": {
  "url": "https://lh3.googleusercontent.com/-Y86IN-vEObo/AAAAAAAAAAI/AAAAAAADO1I/QzjOGHq5kNQ/photo.jpg?sz=50",
  "isDefault": false
 }
}

這個大頭圖的 url 就會出現囉. 大家猜一下是哪位呢?

參考資料:
http://stackoverflow.com/questions/17962759/is-it-possible-to-create-an-avatar-profile-picture-link-from-a-google-id
https://developers.google.com/+/api/oauth?hl=zh-tw

分類
程式技術

Facebook Avatar – 大頭圖取得

可以利用 Facebook 的 Graph API 進行即可.

facebook avatar api:
http://graph.facebook.com/[user-id]/picture default: 50×50

http://graph.facebook.com/[user-id]/picture?height=100&width=100 for 100×100

其中的 [user-id] 直接拿驗證後的 fbid 值即可, 原始的 fbid 也是可以正常使用的, 另外有設定自訂名稱的亦可.

參考資料: https://developers.facebook.com/docs/graph-api/reference/v2.2/user/picture?locale=zh_TW

例如:

http://graph.facebook.com/4/picture
http://graph.facebook.com/zuck/picture
http://graph.facebook.com/4/picture?height=300&width=300

分類
WebTrend

Google QRCode Chart API

使用 Google Chart API 來產生 QRCode 很方便, 可以參考這裡的資料:
https://developers.google.com/chart/infographics/docs/qr_codes

一般來說會用到的參數共有以下:

  1. cht=qr
  2. chs=[width]x[height] (產生的長寬)
  3. chl=[data] (要產生的內容, 可以放文字或網址等資訊)

所以以本站網址為例, QRCode 為:
http://chart.apis.google.com/chart?cht=qr&chs=200×200&chl=http%3A//diary.tw/tim

以圖片顯示為:

Google Chart API 產生 QR Code還真的蠻方便的.

[2014/8/27]
補充, 若是需要大量產生, 可以利用這個網站服務, 一次可以免費批次產生100個QRCode, 也十分方便好用.
http://www.qrexplore.com/generate/

另外也有個線上辨識Barcode、QRCode的服務, 可以用圖片網址或是傳送圖片的方式進行, 方便大家在產生QRCode的驗證.
http://zxing.org/w/decode.jspx

分類
程式技術

使用Facebook FQL查詢留言資料

用 Facebook 的網頁/網站很多, 應該是已經過了大流行的階段, 但是使用 Facebook 的地方還是很多, 如何利用程式將公開性的 Facebook 資料找查出來, 有方便好用的工具可供應用, 就是使用 FQL 查詢. 這裡介紹一般常用在網頁上留言的資料, Comment Plugin, 查找留言資訊.

先來看這篇: https://developers.facebook.com/docs/reference/fql/comment

這篇介紹 FQL 的 comment 資料查找方式, 我們以這個網頁作為例子:
http://sample.diary.tw/18/maps.htm

這裡裝了 Facebook 的 comment plugin, 那我們要查找該頁中 comment 的資料要怎麼查找呢? 首先要先找到該 comment 的 object_id, 該 id 可以利用這頁來找:
https://developers.facebook.com/tools/debug

將上面的 http://sample.diary.tw/18/maps.htm 輸入後, 按下[除錯]鈕, 在最下面的網址可以得到該 comment 的 object_id 為: 10150561101545602, 這個就是在 FQL 中, 查詢 comment 的 object_id. (在 Facebook 中, 會給定的各 object id)

再來就要下 FQL 查找資料了, 語法如下:

SELECT id, text, time, fromid FROM comment WHERE object_id='10150561101545602'

問題是從哪裡下呢? 從這裡 Graph API Explorer:
https://developers.facebook.com/tools/explorer
(若無法使用, 會引導登入 Facebook, 使用 Graph API Explorer需要登入 Facebook)

再將中間原來預設為 Graph API 的功能切到 FQL Query, 接下來把上面的查詢指令輸入, 就會得到目前的留言資料, 以 json 的方式來顯示.
接下來的使用, 相信大家就應該容易多了, 就是解析 json 把資料取出來即可.

那如何使用呢? 在程式中如何呼叫這個查詢, 而不是用 Graph API Explorer, 有沒有看到瀏覽器上方的 url 已經變了, 如下:
https://developers.facebook.com/tools/explorer?fql=SELECT%20id%2C%20text%2C%20time%2C%20fromid%20FROM%20comment%20WHERE%20object_id%3D%2710150561101545602%27
也就是說, 其實就是把查詢放到 url 中的 q 參數即可, 但使用上, 前面的 Graph API Explorer 得改成如下:
https://graph.facebook.com/fql?q=SELECT%20id%2C%20text%2C%20time%2C%20fromid%20FROM%20comment%20WHERE%20object_id%3D%2710150561101545602%27
使用 Graph FQL 查詢即可, 這是不用登入就可以使用的, 也就是說, 在程式中只需要透過 webget 等方法, 就可以取得到內容.

應該會有人問, 這個查詢結果, 其中的 text 是留言沒錯, 但沒有人名, 大頭圖, 那怎麼辦, 很簡單啊, 就再回 FQL 查詢就可以了, 不過若是有 100篇留言就要查 100次耶, 或是 smart 一點, 100篇留言, 共 30 個人在留, 那也需要做 30次的 user 查詢, 怎麼想都很難處理, 所以接下來要介紹的是多重查詢.

多重查詢, 有點像是 SQL 中的子查詢, 在面對這種 FQL 查詢時, 可以利用的技巧, 我們將查詢改一下, 改為如下:

{
"comments": "SELECT id, text, time, fromid FROM comment WHERE object_id='10150561101545602'",
"commenters": "SELECT uid, name, pic_square FROM user WHERE uid IN (SELECT fromid FROM #comments)"
}

對, 正如你看到的, 使用一個 #comments 代替前一個查詢結果, 並代入下一個查詢, 利用 json 格式, 將多重查詢放到 FQL 中, 就可以一次查詢把留言和人帶回來, 忘了說, user FQL 參考資料在這裡:
https://developers.facebook.com/docs/reference/fql/user

第二個查詢中的 uid, name, pic_square 就是常用的使用者代碼, 名稱, 大頭圖資訊.
查詢回傳結果就會有兩個 fql_resulte_set, 分別就是 comments, commenters, 如下:

中間略…
就把留言和留言者一次查回來了.

再來, 如何利用程式 parse json 的回傳結果, 就不用多說了吧, 應該就簡單多了, 快去實做看看吧.

分類
Blog服務

從Google Reader API中獲得RSS Cache的資料

相信很多人有用過 Google Reader, 其中有趣的地方, 是今天要介紹的 Google Reader API 中, 把 RSS Cache 的資料讀出來的部分, 先來參考一下文件:

http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI

其實很容易使用的, 例如:

http://www.google.com/reader/atom/feed/https://diary.tw/tim/rss?n=20
(需要 Google Account 登入)

就可以取得 https://diary.tw/tim/rss 下的資料, 什麼樣的應用情境呢? 例如某網誌的 RSS 只有提供 20 篇最新的資料, 但需要取得舊的資料(當然前提是有其他人在 Google Reader 中訂閱過才行, 也就是 Google Reader 有 cache 過它的 RSS 資料的狀況下), 就可以使用這個 API 了.

又或是原始的網站找不到了, 但在 RSS 中有資料, 就可以利用 RSS Cache 的資料來將原本的網站資料找出來.

使用方式就是上面的說明, 而要換頁的方式, 是使用 more token 的方式, 在 response 的內容中, 會有個 gr:continuation, 這個 tag 就是再下一頁的內容使用, 使用方式是用 c 參數, 如下:

http://www.google.com/reader/atom/feed/https://diary.tw/tim/rss?c=CLK9-LPAya0C

該 token 會依實際狀況改變, 請自行調整. 這樣就可以一直翻頁下去, 直到沒有 gr:continuation tag 時就是沒有更多的最後回應了.

[2012/9/14 18:24]
這裡有 Google Reader API 的資料可供參考:
http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/

分類
懶得分類

Google天氣API失效?!

之前一直用的好好的 Google 天氣 API, 今天同事回報異常, 經檢查後, 發現看起來是 Google 的問題, 不過回覆的訊息讓人摸不著頭緒, 如下:

(訪問 http://www.google.com/ig/api?hl=zh-tw&weather=taipei 的結果)

起先以為是用量過多爆了, 不過查了一下, 發現應該不是, 而且也找到相關的新聞訊息: http://thenextweb.com/google/2012/08/28/did-google-just-quietly-kill-private-weather-api/ 看起來應該是 Google 打算關掉的服務引起的, 而且上面的 copyright 還是 2009, 真是怪怪的.

接下來只好轉換用其他家的 weather api, 原本要用 http://www.wunderground.com/ 這家的, 但是是要收費的, 只好再找, 改用 yahoo 的, 參考 API 介紹: http://developer.yahoo.com/weather/ , 應用起來, 原本 Google Weather API 有的資訊他也都有, 只是都是英文的, 不過倒也不影響使用.

不過若是不知道地點的 w 代碼(WOEID), 可以先到 yahoo weather 上查: http://weather.yahoo.com/ 輸入 taipei, 將會重導到網址: http://weather.yahoo.com/taiwan/null/taipei-2306179/ 就知道 w 代碼是 2306179, 而 API URL 就會是: http://weather.yahooapis.com/forecastrss?w=2306179 預設氣溫單位是華氏, 若是要氣溫單位, 再多加參數 u=c 如: http://weather.yahooapis.com/forecastrss?w=2306179&u=c

回應的內容也都是 xml 格式, 可以容易利用程式實作取出, 花了幾十分鐘的時間, 把原來的 api 由 Google 改到 Yahoo 完成.

附上部分台灣的 WOEID:

2306155 Yungkang City, TW (永康市)
2306179 Taipei City, TW (台北市)
2306180 Kaohsiung City, TW (高雄市)
2306181 Taichung City, TW (台中市)

分類
程式技術

YQL for flickr的問題

之前寫了一篇利用 YQL 查詢 setid 取出 flickr 中的照片功能: 利用YQL抓出Flickr相簿中的照片url

不過最近似乎是失效了, 檢查一下, 發現 YQL 只會回傳 flickr 的 api url, 而不主動回傳 photos 的內容, 訪問該 flickr api url:

http://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&photoset_id={set_id}&page=1&per_page=10

會回傳:

<rsp stat=”fail”>
<err code=”100″ msg=”Invalid API Key (Key has invalid format)”/>
</rsp>

所以只好來去申請 flickr 的 api key, 才能查詢了. 不過這樣就不用透過 YQL 了, 直接向 flickr api 取出內容即可. 申請的網址在這裡: http://www.flickr.com/services/api/keys/ , (有分兩種, free 及 commercial 的, 請依開發用途申請即可) 申請好了之後, 可以直接從該 api 服務介紹來查找這個由 setid 找出照片服務, 不過已經知道由 YQL 給的 flickr api url 了, 所以再掛上 api key 就可以順利輸出結果了, 如下:

http://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&api_key={api_key}&photoset_id={set_id}&format=rest

輸出結果如下:

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
  <photoset id="72157600079438372" primary="460118008" owner="owner_id" ownername="owner_name" page="1" per_page="500" perpage="500" pages="1" total="18">
    <photo id="460118008" secret="4d856aaa72" server="239" farm="1" title="DSC_3989" isprimary="1" />
    <photo id="460125135" secret="15a3d24484" server="208" farm="1" title="DSC_3987" isprimary="0" />
    <photo id="460117456" secret="76bdfd928c" server="191" farm="1" title="DSC_3986" isprimary="0" />
    <photo id="460117112" secret="515535f02e" server="253" farm="1" title="DSC_3983" isprimary="0" />
    <photo id="460116928" secret="68286fc46a" server="200" farm="1" title="DSC_3981" isprimary="0" />
    <photo id="460116620" secret="4245ef4c5a" server="183" farm="1" title="DSC_3980" isprimary="0" />
    <photo id="460123637" secret="68351dfe14" server="236" farm="1" title="DSC_3963" isprimary="0" />
    <photo id="460123365" secret="80edceee74" server="243" farm="1" title="DSC_3961" isprimary="0" />
    <photo id="460115832" secret="80b8d482bf" server="246" farm="1" title="DSC_3958" isprimary="0" />
    <photo id="460122569" secret="2ee7c9e00e" server="242" farm="1" title="DSC_3954" isprimary="0" />
    <photo id="460122271" secret="074ba7710c" server="173" farm="1" title="DSC_3952" isprimary="0" />
    <photo id="460121955" secret="88a7b286b8" server="235" farm="1" title="DSC_3950" isprimary="0" />
    <photo id="460121519" secret="a5c2250e09" server="241" farm="1" title="DSC_3948" isprimary="0" />
    <photo id="460114100" secret="7dd0300dd6" server="199" farm="1" title="DSC_4000" isprimary="0" />
    <photo id="460120927" secret="c07c9eab50" server="189" farm="1" title="DSC_3997" isprimary="0" />
    <photo id="460120523" secret="5c00300368" server="191" farm="1" title="DSC_3995" isprimary="0" />
    <photo id="460120281" secret="affb220ee8" server="218" farm="1" title="DSC_3992" isprimary="0" />
    <photo id="460112878" secret="fcff8d8665" server="246" farm="1" title="DSC_3991" isprimary="0" />
  </photoset>
</rsp>

如此一來, 又能順利正常工作啦, 網址不變, 仍在這裡: http://sample.diary.tw/flickrset/