【ArcGis for javascript从零开始】之三 散点聚合

来源:互联网 发布:中国域名价格排行 编辑:程序博客网 时间:2024/06/04 19:32

  这两天在往地图上标点,好累,眼都花了有木有。我们领导说百度地图上的点不准,得以天地图为标准。呵呵,(此处省略1W字……)天地图官方的demo要么只有搜索控件,要么只有获取经纬度坐标的控件,就没有两者结合起来的控件,我做了一个很简单的两者结合的demo,省了不少事的说~点我下载。没费什么力气,就不用积分了。

  题外话就这么多,今天开始回忆一下当初痛苦地搞散点聚合的过程。ArcGIS官方demo的地址在这里点我打开链接

做出来的效果是要这样式的:



        我们今天的目标就是把这个页面样式给挪到天地图上,就可以了。

加载ArcGIS的散点

        直接把ArcGIS的源码复制到我们的工程路径中,本次我建了一个项目,而不是单个的html了。本宝宝是java工程师,所以本次demo是一个java web 项目~
        直接复制过来,我们运行一下,呵呵,好大一片白屏。打开Console,会报一个找不到文件的异常呃
 GET http://127.0.0.1:8080/ClusterGIS//extras/ClusterLayer.js 404 (Not Found)
     这个找不到,extras是扩展类,请看这一段代码,

var dojoConfig = { 
        paths: {
          extras: location.pathname.replace(/\/[^/]+$/, "") + "/extras"
        }
      };

        这一段代码的大体含义就是把/extras前面的域名替换成本地,不在远程服务器上下载js。
        把再运行一下demo把ClusterLayer从服务器上扒下来。在项目路径下,建一个extras文件夹,再建一个名为ClusterLayer.js的文件。
这个问题解决了,地图是显示出来了,但是没有散点。
又报一个异常,“http://127.0.0.1:8080/ClusterGIS/data/1000-photos.json 404 (Not Found)”,这个是因为它的json是从后台中取出来的,我们也从后台把数据传到前台来。这个josn我也是从它官网那里扒出来的,这个大量无意义的代码,我就不贴了,与我们的最终目标也没有什么关系。懒得扒的同学可以不理这一步,直接进行下一步。做为完美主义的宝宝,本宝宝当然要做完~

只有这么一个可怜的,孤零零的点,只写了一个啦,能显示出来就好。第一步就这样实现了,简直是太曲折了。

加载天地图

 略,见上次的日志吧,详细就不说了……地址在此
  坑死宝宝了。之前直接从ArcGIS复制过来的代码,所以用的是3.15版本,一直显示不出来,报的WebTiledLayer的URL有关的异常。排查了好久,才发现有ArcGIS的版本问题,哎,果然不能随便换版本啊,问题多多。我改成了3.14版好了。
    不出意外,果然地图显示出来了散点又消失了。简直呵呵了~

找回散点

找回散点这一个过程也是哎,不多说了。这个其实就是ClusterLayer这个js没有考虑到我们的天地图用的是不同的坐标体系而已。需要把我们的ClusterLayer.js进行修改,我直接把我从网上找的修改后的js贴上来好了。我还没有看懂这个js的代码。(这个确实是小白,js高级一点的代码对我就抓虾去了,哎……)
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/geometry/webMercatorUtils",        "esri/dijit/PopupTemplate",      "esri/layers/GraphicsLayer"      ], function (          declare, arrayUtils, Color, connect,          SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol, webMercatorUtils,          PopupTemplate, GraphicsLayer          ) {          return declare([GraphicsLayer], {            id:"clusterLayer",            constructor: function(options) {                  // options:                  //   data:  Object[]                  //     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.                  //   distance:  Number?                  //     Optional. The max number of pixels between points to group points in the same cluster. Default value is 50.                  //   labelColor:  String?                  //     Optional. Hex string or array of rgba values used as the color for cluster labels. Default value is #fff (white).                  //   labelOffset:  String?                  //     Optional. Number of pixels to shift a cluster label vertically. Defaults to -5 to align labels with circle symbols. Does not work in IE.                  //   resolution:  Number                  //     Required. Width of a pixel in map coordinates. Example of how to calculate:                   //     map.extent.getWidth() / map.width                  //   showSingles:  Boolean?                  //     Optional. Whether or graphics should be displayed when a cluster graphic is clicked. Default is true.                  //   singleSymbol:  MarkerSymbol?                  //     Marker Symbol (picture or simple). Optional. Symbol to use for graphics that represent single points. Default is a small gray SimpleMarkerSymbol.                  //   singleTemplate:  PopupTemplate?                  //     PopupTemplate</a>. Optional. Popup template used to format attributes for graphics that represent single points. Default shows all attributes as "attribute = value" (not recommended).                  //   maxSingles:  Number?                  //     Optional. Threshold for whether or not to show graphics for points in a cluster. Default is 1000.                  //   webmap:  Boolean?                  //     Optional. Whether or not the map is from an ArcGIS.com webmap. Default is false.                  //   spatialReference:  SpatialReference?                  //     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.                          this._clusterTolerance = options.distance || 50;                  this._clusterData = options.data || [];                  this._clusters = [];                  this._clusterLabelColor = options.labelColor || "#000";                  // labelOffset can be zero so handle it differently                  this._clusterLabelOffset = (options.hasOwnProperty("labelOffset")) ? options.labelOffset : -5;                  // graphics that represent a single point                  this._singles = []; // populated when a graphic is clicked                  this._showSingles = options.hasOwnProperty("showSingles") ? options.showSingles : true;                  // symbol for single graphics                  var sms = SimpleMarkerSymbol;                  this._singleSym = options.singleSymbol || new sms("circle", 6, null, new Color("#888"));                  this._singleTemplate = options.singleTemplate || new PopupTemplate({                    "title": "",                     "description": "{*}"                });                  this._maxSingles = options.maxSingles || 1000;                    this._webmap = options.hasOwnProperty("webmap") ? options.webmap : false;                    this._sr = options.spatialReference || new SpatialReference({                    "wkid": 102100                });                    this._zoomEnd = null;              },                // override esri/layers/GraphicsLayer methods               _setMap: function(map, surface) {                  // calculate and set the initial resolution                  //      this._clusterResolution = map.extent.getWidth() / map.width; // probably a bad default...                  this._clusterGraphics();                    // connect to onZoomEnd so data is re-clustered when zoom level changes                  this._zoomEnd = connect.connect(map, "onZoomEnd", this, function() {                      // update resolution                      //        this._clusterResolution = this._map.extent.getWidth() / this._map.width;                     if (map.spatialReference.isWebMercator()) {                        this._clusterResolution = map.extent.getWidth() / map.width; // probably a bad default...                    }                    else {                        //WGS 84坐标,转换为web Mercator                        var latlng1 = new Point(map.extent.xmax, map.extent.ymax, map.spatialReference); //右上角                        var latlng2 = new Point(map.extent.xmin, map.extent.ymin, map.spatialReference); //左下角                        var webMercator1 = webMercatorUtils.geographicToWebMercator(latlng1);                        var webMercator2 = webMercatorUtils.geographicToWebMercator(latlng2);                        this._clusterResolution = (webMercator1.x - webMercator2.x) / map.width;                    }                    this.clear();                      this._clusterGraphics();                  });                    // GraphicsLayer will add its own listener here                  var div = this.inherited(arguments);                  return div;              },                _unsetMap: function() {                  this.inherited(arguments);                  connect.disconnect(this._zoomEnd);              },                // public ClusterLayer methods              add: function(p) {                  // 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.                  //                  // if passed a graphic, use the GraphicsLayer's add method                                  if ( p.declaredClass ) {                      this.inherited(arguments);                      return;                  }                  // add the new data to _clusterData so that it's included in clusters                  // when the map level changes                  this._clusterData.push(p);                  var clustered = false;                  // look for an existing cluster for the new point                  for ( var i = 0; i < this._clusters.length; i++ ) {                      var c = this._clusters[i];                      if ( this._clusterTest(p, c) ) {                          // add the point to an existing cluster                          this._clusterAddPoint(p, c);                          // update the cluster's geometry                          this._updateClusterGeometry(c);                          // update the label                          this._updateLabel(c);                          clustered = true;                          break;                      }                  }                    if ( ! clustered ) {                      this._clusterCreate(p);                      p.attributes.clusterCount = 1;                      this._showCluster(p);                  }              },                clear: function() {                  // Summary:  Remove all clusters and data points.                  this.inherited(arguments);                  this._clusters.length = 0;              },                clearSingles: function(singles) {                  // Summary:  Remove graphics that represent individual data points.                  var s = singles || this._singles;                  arrayUtils.forEach(s, function(g) {                      this.remove(g);                  }, this);                  this._singles.length = 0;              },                onClick: function(e) {                  // remove any previously showing single features                  this.clearSingles(this._singles);                    // find single graphics that make up the cluster that was clicked                  // 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 {                      // stop the click from bubbling to the map                      e.stopPropagation();                      this._map.infoWindow.show(e.graphic.geometry);                      this._addSingles(singles);                  }              },                // internal methods               _clusterGraphics: function() {                  // first time through, loop through the points                  for ( var j = 0, jl = this._clusterData.length; j < jl; j++ ) {                      // see if the current feature should be added to a cluster                      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);              },                // points passed to clusterAddPoint should be included               // in an existing cluster              // also give the point an attribute called clusterId               // that corresponds to its cluster              _clusterAddPoint: function(p, cluster) {                  // average in the new point to the cluster geometry                  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;                    // build an extent that includes all points in a cluster                  // extents are for debug/testing only...not used by the layer                  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;                  }                    // increment the count                  cluster.attributes.clusterCount++;                  // attributes might not exist                  if ( ! p.hasOwnProperty("attributes") ) {                      p.attributes = {};                  }                  // give the graphic a cluster id                  p.attributes.clusterId = cluster.attributes.clusterId;              },                // point passed to clusterCreate isn't within the               // clustering distance specified for the layer so              // create a new cluster for it              _clusterCreate: function(p) {                  var clusterId = this._clusters.length + 1;                  // console.log("cluster create, id is: ", clusterId);                  // p.attributes might be undefined                  if ( ! p.attributes ) {                      p.attributes = {};                  }                  p.attributes.clusterId = clusterId;                  // create the cluster                  var cluster = {                       "x": p.x,                      "y": p.y,                      "attributes" : {                          "clusterCount": 1,                          "clusterId": clusterId,                          "extent": [ p.x, p.y, p.x, p.y ]                      }                  };                  this._clusters.push(cluster);              },                _showAllClusters: function () {                var tp;                if (map.spatialReference.isWebMercator()) {                    //map为WebMercator坐标系                    tp="webm";                }                else {                    //map为非WebMercator坐标系                    tp="nowebm";                }                for (var i = 0, il = this._clusters.length; i < il; i++) {                    var c = this._clusters[i];                    this._showCluster(c,tp);                }            },              _showCluster: function (c, tp) {                var point                if (tp == "webm") {                    point = new Point(c.x, c.y, this._sr);                }                else {                    var latlng = new Point(parseFloat(c.x), parseFloat(c.y), this._sr);                    point = webMercatorUtils.webMercatorToGeographic(latlng);                }                            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)                  .setColor(new Color(this._clusterLabelColor))                  .setOffset(0, this._clusterLabelOffset);                  this.add(                      new Graphic(                          point,                          label,                          c.attributes                          )                      );              },              _getPoint:function(p,_this){                if (map.spatialReference.isWebMercator()) {                    //map为WebMercator坐标系                    return  new Point(p.x, p.y, _this._sr);                }                else {                    //map为非WebMercator坐标系                    var latlng = new Point(parseFloat(p.x), parseFloat(p.y), _this._sr);                    return webMercatorUtils.webMercatorToGeographic(latlng);                }            },            _addSingles: function(singles) {                  // add single graphics to the map                  arrayUtils.forEach(singles, function(p) {                      var g = new Graphic(                          //new Point(p.x, p.y, this._sr),                          this._getPoint(p,this),                        this._singleSym,                          p.attributes,                          this._singleTemplate                          );                      this._singles.push(g);                      if ( this._showSingles ) {                          this.add(g);                      }                  }, this);                  this._map.infoWindow.setFeatures(this._singles);              },                _updateClusterGeometry: function(c) {                  // find the cluster graphic                  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) {                  // find the existing label                  console.log(11111);                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),                              this._getPoint(c,this),                            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() {                  // print total number of features                  console.log("Total:  ", this._clusterData.length);                    // add up counts and print it                  var count = 0;                  arrayUtils.forEach(this._clusters, function(c) {                      count += c.attributes.clusterCount;                  });                  console.log("In clusters:  ", count);              }            });      });  
另外js也需要换算坐标体系的
var latlng1 = new Point(map.extent.xmax, map.extent.ymax, map.spatialReference); //右上角                var latlng2 = new Point(map.extent.xmin, map.extent.ymin, map.spatialReference); //左下角                var webMercator1 = webMercatorUtils.geographicToWebMercator(latlng1);                var webMercator2 = webMercatorUtils.geographicToWebMercator(latlng2);                var clusterResolution = (webMercator1.x - webMercator2.x) / map.width;            // cluster layer that uses OpenLayers style clustering            clusterLayer = new ClusterLayer({                "data": photoInfo.data,                "distance": 100,                "id": "clusters",                "labelColor": "#fff",                "labelOffset": 10,                "singleColor": "#888",                "singleTemplate": popupTemplate,                "resolution":clusterResolution,                "spatialReference":new SpatialReference({ "wkid": 4326 })            });
后台的点是我的有随机数生成的,在首都附近。
显示出来的效果是这样的

最后,demo在此 http://download.csdn.net/detail/pixie15/9374093,由于刚来CSDN,本宝宝还没有什么积分,希望各位老大们捧个场,谢谢啦~

    由于本宝宝关于地图方面的工作暂时告一段落,暂时关于ArcGIS与天地图那点东西暂停更新了……后面如果客户有新的需求,本宝宝还会再加来的。

    当然,博客本宝宝会持续汇报记录学习与工作所得。谢谢您看到这里,Bye~



2 0