昨天完成了儲存繪圖圖形,今天就是要將那些儲存的圖形列表撈出來,並讓使用者套疊和管理。
STEP1. 跟前面一樣,首先要先建立Model
在 BasicModels.cs
類別頁面新增 UserDrawCaseOutput
,為輸出的欄位。
public class UserDrawCaseOutput
{
public string drawsaveid { get; set; }
public string DDate { get; set; }
public string title { get; set; }
public string info { get; set; }
}
STEP2. 接著建立Infrastructure裡的function
在 BasicInfoFunc.cs
新增 getUserDrawCaseList()
用來取的登入的使用者的繪圖儲存列表,由於我是依照每個feature下去進行儲存,因此同一筆儲存案會有很多列的feature在資料表內,在撈取的時候要取 drawsaveid
為不重複的資料,撈取同一個drawsaveid,但也要撈出最早的 DDate
。
public static async Task<List<UserDrawCaseOutput>> getUserDrawCaseList(string userid)
{
SqlDataReader reader = null;
SqlConnection myConnection = new SqlConnection();
string Constr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
myConnection.ConnectionString = Constr;
SqlCommand sqlCmd = new SqlCommand();
string sqlStr;
sqlStr = "SELECT * FROM (SELECT [drawsaveid],[DDate],[title],[info],ROW_NUMBER() OVER (PARTITION BY [drawsaveid] ORDER BY [DDate]) AS RowNumber FROM [OLDemo].[dbo].[UserDrawSave] where [userid]=@userid ) AS a WHERE a.RowNumber = 1";
sqlCmd.Parameters.AddWithValue("@userid", userid.Trim());
sqlCmd.CommandText = sqlStr;
sqlCmd.CommandType = CommandType.Text;
sqlCmd.Connection = myConnection;
List<UserDrawCaseOutput> data = new List<UserDrawCaseOutput> { };
try
{
myConnection.Open();
reader = sqlCmd.ExecuteReader();
while (reader.Read())
{
data.Add(new UserDrawCaseOutput()
{
drawsaveid = reader["drawsaveid"].ToString(),
DDate = reader["DDate"].ToString(),
title = reader["title"].ToString(),
info = reader["info"].ToString()
});
}
myConnection.Close();
myConnection.Dispose();
return data;
}
catch (Exception ex)
{
throw;
}
}
STEP3. 建立Controller,開發獲得使用者儲存繪圖列表的API getUserDrawCase()
。
/// <summary>
/// 獲得使用者儲存繪圖列表
/// </summary>
/// <returns></returns>
[Route("getUserDrawCase")]
[HttpGet]
[SwaggerResponse(HttpStatusCode.OK, "OK", typeof(List<UserDrawCaseOutput>))]
public async Task<HttpResponseMessage> getUserDrawCase()
{
string token = authFunc.parseTokenFromHeader(this.Request);
string userid = authFunc.getUserNameByToken_true(token);
try
{
return Request.CreateResponse(HttpStatusCode.OK, await BasicInfoFunc.getUserDrawCaseList(userid));
}
catch (Exception SqlException)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Internal Server Error");
}
}
為了要將儲存的geometry和style還原,寫了一個小工具,建立 js/GraphicTrans.js
程式碼檔。
GraphicFromString()
:分別將geom和style兩個字串,利用 GraphicGeomTrans()
建立feature,並利用 GraphicStyleTrans()
將style設定回去。
GraphicGeomTrans()
:從GeoJSON還原geom字串。GraphicStyleTrans()
:還原樣式並存為符合Openlayers的style格式。var GraphicTrans = function () {
function GraphicGeomTrans(geostring) {
var geoObj = new ol.format.GeoJSON().readGeometry(geostring);
var newgeo = new ol.Feature({
geometry: geoObj
});
return newgeo;
}
function GraphicStyleTrans(stylestring) {
var styleObj = JSON.parse(stylestring);
var stylejson = createStyle(styleObj);
var newstyle = new ol.style.Style(stylejson);
function createStyle(Obj1) {
var styleArr = ["fill", "stroke", "image", "geometry", "renderer", "text"];
var styleAll = {};
if (Obj1 === null) {
styleAll = null;
} else {
Object.keys(Obj1).forEach(function (item, idx) {
var newkey = item.replace(/\_$/g, '');
if (Obj1[item] !== null) {
if (typeof Obj1[item] === 'object' && Array.isArray(Obj1[item]) === false) {
if (newkey === "fill") {
styleAll[newkey] = new ol.style.Fill(createStyle(Obj1.fill_));
} else if (newkey === "stroke") {
styleAll[newkey] = new ol.style.Stroke(
createStyle(Obj1.stroke_));
} else if (newkey === "image") {
styleAll[newkey] = new ol.style.Circle(
createStyle(Obj1.image_));
} else if (newkey === "geometry") {
styleAll[newkey] = new ol.style.Circle(
createStyle(Obj1.geometry_));
} else if (newkey === "renderer") {
styleAll[newkey] = new ol.style.Renderer(
createStyle(Obj1.renderer_));
} else if (newkey === "text") {
styleAll[newkey] = new ol.style.Text(createStyle(Obj1.text_));
} else {
styleAll[newkey] = createStyle(Obj1[item]);
}
} else {
styleAll[newkey] = Obj1[item];
}
} else {
styleAll[newkey] = null;
}
});
}
return styleAll;
}
return newstyle;
}
function GraphicFromString(geostring, stylestring) {
var feature = GraphicTrans.GraphicGeomTrans(geostring);
feature.setStyle(GraphicTrans.GraphicStyleTrans(stylestring));
return feature;
}
return {
GraphicGeomTrans: GraphicGeomTrans,
GraphicStyleTrans: GraphicStyleTrans,
GraphicFromString: GraphicFromString
};
}();
在前端 Draw.html
新增繪圖儲存的tab頁面。
<div class="ui segment" style="display:none;">
<p style="margin:0px 0px 10px 0px;">使用者已儲存列表:</p>
<div class="ui small cards" id="drawcasescards">
</div>
</div>
於 jDraw.js
建立撈取使用者儲存的圖形列表 getUserDrawCaseList()
,並於畫面上顯示標題、內容、時間與兩個按鈕,分別為:
getUserDrawGeom()
。delUserDrawCase()
。function getUserDrawCaseList() {
$("#drawcasescards").html("");
$.ajax({
type: "GET",
url: config_OLMapWebAPI + "/Basic/getUserDrawCase",
headers: {
"Authorization": localStorage["token"]
},
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (d) {
//var data = $.parseJSON(d.d);
var data = d;
console.log(data);
data.forEach(function (item, idx) {
var cardstr = '<div class="card" id="' + item.drawsaveid + '"><div class="content"><div class="header">' + item.title + '</div><div class="meta"><span>' + item.DDate + '</span></div><div class="description">' + item.info + '</div></div><div class="extra content"><div class="ui two buttons"><div class="ui basic green button" onclick="draw.getUserDrawGeom(\'' + item.drawsaveid + '\')">加到地圖</div><div class="ui basic red button" onclick="draw.delUserDrawCase(\'' + item.drawsaveid + '\')">刪除</div></div></div></div>';
$("#drawcasescards").append(cardstr);
});
$("#drawcasescards").parents(" div.segment").show();
},
error: function (jqXHR, exception) {
ajaxError(jqXHR, exception);
}
});
}
getUserDrawGeom()
為從資料庫撈取儲存的 geomstr 和 stylestr 兩者,篩選符合相對應 drawsaveid
的圖形,並以迴圈執行 GraphicTrans.GraphicFromString()
還原features。
function getUserDrawGeom(drawsaveid) {
var drawsaveobj = {
"SQLtype": "Select",
"title": "",
"info": "",
"features": []
};
$.ajax({
type: "POST",
url: config_OLMapWebAPI + "/Basic/UserDrawFeatures_SQL",
headers: {
"Authorization": localStorage["token"]
},
data: JSON.stringify(drawsaveobj),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (d) {
var data = d;
console.log(data);
var onecasegeom = data.filter(o => o.drawsaveid === drawsaveid);
onecasegeom.forEach(function (item, idx) {
var f = GraphicTrans.GraphicFromString(item.geom, item.style);
f.id = drawsaveid;
map.e_getLayer("drawLyr").getSource().addFeature(f);
if (onecasegeom.length-1 === idx) {
var extent = map.e_getLayer("drawLyr").getSource().getExtent();
map.getView().fit(extent, map.getSize());
}
});
console.log(onecasegeom);
},
error: function (jqXHR, exception) {
ajaxError(jqXHR, exception);
}
});
}
點選刪除按鈕後,執行 delUserDrawCase()
透過 UserDrawFeatures_SQL
,SQLType設為Del,進行刪除。
function delUserDrawCase(drawsaveid) {
if (confirm("確定刪除此儲存圖形?")) {
var drawsaveobj = {
"SQLtype": "Del",
"title": "",
"info": "",
"drawsaveid": drawsaveid,
"features": []
};
$.ajax({
type: "POST",
url: config_OLMapWebAPI + "/Basic/UserDrawFeatures_SQL",
headers: {
"Authorization": localStorage["token"]
},
data: JSON.stringify(drawsaveobj),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (d) {
var data = d;
console.log(data);
draw.getUserDrawCaseList();
alert("已刪除完成!");
},
error: function (jqXHR, exception) {
ajaxError(jqXHR, exception);
}
});
}
}
繪圖儲存後,顯示列表示意圖:
根據 GeoJSON技術文件 可以得知GeoJSON的格式並不包含Circle,因此若將畫圓圈的圖形存入,則會造成無法轉換為GeoJSON的問題存在,自然也無法還原圖形。
這部分我尚未實際下去debug解決,但有Google到不少解決方法,大家可以找找看。
太多隻了,只好找一隻顏色比較單調、比較好畫的神奇寶貝寶可夢「海豹球」當作範例,我知道很醜大家請見諒QAQ:
將上述的圖案存到資料庫會長這樣:
到了 Day26 終於完成了為期3天的繪圖功能的建置,WebGIS已完成了90%了,任何的功能都可以大概依照這種模式進行建立。
明天是最後一次的 不寫程式改來學知識
系列,身為一個毫無美感的工程師,若也缺乏精通前端介面的同事,前端UI/UX的套件是不可或缺的,明天來討論有哪些好用的圖表套件和RWD介面可供套用。