ArcGIS for JavaScript开发Cluster思路解析

曾经接到一位朋友的咨询,在Web端我怎么能够加载大量的点数据,而且不至于影响效率。说实话这个问题本身就是一个矛盾,对B/S架构的程序,非常忌讳的就是大数据量的加载,这样势必会影响前段展示的效率,但是如果非要较真这个问题,我觉得可以从以下几个方面入手:

1:建议地理数据库为只读数据,如果是版本化肯定会影响效率,所以需要用户重建空间索引,分析数据,其实也可以在ArcGIS Desktop对相关数据进行测试,确定在桌面端显示速度还是比较能够接受为之,但是要记得,在Web显示肯定比桌面显示效率要低。

2:保证网络的流畅传输,那么带宽和延迟也是需要考虑的

3:如果需要前段渲染,建议尽可能的使用简单符号,毕竟越复杂的符号越影响效率

4:使用Cluster方式变相显示,也就是本博客的主题,Cluster是用点符号的形式显示一个cluster数值,点开这个cluster就会将包含的数值的真实数据进行显示,这样无疑在满足用户业务需求的情况下也可以平衡效率。


当然,大家都知道ArcGIS for Server为了防止用户的大数据量传输,针对每个服务都有1000条记录的限制,测试之前,我们可以将这个限制进行修改。



环境:ArcGIS 10.2.2 for Server、ArcGIS for JS 3.9、ArcSDE10.1

数据:只要包括稍微大量要素的点即可。

该程序代码也是以Esri提供的Sample为例,进行相关的修改。


思路解析:

Sample中Esri提供了一个已经写好的ClusterLayer类,如果熟悉JS的朋友也可以对该类进行扩展,该类的构造函数主要包括以下几个部分:

  1. //     Optional. Number of pixels to shift a cluster label vertically. Defaults to -5 to align labels with circle symbols. Does not work in IE.  
  2. //   resolution:  Number。分辨率,必选  
  3. //     Required. Width of a pixel in map coordinates. Example of how to calculate:   
  4. //     map.extent.getWidth() / map.width  
  5. //   showSingles:  Boolean?点击cluster对象是否显示具体信息,默认为true  
  6. //     Optional. Whether or graphics should be displayed when a cluster graphic is clicked. Default is true.  
  7. //   singleSymbol:  MarkerSymbol?  
  8. //     Marker Symbol (picture or simple). Optional. Symbol to use for graphics that represent single points. Default is a small gray SimpleMarkerSymbol.  
  9. //   singleTemplate:  PopupTemplate?  
  10. //     PopupTemplate</a>. Optional. Popup template used to format attributes for graphics that represent single points. Default shows all attributes as "attribute = value" (not recommended).  
  11. //   maxSingles:  Number?  
  12. //     Optional. Threshold for whether or not to show graphics for points in a cluster. Default is 1000.  
  13. //   webmap:  Boolean?  
  14. //     Optional. Whether or not the map is from an ArcGIS.com webmap. Default is false.  
  15. //   spatialReference:  SpatialReference?  
  16. //     Optional. Spatial reference for all graphics in the layer. This has to match the spatial reference of the map. Default is 102100. Omit this if the map uses basemaps in web mercator.  


相关源代码如下

  1. define([  
  2.   "dojo/_base/declare",  
  3.   "dojo/_base/array",  
  4.   "esri/Color",  
  5.   "dojo/_base/connect",  
  6.   
  7.   "esri/SpatialReference",  
  8.   "esri/geometry/Point",  
  9.   "esri/graphic",  
  10.   "esri/symbols/SimpleMarkerSymbol",  
  11.   "esri/symbols/TextSymbol",  
  12.   
  13.   "esri/dijit/PopupTemplate",  
  14.   "esri/layers/GraphicsLayer"  
  15. ], function (  
  16.   declare, arrayUtils, Color, connect,  
  17.   SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol,   
  18.   PopupTemplate, GraphicsLayer  
  19. ) {  
  20.   return declare([GraphicsLayer], {  
  21.     constructor: function(options) {  
  22.       // options:  
  23.       //   data:  Object[]  
  24.       //     Array of objects. Required. Object are required to have properties named x, y and attributes. The x and y coordinates have to be numbers that represent a points coordinates.  
  25.       //   distance:  Number?  
  26.       //     Optional. The max number of pixels between points to group points in the same cluster. Default value is 50.  
  27.       //   labelColor:  String?  
  28.       //     Optional. Hex string or array of rgba values used as the color for cluster labels. Default value is #fff (white).  
  29.       //   labelOffset:  String?  
  30.       //     Optional. Number of pixels to shift a cluster label vertically. Defaults to -5 to align labels with circle symbols. Does not work in IE.  
  31.       //   resolution:  Number  
  32.       //     Required. Width of a pixel in map coordinates. Example of how to calculate:   
  33.       //     map.extent.getWidth() / map.width  
  34.       //   showSingles:  Boolean?  
  35.       //     Optional. Whether or graphics should be displayed when a cluster graphic is clicked. Default is true.  
  36.       //   singleSymbol:  MarkerSymbol?  
  37.       //     Marker Symbol (picture or simple). Optional. Symbol to use for graphics that represent single points. Default is a small gray SimpleMarkerSymbol.  
  38.       //   singleTemplate:  PopupTemplate?  
  39.       //     PopupTemplate</a>. Optional. Popup template used to format attributes for graphics that represent single points. Default shows all attributes as "attribute = value" (not recommended).  
  40.       //   maxSingles:  Number?  
  41.       //     Optional. Threshold for whether or not to show graphics for points in a cluster. Default is 1000.  
  42.       //   webmap:  Boolean?  
  43.       //     Optional. Whether or not the map is from an ArcGIS.com webmap. Default is false.  
  44.       //   spatialReference:  SpatialReference?  
  45.       //     Optional. Spatial reference for all graphics in the layer. This has to match the spatial reference of the map. Default is 102100. Omit this if the map uses basemaps in web mercator.  
  46.         
  47.       this._clusterTolerance = options.distance || 50;  
  48.       this._clusterData = options.data || [];  
  49.       this._clusters = [];  
  50.       this._clusterLabelColor = options.labelColor || "#000";  
  51.       // labelOffset can be zero so handle it differently  
  52.       this._clusterLabelOffset = (options.hasOwnProperty("labelOffset")) ? options.labelOffset : -5;  
  53.       // graphics that represent a single point  
  54.       this._singles = []; // populated when a graphic is clicked  
  55.       this._showSingles = options.hasOwnProperty("showSingles") ? options.showSingles : true;  
  56.       // symbol for single graphics  
  57.       var sms = SimpleMarkerSymbol;  
  58.       this._singleSym = options.singleSymbol || new sms("circle", 6, nullnew Color("#888"));  
  59.       this._singleTemplate = options.singleTemplate || new PopupTemplate({ "title""""description""{*}" });  
  60.       this._maxSingles = options.maxSingles || 1000;  
  61.   
  62.       this._webmap = options.hasOwnProperty("webmap") ? options.webmap : false;  
  63.   
  64.       this._sr = options.spatialReference || new SpatialReference({ "wkid": 102100 });  
  65.   
  66.       this._zoomEnd = null;  
  67.     },  
  68.   
  69.     // override esri/layers/GraphicsLayer methods   
  70.     _setMap: function(map, surface) {  
  71.       // calculate and set the initial resolution  
  72.       this._clusterResolution = map.extent.getWidth() / map.width; // probably a bad default...  
  73.       this._clusterGraphics();  
  74.   
  75.       // connect to onZoomEnd so data is re-clustered when zoom level changes  
  76.       this._zoomEnd = connect.connect(map, "onZoomEnd"thisfunction() {  
  77.         // update resolution  
  78.         this._clusterResolution = this._map.extent.getWidth() / this._map.width;  
  79.         this.clear();  
  80.         this._clusterGraphics();  
  81.       });  
  82.   
  83.       // GraphicsLayer will add its own listener here  
  84.       var div = this.inherited(arguments);  
  85.       return div;  
  86.     },  
  87.   
  88.     _unsetMap: function() {  
  89.       this.inherited(arguments);  
  90.       connect.disconnect(this._zoomEnd);  
  91.     },  
  92.   
  93.     // public ClusterLayer methods  
  94.     add: function(p) {  
  95.       // Summary:  The argument is a data point to be added to an existing cluster. If the data point falls within an existing cluster, it is added to that cluster and the cluster's label is updated. If the new point does not fall within an existing cluster, a new cluster is created.  
  96.       //  
  97.       // if passed a graphic, use the GraphicsLayer's add method  
  98.       if ( p.declaredClass ) {  
  99.         this.inherited(arguments);  
  100.         return;  
  101.       }  
  102.   
  103.       // add the new data to _clusterData so that it's included in clusters  
  104.       // when the map level changes  
  105.       this._clusterData.push(p);  
  106.       var clustered = false;  
  107.       // look for an existing cluster for the new point  
  108.       for ( var i = 0; i < this._clusters.length; i++ ) {  
  109.         var c = this._clusters[i];  
  110.         if ( this._clusterTest(p, c) ) {  
  111.           // add the point to an existing cluster  
  112.           this._clusterAddPoint(p, c);  
  113.           // update the cluster's geometry  
  114.           this._updateClusterGeometry(c);  
  115.           // update the label  
  116.           this._updateLabel(c);  
  117.           clustered = true;  
  118.           break;  
  119.         }  
  120.       }  
  121.   
  122.       if ( ! clustered ) {  
  123.         this._clusterCreate(p);  
  124.         p.attributes.clusterCount = 1;  
  125.         this._showCluster(p);  
  126.       }  
  127.     },  
  128.   
  129.     clear: function() {  
  130.       // Summary:  Remove all clusters and data points.  
  131.       this.inherited(arguments);  
  132.       this._clusters.length = 0;  
  133.     },  
  134.   
  135.     clearSingles: function(singles) {  
  136.       // Summary:  Remove graphics that represent individual data points.  
  137.       var s = singles || this._singles;  
  138.       arrayUtils.forEach(s, function(g) {  
  139.         this.remove(g);  
  140.       }, this);  
  141.       this._singles.length = 0;  
  142.     },  
  143.   
  144.     onClick: function(e) {  
  145.       // remove any previously showing single features  
  146.       this.clearSingles(this._singles);  
  147.   
  148.       // find single graphics that make up the cluster that was clicked  
  149.       // would be nice to use filter but performance tanks with large arrays in IE  
  150.       var singles = [];  
  151.       for ( var i = 0, il = this._clusterData.length; i < il; i++) {  
  152.         if ( e.graphic.attributes.clusterId == this._clusterData[i].attributes.clusterId ) {  
  153.           singles.push(this._clusterData[i]);  
  154.         }  
  155.       }  
  156.       if ( singles.length > this._maxSingles ) {  
  157.         alert("Sorry, that cluster contains more than " + this._maxSingles + " points. Zoom in for more detail.");  
  158.         return;  
  159.       } else {  
  160.         // stop the click from bubbling to the map  
  161.         e.stopPropagation();  
  162.         this._map.infoWindow.show(e.graphic.geometry);  
  163.         this._addSingles(singles);  
  164.       }  
  165.     },  
  166.   
  167.     // internal methods   
  168.     _clusterGraphics: function() {  
  169.       // first time through, loop through the points  
  170.       for ( var j = 0, jl = this._clusterData.length; j < jl; j++ ) {  
  171.         // see if the current feature should be added to a cluster  
  172.         var point = this._clusterData[j];  
  173.         var clustered = false;  
  174.         var numClusters = this._clusters.length;  
  175.         for ( var i = 0; i < this._clusters.length; i++ ) {  
  176.           var c = this._clusters[i];  
  177.           if ( this._clusterTest(point, c) ) {  
  178.             this._clusterAddPoint(point, c);  
  179.             clustered = true;  
  180.             break;  
  181.           }  
  182.         }  
  183.   
  184.         if ( ! clustered ) {  
  185.           this._clusterCreate(point);  
  186.         }  
  187.       }  
  188.       this._showAllClusters();  
  189.     },  
  190.   
  191.     _clusterTest: function(p, cluster) {  
  192.       var distance = (  
  193.         Math.sqrt(  
  194.           Math.pow((cluster.x - p.x), 2) + Math.pow((cluster.y - p.y), 2)  
  195.         ) / this._clusterResolution  
  196.       );  
  197.       return (distance <= this._clusterTolerance);  
  198.     },  
  199.   
  200.     // points passed to clusterAddPoint should be included   
  201.     // in an existing cluster  
  202.     // also give the point an attribute called clusterId   
  203.     // that corresponds to its cluster  
  204.     _clusterAddPoint: function(p, cluster) {  
  205.       // average in the new point to the cluster geometry  
  206.       var count, x, y;  
  207.       count = cluster.attributes.clusterCount;  
  208.       x = (p.x + (cluster.x * count)) / (count + 1);  
  209.       y = (p.y + (cluster.y * count)) / (count + 1);  
  210.       cluster.x = x;  
  211.       cluster.y = y;  
  212.   
  213.       // build an extent that includes all points in a cluster  
  214.       // extents are for debug/testing only...not used by the layer  
  215.       if ( p.x < cluster.attributes.extent[0] ) {  
  216.         cluster.attributes.extent[0] = p.x;  
  217.       } else if ( p.x > cluster.attributes.extent[2] ) {  
  218.         cluster.attributes.extent[2] = p.x;  
  219.       }  
  220.       if ( p.y < cluster.attributes.extent[1] ) {  
  221.         cluster.attributes.extent[1] = p.y;  
  222.       } else if ( p.y > cluster.attributes.extent[3] ) {  
  223.         cluster.attributes.extent[3] = p.y;  
  224.       }  
  225.   
  226.       // increment the count  
  227.       cluster.attributes.clusterCount++;  
  228.       // attributes might not exist  
  229.       if ( ! p.hasOwnProperty("attributes") ) {  
  230.         p.attributes = {};  
  231.       }  
  232.       // give the graphic a cluster id  
  233.       p.attributes.clusterId = cluster.attributes.clusterId;  
  234.     },  
  235.   
  236.     // point passed to clusterCreate isn't within the   
  237.     // clustering distance specified for the layer so  
  238.     // create a new cluster for it  
  239.     _clusterCreate: function(p) {  
  240.       var clusterId = this._clusters.length + 1;  
  241.       // console.log("cluster create, id is: ", clusterId);  
  242.       // p.attributes might be undefined  
  243.       if ( ! p.attributes ) {  
  244.         p.attributes = {};  
  245.       }  
  246.       p.attributes.clusterId = clusterId;  
  247.       // create the cluster  
  248.       var cluster = {   
  249.         "x": p.x,  
  250.         "y": p.y,  
  251.         "attributes" : {  
  252.           "clusterCount": 1,  
  253.           "clusterId": clusterId,  
  254.           "extent": [ p.x, p.y, p.x, p.y ]  
  255.         }  
  256.       };  
  257.       this._clusters.push(cluster);  
  258.     },  
  259.   
  260.     _showAllClusters: function() {  
  261.       for ( var i = 0, il = this._clusters.length; i < il; i++ ) {  
  262.         var c = this._clusters[i];  
  263.         this._showCluster(c);  
  264.       }  
  265.     },  
  266.   
  267.     _showCluster: function(c) {  
  268.       var point = new Point(c.x, c.y, this._sr);  
  269.       this.add(  
  270.         new Graphic(  
  271.           point,   
  272.           null,   
  273.           c.attributes  
  274.         )  
  275.       );  
  276.       // code below is used to not label clusters with a single point  
  277.       if ( c.attributes.clusterCount == 1 ) {  
  278.         return;  
  279.       }  
  280.   
  281.       // show number of points in the cluster  
  282.       var label = new TextSymbol(c.attributes.clusterCount)  
  283.         .setColor(new Color(this._clusterLabelColor))  
  284.         .setOffset(0, this._clusterLabelOffset);  
  285.       this.add(  
  286.         new Graphic(  
  287.           point,  
  288.           label,  
  289.           c.attributes  
  290.         )  
  291.       );  
  292.     },  
  293.   
  294.     _addSingles: function(singles) {  
  295.       // add single graphics to the map  
  296.       arrayUtils.forEach(singles, function(p) {  
  297.         var g = new Graphic(  
  298.           new Point(p.x, p.y, this._sr),  
  299.           this._singleSym,  
  300.           p.attributes,  
  301.           this._singleTemplate  
  302.         );  
  303.         this._singles.push(g);  
  304.         if ( this._showSingles ) {  
  305.           this.add(g);  
  306.         }  
  307.       }, this);  
  308.       this._map.infoWindow.setFeatures(this._singles);  
  309.     },  
  310.   
  311.     _updateClusterGeometry: function(c) {  
  312.       // find the cluster graphic  
  313.       var cg = arrayUtils.filter(this.graphics, function(g) {  
  314.         return ! g.symbol &&  
  315.                g.attributes.clusterId == c.attributes.clusterId;  
  316.       });  
  317.       if ( cg.length == 1 ) {  
  318.         cg[0].geometry.update(c.x, c.y);  
  319.       } else {  
  320.         console.log("didn't find exactly one cluster geometry to update: ", cg);  
  321.       }  
  322.     },  
  323.   
  324.     _updateLabel: function(c) {  
  325.       // find the existing label  
  326.       var label = arrayUtils.filter(this.graphics, function(g) {  
  327.         return g.symbol &&   
  328.                g.symbol.declaredClass == "esri.symbol.TextSymbol" &&  
  329.                g.attributes.clusterId == c.attributes.clusterId;  
  330.       });  
  331.       if ( label.length == 1 ) {  
  332.         // console.log("update label...found: ", label);  
  333.         this.remove(label[0]);  
  334.         var newLabel = new TextSymbol(c.attributes.clusterCount)  
  335.           .setColor(new Color(this._clusterLabelColor))  
  336.           .setOffset(0, this._clusterLabelOffset);  
  337.         this.add(  
  338.           new Graphic(  
  339.             new Point(c.x, c.y, this._sr),  
  340.             newLabel,  
  341.             c.attributes  
  342.           )  
  343.         );  
  344.         // console.log("updated the label");  
  345.       } else {  
  346.         console.log("didn't find exactly one label: ", label);  
  347.       }  
  348.     },  
  349.   
  350.     // debug only...never called by the layer  
  351.     _clusterMeta: function() {  
  352.       // print total number of features  
  353.       console.log("Total:  "this._clusterData.length);  
  354.   
  355.       // add up counts and print it  
  356.       var count = 0;  
  357.       arrayUtils.forEach(this._clusters, function(c) {  
  358.         count += c.attributes.clusterCount;  
  359.       });  
  360.       console.log("In clusters:  ", count);  
  361.     }  
  362.   
  363.   });  
  364. });  

------------------------------------------------------------------

版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!

建议看到转载,请直接访问正版链接获得最新的ArcGIS技术文章

Blog:               http://blog.csdn.net/linghe301 

------------------------------------------------------------------


既然最主要的参数是一个带有XY坐标和属性的数组,那么我们从发布的MapService中进行Query,获得相关的记录进行循环处理,生成符合ClusterLayer要求的数组对象即可。

在生成ClusterLayer对象后,使用分级进行渲染,比如不同的颜色代表不同的数据量。


相关源代码如下

  1. <!doctype html>  
  2. <html>  
  3. <head>  
  4.     <meta charset="utf-8">  
  5.     <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">  
  6.     <title>Cluster</title>  
  7.     <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css">  
  8.     <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">  
  9.     <style>  
  10.         html, body {  
  11.             height: 100%;  
  12.             width: 100%;  
  13.             margin: 0;  
  14.             padding: 0;  
  15.         }  
  16.  
  17.         #map {  
  18.             margin: 0;  
  19.             padding: 0;  
  20.         }  
  21.   
  22.         /* center the image in the popup */  
  23.         .esriViewPopup .gallery {  
  24.             margin: 0 auto !important;  
  25.         }  
  26.     </style>  
  27.   
  28.     <script>  
  29.         // helpful for understanding dojoConfig.packages vs. dojoConfig.paths:  
  30.   
  31.         var dojoConfig = {  
  32.             paths: {  
  33.                 extras: location.pathname.replace(/\/[^/]+$/, "") + "/extras"  
  34.             }  
  35.         };  
  36.     </script>  
  37.     <script src="http://js.arcgis.com/3.10/"></script>  
  38.     <script>  
  39.         var map;  
  40.         require([  
  41.           "dojo/parser",  
  42.           "dojo/ready",  
  43.           "dojo/_base/array",  
  44.           "esri/Color",  
  45.           "dojo/dom-style",  
  46.           "dojo/query",  
  47.           "esri/map",  
  48.           "esri/request",  
  49.           "esri/graphic",  
  50.           "esri/geometry/Extent",  
  51.           "esri/tasks/query",  
  52.           "esri/tasks/QueryTask",  
  53.           "esri/symbols/SimpleMarkerSymbol",  
  54.           "esri/symbols/SimpleFillSymbol",  
  55.           "esri/symbols/PictureMarkerSymbol",  
  56.           "esri/renderers/ClassBreaksRenderer",  
  57.           "esri/layers/GraphicsLayer",  
  58.           "esri/dijit/PopupTemplate",  
  59.           "esri/geometry/Point",  
  60.           "esri/config",  
  61.           "extras/ClusterLayer",  
  62.           "dijit/layout/BorderContainer",  
  63.           "dijit/layout/ContentPane",  
  64.           "dojo/domReady!"  
  65.         ], function (  
  66.           parser, ready, arrayUtils, Color, domStyle, query,  
  67.           Map, esriRequest, Graphic, Extent,Query, QueryTask,  
  68.           SimpleMarkerSymbol, SimpleFillSymbol, PictureMarkerSymbol, ClassBreaksRenderer,  
  69.           GraphicsLayer, PopupTemplate, Point,esriConfig,  
  70.           ClusterLayer  
  71.         ) {  
  72.             ready(function () {  
  73.                 esriConfig.defaults.io.proxyUrl = "/proxy";  
  74.                 parser.parse();  
  75.   
  76.                 var clusterLayer;  
  77.                
  78.                 map = new Map("map", {  
  79.                     basemap: "streets",  
  80.                     center: [116.408386, 39.91395],  
  81.                     zoom: 12,  
  82.                 });  
  83.   
  84.                 map.on("load"function () {  
  85.             //使用Query 进行查询要素  
  86.                     var queryTask = new QueryTask("http://localhost:6080/arcgis/rest/services/JS/MapServer/1");  
  87.                     var query = new Query();  
  88.                     query.returnGeometry = true;  
  89.                     query.outFields = ["*"];  
  90.                     query.outSpatialReference = { wkid: 102100 };  
  91.                     query.where = "ObjectID<10000";  
  92.                     queryTask.execute(query, addClusters);  
  93.                 });  
  94.   
  95.                 function addClusters(resp) {  
  96.                     var photoInfo = {};  
  97.                     //将查询的要素安装ClusterLayer要求的数组对象进行重新组合  
  98.                         photoInfo.data = arrayUtils.map(resp.features, function (p) {  
  99.                             var attributes = {  
  100.                                 "address": p.attributes["ADDRESS"],  
  101.                                 "districtna": p.attributes["DISTRICTNA"],  
  102.                                 "name": p.attributes["NAME"],  
  103.                                 "type": p.attributes["TYPE"]  
  104.                             };  
  105.                             return {  
  106.                                 "x": p.geometry.x,  
  107.                                 "y": p.geometry.y,  
  108.                                 "attributes": attributes  
  109.                             };  
  110.                         });  
  111.                    // cluster layer that uses OpenLayers style clustering  
  112.                     clusterLayer = new ClusterLayer({  
  113.                         "data": photoInfo.data,  
  114.                         "distance": 100,  
  115.                         "id""clusters",  
  116.                         "labelColor""#fff",  
  117.                         "labelOffset": 10,  
  118.                         "resolution": map.extent.getWidth() / map.width,  
  119.                         "singleColor""#888"  
  120.                           
  121.                     });  
  122.                     var defaultSym = new SimpleMarkerSymbol().setSize(4);  
  123.                     var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");  
  124.   
  125.                     var picBaseUrl = "http://static.arcgis.com/images/Symbols/Shapes/";  
  126.                     var blue = new PictureMarkerSymbol(picBaseUrl + "BluePin1LargeB.png", 32, 32).setOffset(0, 15);  
  127.                     var green = new PictureMarkerSymbol(picBaseUrl + "GreenPin1LargeB.png", 64, 64).setOffset(0, 15);  
  128.                     var red = new PictureMarkerSymbol(picBaseUrl + "RedPin1LargeB.png", 72, 72).setOffset(0, 15);  
  129.                     renderer.addBreak(0, 2, blue);  
  130.                     renderer.addBreak(2, 50, green);  
  131.                     renderer.addBreak(51, 1001, red);  
  132.   
  133.                     clusterLayer.setRenderer(renderer);  
  134.                     map.addLayer(clusterLayer);  
  135.   
  136.                     // close the info window when the map is clicked  
  137.                     map.on("click", cleanUp);  
  138.                     // close the info window when esc is pressed  
  139.                     map.on("key-down"function (e) {  
  140.                         if (e.keyCode === 27) {  
  141.                             cleanUp();  
  142.                         }  
  143.                     });  
  144.                 }  
  145.   
  146.                 function cleanUp() {  
  147.                     map.infoWindow.hide();  
  148.                     clusterLayer.clearSingles();  
  149.                 }  
  150.   
  151.                 function error(err) {  
  152.                     console.log("something failed: ", err);  
  153.                 }       
  154.             });  
  155.         });  
  156.   
  157.      
  158.   
  159.   
  160.     </script>  
  161. </head>  
  162.   
  163. <body>  
  164.     <div data-dojo-type="dijit/layout/BorderContainer"  
  165.          data-dojo-props="design:'headline',gutters:false"  
  166.          style="width: 100%; height: 100%; margin: 0;">  
  167.         <div id="map"  
  168.              data-dojo-type="dijit/layout/ContentPane"  
  169.              data-dojo-props="region:'center'">  
  170.         </div>  
  171.     </div>  
  172. </body>  
  173. </html>  


该代码有几个点需要注意:

1:引用外部JS文件(dojo)

有两种方法都可以引入外部JS

关于两种方法的比较请参考:http://www.sitepen.com/blog/2013/06/20/dojo-faq-what-is-the-difference-packages-vs-paths-vs-aliases/

A:dojoConfig.pahts

  1. var dojoConfig = {  
  2.            paths: {  
  3.                extras: location.pathname.replace(/\/[^/]+$/, "") + "/extras"  
  4.            }  
  5.        };  
使用location.pathname.replace(/\/[^/]+$/, "")这种正则表达式代表该程序的路径,然后我的js文件放在/extras文件夹中,该js文件以extras标识。那么在引用该js的clusterlayer时,就需要使用 "extras/ClusterLayer",


B:dojoConfig.Packages

  1. var lo = location.pathname.replace(/\/[^/]+$/, '');  
  2.        var dojoConfig = {  
  3.            //baseU  
  4.            parseOnLoad: true,  
  5.            packages: [  
  6.             {  
  7.                 "name""extras",  
  8.                 "location": lo + "/extras"  
  9.             }  
  10.            ]  
  11.        };  
这个其实跟paths比较类似。


2:如果你是经纬度坐标,需要进行转换为平面坐标

  1. var photoInfo = {};  
  2.             var wgs = new SpatialReference({  
  3.               "wkid": 4326  
  4.             });  
  5.             photoInfo.data = arrayUtils.map(resp, function(p) {  
  6.               var latlng = new  Point(parseFloat(p.lng), parseFloat(p.lat), wgs);  
  7.               var webMercator = webMercatorUtils.geographicToWebMercator(latlng);  
  8.               var attributes = {  
  9.                 "Caption": p.caption,  
  10.                 "Name": p.full_name,  
  11.                 "Image": p.image,  
  12.                 "Link": p.link  
  13.               };  
  14.               return {  
  15.                 "x": webMercator.x,  
  16.                 "y": webMercator.y,  
  17.                 "attributes": attributes  
  18.               };  
  19.             });  

最终的显示效果图



------------------------------------------------------------------

版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!

建议看到转载,请直接访问正版链接获得最新的ArcGIS技术文章

Blog:               http://blog.csdn.net/linghe301 

                欢迎添加微信公众号:ArcGIS技术分享(arcgis_share),直接回复1就可以在移动端获取最新技术文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值