問題描述
出差的某一天晚上在賓館沒事幹瞎想,突然想到白天做過的項目功能的時候,有個點選查詢的功能引起了我的注意。在項目中爲了實現點選查詢,是在ArcGIS Server裏面發佈了一個要素服務,然後將其添加到地圖上渲染,並實現了鼠標的點選查詢功能,那這個功能可不可以不通過發佈服務來實現呢?想到這,打開電腦仔細翻看了了一下ArcGIS JS API的官方文檔,發現好像是可以,所以就立即動手了,幸運的是,我成功了,先給大家上一張效果圖:
上圖中的鼠標點選查詢,並出現彈窗的功能實現的數據來源並不是一個發佈的要素服務,而是我模擬了六個數據點,將它們保存成了一個數組,這個數組就代表我從後臺拿到的數據,因爲我不可能爲了這樣一個小功能再自己去寫一個後臺吧。好了,現在講講主要的實現步驟。
實現步驟
1、首先呢,這個demo是基於Vue來寫的,所以我先初始化了一個Vue的demo,當然了,你直接弄成一個HTML頁面文件是沒有任何問題的,看自己喜好。然後我再項目裏安裝了esri-loader插件,因爲要在Vue的demo裏要使用ArcGIS JS API,所以要用到這東西,如果大家對這個過程不瞭解的話請移步至另一篇文章《【番外】 Vue中使用ArcGIS JS API 4.14開發》,在這裏不做詳細介紹。
2、初始化完demo,安裝完插件之後,接下來我們引入esri-loader,並實例化一個基礎的二維地圖,代碼如下:
_createMapview: function() {
const _self = this;
const option = {
url: 'https://js.arcgis.com/4.15/init.js',
css: 'https://js.arcgis.com/4.15/esri/themes/light/main.css',
};
loadModules(['esri/Map', 'esri/views/MapView', 'esri/layers/FeatureLayer'], option)
.then(([Map, MapView, FeatureLayer]) => {
let map = new Map({
basemap: 'osm',
});
let view = new MapView({
container: 'mapview',
map: map,
zoom: 10,
center: [104.071308, 30.663028],
});
console.log(view);
})
.catch((err) => {
console.log('地圖創建失敗:', err);
});
},
3、地圖初始化完成之後,我們引入我們的數據,這個過程就相當於是你用AJAX從後臺拿到數據了,因爲我的數據我單獨放在了一份JS文件裏。數據引入之後,我們對它進行一下處理,因爲你有可能從後臺拿到的數據裏面,關於經緯度信息是字符串,而不是數值類型,代碼如下:
數據文件:
let defaultData = [
{
address: '2號線地鐵人民公園旁邊',
time: '9:30——18:00',
coordinate: '[104.06369,30.663774]',
name: '人民公園',
phone: '028-86080000',
},
{
address: '2號線地鐵天府廣場',
time: '9:30——18:00',
coordinate: '[104.07235,30.663245]',
name: '天府廣場',
phone: '028-86080000',
},
{
address: '3號線地鐵春熙路站',
time: '9:30——22:00',
coordinate: '[104.08586,30.65958]',
name: '春熙路',
phone: '028-86080000',
},
{
address: '四川科技館背後',
time: '9:30——18:00',
coordinate: '[104.073787,30.669334]',
name: '成都體育中心',
phone: '028-86080000',
},
{
address: '天府大道北段',
time: '9:30——18:00',
coordinate: '[104.070095,30.575247]',
name: '環球中心',
phone: '028-86080000',
},
{
address: '4號線寬窄巷子地鐵站',
time: '9:30——18:00',
coordinate: '[104.056441,30.671462]',
name: '寬窄巷子',
phone: '028-86080000',
},
];
export default defaultData;
處理數據函數:
//處理經緯度數據,返回features
_translateLonLat: function(data) {
const _self = this;
if (data.length > 0) {
data.map((value, key) => {
let lonlatStr = value.coordinate.split(',');
let lonStr = lonlatStr[0].split('[')[1];
let latStr = lonlatStr[1].split(']')[0];
_self.geodata.push({
geometry: {
type: 'point',
x: Number(lonStr),
y: Number(latStr),
},
attributes: {
ObjectID: key,
address: value.address,
time: value.time,
name: value.name,
phone: value.phone,
},
});
});
}
return _self.geodata;
},
4、接下來我們拿到處理過後的數據,其實這就是一個features,用來實例化要素圖層的。然後我們用它去實例化一個要素圖層,並將它添加到地圖上:
//實例化featurelayer
let layer = new FeatureLayer({
source: resultData,
objectIdField: 'ObjectID',
});
view.map.add(layer);
5、到此爲止呢,我們的數據點其實已經添加到地圖上了,但這時候還不能點擊查詢,所以我們要配置一個pupoptemplate,代碼如下:
//實例化彈窗
let template = {
title: '{name}',
content: [
{
type: 'fields',
fieldInfos: [
{
fieldName: 'address',
label: '地址',
},
{
fieldName: 'time',
label: '開放時間',
},
{
fieldName: 'phone',
label: '相關電話',
},
],
},
],
};
//給要素圖層實例化的屬性中配置pupoptemplate
let layer = new FeatureLayer({
source: resultData,
objectIdField: 'ObjectID',
fields: [
{
name: 'OBJECTID',
type: 'oid',
},
{
name: 'time',
type: 'string',
},
{
name: 'address',
type: 'string',
},
{
name: 'phone',
type: 'string',
},
{
name: 'name',
type: 'string',
},
],
popupTemplate: template,
});
view.map.add(layer);
6、這樣一來我們就直接通過後臺返回的數據實例化了一個要素圖層,並實現了鼠標點擊查詢功能了。
附:
完整代碼:
import { loadModules } from 'esri-loader';
import defaultData from '../assets/data';
export default {
name: 'HelloWorld',
data: function() {
return {
geodata: [],
};
},
mounted: function() {
this._createMapview();
},
methods: {
_createMapview: function() {
const _self = this;
const option = {
url: 'https://js.arcgis.com/4.15/init.js',
css: 'https://js.arcgis.com/4.15/esri/themes/light/main.css',
};
loadModules(['esri/Map', 'esri/views/MapView', 'esri/layers/FeatureLayer'], option)
.then(([Map, MapView, FeatureLayer]) => {
let map = new Map({
basemap: 'osm',
});
let view = new MapView({
container: 'mapview',
map: map,
zoom: 10,
center: [104.071308, 30.663028],
});
console.log(view);
let resultData = _self._translateLonLat(defaultData);
//實例化彈窗
let template = {
title: '{name}',
content: [
{
type: 'fields',
fieldInfos: [
{
fieldName: 'address',
label: '地址',
},
{
fieldName: 'time',
label: '開放時間',
},
{
fieldName: 'phone',
label: '相關電話',
},
],
},
],
};
//實例化featurelayer
let layer = new FeatureLayer({
source: resultData,
objectIdField: 'ObjectID',
fields: [
{
name: 'OBJECTID',
type: 'oid',
},
{
name: 'time',
type: 'string',
},
{
name: 'address',
type: 'string',
},
{
name: 'phone',
type: 'string',
},
{
name: 'name',
type: 'string',
},
],
popupTemplate: template,
});
view.map.add(layer);
})
.catch((err) => {
console.log('地圖創建失敗:', err);
});
},
//處理經緯度數據,返回features
_translateLonLat: function(data) {
const _self = this;
if (data.length > 0) {
data.map((value, key) => {
let lonlatStr = value.coordinate.split(',');
let lonStr = lonlatStr[0].split('[')[1];
let latStr = lonlatStr[1].split(']')[0];
_self.geodata.push({
geometry: {
type: 'point',
x: Number(lonStr),
y: Number(latStr),
},
attributes: {
ObjectID: key,
address: value.address,
time: value.time,
name: value.name,
phone: value.phone,
},
});
});
}
return _self.geodata;
},
},
};