From 73b738f558b982827c15fe4486a56212e1453300 Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Wed, 17 Feb 2016 16:49:34 -0500 Subject: [PATCH 1/6] add event when singles are clicked to get original graphic attribute --- src/clusterfeaturelayer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index 6f1b3a4..b73bbe3 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -659,6 +659,7 @@ define([ this._map.infoWindow.show(e.graphic.geometry); this._map.infoWindow.show(e.graphic.geometry); } + this.emit('singles-click',{singles: singles}); } // Multi-cluster click, super zoom to cluster else if (this._zoomOnClick && e.graphic.attributes.clusterCount > 1 && this._map.getZoom() !== this._map.getMaxZoom()) @@ -693,6 +694,7 @@ define([ this._map.infoWindow.show(e.graphic.geometry); this._map.infoWindow.show(e.graphic.geometry); } + this.emit('singles-click',{singles: singles}); } } }, From 6d76886af2790490b640c885ab987703948fef4f Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Thu, 17 Mar 2016 16:56:03 -0400 Subject: [PATCH 2/6] add event when ids are returned --- src/clusterfeaturelayer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index 4d53946..c75733d 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -466,6 +466,7 @@ define([ }, _onIdsReturned: function (results) { + this.emit('ids-returned',{results: results}); var uncached = difference(results, this._objectIdCache.length, this._objectIdHash); this._objectIdCache = concat(this._objectIdCache, uncached); if (uncached && uncached.length) { From 256a2a88ff50b2ce187c053d050a9f2230948d1c Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Fri, 27 May 2016 13:09:53 -0400 Subject: [PATCH 3/6] add option to query all feature attachments and store as "feature.attachmentInfos" using new queryAttachments API --- src/clusterfeaturelayer.js | 60 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index c75733d..2fb1454 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -5,6 +5,7 @@ define([ 'dojo/_base/Color', 'dojo/_base/connect', 'dojo/on', + 'dojo/Deferred', 'dojo/promise/all', 'esri/SpatialReference', @@ -35,7 +36,7 @@ define([ 'esri/tasks/QueryTask' ], function ( - declare, arrayUtils, lang, Color, connect, on, all, + declare, arrayUtils, lang, Color, connect, on, Deferred, all, SpatialReference, Point, Polygon, Multipoint, Extent, Graphic, esriConfig, normalizeUtils, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, TextSymbol, Font, @@ -143,6 +144,8 @@ define([ // Optional. Defines the OBJECTID field of service. Default is 'OBJECTID'. // where: String? // Optional. Where clause for query. + // queryAttachments: Boolean? + // Optional. If true, features within the current extent will have their attachments queried and an "attachmentInfos" object will be added to the feature object. // useDefaultSymbol: Boolean? // Optional. Use the services default symbology for single features. // returnLimit: Number? @@ -203,6 +206,7 @@ define([ this._outFields = options.outFields || ['*']; this.queryTask = new QueryTask(this.url); this._where = options.where || null; + this._queryAttachments = options.queryAttachments || false; this._useDefaultSymbol = options.hasOwnProperty('useDefaultSymbol') ? options.useDefaultSymbol : false; this._returnLimit = options.returnLimit || 1000; this._singleRenderer = options.singleRenderer; @@ -477,7 +481,7 @@ define([ while(uncached.length) { // Improve performance by just passing list of IDs this._query.objectIds = uncached.splice(0, this._returnLimit - 1); - queries.push(this.queryTask.execute(this._query)); + queries.push(this._queryFeatures()); } all(queries).then(lang.hitch(this, function(res) { var features = arrayUtils.map(res, function(r) { @@ -490,7 +494,7 @@ define([ } else { // Improve performance by just passing list of IDs this._query.objectIds = uncached.splice(0, this._returnLimit - 1); - this.queryTask.execute(this._query).then( + this._queryFeatures().then( lang.hitch(this, '_onFeaturesReturned'), this._onError ); } @@ -504,6 +508,56 @@ define([ } }, + _queryFeatures: function() { + var deferred = new Deferred(); + var queries = { + features: this.queryTask.execute(this._query), + }; + + if (this._queryAttachments) { + var attachmentQueryUrl = this.url + (this.url.substr(-1) === '/' ? '' : '/') + 'queryAttachments'; + var attachmentQuery = esriRequest({ + url: attachmentQueryUrl, + content: { + objectIds: this._query.objectIds, + f: 'json' + }, + handleAs: 'json' + },{ + usePost: true + }); + + queries.attachments = attachmentQuery; + } + + all(queries).then(lang.hitch(this,function(result) { + var objectIdField = lang.getObject('features.objectIdFieldName',false,result); + var features = lang.getObject('features.features',false,result); + var attachments = lang.getObject('attachments.attachmentGroups',false,result); + + if (this._queryAttachments && objectIdField && features && attachments) { + // extend features with corresponding attachments + arrayUtils.forEach(features,function(ftr) { + var ftrId = ftr.attributes[objectIdField]; + var ftrAttachments = arrayUtils.filter(attachments, function(attachment) { + return attachment.parentObjectId === ftrId; + })[0]; + + lang.mixin(ftr,{ + attachmentInfos: lang.getObject('attachmentInfos',false,ftrAttachments) + }); + }); + deferred.resolve(result.features); + } else if (!this._queryAttachments && features) { + deferred.resolve(result.features); + } else { + deferred.reject(result.features); + } + }),deferred.reject); + + return deferred; + }, + // Return a cache of features in the current extent _inExtent: function() { // debug From 2abfa5e59aeb963c4e8596a762b4ce439d93e869 Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Mon, 6 Jun 2016 13:16:58 -0400 Subject: [PATCH 4/6] fix cluster not always breaking up when clicked --- src/clusterfeaturelayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index 2fb1454..a269369 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -722,7 +722,7 @@ define([ // Zoom to level that shows all points in cluster, not necessarily the extent var extent = this._getClusterExtent(e.graphic); if (extent.getWidth()) { - this._map.setExtent(extent.expand(1.5), true); + this._map.setExtent(extent.expand(1.15), true); } else { this._map.centerAndZoom(e.graphic.geometry, this._map.getMaxZoom()); } From ffadc03967ff6ef9474b5a00fb0ef902650c794a Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Wed, 8 Jun 2016 11:04:00 -0400 Subject: [PATCH 5/6] filter out points without proper geometry --- src/clusterfeaturelayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index a269369..a7cb739 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -571,7 +571,7 @@ define([ while (len--) { var oid = this._objectIdCache[len]; var cached = this._clusterCache[oid]; - if (cached && ext.contains(cached.geometry)) { + if (cached && cached.geometry && cached.geometry.spatialReference && ext.contains(cached.geometry)) { valid.push(cached); } } From f54ba1604a73ccb1f81cfeca9b399ba701b8624d Mon Sep 17 00:00:00 2001 From: Stephen Sylvia Date: Mon, 21 Nov 2016 11:01:59 -0500 Subject: [PATCH 6/6] Add options to filter features before adding to map. --- src/clusterfeaturelayer.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/clusterfeaturelayer.js b/src/clusterfeaturelayer.js index a7cb739..294a22a 100755 --- a/src/clusterfeaturelayer.js +++ b/src/clusterfeaturelayer.js @@ -146,6 +146,8 @@ define([ // Optional. Where clause for query. // queryAttachments: Boolean? // Optional. If true, features within the current extent will have their attachments queried and an "attachmentInfos" object will be added to the feature object. + // filterFeaturesOnResponse: false or function(features) {return features} + // Optional. If a function, this function will be called with the current feature array before if is added to the map and exects an array of features to be returned. // useDefaultSymbol: Boolean? // Optional. Use the services default symbology for single features. // returnLimit: Number? @@ -207,6 +209,7 @@ define([ this.queryTask = new QueryTask(this.url); this._where = options.where || null; this._queryAttachments = options.queryAttachments || false; + this._filterFeaturesOnResponse = options.filterFeaturesOnResponse || false; this._useDefaultSymbol = options.hasOwnProperty('useDefaultSymbol') ? options.useDefaultSymbol : false; this._returnLimit = options.returnLimit || 1000; this._singleRenderer = options.singleRenderer; @@ -478,7 +481,7 @@ define([ this._query.geometry = null; var queries = []; if (uncached.length > this._returnLimit) { - while(uncached.length) { + while (uncached.length) { // Improve performance by just passing list of IDs this._query.objectIds = uncached.splice(0, this._returnLimit - 1); queries.push(this._queryFeatures()); @@ -595,6 +598,11 @@ define([ } else { features = results.features; } + + if (typeof this._filterFeaturesOnResponse === 'function') { + features = this._filterFeaturesOnResponse(features) || features; + } + var len = features.length; //this._clusterData.length = 0; //this.clear();