各種外掛範例
在開始以前,需要先建立基本專案。
步驟 1. 目標是使用 MicroSoft Visual Studio 2019(或以上之版本)建立一個名為 MyClass.dll 的函式庫。首先新增類別庫
專案,在此請使用[.Net Framework 4.7.2],接著為專案命名,在本範例命名為 MyClass。
步驟 2. 請在右邊[方案總管]中找到[參考],點擊滑鼠右鍵後點選[加入參考…],視窗開啟後,選擇[瀏覽]頁籤,至安裝目錄下找到TMPEngine.dll
檔案並按下[確定],即可將 TMPEngine.dll 加入參考。
步驟 3. 加入參考後請於`Class1.cs上方加入以下程式碼:
using PilotGaea.Geometry;
using PilotGaea.TMPEngine;
using PilotGaea.Serialize;
以上為所有外掛的前置作業,完成後下面將示範各個外掛的實作過程。
DoCommand
[info] 小提示:
範例程式碼:Github
這邊會實作兩個 Docommand 功能 ─ GetAllLayerInfo 與 GetLayerInfo,這兩個功能已存在於預設外掛DefaultPlugin.dll。
步驟 1. 專案建置後,請在Class1
後方加入繼承DoCmdBaseClass
:
public class Class1 : DoCmdBaseClass
步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,接著請點擊燈泡圖案,接著點選[實作抽象類別]:
點選後系統會自動產生預設的繼承函式,自動生成的程式碼約如下所示:
public class Class1 : DoCmdBaseClass
{
public override void DeInit()
{
throw new NotImplementedException();
}
public override bool DoCmd(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParm, out VarStruct RetParm)
{
throw new NotImplementedException();
}
public override string[] GetSupportCmds()
{
throw new NotImplementedException();
}
public override bool Init()
{
throw new NotImplementedException();
}
}
步驟 3. 請宣告一個List
的全域變數,用來儲存要新增的指令。
private List<string> m_Cmds;
步驟 4. 實作Init
函式:找到系統已產生覆寫(Override)繼承自DoCmdBaseClass
的Init
函式,此函式為初始化函式庫,我們將在此函式中新增所有此函式庫支援之 DoCommand 指令名稱,可依需求自行新增。
public override bool Init()
{
m_Cmds = new List<string>();
m_Cmds.Add("GetAllLayerInfo");
m_Cmds.Add("GetLayerInfo");
return true;
}
步驟 5. DeInit
函式為覆寫(Override)繼承自DoCmdBaseClass
之函式DeInit()
,此函式將在外掛重新載入或主程式結束時被呼叫,預設為不執行任何指令。
public override void DeInit() {
// 預設為不執行任何指令
}
步驟 6. 實作 Docmd 函式:請找到系統已產生覆寫(Override)繼承自DoCmdBaseClass
的 Docmd 函式,此函式為呼叫功能之主要進入點,在此我們將判斷傳進來的指令字串,並呼叫相對應的函式執行我們寫好的功能。如果此函式回傳為false
,client 將會收到http status code 500
(伺服器內部錯誤)。
public override bool DoCmd(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParm, out VarStruct RetParm)
{
bool Ret = false;
RetParm = null;
switch (Cmd)
{ // 在此的指令需對應上方初始化時建立的指令
case "GetAllLayerInfo":
Ret = GetAllLayerInfo(DB, SessionID, out RetParm);
break;
case "GetLayerInfo":
Ret = GetLayerInfo(DB, SessionID, InputParm, out RetParm);
break;
}
return Ret;
}
[warning] 注意事項: 此時會因為尚未實作函式而顯示錯誤,請先忽略。
步驟 7. 實作GetSupportCmds
函式:找到系統已產生覆寫(Override)繼承自DoCmdBaseClass
的GetSupportCmds
函式,此函式功能為讓外部取得此函式庫中所有支援之指令字串。
public override string[] GetSupportCmds()
{
return m_Cmds.ToArray();
}
步驟 8. 在此將實作一個自定義的函式,此函式會以遞迴的方式讀取圖層,在此函式中,我們先判斷此圖層是否為一個群組,若是群組,則進一步取出群組中的子圖層;若不是群組,則直接取得圖層資訊放入Result
參數物件中,以此方式遞迴。
[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。
private void RecursiveLayerInfo(CLayer Layer, VarStruct Result)
{
Result["islayerset"].Set(Layer.Type == LAYER_TYPE.SET);
Result["layername"].Set(Layer.Name);
Result["setting"].Set(Layer.GetSetting());
if (Layer.Type == LAYER_TYPE.SET)
{
int count = ((CLayerSet)Layer).Layers.Count;
if (count > 0)
{
Result["layers"].CreateArray(count);
for (int i = 0; i < count; i++)
{
VarStruct _Result = (Result["layers"].GetArray())[i].CreateStruct();
RecursiveLayerInfo(((CLayerSet)Layer).Layers[i], _Result);
}
}
} else {
Result["epsgcode"].Set(Layer.EPSG);
Result["type"].Set(Convert.ToInt32(Layer.Type));
Result["boundary"].Set(Layer.Boundary);
}
}
步驟 9. 將上述函式完成後,就可以實作GetLayerInfo
與GetAllLayerInfo
函式了。首先是GetLayerInfo
,此函式功能為取得指定名稱之 2D 圖層;此函式會先從傳進的參數InputParm
取得參數內容,接著判斷 DB 中的根群組中是否含有此圖層,若圖層存在則使用已建立之RecursiveLayerInfo
函式取得圖層資訊。
[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。
private bool GetLayerInfo(CGeoDatabase DB, string SessionID, VarStruct InputParm, out VarStruct RetParm)
{
bool Ret = true;
RetParm = new VarStruct();
CGroup Group = DB.GetGroup();
string LayerName = InputParm["layername"].GetString();
CLayer Layer = null;
if (Group.IsLayerOK(LayerName))
{
Layer = DB.FindLayer(LayerName);
}
if (Layer == null)
{
DB.FindSessionLayer(LayerName);
}
if (Layer != null)
{
RetParm["success"].Set(true);
VarStruct Result = new VarStruct();
RecursiveLayerInfo(Layer, Result);
RetParm["ret"].Set(Result);
} else {
RetParm["success"].Set(false);
}
return Ret;
}
步驟 10. 接著是實作GetAllLayerInfo
函式,此函式功能為取得 MapServer 上所有已發布之 2D 圖層資訊;此函式會先建立要回傳的RetParm
參數物件,此物件中將會存放所有回傳內容。由於能用的圖層都來自於 MapServer 的 DataBase (DB) ,因此須從 DB 取得根群組,再取得群組中的所有圖層,就可以得到所有 2D 圖層的數量,最後就可以使用以此數量為上限的迴圈執行已建立之RecursiveLayerInfo
函式來取得所有圖層資訊並回傳。
[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。
private bool GetAllLayerInfo(CGeoDatabase DB, string SessionID, out VarStruct RetParm)
{
bool Ret = true;
RetParm = new VarStruct();
RetParm["success"].Set(true);
CGroup Group = DB.GetGroup();
int Count = Group.Layers.Count;
VarArray result = RetParm["ret"].CreateArray(Count);
for (int i = 0; i < Count; i++)
{
VarStruct _result = result[i].CreateStruct();
RecursiveLayerInfo(Group.Layers[i], _result);
}
return Ret;
}
步驟 11. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug
(或是\bin\Release
,依建置類型決定)目錄內將檔案複製到安裝目錄下的plugins
目錄中,最後用 client 進行呼叫查看執行結果。
DoCommand 非同步版本
[info] 小提示:
範例程式碼:Github
DoCommand
也有提供非同步版本的實作。當你需要 server 同時執行多項DoCommand
作業,或者你想讓這項作業可以由前端詢問進度或是中斷,你可以使用非同步的DoCommand
。
在這裡會示範加入一個簡單的非同步DoCommand
範例。
步驟 1. 這裡的程式碼接續之前DoCommand
章節的內容。同樣先在Init()
裡加入新的指令名稱。我們叫它"ConnectionTest
"。希望它在呼叫之後回傳一筆簡單的資料,讓我們知道DoCommand
當前是成功運行的。
public override bool Init()
{
m_Cmds = new List<string>();
m_Cmds.Add("GetAllLayerInfo");
m_Cmds.Add("GetLayerInfo");
m_Cmds.Add("ConnectionTest");
return true;
}
接著需要複寫DoCmdAsync
這個函式。此函式是以virtual
關鍵字宣告的,不強迫實作,所以 Visual Studio 不會幫你加入,請自己加。之後比照之前DoCommand
的方式加入判斷式跟函式。
public override bool DoCmdAsync(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParam, int CommandID, CommandStatus Status)
{
bool Ret = false;
switch (Cmd)
{
case "ConnectionTest":
Ret = ConnectionTest(DB, SessionID, InputParam,Status);
break;
}
return Ret;
}
接下來我們實作ConnectionTest
這個函式。
private bool ConnectionTest(CGeoDatabase dB, string sessionID, VarStruct inputParam, CommandStatus status)
{
status.m_Data["success"].Set(false);
for (int i = 0; i <= 100; i++)
{
status.SetProgress(i);
if (status.isAbort())
{
string msg_aborted = "Connection test was aborted.";
status.m_Data["message"].Set(msg_aborted);
return true;
}
}
string msg_succeeded = "Connection test succeeded.";
status.m_Data["message"].Set(msg_succeeded);
status.m_Data["success"].Set(true);
return true;
}
這樣就完成了。
這裡可以發現到,你需要自己在 server 端設定進度和建立中斷作業的機制。
步驟 2. 客戶端發送非同步的DoCommand
請求方式與發送同步DoCommand
方式相同,差別在於取得資料時會透過函式回傳的手柄來操作。除了取得資料,還有中斷、詢問進度等功能都需要透過手柄。
這邊示範一下JavaScript
端的寫法。
首先我們先宣告伺服器的連線資訊。
let ServerUrl = "127.0.0.1";
let ServerPort = 8080;
let ProxyUrl = "http://" + ServerUrl + ":" + ServerPort;
為了方便,我們寫一個可以幫我們快速加入按鈕的函式AddButton()
。
// 加入按鈕
function AddButton(text, event, id = "") {
const button = document.createElement("button");
button.innerText = text;
button.onclick = event;
if (id != "") {
button.id = id;
}
document.body.appendChild(button);
}
再來我們需要可以在送出非同步DoCommand
之後,每隔一秒鐘向 server 詢問一次進度的函式GetProgress()
。
function GetProgress(handle) {
function work() {
let ret = handle.getProgress();
console.log(ret);
return ret;
}
let itvId = setInterval(() => {
let ret = work();
if (parseInt(ret.Progress) >= 100) {
// 進度 >= 100時停止詢問
clearInterval(itvId);
}
}, 1000); // 每一秒問一次
return itvId; // 回傳 setInterval 的 Id,讓 setInterval 能從外面被中斷
}
再來我們建立一個Main()
,將主要的行為囊括在內。
function Main() {
let handle = null;
let itvId = null;
AddButton("doByHandle", () => {
// 以手柄方式呼叫 docmd
let param = {};
handle = ov.DoCommand.doByHandle(proxyUrl, "ConnectionTest", param);
// 呼叫完成後開始向 server 問進度
itvId = getProgress(handle);
});
AddButton("getResult", () => {
// 取得手柄 docmd 資料
if (handle === null) return;
let ret = handle.getResult();
console.log(ret);
if (parseInt(ret.Progress) >= 100) {
handle = null;
}
});
AddButton("abort", () => {
// 中斷手柄 docmd 作業
if (itvId === null || handle === null) return;
let ret = handle.abort();
console.log(ret);
if (ret.success) {
clearInterval(itvId);
console.log("aborted.");
} else {
console.log("not aborted.");
}
});
}
可以看到,當呼叫ov.DoCommand.doByHandle()
之後,它會回傳一個手柄(handle)。若需要進行中斷作業,詢問進度或是取得資料的行為,都會透過這個手柄來操作。
最後呼叫一次Main()
。
Main();
這樣 Client 端也完成了。
Account
[info] 小提示:
範例程式碼:Github
這邊會實作具有登入的功能。
每個圖層設定都有個AccessControl
,當這個值被設定為true
時,此圖層就必須登入才能夠存取。
步驟 1. 首先請在Class
後方加入繼承AccountBaseClass
:
public class AccessControlClass : AccountBaseClass
步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]
:
點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:
public class AccessControlClass : AccountBaseClass
{
public override void DeInit()
{
throw new NotImplementedException();
}
public override bool Init()
{
throw new NotImplementedException();
}
public override bool Login(LoginInputParameter InputData, out LoginOutputParameter OutputData)
{
throw new NotImplementedException();
}
}
步驟 3. 實作Init
函式–找到系統已產生覆寫(Override)繼承自AccountBaseClass
的Init
函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。
public override bool Init()
{
return true;
}
步驟 4. DeInit
函式為覆寫(Override)繼承自AccountBaseClass
之函式DeInit()
,此函式將在AccessCntrol
函式庫結束時被呼叫,預設為不執行任何指令。
public override void DeInit() {
// 預設為不執行任何指令
}
步驟 5. 實作Login
函式–找到系統已產生覆寫(Override)繼承自AccountBaseClass
的Login
函式,此函式為呼叫功能之主要進入點。
在此我們將判斷傳進來的 InputData,接著做出我們想要的判斷,最後再由OutputData.CanLogin
來決定是否要讓此請求存取圖層,並將所屬群組名稱一同傳回,此範例為簡單的帳號密碼判斷。
由於網頁 Client 端無法使用參數輸入帳號密碼,所以可以在 Login 函式中新增一個判斷 IP 的條件式,讓使用網頁 Client 端的使用者可以使用白名單登入。
public override bool Login(LoginInputParameter InputData, out LoginOutputParameter OutputData)
{
bool Ret = false;
OutputData = new LoginOutputParameter();
if ((InputData.Username.ToLower() == "pilotgaea" && InputData.Password == "aeagtolip") || InputData.IP == "192.168.17.1")
{
bool Admin = false;
for (int i = 0; i < InputData.Groups.Count; i++)
{
if (InputData.Groups[i].Name == "Administrators")
{
Admin = true;
break;
}
}
OutputData.CanLogin = true;
if (Admin) OutputData.GroupName = "Administrators";
else OutputData.GroupName = "Everyone";
OutputData.Memo = "";
}
Ret = true;
return Ret;
}
[info] 補充說明: 其他詳細參數如下列介紹:
- InputData:
- Groups:請求者所在的群組列表。
- IP:請求者的 IP。
- LayerName:請求圖層的圖層名稱。
- Password:請求者輸入的密碼。
- ServiceType:請求圖層的類型(wmts、wms……)。
- SessionID:請求者的 SessionID。
- UserName:請求者輸入的使用者名稱。
- OutputData:
- CanLogin:是否同意登入存取圖層。
- GroupName:可以回傳請求者所在的群組。
- Memo:備忘錄。
步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug
目錄內將檔案複製到安裝目錄下的plugins
目錄中,接著請開啟 MapServer 勾選圖層的AccessControl
功能,將伺服器儲存後並重新啟動。
步驟 7. 在此以第二章與第六章所完成的網頁與視窗程式作為範例,可以發現兩者皆已經無法顯示圖層。
步驟 8. 請打開視窗程式專案,並到程式碼分頁中,請在Form1_Shown
事件中找到此行程式碼:
int id = m_MapDocument.NewTileMapLayer(m_sLayer, urlPatterns, mtxSet);
請將此行重新輸入,可看見此函式可輸入參數作為帳號密碼:
接著將程式碼增加輸入用參數,並重新建置啟動程式:
int id = m_MapDocument.NewTileMapLayer(m_sLayer, urlPatterns, mtxSet,-1,"pilotgaea","aeagtolip");
執行後便可看到可以再次讀取出圖層。
FeatureInfo
[info] 小提示:
範例程式碼:Github
這邊會實作 WMTS 下查詢向量圖層資訊的功能(GetFeatureInfo)。
步驟 1. 首先請在Class
後方加入繼承FeatureInfoBaseClass
:
public class FeatureInfoClass : FeatureInfoBaseClass
步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]
:
點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:
public class FeatureInfoClass : FeatureInfoBaseClass
{
public override void DeInit()
{
throw new NotImplementedException();
}
public override bool GetFeatureInfo(CGeoDatabase DB, string SessionID, string LayerName, int EPSG, GeoPoint Point, double Distance, out VarStruct Ret)
{
throw new NotImplementedException();
}
public override bool Init()
{
throw new NotImplementedException();
}
}
步驟 3. 實作Init
函式–找到系統已產生覆寫(Override)繼承自FeatureInfoBaseClass
的Init
函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。
public override bool Init()
{
return true;
}
步驟 4. DeInit
函式為覆寫(Override)繼承自FeatureInfoBaseClass
之函式DeInit()
,此函式將在FeatureInfoBaseClass
函式庫結束時被呼叫,預設為不執行任何指令。
public override void DeInit() {
// 預設為不執行任何指令。
}
步驟 5. 實作GetFeatureInfo
函式–找到系統已產生覆寫(Override)繼承自FeatureInfoBaseClass
的GetFeatureInfo
函式,此函式為呼叫功能之主要進入點。
在此我們將判斷傳進來的LayerName
,查詢目標範圍內的圖素,最後再根據圖素類型傳回,其中Distance
為每個Pixel
代表的公尺乘上 5。
public override bool GetFeatureInfo(CGeoDatabase DB, stringSessionID, string LayerName, int EPSG, GeoPoint Point, doubleDistance, out VarStruct Ans)
{
bool Ret = false;
Ans = new VarStruct();
CVectorLayer Layer = DB.FindLayer(LayerName) as CVectorLayer_Base;
if (Layer == null) return Ret;
CEntityFetcher Fetcher = Layer.SearchByDistance(EPSG, Point, Distance);
VarArray Arr = Ans["features"].CreateArray(Fetcher.Count);
for (int i = 0; i < Fetcher.Count; i++)
{
GeoPoint p = new GeoPoint();
GeoPolyline pl = new GeoPolyline();
GeoPolygonSet pgs = new GeoPolygonSet();
VarStruct feature = Arr[i].CreateStruct();
switch (Fetcher.GetType(i))
{
case GEO_TYPE.POINT : {
Fetcher.GetGeo(i, ref p);
feature["geometry"].Set(p);
}
break;
case GEO_TYPE.POLYLINE : {
Fetcher.GetGeo(i, ref pl);
feature["geometry"].Set(pl);
}
break;
case GEO_TYPE.POLYGONSET : {
Fetcher.GetGeo(i, ref pgs);
feature["geometry"].Set(pgs);
}
break;
}
}
Ret = true;
return Ret;
}
步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug
目錄內將檔案複製到安裝目錄下的plugins
目錄中,接著請啟動 MapServer。
步驟 7. 確認 MapServer 中有加入向量圖層,並將其命名為範例向量圖層
,開起瀏覽器並在網址列輸入:
http://127.0.0.1:8080/wmts?Layer=範例向量圖層&Request=GetFeatureInfo&TileMatrixSet=EPSG:3857&i=127&j=127&TileRow=877&TileCol=1713&TileMatrix=11&InfoFormat=application/json
[info] 補充說明:
其他詳細參數如下列介紹:
- Layer:要讀取資訊的圖層名稱。
- TileMatrixSet:圖層右鍵編輯 → 進階設定就能看到。
- i、j:在圖磚中的坐標。
- TileRow、TileCol:圖磚縱、橫軸索引。
- TileMatrix:圖磚資料層集合。
- InfoFormat:回傳的結構。
上述所要代入的參數會根據向量圖的位置有所不同,但不管在哪個位置,GetFeatureInfo
都會被呼叫,範例結果如下:
Snap
[info] 小提示:
範例程式碼:Github
這邊會實作鎖點提示功能,外掛部分只會提供圖素讓 Server 計算決定結果。
步驟 1. 首先請在Class
後方加入繼承SnapBaseClass
:
public class SnapClass : SnapBaseClass
步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]
:
點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:
public class SnapClass : SnapBaseClass
{
public override void DeInit()
{
throw new NotImplementedException();
}
public override bool GetSnapGeometry(CGeoDatabase DB, string LayerName, GeoPoint Point, double Distance, int EPSGCode, out List<Geo> Geos)
{
throw new NotImplementedException();
}
public override bool Init()
{
throw new NotImplementedException();
}
}
步驟 3. 實作Init
函式–找到系統已產生覆寫(Override)繼承自SnapBaseClass
的Init
函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。
public override bool Init()
{
return true;
}
步驟 4. DeInit
函式為覆寫(Override)繼承自SnapBaseClass
之函式DeInit()
,此函式將在SnapBaseClass
函式庫結束時被呼叫,預設為不執行任何指令。
public override void DeInit() {
// 預設為不執行任何指令
}
步驟 5. 實作GetSnapGeometry
函式–找到系統已產生覆寫(Override)繼承自SnapBaseClass
的GetSnapGeometry
函式,此函式為呼叫功能之主要進入點,在此我們將判斷傳進來的LayerName
,查詢目標範圍內圖素的所有點,將這群點作為鎖點計算的一部分來源。
public override bool GetSnapGeometry(CGeoDatabase DB, string LayerName, GeoPoint Point, double Distance, int EPSGCode, out List<Geo> Geos)
{
bool Ret = false;
Geos = new List<Geo>();
CVectorLayer Layer = DB.FindLayer(LayerName) as CVectorLayer_Base;
if (Layer == null) return Ret;
CEntityFetcher Fetcher = Layer.SearchByDistance(EPSGCode, Point, Distance);
for (int i = 0; i < Fetcher.Count; i++)
{
GeoPoint p = new GeoPoint();
GeoPolyline pl = new GeoPolyline();
GeoPolygonSet pgs = new GeoPolygonSet();
switch (Fetcher.GetType(i))
{
case GEO_TYPE.POINT:
Fetcher.GetGeo(i, ref p);
Geos.Add(p);
break;
case GEO_TYPE.POLYLINE:
Fetcher.GetGeo(i, ref pl);
Geos.Add(pl);
break;
case GEO_TYPE.POLYGONSET:
Fetcher.GetGeo(i, ref pgs);
Geos.Add(pgs);
break;
}
}
// Ret = true;
// 如果傳回true,表示只拿這些圖素做計算
return Ret;
}
步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug
目錄內將檔案複製到安裝目錄下的plugins
目錄中,接著請啟動 MapServer。
步驟 7. 延續第二章的網頁程式新增一個新的按鈕
<div id="MyControl" style="position: absolute;z-index: 1;">
<button id="measure-length">MeasureLength</button>
<button id="measure-area">MeasureArea</button>
<button id="clear">Clear</button>
<button id="change-color-by-distance">ChangeColorByDistance</button>
<button id="snap">Snap</button> // 新增
</div>
步驟 8. 確認 MapServer 中有加入向量圖層,將其命名為範例向量圖層
,並在 Web 中載入
var layerName = "範例向量圖層";
var host = "http://127.0.0.1:8080/wmts?"; // 以本機MapServer為例。
var wmtsUrl =
host +
"Layer=" +
layerName +
"&style=default&TileMatrixSet=EPSG:3857Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix={TileZ}&TileCol{TileC}&TileRow={TileR}";
var Patterns = [wmtsUrl];
var im = mapDoc.NewTileMapLayerByMatrixSet("Vector", Patterns, m, -1);
步驟 9. 綁定點擊事件到剛剛新增的按鈕上,使其觸發鎖點功能
document.querySelector("#snap ").onclick = function () {
var layerNam = "Vector";
var pixel = 100;
var type = "node";
var radius = 10;
var fillColor = "rgba(255, 0, 0, 1)";
var strokeColor = "rgba(0, 255, 0, 1)";
mapView.SetSnapPointSetting(
layerNam,
pixel,
type,
radius,
fillColor,
strokeColor
);
};
點擊按鈕啟動,再點擊量測鈕,當靠近到指定範圍時,便會看到鎖點效果。