GIS地圖學習筆記六之按圖層縮放地圖
ArcGis中設定地圖縮放比例的方法
mMapView.setViewpointScaleAsync(scale);
需求
點選地圖上的縮放按鈕“+”“-” ,讓地圖按照地圖的圖層進行縮放,比如一個地圖包含以下圖層,每一個圖層都有一個縮放比例scale,就是我們在點選縮放按鈕“+”“-” 的時候需要按照下面的不同層級(level)的縮放比(scale)來設定地圖的縮放比。
"lods": [
{
"level": 0,
"resolution": 0.009746272279880825,
"scale": 4096000
},
{
"level" : 1,
"resolution": 0.004873136139940413,
"scale": 2048000
},
{
"level": 2,
"resolution": 0.0024365680699702063,
"scale": 1024000
},
{
"level": 3,
"resolution": 0.0012182840349851032,
"scale": 512000
},
{
"level": 4,
"resolution": 6.091420174925516E-4,
"scale": 256000
},
{
"level" : 5,
"resolution": 3.045710087462758E-4,
"scale": 128000
},
{
"level": 6,
"resolution": 1.522855043731379E-4,
"scale": 64000
},
{
"level": 7,
"resolution": 7.614275218656895E-5,
"scale": 32000
},
{
"level": 8,
"resolution": 3.8071376093284474E-5,
"scale" : 16000
},
{
"level": 9,
"resolution": 1.9035688046642237E-5,
"scale": 8000
},
{
"level": 10,
"resolution": 9.517844023321119E-6,
"scale": 4000
},
{
"level": 11,
"resolution": 4.758922011660559E-6,
"scale": 2000
},
{
"level": 12,
"resolution": 2.3794610058302796E-6,
"scale": 1000
},
{
"level": 13,
"resolution": 1.1897305029151398E-6,
"scale": 500
}
]
程式碼實現
1、圖層資訊獲取工具類
要實現按圖層縮放,我們需要先來獲取對應地圖服務的圖層資訊,使用的工具類ReturnJson.java
,使用handler 返回地圖服務地址、地圖最大縮放比和最小縮放比,注意有聯網請求,需要在子執行緒中執行。使用url格式是“your map server url ”+”?f=pjson” , 例如:
http://119.97.224.2:8399/PBS/rest/services/MapsRoad/MapServer?f=pjson
注意你的地圖服務地址不要用 “/” 結尾,要和示例相同的格式 ,直接在MapServer後面接?f=pjson 。
public class ReturnJson {
private Handler mHandler;
private String mURL;
public ReturnJson(String strURL, Handler handler) {
this.mHandler = handler;
this.mURL = strURL;
//判斷strURL
String end = "";
if (!TextUtils.isEmpty(strURL)) {
end = strURL.substring(strURL.length() - 1, strURL.length());
}else {
return;
}
HttpURLConnection httpConnection = null;
try {
if (!MyUtils.isUrl(strURL))return;
if ("/".equals(end)) {
strURL = strURL.substring(0,strURL.length() - 1);
}
URL url = new URL(strURL+"?f=pjson");
byte[] buf = new byte[1024];
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.connect();
InputStream in = httpConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer response = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
String string = response.toString();
httpConnection.disconnect();
ExplainJson(string);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpConnection != null){
httpConnection.disconnect();
}
}
}
// 解析json中縮放比率儲存起來
private void ExplainJson(String retStr) {
try {
TileInfoBean infoBean = new TileInfoBean();
ArrayList<TileInfoBean.LodsBean> list = new ArrayList<>();
JSONObject tileInfo = new JSONObject(retStr).getJSONObject("tileInfo");
JSONArray jsonArray_lods = tileInfo.getJSONArray("lods");
if (jsonArray_lods!=null&&jsonArray_lods.length()>0){
//最大值的縮放比
JSONObject jsonObjectMax = (JSONObject) jsonArray_lods.opt(0);
double fastScale = jsonObjectMax.getDouble("scale");
//最小值的縮放比
JSONObject jsonObjectMin = (JSONObject) jsonArray_lods.opt(jsonArray_lods.length()-1);
double lastScale = jsonObjectMin.getDouble("scale");
Message message = new Message();
message.what = 13;
Bundle bundle = new Bundle();
bundle.putString("url",mURL);
bundle.putDouble("fastScale",fastScale);
bundle.putDouble("lastScale",lastScale);
message.setData(bundle);
mHandler.sendMessage(message);
}
for (int i = 0; i < jsonArray_lods.length(); i++) {
TileInfoBean.LodsBean lodsBean = new TileInfoBean.LodsBean();
JSONObject jsonObject3 = (JSONObject) jsonArray_lods.opt(i);
int level = jsonObject3.getInt("level");
double scale = jsonObject3.getDouble("scale");
double resolution = jsonObject3.getDouble("resolution");
lodsBean.setLevel(level);
lodsBean.setResolution(resolution);
lodsBean.setScale(scale);
list.add(lodsBean);
}
infoBean.setLods(list);
MyApplication.getInstance().setTileInfoBean(infoBean);
} catch (Exception e) {
// TODO: handle exception
}
}
}
程式碼中相關的工具類,MyUtils.isUrl(strURL)
/**
* 匹配URL地址
*/
public static boolean isUrl(String str) {
return match(str, "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
}
/**
* 正則表示式匹配
* @param text 待匹配的文字
* @param reg 正則表示式
* @return
*/
private static boolean match(String text, String reg) {
if (TextUtils.isEmpty(text) || TextUtils.isEmpty(reg)) return false;
return Pattern.compile(reg).matcher(text).matches();
}
程式碼中相關的實體類,TileInfoBean.java
,因為我只需要圖層資訊,所以定義的實體類只包含圖層的相關資訊,如果有其他需求可以自己重新定義。
public class TileInfoBean implements Parcelable{
private List<LodsBean> lods;
public List<LodsBean> getLods() {
return lods;
}
public void setLods(List<LodsBean> lods) {
this.lods = lods;
}
protected TileInfoBean(Parcel in) {
}
public TileInfoBean() {
}
public static final Creator<TileInfoBean> CREATOR = new Creator<TileInfoBean>() {
@Override
public TileInfoBean createFromParcel(Parcel in) {
return new TileInfoBean(in);
}
@Override
public TileInfoBean[] newArray(int size) {
return new TileInfoBean[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
public static class LodsBean {
private int level;
private double resolution;
private double scale;
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public double getResolution() {
return resolution;
}
public void setResolution(double resolution) {
this.resolution = resolution;
}
public double getScale() {
return scale;
}
public void setScale(double scale) {
this.scale = scale;
}
}
}
2、載入地圖,獲取圖層資訊
在載入地圖的時候呼叫,注意要在子執行緒中執行
new Thread(new Runnable() {
@Override
public void run() {
new ReturnJson(url,mHandler); //存地圖縮放比例
}
}).start();
3、點選縮放
case R.id.scale_max: // + 運算
changeScale(MAX);
break;
case R.id.scale_min: // - 運算
changeScale(MIN);
break;
private double CurrentScale = 15500;
...
//改變地圖縮放比例--按圖層
private void changeScale(String type) {
TileInfoBean bean = instance.getTileInfoBean();
if (bean == null) {
new CenterHintToast(MainActivity.this, "獲取縮放比例失敗");
return;
}
List<TileInfoBean.LodsBean> lods = bean.getLods();
if (lods == null || lods.size() <= 0) return;
double mapScale = mMapView.getMapScale();
double fastScale = lods.get(0).getScale();
double lastScale = lods.get(lods.size() - 1).getScale();
if (mapScale>=fastScale&&MIN.equals(type))return;
if (mapScale<=lastScale&&MAX.equals(type))return;
for (int i = 0; i < lods.size() - 1; i++) {
if (MAX.equals(type)) { // + 運算(放大地圖、顯示區域變小)
if (mapScale <= lods.get(i).getScale() && mapScale > lods.get(i+1).getScale()) {
CurrentScale = lods.get(i+1).getScale();
}
} else if (MIN.equals(type)) { // - 運算(縮小地圖、顯示區域變大)
if (mapScale < lods.get(i).getScale() && mapScale >= lods.get(i + 1).getScale()) {
CurrentScale = lods.get(i).getScale();
}
}
}
mMapView.setViewpointScaleAsync(CurrentScale);
}
上面for
迴圈的時候使用i < lods.size() - 1
而不是i < lods.size()
是為了防止下標越界,因為運算使用了i+1
4、利用圖層資訊配置地圖最大、最小縮放比
獲取地圖配置資訊成功後,利用handler傳遞資訊,配置地圖最大和最小縮放比,並設定地圖中心點及當前顯示比例。
//--獲取地圖配置資訊成功
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 13:
Bundle data = msg.getData();
String url = data.getString("url");
MinScale = data.getDouble("fastScale");
MaxScale = data.getDouble("lastScale");
ArcGISTiledLayer tiledLayer = new ArcGISTiledLayer(url);
tiledLayer.setMinScale(MinScale); //控制縮小,數值越大,縮小倍數越大,看的範圍越廣
tiledLayer.setMaxScale(MaxScale); //控制放大,數值越小,放大倍數越高
Basemap basemap = new Basemap(tiledLayer);
mArcGISMap = new ArcGISMap(basemap);
mMapView.setMap(mArcGISMap);
Point point = CoordinateFormatter.fromLatitudeLongitude(center, SpatialReferences.getWgs84());
mMapView.setViewpointCenterAsync(point, CurrentScale);
break;
}
}
};
5、結束
ok,到這裡就寫完了,使用上面的程式碼,當地圖縮放到最大或最小比例之後,地圖將不再縮放,程式碼還是會執行,只是給地圖設定的縮放比CurrentScale
的數值不會變化。
另外,如果你在點選縮放按鈕“+”“-” 之前先使用手勢識別進行了地圖縮放也沒有關係,因為上面的程式碼取的是地圖當前的縮放比進行計算的。