arcgis 3x 聚类实现 点击弹出infowindow 附带
2019-12-11 本文已影响0人
channel_puls
-
首先官方也给出了例子 但是这不能满足我们的需求
image.png
改造后 当然设置了他的 renderer 达到效果
ss.png
define([
"dojo/_base/declare",
"dojo/_base/array",
"esri/Color",
"dojo/_base/connect",
"esri/SpatialReference",
"esri/geometry/Point",
"esri/graphic",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/TextSymbol",
"esri/dijit/PopupTemplate",
"esri/layers/GraphicsLayer",
"esri/InfoTemplate",
"esri/geometry/Extent",
"dojo/dom-construct",
"esri/symbols/PictureMarkerSymbol",
"esri/dijit/InfoWindow"
], function(
declare, arrayUtils, Color, connect,
SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol,
PopupTemplate, GraphicsLayer,
InfoTemplate,
Extent,
domConstruct,PictureMarkerSymbol,
InfoWindow
) {
return declare([GraphicsLayer], {
constructor: function(options) {
this._clusterTolerance = options.distance || 50;
// 页面初始数据
this._clusterData = options.data || [];
//
this._clusters = [];
this._clusterLabelColor = options.labelColor || "#000";
// 标签偏移可以是零,所以处理方式不同
this._clusterLabelOffset = (options.hasOwnProperty("labelOffset")) ? options.labelOffset : -5;
this._singles = []; // 在单击图形时填充
this._showSingles = options.hasOwnProperty("showSingles") ? options.showSingles : true;
// 表示单个点的图形
var SMS = SimpleMarkerSymbol;
this._singleSym = options.singleSymbol || new SMS("circle", 3, null, new Color("#097"));
this._singleTemplate = options.singleTemplate || new InfoTemplate("Attributes", "{*}");
this._maxSingles = options.maxSingles || 1000;
this._webmap = options.hasOwnProperty("webmap") ? options.webmap : false;
this._sr = options.spatialReference || new SpatialReference({
"wkid": 4326
});
this._zoomEnd = null;
this._mapclick = null;
},
// override esri/layers/GraphicsLayer methods
_setMap: function(map, surface) {
// 计算并设置初始分辨率
this._clusterResolution = map.extent.getWidth() / map.width; // probably a bad default...
if(this._zoomEnd==null){this._clusterGraphics();}
// 连接到onZoomEnd,以便在缩放级别更改时重新聚集数据
this._zoomEnd = connect.connect(map, "onZoomEnd", this, function() {
// 更新分辨率
this._clusterResolution = this._map.extent.getWidth() / this._map.width;
this.clear();
this._clusterGraphics();
});
// GraphicsLayer将在这里添加自己的侦听器
var div = this.inherited(arguments);
return div;
},
_unsetMap: function() {
this.inherited(arguments);
connect.disconnect(this._zoomEnd);
},
// 公共ClusterLayer方法
add: function(p) {
//参数是要添加到现有集群中的数据点。如果数据点落在现有集群内,
// 则将其添加到该集群,并更新集群的标签。如果新点不在现有集群中,则创建一个新集群
// 如果传递了一个图形,使用GraphicsLayer的add方法
if (p.declaredClass) {
this.inherited(arguments);
return;
}
// 将新数据添加到_clusterData中,以便将其包含在集群中
this._clusterData.push(p);
var clustered = false;
// 当地图级别改变时
// 在现有集群中查找新点
for (var i = 0; i < this._clusters.length; i++) {
var c = this._clusters[i];
// 将该点添加到现有集群
this._clusterAddPoint(p, c);
// 更新集群的几何形状
this._updateClusterGeometry(c);
// 更新标签
this._updateLabel(c);
clustered = true;
}
if (!clustered) {
p.attributes.clusterCount = 1;
this._clusterCreate(p);
this._showCluster(p);
}
},
showSingles: function() {
var singles = [];
for (var i = 0, il = this._clusterData.length; i < il; i++) {
singles.push(this._clusterData[i]);
}
this._addSingles(singles);
},
clear: function() {
// 摘要:删除所有集群和数据点
this.inherited(arguments);
this._clusters.length = 0;
},
clearSingles: function(singles) {
// 摘要:删除表示单个数据点的图形。
var s = singles || this._singles;
arrayUtils.forEach(s, function(g) {
this.remove(g);
}, this);
this._singles.length = 0;
},
onClick: function(e) {
// 删除任何以前显示的单一功能
this._map.infoWindow.resize(440, 350)
this.clearSingles(this._singles);
// 查找组成被单击的集群的单个图形
// would be nice to use filter but performance tanks with large arrays in IE
var singles = [];
for (var i = 0, il = this._clusterData.length; i < il; i++) {
if (e.graphic.attributes.clusterId == this._clusterData[i].attributes.clusterId) {
singles.push(this._clusterData[i]);
}
}
if (singles.length > this._maxSingles) {
alert("Sorry, that cluster contains more than " + this._maxSingles + " points. Zoom in for more detail.");
return;
} else {
e.stopPropagation();
// 停止从弹出到地图的单击
if (singles.length == 1) {
// 单一的时候
// this._map.infoWindow.show(e.graphic.geometry);
// this._graphicOnClick(e.graphic.attributes);
this._graphicOnClick(e);
} else if(this._map.getMaxZoom()-this._map.getZoom()>2 && singles.length > 1){
//点击singles时得到符号的extent 然后设置为当前可见范围 放大地图 达到放大地图等级 触发重新渲染点 从而分开点
var xmax, ymax, xmin, ymin;
xmax = this._find(singles, "x", "max");
ymax = this._find(singles, "y", "max");
xmin = this._find(singles, "x", "min");
ymin = this._find(singles, "y", "min");
var extent = new Extent(xmin, ymin, xmax, ymax, this._sr)
this._map.setExtent(extent);
this._clusterResolution = this._map.extent.getWidth() / this._map.width;
this.clear();
this._clusterGraphics();
this._addSingles(singles);
}
}
},
//如果点前是一个点 则触发此事件
_graphicOnClick: function(e) {
var _this = this;
var id;
if (e.graphic.attributes.id.id) {
id = e.graphic.attributes.id.id;
} else {
id = e.graphic.attributes.id;
}
this.addInfo(id, function(res) {
// var node = domConstruct.create("div", {
// innerHTML: "<div class='content_doms'>" +
// "<div class='content_doms_header'>" +
// "<table class='table table-bordered table-condensed'><thead><tr class='info'><th>户主姓名</th><th>所在自然村</th><th>本户人数</th><th>联系电话</th></tr></thead>" +
// "<tbody><tr><td>" + res.nhFarmerInfo.name + "</td><td>" + res.nhFarmerInfo.naturalvillagename +
// "</td><td>" + res.nhFarmerInfo.peoples + "</td><td>" + res.nhFarmerInfo.telephone +
// "</td></tr></tbody></table>" +
// "</div>" +
// "<div class='content_doms_footer'>" + _this.createList(res.nhOutletList) + "<div>" +
// "</div>"
// });
// 表格生成代码
var node = domConstruct.create("div", {
innerHTML: "<div class='content_doms'>" +
"<div class='content_doms_header'>" +
// <table class='table table-bordered table-condensed'>" + createTableList(res.nhFarmerInfo) +"</table>
generateTable(res.nhFarmerInfo,2)+
"</div>" +
"<div class='content_doms_footer'>" +createList(res.nhOutletList) + "<div>" +
"</div>"
});
// var infoTemplate = new InfoTemplate("农户信息", node);
// 排口信息
res.id = id;
// e.graphic.setAttributes(res);
// e.graphic.setInfoTemplate(infoTemplate);
_this._map.infoWindow.setTitle("农户信息");
_this._map.infoWindow.setContent(node);
_this._map.infoWindow.show(e.graphic.geometry);
});
},
// 查找数组中最大值 或者 最小值
_find: function(arr, pro, single) {
return Math[single].apply(Math, arr.map(function(o) {
return o[pro]
}))
},
addInfo: function(id, cb) {
var url ='/hbnhcj/farmer/nhFarmerInfo/getFarmerWithOutlet';
$ajax(url,"GET",{id:id},function(data){
cb(data.result)
});
},
// 内部方法 ***************************起点*********************************
_clusterGraphics: function() {
// ,遍历这些点
for (var j = 0, jl = this._clusterData.length; j < jl; j++) {
// 查看当前特性是否应该添加到集群中
var point = this._clusterData[j];
var clustered = false;
var numClusters = this._clusters.length;
for (var i = 0; i < this._clusters.length; i++) {
// 当前集群
var c = this._clusters[i];
// 查看是否满足距离公式
if (this._clusterTest(point, c)) {
// 如果满足 就将当前点添加到
this._clusterAddPoint(point, c);
clustered = true;
break;
}
}
if (!clustered) {
this._clusterCreate(point);
}
}
this._showAllClusters();
},
_clusterTest: function(p, cluster) {
var distance = (
Math.sqrt(
Math.pow((cluster.x - p.x), 2) + Math.pow((cluster.y - p.y), 2)
) / this._clusterResolution
);
return (distance <= this._clusterTolerance);
},
// 应该包括传递给clusterAddPoint的点
//在现有集群中
//还为该点提供一个名为clusterId的属性
//这与它的星系团相对应
_clusterAddPoint: function(p, cluster) {
//平均在新的点集群几何
var count, x, y;
count = cluster.attributes.clusterCount;
x = (p.x + (cluster.x * count)) / (count + 1);
y = (p.y + (cluster.y * count)) / (count + 1);
cluster.x = x;
cluster.y = y;
//构建一个包括集群中所有点的范围
//扩展只用于调试/测试…该层不使用
if (p.x < cluster.attributes.extent[0]) {
cluster.attributes.extent[0] = p.x;
} else if (p.x > cluster.attributes.extent[2]) {
cluster.attributes.extent[2] = p.x;
}
if (p.y < cluster.attributes.extent[1]) {
cluster.attributes.extent[1] = p.y;
} else if (p.y > cluster.attributes.extent[3]) {
cluster.attributes.extent[3] = p.y;
}
// 增加数
cluster.attributes.clusterCount++;
// 属性可能不存在
if (!p.hasOwnProperty("attributes")) {
p.attributes = {};
}
// 给图形一个集群id
p.attributes.clusterId = cluster.attributes.clusterId;
},
//传递给clusterCreate的点不在
//为层指定的聚类距离
//为它创建一个新的集群
_clusterCreate: function(p) {
var clusterId = this._clusters.length + 1;
// console.log("cluster create, id is: ", clusterId);
// p.attributes might be undefined
//控制台。日志(“集群创建,id是:”,clusterId);
// p。属性可能未定义
if (!p.attributes) {
p.attributes = {};
}
p.attributes.clusterId = clusterId;
// 创建集群
var cluster = {
"x": p.x,
"y": p.y,
"attributes": {
"clusterCount": 1,
"clusterId": clusterId,
"id": p.attributes,
"extent": [p.x, p.y, p.x, p.y]
}
};
this._clusters.push(cluster);
},
// 展示所有聚类
_showAllClusters: function() {
for (var i = 0, il = this._clusters.length; i < il; i++) {
var c = this._clusters[i];
this._showCluster(c);
}
},
// 展示单一聚类
_showCluster: function(c) {
// 单一集群
console.log(c);
var point = new Point(c.x, c.y, this._sr);
this.add(
new Graphic(
point,
null,
c.attributes
)
);
// 下面的代码用于不使用单点标记集群
if (c.attributes.clusterCount == 1) {
return;
}
// show number of points in the cluster
// 显示集群中的点的数量
var label = new TextSymbol(c.attributes.clusterCount.toString())
.setColor(new Color(this._clusterLabelColor))
.setOffset(0, this._clusterLabelOffset);
this.add(
new Graphic(
point,
label,
c.attributes
)
);
},
_addSingles: function(singles) {
// 向地图添加单个图形
arrayUtils.forEach(singles, function(p) {
var g = new Graphic(
new Point(p.x, p.y, this._sr),
new PictureMarkerSymbol("https://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png", 32, 32)
.setOffset(0, 15),
p.attributes,
this._singleTemplate
);
this._singles.push(g);
if (this._showSingles) {
this.add(g);
}
}, this);
// this._map.infoWindow.show
// this._map.infoWindow.setFeatures(this._singles);
},
_updateClusterGeometry: function(c) {
// 查找集群图
var cg = arrayUtils.filter(this.graphics, function(g) {
return !g.symbol &&
g.attributes.clusterId == c.attributes.clusterId;
});
if (cg.length == 1) {
cg[0].geometry.update(c.x, c.y);
} else {
console.log("didn't find exactly one cluster geometry to update: ", cg);
}
},
_updateLabel: function(c) {
// 查找现有的标签
var label = arrayUtils.filter(this.graphics, function(g) {
return g.symbol &&
g.symbol.declaredClass == "esri.symbol.TextSymbol" &&
g.attributes.clusterId == c.attributes.clusterId;
});
if (label.length == 1) {
// console.log("update label...found: ", label);
this.remove(label[0]);
var newLabel = new TextSymbol(c.attributes.clusterCount)
.setColor(new Color(this._clusterLabelColor))
.setOffset(0, this._clusterLabelOffset);
this.add(
new Graphic(
new Point(c.x, c.y, this._sr),
newLabel,
c.attributes
)
);
// console.log("updated the label");
} else {
console.log("didn't find exactly one label: ", label);
}
},
// debug only...never called by the layer 调试只有……从未被层调用
_clusterMeta: function() {
// 打印总功能数
console.log("Total: ", this._clusterData.length);
// 加起来并打印出来
var count = 0;
arrayUtils.forEach(this._clusters, function(c) {
count += c.attributes.clusterCount;
});
console.log("In clusters: ", count);
}
});
});
- 外部使用
loadClusterLayer: function(data,map) {
var photoInfo = {},
clusterLayer;
var wgs = new SpatialReference({
"wkid": 4326
});
photoInfo.data = array.map(data, function(p) {
var latlng = new Point(parseFloat(p.lon), parseFloat(p.lat), wgs);
// 转成webMercator坐标系
// var webMercator = webMercatorUtils.geographicToWebMercator(latlng);
var attributes = {
"id": p.id
};
return {
"x": latlng.x,
"y": latlng.y,
"attributes": attributes
};
});
var one = new PictureMarkerSymbol("https://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png", 32, 32)
.setOffset(0, 15);
// cluster layer that uses OpenLayers style clustering
clusterLayer = new ClusterLayer({
"data": photoInfo.data,
"distance": 1,
"id": "clusters",
"labelColor": "#000",
"labelOffset": -5,
"resolution": map.extent.getWidth() / map.width,
"singleColor": "#888",
"singleTemplate": '',
"spatialReference": wgs,
});
var defaultSym = new SimpleMarkerSymbol().setSize(4);
var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
var first = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 50,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 125, 3, 0.2]), 10),
new Color([241, 128, 23, 0.9]));
var second = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 35,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([241, 211, 87, 0.6]), 10),
new Color([240, 194, 13, 0.9]));
var third = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 25,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([181, 226, 140, 0.6]), 10),
new Color([110, 204, 57, 0.9]));
//渲染等级
renderer.addBreak(0, 1, one);
renderer.addBreak(2, 3, third);
renderer.addBreak(4, 20, second);
renderer.addBreak(21, 100, first);
clusterLayer.setRenderer(renderer);
return clusterLayer
}
添加到地图
//调取api 获取要渲染的点
this._loadData("460000", 1, 100000, function(data) {
// 采集信息
layer = this.loadClusterLayer(data,map);
layer.setVisibility(layerConfig.visible);
map.addLayer(layer);
})
- 要点
通过设置distance大小改变两个点的聚合和距离
在引入这个写好的图层类的时候将其放入与根目录同级 代码引入
"extras/ClusterLayer",
若你是gis 完整的项目 需要在init.js 设置dojoConfig
dojoConfig = {
parseOnLoad: false,
async: true,
tlmSiblingOfDojo: false,
has: {
'extend-esri': 1
},
paths: {
//我放到了我的项目的根目录下了 若放在服务器根目录下就改为/extras
extras:"../extras"
}
};
sss (2).png