为arcgis for js封装自己的map

本文介绍了一种将地图功能封装成类的方法,以便简化地图的使用。通过创建GridMap类,实现了快速加载天地图并添加自定义图层,同时提供了要素图层的添加功能和随机点生成器。此外,还探讨了地图聚合功能的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个项目内可能有很多地方会用到地图,而这些代码相似度都很高,而且arcgis for js常用的东西本来就不多,所以可以将其封装出一个类,每次调用地图只需要简单的代码就可以了,在最近的项目里弄了一个半成品,先贴出来,将来有人接手的话上手会快一点。

使用amd方式的话,跨js文件可能会有些麻烦,所以尽量将常用的功能封装到一个类里面去。

按照公司目前的需求,地图全部使用天地图,第一步就是将天地图封装进来。

var GridMap;require(....,function(){...});将其设为一个全局的类,然后在require后面的函数里写具体的内容

GridMap = function(divid) {
this.isClustered = false;//后面会加入聚合功能
this.map = new Map(divid, {
slider: false
});
this.commonGraphicsLayer = new GraphicsLayer({
id: "commonGraphicsLayer"
});//通用的绘图图层
var layer = new TianDiTuLayer(TianDiTuLayer.VEC_BASE_GCS);
var ano_layer = new TianDiTuLayer(TianDiTuLayer.VEC_ANNO_GCS);
this.map.addLayer(layer);
this.map.addLayer(ano_layer);
this.map.centerAndZoom(new Point(120.263391, 31.486093), 12);
this.map.addLayer(this.commonGraphicsLayer);
};

这个构造函数可以将中心点和zoom设为参数,因为目前的需求里都是同样的,所以写死了。

然后加载业务图层,按照领导的想法,使用ArcGISDynamicMapServiceLayer,然后每次点击后根据点击的坐标点去查询数据,这种方式不需要进行点渲染,加载速度快;而我比较喜欢用featureLayer,灵活。而且使用featureLayer造假数据比较方便,还不用发布图层,在没有数据和环境且急着出版本或者演示的时候可以用要素图层先顶一下。

如果不发布图层,则可以使用featureCollection构建图层,贴出一些简要的代码。

//增加要素图层,通过要素集增加图层,测试用
addFeatureLayerByCollection: function(layerid, infoTemplateObj,
featureCollectionObject, features, isShow, isScale) {
featureCollectionObject.featureSet.features = features;
var infoTemplate = null;
if(infoTemplateObj){
infoTemplate = new InfoTemplate(
infoTemplateObj.title,
infoTemplateObj.content
);
}

var featureLayer = new FeatureLayer(featureCollectionObject, {
id: layerid,
infoTemplate: infoTemplate,
visible: !!isShow
});
if(typeof isScale === "undefined") {
isScale = true;
}
this.setRenderer(featureLayer, this.getRenderer(layerid), isScale);
this.map.addLayer(featureLayer);
return featureLayer;

而要素集的格式大概如下:

var letHouseCollection = {
  "layerDefinition": null,
  "featureSet": {
    "features": [],
    "geometryType": "esriGeometryPoint"
  }
};
letHouseCollection.layerDefinition = {
  "geometryType": "esriGeometryPoint",
  "objectIdField": "ObjectID",
//"drawingInfo": {
//  "renderer": {
//    "type": "simple",
//    "symbol": {
//      "type": "esriPMS",
//      "url": "../images/letHouse.png",
//      "contentType": "image/png",
//      "width": 24,
//      "height": 30
//    }
//  }
//},
  "fields": [{
    "name": "ObjectID",
    "alias": "ObjectID",
    "type": "esriFieldTypeOID"
  }, {
    "name": "name",
    "alias": "name",
    "type": "esriFieldTypeString"
  }, {
    "name": "account",
    "alias": "account",
    "type": "esriFieldTypeString"
  }, {
    "name": "partialLet",
    "alias": "partialLet",
    "type": "esriFieldTypeString"
  }, {
    "name": "floatPopulation",
    "alias": "floatPopulation",
    "type": "esriFieldTypeString"
  }, {
    "name": "children",
    "alias": "children",
    "type": "esriFieldTypeString"
  }, {
  "name": "disabled",
    "alias": "disabled",
    "type": "esriFieldTypeString"
  }]
};

使用要素图层,首先会向url的地址发送请求,这个请求用jsonp处理了,请求的内容就是要素集,可以随便找个点线面图层发个请求看一下格式。

这里面我将drawingInfo注了是因为我过会儿会使用自定义的渲染器,并且图标还需要根据缩放等级调整大小。但是首先得解决features": []这个问题。

既然是假数据,那我就将所有点的数据设为一样的,只要显示相应数量的点看个效果就可以。

//生成随机点,供测试用
getRandomGraphics: function(account, attribute) { //生成account个随机graphics,测试用
var graphics = [];
for(var i = 0; i < account; i++) {
var pt = new Point(120 + parseFloat(Math.random().toFixed(3)), 31 + parseFloat(Math.random().toFixed(3)), this.map.spatialReference);
var sms = new SimpleMarkerSymbol({
"color": [255, 255, 255, 64],
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": [0, 0, 0, 255],
"width": 1,
"type": "esriSLS",
"style": "esriSLSSolid"
}
});
var attr = this._deepClone(attribute);
attr.ObjectID = i;
var graphic = new Graphic(pt, sms, attr);
graphics.push(graphic);
}
return graphics;
},

传进来要生成的点的数量和属性,这里面会用到深克隆,因为我还得给每一个点的属性加上objectid。

GridMap.prototype = {
_deepClone: function(initalObj, finalObj) { //深克隆
var obj = finalObj || {};
for(var i in initalObj) {
var prop = initalObj[i];
// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if(typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
},

其实对一些标准json格式对象,深克隆可以简单使用JSON.parse(JSON.stringify(simpleJson)); //深克隆的黑科技

使用的时候:

var gridMap = new GridMap("map");

var gridmanLayer = gridMap.addFeatureLayerByCollection("gridmanLayer",
/*{
title:"${name}【${position}】",
content:"<div>联系电话:"+
"${tel}</div>"+
"<div >所属网格:"+
"${belong}</div>"+
"<div >待办事项:"+
"${todoList}</div>"+
"<div >完成事项:"+
"${doneList}</div>"+
"<div >重点服务对象:"+
"${vip}</div>"
}*/null,gridmanCollection,gridmanFeatures,false,true);

后面两个布尔值分别表示一开始是否显示,是否按照比例尺调整图标大小。中间注释部分内容表示弹窗内容,领导不喜欢这种,所以去掉了。

下面还有聚合功能。开启和关闭分别调用方法gridMap.activeCluster(layerId);gridMap.deactiveCluster(layerId);聚合图层只能聚合单图层,多图层聚合的话没意思了。

下面是简易代码

//根据数据聚合
clusterByData: function(features, infotemplate) {
var map = this.map;
var data = features.map(function(f) {
var latlng = f.geometry;
var attributes = f.attributes;
return {
"x": latlng.x,
"y": latlng.y,
"attributes": attributes
};
});
var clusterLayer = new ClusterLayer({
"data": data,
"distance": 100,
"id": "clusters",
"labelColor": "#fff",
"labelOffset": 10,
"resolution": map.extent.getWidth() / map.width,
"singleColor": "#888",
"singleTemplate": infotemplate
});
var defaultSym = new SimpleMarkerSymbol().setSize(4);
var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");


var picBaseUrl = window.location.origin + location.pathname.substring(0, location.pathname.indexOf("/", 1)) + "/images/";
var blue = new PictureMarkerSymbol(picBaseUrl + "BluePin1LargeB.png", 32, 32).setOffset(0, 15);
var green = new PictureMarkerSymbol(picBaseUrl + "GreenPin1LargeB.png", 64, 64).setOffset(0, 15);
var red = new PictureMarkerSymbol(picBaseUrl + "RedPin1LargeB.png", 72, 72).setOffset(0, 15);
renderer.addBreak(0, 2, blue);
renderer.addBreak(2, 200, green);
renderer.addBreak(200, 10000, red);
clusterLayer.setRenderer(renderer);
map.addLayer(clusterLayer);
},
//激活聚合
activeCluster: function(layerId) {
if(this.isClustered) {
return;
}
//1.先获取数据
var layer = this.map.getLayer(layerId);
var url = layer.url;
var _self = this;
if(url) {
var map = this.map;
var query = new Query();
query.outFields = ["*"];
query.returnGeometry = true;
var defn = this.loadedLayer._defnExpr;
if(defn) {
query.where = defn;
} else {
query.where = "1=1";
}
var queryTask = new QueryTask(url);
queryTask.execute(query, function(featureSet) {
//进行聚合
try {
_self.clusterByData(featureSet.features, layer.infoTemplate);
layer.hide();
_self.isClustered = true;
} catch(e) {
console.error(e);
}
});
} else {
//进行聚合
try {
//测试
_self.clusterByData(layer.graphics, layer.infoTemplate);
layer.hide();
_self.isClustered = true;
} catch(e) {
console.error(e);
}


}
},
//取消聚合
deactiveCluster: function(layerId) {
var map = this.map;
map.infoWindow.hide();
var clusterLayer = map.getLayer("clusters");
if(clusterLayer) {
clusterLayer.clearSingles();
map.removeLayer(clusterLayer);
map.getLayer(layerId).show();
this.isClustered = false;
}
},

主要是领导不喜欢这功能,所以这里面只完成了50%的样子,大体上能实现效果,只是各种情况和图层的兼容性还没考虑,如果将来有人来接手的话再慢慢研究吧。

我还开放了一个地图事件监听的接口:

//对地图增加事件监听
addEventListener: function(evtName, callback) {
this.map.on(evtName, function(evt) {
callback(evt)
});
},

而对于渲染器这块的代码还是写的比较死

//设置渲染器,有简单渲染和多比例尺渲染
setRenderer: function(layer, renderers, isScale) { //设置多比例尺渲染器
var scaleDependentRenderer = new ScaleDependentRenderer({
rendererInfos: [{
renderer: renderers[1], //小图标
maxZoom: 10,
minZoom: 0


}, {
renderer: renderers[0], //大图标
maxZoom: 17,
minZoom: 11
}]
});
if(!!isScale) {
layer.setRenderer(scaleDependentRenderer);
} else {
layer.setRenderer(renderers[0]);
}


},

生成渲染器也是死的,一共6个图层,实现将各图层的渲染器json写好,然后根据图层id去找,如果是多比例尺渲染器,就额外多一步设置图片缩放参数和zoom关系

getRenderer: function(layerId) {...}

渲染器json如下:

"liftLayer": {
"type": "simple",
"symbol": {
"type": "esriPMS",
"url": "../images/lift.png",
"contentType": "image/png",
"width": 21,
"height": 21
}
},

以上就是一些不太成熟的想法,原计划这个项目做完时能出一个通用的map工具类,能在我没有数据和图层的时候展示效果,当我有图层和数据的时候改变少量代码就可以兼容,不过需求几番变更时间越来越紧,大概是不大有机会能出个完成版的了,所以我还是早点把这些想法记下来,等以后项目再慢慢完善吧。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值