出差的某一天晚上在宾馆没事干瞎想,突然想到白天做过的项目功能的时候,有个点选查询的功能引起了我的注意。在项目中为了实现点选查询,是在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;
},
},
};