Archive

Posts Tagged ‘GIS’

GBIF為EOL開發網路地圖之物種應用服務

June 6th, 2009 No comments

全球生物多樣性資訊機構(GBIF)和生命大百科(EOL)合作,開發出一套一般性、豐富且是Web-based的網路地圖應用軟體,以動態方式呈現物種出現密度。此軟體讓使用者有經由高階縮放功能取得物種分佈的特別體驗,並有機會看到資料出版者的其他貢獻以及連回GBIF的資料入口網;其網路作圖是採取開放原始碼的方式,提供大眾使用。聯絡人為GBIF秘書處的Tim Robertson (trobertson@gbif.org)

 

 

Categories: GBIF Tags: , ,

Taibif 的 Google Map 應用-2

May 5th, 2009 No comments

http://taibif.org.tw/taibif_search/searchResult.php?op=instit&institution=TAIF 為例,在這個網頁的 html 輸出時就會執行 initialize() 這個 javascript 程式碼,這個程式碼的部分內容如表格一: 

  1. function initialize()
  2. {
  3.    if (GBrowserIsCompatible())
  4.    {
  5.       var map = new GMap2(document.getElementById(“map_canvas”));
  6.       map.setCenter(dataCenter, minZoom);
  7.       map.addControl(new GLargeMapControl());
  8.       map.addControl(new GMapTypeControl());
  9.       map.addControl(new MDControl());
  10.       map.addControl(new GScaleControl());
  11.       //繪圖用的 div 節點不必顯示出來
  12.       var bounds = new GLatLngBounds(dataSW, dataNE);
  13.       var display = new Display(bounds, ‘#FFF’, ‘hidden’);
  14.       map.addOverlay(display);
  15.       GEvent.addListener(map, ‘dragend’, function()
  16.       {
  17.          display.redraw(true);
  18.       });
  19.    }
  20. }

 表格一 – initialize() 部分程式碼

在表格一第12行我們可以看到其實 google map 圖中有一個看不見(顯示設定為 hidden)的 div 區塊,這個區塊的作用是在執行色塊的運算與產生,又因為需要動態顯示色塊,所以第15行到第18行又增加了一個結束拖曳(dragend)的事件(GEvent),當使用者結束拖曳時會呼叫第13行中 Display 類別的 redraw 函式,請注意,如果沒有新增這個拖曳事件,那麼只要一開始沒有出現的色塊,在拖曳完地圖後也不會出現。

  1.          Display.prototype.redraw = function(force)
  2.          {
  3.             if (!force)
  4.                return;
  5.             var zoom = this.map_.getZoom();
  6.             if (zoom < minZoom)
  7.             {
  8.                zoom = minZoom;
  9.                this.map_.setZoom(zoom);
  10.             }
  11.             if (zoom > maxZoom)
  12.             {
  13.                zoom = maxZoom;
  14.                this.map_.setZoom(zoom);
  15.             }
  16.             var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
  17.             var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());
  18.             this.div_.style.width = Math.abs(c2.x – c1.x) + ‘px’;
  19.             this.div_.style.height = Math.abs(c2.y – c1.y) + ‘px’;
  20.             this.div_.style.left = Math.min(c2.x, c1.x) + ‘px’;
  21.             this.div_.style.top = Math.min(c2.y, c1.y) + ‘px’;
  22.             this.div_.style.background = this.bgColor_;
  23.             //將舊的節點刪除
  24.             this.removeAllChildren();
  25.             //新增節點
  26.             this.createChildren();
  27.          }

表格二 – Display 類別的 redraw 函式

網頁的動態效果是由 redraw 函式產生。此外因為我有限制解析度,所以從第5行開始到第15行結束就是在設定當解析度超出最大最小解析度時就強制設定解析度為最大或最小解析度。第16行到第22行都是在畫控制色塊運算的那個看不見的 div 區塊,第16行與第17行是在將單位由原本的 google map 經緯度單位轉換成網頁的 pixel 單位,第18行到第22行在設定區塊的屬性。當 google map 發生改變時(例如使用者拖曳滑鼠改變顯示位置或是解析度改變),地圖中的區塊的大小,顏色,顯示與否都可能會發生變化,發生變化也就是刪除舊節點,產生新節點,也就是24行與26行中這兩個函式的功能。

  1.             this.createChildren = function()
  2.             {
  3.                var startLat = this.bounds_.getSouthWest().lat();
  4.                var stopLat  = this.bounds_.getNorthEast().lat();
  5.                var startLng = this.bounds_.getSouthWest().lng();
  6.                var stopLng  = this.bounds_.getNorthEast().lng();
  7.                var nowZoom = this.map_.getZoom();
  8.                var nowBounds = this.map_.getBounds();
  9.                var nowSW = nowBounds.getSouthWest();
  10.                var nowNE = nowBounds.getNorthEast();
  11.                for (var kiloSpan in data)
  12.                {
  13.                   kiloSpan = parseInt(kiloSpan);
  14.                   if (typeof(showData[kiloSpan] != ‘undefined’) && showData[kiloSpan].in_array(nowZoom))
  15.                   {
  16.                      var span   = parseFloat(kiloSpan / 100);
  17.                      var startM = 0;
  18.                      var stopM  = (stopLat – startLat) / span;
  19.                      var startN = 0;
  20.                      var stopN  = (stopLng – startLng) / span;
  21.                      if (nowSW.lng() > startLng)
  22.                      {
  23.                         startN = Math.floor((nowSW.lng() – startLng) / span);
  24.                      }
  25.                      if (stopLng > nowNE.lng())
  26.                      {
  27.                         stopN = Math.floor((nowNE.lng() – startLng) / span);
  28.                      }
  29.                      if (nowSW.lat() > startLat)
  30.                      {
  31.                         startM = Math.floor((nowSW.lat() – startLat) / span);
  32.                      }
  33.                      if (stopLng > nowNE.lat())
  34.                      {
  35.                         stopM = Math.floor((nowNE.lat() – startLat) / span);
  36.                      }
  37.                      for (var m in data[kiloSpan])
  38.                      {
  39.                         if ((m >= startM) && (m <= stopM))
  40.                         {
  41.                            m = parseInt(m);
  42.                            for (var n in data[kiloSpan][m])
  43.                            {
  44.                               if ((n >= startN) && (n <= stopN))
  45.                               {
  46.                                  n = parseInt(n);
  47.                                  var cnt = data[kiloSpan][m][n];
  48.                                  var index = 0;
  49.                                  for (; (cnt > boundSet[index]) && (index < boundSet.length); index++)
  50.                                  {
  51.                                     ;
  52.                                  }
  53.                                  if (index >= boundSet.length)
  54.                                     index = boundSet.length – 1;
  55.                                  var bgColor   = colorSet[index];
  56.                                  var textColor = textColorSet[index];
  57.                                  var boldColor = textColorSet[index];
  58.                                  if ((typeof(fadeData[kiloSpan]) != ‘undefined’) && fadeData[kiloSpan].in_array(nowZoom))
  59.                                  {
  60.                                     bgColor   = fadeColor;
  61.                                     textColor = fade;
  62.                                  }
  63.                                  var colorSW = new GLatLng(startLat + m * span, startLng + n * span);
  64.                                  var colorNE = new GLatLng(startLat + (m + 1) * span, startLng + (n + 1) * span);
  65.                                  var c1 = this.map_.fromLatLngToDivPixel(colorSW);
  66.                                  var c2 = this.map_.fromLatLngToDivPixel(colorNE);
  67.                                  var lngSpan = (colorNE.lng() – colorSW.lng()) / span;
  68.                                  var latSpan = (colorNE.lat() – colorSW.lat()) / span;
  69.                                  var xSpan = (c2.x – c1.x) / lngSpan;
  70.                                  var ySpan = (c2.y – c1.y) / latSpan;
  71.                                  var color = document.createElement(‘div’);
  72.                                  color.id = ‘color’;
  73.                                  color.style.width = Math.abs(c2.x – c1.x) + ‘px’;
  74.                                  color.style.height = Math.abs(c2.y – c1.y) + ‘px’;
  75.                                  color.style.left = (Math.min(c2.x, c1.x) – weight) + ‘px’;
  76.                                  color.style.top = (Math.min(c2.y, c1.y) – weight) + ‘px’;
  77.                                  color.style.position = ‘absolute’;
  78.                                  color.style.background = bgColor;
  79.                                  color.style.border = weight + “px solid ” + boldColor;
  80.                                  color.innerHTML = ‘<font color=\” + textColor + ‘\’>(SW) | ‘ + (startLat + (m * span)) + ‘, ‘ + (startLng + (n * span)) + ‘ | kiloSpan | ‘ + kiloSpan + ‘ | </font>’;
  81.                                  color.style.opacity = opacityData[kiloSpan];
  82.                                  color.style.filter = ‘alpha(opacity=’ + opacityData[kiloSpan] * 100 + ‘)’;
  83.                                  color.style.overflow = ‘hidden’;
  84.                                  if ((typeof(connectSet) != “undefined”) && connectSet.in_array(kiloSpan))
  85.                                  {
  86.                                     color.style.cursor = ‘pointer’;
  87.                                     color.onclick = function(){connectUrl(this)};
  88.                                  }
  89.                                  this.map_.getPane(G_MAP_MAP_PANE).appendChild(color);
  90.                               }
  91.                            }
  92.                         }
  93.                      }
  94.                   }
  95.                }
  96.             }

表格三 – Display 類別的 createChildren 函式

createChildren 函式是整個 javascript 中最重要的函式,所以我把他從 redraw 函式中獨立出來寫成 Display 的成員函式。表格三中的第3行到第6行分別是取得台灣區塊的西南端與東北端的經度與緯度。第7行是取得地圖的可視範圍,第9行與第10行則是取得地圖可視範圍的西南端與東北端。取得這些資料的目的是在過濾掉一些不必顯示的 div 區塊,節省客戶端電腦的運算時間。接下來就要開始處理資料了,php 會把從資料庫取得的資料以 javascript 中的 data 陣列呈現,所以處理資料也就是在處理 data 陣列的資料,data 陣列的格式解釋請見另外一篇文章。我在一開始的時候有提到區塊有不同的範圍,也不是每個解析度下每種範圍的區塊都要顯示,所以第14行是在判斷某個解析度下色塊是否要顯示,如果不用顯示則跳過下一輪的處理。當區塊在地圖可視範圍外時就一定不會顯示,所以也可以直接排除,而第21行到第36行就是在建立排除的規則。在確定要將 data 陣列內的某筆資料以 div 區塊的方式顯現時,就要開始設定這個區塊的顯示參數了。div 區塊除了顯示顏色之外,還必須在區塊中加入位置的文字資料(第80行的 innerHTML 屬性)作為後續的處理。每個色塊都是一個 id = ‘color’ 的 div 區塊(第72行開始),設定語法從第71行到89行,在第83行的 overflow 屬性如果沒設定為 hidden 的話,那麼使用 firefox 瀏覽器瀏覽時區塊內的文字就會跑出來而出現預期外的畫面(如圖一)。最後,當滑鼠移到有超連結功能(第84行判斷)的區塊的話就會改變滑鼠的游標,點擊這些區塊就會執行 connectUrl 函式。

圖一

圖一

Categories: TaiBIF Tags: , ,

Taibif 的 Google Map 應用 – data 陣列

May 5th, 2009 No comments

本文章將解釋 Taibif 中 google map 應用的 javascript 的 data 陣列的格式。data 陣列請到 http://taibif.org.tw/taibif_search/searchResult.php?op=instit&institution=TAIF 按右鍵檢視原始檔,其中一個範例如表格一,陣列的介紹如圖一。

Read more…

Categories: TaiBIF Tags: , ,

Taibif 的 Google Map 應用-1

May 5th, 2009 No comments

因為 Taibif 有展示資料地理分布的需要,所以我使用 Google Map 完成了這個應用(結果如圖一),實際操作畫面請見 http://taibif.org.tw/?tid=459。這個應用是用不同顏色的 div 區塊表示某個範圍內的資料數,當使用者改變解析度或是拖曳地圖的可視範圍時,地圖會動態的畫出區塊的大小顏色位置,使用者也可以點選 div 區塊,連結到區塊內相關資料的網頁。 Read more…

Categories: TaiBIF Tags: , ,

什麼是生物多樣性資訊學(Biodiversity Informatics)

April 21st, 2009 No comments

生物多樣性資訊學是協助處理生物多樣性資訊,其涵蓋的範疇相當廣泛,從基因、物種到生態系。不但資料之屬性、格式與形式多樣化,且使用之語言不同,時間與空間尺度亦不一。再加上缺失資料及智財權之問題複雜,故其資料之整合相當困難且具挑戰性,相較於以基因序列為主的生物資訊(Bioinformatics)複雜甚多。

生物多樣性資訊學第一次被提出大約1992年 ,主要結合GIS、GPS、資料庫管理、環境管理、博物館分類系統。後續亦有學者提出為利用運用資訊工具與資訊技術於生物多樣性,特別是在生物體方面層級;或將物種的原始資料透過資訊技術協助完成資料管理、分析、運算;或將生物個體和群聚的分類資料、生態及基因資料,透過任何形式資訊分享。生物多樣性資訊學其精神為運用資訊工具與資訊技術協助物種的原始資料,達成資料管理、分析、運算,最後再透過網路或其他媒介完成資訊分享。

TaiBIF 地理分布呈現-2

April 14th, 2009 2 comments

上一篇文章中提到GBIF的地理分布呈現方法,在1度與0.1度地圖中利用JavaScript的方式不同的網格大小,但在1度的網格中,台灣(包含離島澎湖、金門等地方)大約14網格左右,若用於呈現台灣的物種出現紀錄,其解析度稍嫌過大。且GBIF的1度與 0.1度的網格中所使用的地圖為一張靜態地圖,相較於使用google map 而言,少了地圖的精確度。

有鑑於此,TaiBIF將發展利用 google map作為地圖呈現的主要工具,分別設計0.1 度(約10公里)與 0.02度(約2公里)的網格。此系統即將完成,敬請期待。

Categories: TaiBIF Tags: , ,

TaiBIF 地理分布呈現-1

April 14th, 2009 No comments

GBIF 在新版資料入口網中,更是以地理資訊系統提供資料整合另外一種方式,無論是單一物種、類群,或是特定國家、特定資料提供者,都可以地圖方式呈現其物種分布的概況。為了要保持搜尋速度,呈現方式先以經緯度1度的方格來繪製(圖一),更精細圖層中再以經緯度0.1度的方格(圖二),最後呈現單一物種分布時,在提供最精確的地理位置(圖三),利用簡化的方式,已滿足GBIF大量地理空間(1.7億筆物種出現記錄資料)呈現的問題。

1 度網格地理分布

1 度網格地理分布

0.1 度地理分布

0.1 度地理分布

物種出現記錄,以點的方式呈現

物種出現記錄,以點的方式呈現

Categories: TaiBIF Tags: ,