· 4 years ago · Aug 06, 2021, 03:12 PM
1///////////////////////////////////////////////////////////////////////////
2// Copyright © Esri. All Rights Reserved.
3//
4// Licensed under the Apache License Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15///////////////////////////////////////////////////////////////////////////
16
17define([
18 'dojo/_base/declare',
19 'dojo/_base/lang',
20 'dojo/aspect',
21 'dojo/on',
22 'dojo/keys',
23 'dojo/Deferred',
24 'dojo/_base/html',
25 'jimu/LayerInfos/LayerInfos',
26 'esri/layers/GraphicsLayer',
27 'esri/layers/FeatureLayer',
28 'esri/graphic',
29 // 'esri/symbols/TextSymbol',
30 // 'esri/symbols/Font',
31 // 'dojo/_base/Color',
32 'jimu/dijit/LoadingIndicator',
33 'dijit/_WidgetsInTemplateMixin',
34 'jimu/BaseWidget',
35 'jimu/portalUtils',
36 'jimu/dijit/Message',
37 'esri/units',
38 'esri/dijit/Measurement',
39 'jimu/utils',
40 "esri/symbols/jsonUtils"
41 ],
42 function(
43 declare,
44 lang,
45 aspect,
46 on,
47 keys,
48 Deferred,
49 html, LayerInfos, GraphicsLayer, FeatureLayer, Graphic,
50 // TextSymbol, Font, Color,
51 LoadingIndicator,
52 _WidgetsInTemplateMixin,
53 BaseWidget,
54 PortalUtils,
55 Message,
56 esriUnits,
57 Measurement,
58 jimuUtils,
59 jsonUtils) {
60 var clazz = declare([BaseWidget, _WidgetsInTemplateMixin], {
61
62 name: 'Measurement',
63 baseClass: 'jimu-widget-Measurement',
64 measurement: null,
65 _pcDef: null,
66
67 toolName: null, //includes: location, distance, area
68 currentFeatureLayer: null, //layer which saves drawing graphics
69 linePicGraphicsLayer: null, //layer which save pic graphics for line
70 linePicGraphics: [], //save pic graphics for line
71 isClose: false, //set true when closing the widget
72
73 _objectIdName: 'OBJECTID',
74 _objectIdType: 'esriFieldTypeOID',
75
76 postMixInProperties: function(){
77 this.inherited(arguments);
78 this.jimuNls = window.jimuNls;
79 },
80
81 startup: function() {
82 if (this.measurement || this._pcDef) {
83 return;
84 }
85 this.inherited(arguments);
86
87 this._isPCS = this.map.cs !== "Web Mercator" &&
88 (this.map.spatialReference && this.map.spatialReference.wkid !== 4326);
89
90 this._clearAbledLabel = this.clearGraphicsBtn.innerHTML;
91 this._clearDisabledLabel = this._clearAbledLabel + ' ' + window.jimuNls.common.disabled;
92
93 var json = this.config.measurement;
94 json.map = this.map;
95 if (json.lineSymbol) {
96 json.lineSymbol = jsonUtils.fromJson(json.lineSymbol);
97 }
98 if (json.pointSymbol) {
99 json.pointSymbol = jsonUtils.fromJson(json.pointSymbol);
100 }
101
102 //add snap tips
103 this._addSnappingTips();
104
105 this._processConfig(json).then(lang.hitch(this, function(measurementJson) {
106 this.measurement = new Measurement(measurementJson, this.measurementDiv);
107 this.own(aspect.after(this.measurement, 'setTool', lang.hitch(this, function() {
108 if (this.measurement.activeTool) {
109 this.disableWebMapPopup();
110 } else {
111 this.enableWebMapPopup();
112 }
113 })));
114 this.own(on(this.measurement, 'tool-change', lang.hitch(this, this._toolChange)));
115 this.own(on(this.measurement, 'measure-start', lang.hitch(this, this._onMeasureStart)));
116 this.own(on(this.measurement, 'measure-end', lang.hitch(this, this._onMeasureEnd)));
117 this.measurement.startup();
118
119 this._initGraphicsLayers();
120
121 this._hideToolsByConfig();
122 this._initFirstFocusNode();
123 }), lang.hitch(this, function(err) {
124 new Message({
125 message: err.message || err
126 });
127 }));
128 },
129
130 _addSnappingTips: function(){
131 if(this.map.snappingManager){
132 var dom = document.createElement('div');
133 dom.className = "snapingLabel";
134 dom.innerHTML = this.jimuNls.snapping.pressStr + "<b>" +
135 this.jimuNls.snapping.ctrlStr + "</b> " +
136 this.jimuNls.snapping.snapStr;
137 this.domNode.parentNode.appendChild(dom);
138 }
139 },
140
141 _initGraphicsLayers: function(){
142 if(!this.config.isOperationalLayer){
143 this.currentFeatureLayer = new GraphicsLayer();
144 this.map.addLayer(this.currentFeatureLayer);
145 this._setCurrentFeatureLayerVisible();
146 }
147 //use a graphicLayer to save graphics for line node pic
148 this.linePicGraphicsLayer = new GraphicsLayer();
149 this.map.addLayer(this.linePicGraphicsLayer);
150 },
151
152 _clearAllGraphics: function(){
153 if(this.currentFeatureLayer){
154 this.currentFeatureLayer.clear();
155 if(this.linePicGraphicsLayer){
156 this.linePicGraphicsLayer.clear();
157 this.linePicGraphics = [];
158 }
159 html.addClass(this.clearGraphicsBtn, 'jimu-state-disabled');
160 html.attr(this.clearGraphicsBtn, "aria-label", this._clearDisabledLabel);
161 }
162 },
163
164 //clear current graphics from map (for measurement dijit api)
165 _clearMapGraphics: function(toolName){
166 var graphicsLayer = this.map.graphics;
167 if(toolName === 'distance'){
168 var mapGraphics = graphicsLayer.graphics;
169 this.linePicGraphics = [];
170 for(var key = 0; key < mapGraphics.length; key ++){ //need to keep the pic markers
171 var gra = mapGraphics[key];
172 var gType = (gra.symbol && gra.symbol.type) ? gra.symbol.type : null;
173 if(gType === 'picturemarkersymbol'){
174 var newGra = new Graphic(gra.geometry, gra.symbol, null, null);
175 this.linePicGraphics.push(newGra);
176 }
177 }
178 }
179 graphicsLayer.clear();
180 },
181
182 _onMeasureStart: function(){
183 if(this._isPCS){
184 this._isMeasureEnd = false;
185 }
186 this._clearAllGraphics();
187 html.addClass(this.clearGraphicsBtn, 'jimu-state-disabled');
188 html.attr(this.clearGraphicsBtn, "aria-label", this._clearDisabledLabel);
189 },
190
191 _onMeasureEnd:function(measureInfo){
192 if(this._isPCS && measureInfo.toolName !== 'location'){
193 if(this._isMeasureEnd){
194 return; //block multiple renders, #16294
195 }else{
196 this._isMeasureEnd = true;
197 }
198 }
199 //use graphicLayer
200 if(measureInfo.toolName === 'location' && this._isPCS){
201 html.removeClass(this.clearGraphicsBtn, 'jimu-state-disabled');
202 html.attr(this.clearGraphicsBtn, "aria-label", this._clearAbledLabel);
203 return;
204 }
205 this._clearMapGraphics(measureInfo.toolName);
206
207 var graphic, symbol, value = '';
208 if(measureInfo.toolName === 'location'){
209 this._clearAllGraphics(); //location won't enter measure-start event
210 value = measureInfo.values[0] + ',' + measureInfo.values[1] + measureInfo.unitName;
211 symbol = this.measurement._pointSymbol;
212 }else if(measureInfo.toolName === 'distance'){
213 symbol = this.measurement._lineSymbol;
214 value = Math.round(measureInfo.values) + measureInfo.unitName;
215 for(var key = 0; key < this.linePicGraphics.length; key ++){
216 this.linePicGraphicsLayer.add(this.linePicGraphics[key]);
217 }
218 }else{ //area
219 symbol = this.measurement._fillSymbol;
220 value = Math.round(measureInfo.values) + measureInfo.unitName;
221 }
222 graphic = new Graphic(measureInfo.geometry, symbol, {'OBJECTID': 1}, null);
223
224 //add label
225 // var a = Font.STYLE_ITALIC, b = Font.VARIANT_NORMAL, c = Font.WEIGHT_BOLD;
226 // var symbolFont = new Font("16px", a, b, c, "Courier");
227 // var fontColor = new Color([0, 0, 0, 1]);
228 // var textSymbol = new TextSymbol(value, symbolFont, fontColor);
229 // var labelGraphic = new Graphic(measureInfo.geometry, textSymbol.setOffset(0, 20 ));
230
231 this.currentFeatureLayer.add(graphic);
232 html.removeClass(this.clearGraphicsBtn, 'jimu-state-disabled');
233 html.attr(this.clearGraphicsBtn, "aria-label", this._clearAbledLabel);
234 },
235
236 _toolChange: function(toolInfo){
237 this.toolName = toolInfo.toolName;
238 if(!this.isClose){
239 html.addClass(this.clearGraphicsBtn, 'jimu-state-disabled');
240 html.attr(this.clearGraphicsBtn, "aria-label", this._clearDisabledLabel);
241 this._clearAllGraphics();
242 }
243 this.isClose = false;
244 if(this.config.isOperationalLayer){
245 if(this.toolName){ //checked
246 this._checkOperateLayers(this.toolName);
247 }
248 }else{
249 }
250 },
251
252 _checkOperateLayers: function(type){
253 if(this.currentFeatureLayer){
254 this.map.removeLayer(this.currentFeatureLayer);
255 this.currentFeatureLayer = null;
256 }
257 var layerDefinition = {
258 "name": this.nls._widgetLabel,
259 "geometryType": "",
260 "fields": [{
261 "name": this._objectIdName,
262 "type": this._objectIdType,
263 "alias": this._objectIdName
264 }]
265 };
266 // var layerDefinition = lang.clone(definition);
267 if(type === 'location'){
268 layerDefinition.geometryType = "esriGeometryPoint";
269 }else if(type === 'distance' && !this._polylineLayer){
270 layerDefinition.geometryType = "esriGeometryPolyline";
271 }else if(type === 'area' && !this._polygonLayer){
272 layerDefinition.geometryType = "esriGeometryPolygon";
273 }
274
275 var layer = this._getFeatureLayer(layerDefinition);
276 this.currentFeatureLayer = layer;
277 this.linePicGraphicsLayer.setVisibility(true);
278 this._setCurrentFeatureLayerVisible();
279
280 this._addLayerFromLayerInfos(layer);
281 },
282
283 _getFeatureLayer: function(labelDefinition){
284 return new FeatureLayer({
285 layerDefinition: labelDefinition,
286 featureSet: null
287 });
288 },
289
290 _setCurrentFeatureLayerVisible: function(){
291 this.own(on(this.currentFeatureLayer, 'visibility-change', lang.hitch(this, function(){
292 if(this.linePicGraphicsLayer){
293 this.linePicGraphicsLayer.setVisibility(this.currentFeatureLayer.visible);
294 }
295 })));
296 },
297
298 _addLayerFromLayerInfos: function(layer){
299 var loading = new LoadingIndicator();
300 loading.placeAt(this.domNode);
301 LayerInfos.getInstance(this.map, this.map.itemInfo)
302 .then(lang.hitch(this, function(layerInfos){
303 if(!this.domNode){
304 return;
305 }
306 loading.destroy();
307 var layername = layer.name;
308 layerInfos.addFeatureCollection([layer], this.label + "_" + layername);
309 }), lang.hitch(this, function(err){
310 loading.destroy();
311 console.error("Can not get LayerInfos instance", err);
312 }));
313 },
314
315 _processConfig: function(configJson) {
316 this._pcDef = new Deferred();
317 if (configJson.defaultLengthUnit && configJson.defaultAreaUnit) {
318 this._pcDef.resolve(configJson);
319 } else {
320 PortalUtils.getUnits(this.appConfig.portalUrl).then(lang.hitch(this, function(units) {
321 configJson.defaultAreaUnit = units === 'english' ?
322 esriUnits.SQUARE_MILES : esriUnits.SQUARE_KILOMETERS;
323 configJson.defaultLengthUnit = units === 'english' ?
324 esriUnits.MILES : esriUnits.KILOMETERS;
325 this._pcDef.resolve(configJson);
326 }), lang.hitch(this, function(err) {
327 console.error(err);
328 configJson.defaultAreaUnit = esriUnits.SQUARE_MILES;
329 configJson.defaultLengthUnit = esriUnits.MILES;
330 this._pcDef.resolve(configJson);
331 }));
332 }
333
334 return this._pcDef.promise;
335 },
336
337 _hideToolsByConfig: function() {
338 if (false === this.config.showArea) {
339 this.measurement.hideTool("area");
340 }
341 if (false === this.config.showDistance) {
342 this.measurement.hideTool("distance");
343 }
344 if (false === this.config.showLocation) {
345 this.measurement.hideTool("location");
346 }
347 },
348
349 _initFirstFocusNode: function(){
350 var firstTool = null;
351 if (this.config.showArea) {
352 firstTool = this.measurement._areaButton;
353 }else if (this.config.showDistance) {
354 firstTool = this.measurement._distanceButton;
355 }else if (this.config.showLocation) {
356 firstTool = this.measurement._locationButton;
357 }
358 jimuUtils.initFirstFocusNode(this.domNode, firstTool.focusNode);
359 },
360
361 disableWebMapPopup: function() {
362 this.map.setInfoWindowOnClick(false);
363 },
364
365 enableWebMapPopup: function() {
366 this.map.setInfoWindowOnClick(true);
367 },
368
369 onDeActive: function() {
370 if(this.toolName === 'location' && this._isPCS){
371 var graphicLayer = this.map.graphics;
372 var mapGraphics = graphicLayer.graphics; //popup rect my in this array.
373 for(var key = 0; key < mapGraphics.length; key ++){ //find the pic markers
374 var gra = mapGraphics[key];
375 var gType = (gra.symbol && gra.symbol.type) ? gra.symbol.type : null;
376 if(gType === 'picturemarkersymbol' && this.measurement._pointSymbol === gra.symbol){
377 var newGra = new Graphic(gra.geometry, gra.symbol, {'OBJECTID': 1}, null);
378 this.currentFeatureLayer.add(newGra);
379 graphicLayer.remove(gra);
380 break;
381 }
382 }
383 }
384 this.onClose();
385 },
386
387 onOpen: function(){
388 },
389
390 onClose: function() {
391 if (this.measurement && this.measurement.activeTool) {
392 // this.measurement.clearResult();
393 this.isClose = true;
394 this.measurement.setTool(this.measurement.activeTool, false);
395 }
396 this.keepGraphics();
397 },
398
399 keepGraphics: function(){
400 if(this.config.isOperationalLayer){
401 if(this.currentFeatureLayer && this.currentFeatureLayer.graphics.length === 0){
402 this.map.removeLayer(this.currentFeatureLayer);
403 this.currentFeatureLayer = null;
404 }
405 }
406 },
407
408 undoLast: function(){
409 console.log("undoLast function");
410
411 var dgraphicLayer = this.linePicGraphicsLayer;
412 var dmapGraphics = dgraphicLayer.graphics;
413 console.log("Plotted Points Count: " + dmapGraphics.length);
414 for(var dkey = 0; dkey < dmapGraphics.length; dkey++) {
415 var dgra = dmapGraphics[dkey];
416 var dSymbol = dgra.symbol;
417 var dType = dgra.symbol.type;
418 console.log("symbol " + dkey + " symbol " + dSymbol + " type " + dType);
419 }
420 dgraphicLayer.remove(dmapGraphics[dmapGraphics.length-1]);
421 },
422
423 undoLastKeydown: function(evt) {
424 console.log("undoLastKeydown function");
425 if(evt.keyCode == keys.ENTER || evt.keyCode == keys.SPACE) && !html.hasClass(this.undoGraphicsBtn, 'jimu-state-disabled') {
426 this.undoLast();
427 }
428 },
429
430 clearGraphics: function(){
431 this.measurement.clearResult();
432 if(this.currentFeatureLayer){
433 this.currentFeatureLayer.clear();
434 if(this.linePicGraphicsLayer){
435 this.linePicGraphicsLayer.clear();
436 }
437 }
438 html.addClass(this.clearGraphicsBtn, 'jimu-state-disabled');
439 html.attr(this.clearGraphicsBtn, "aria-label", this._clearDisabledLabel);
440 },
441
442 clearGraphicsKeydown: function(evt){
443 if((evt.keyCode === keys.ENTER || evt.keyCode === keys.SPACE) &&
444 !html.hasClass(this.clearGraphicsBtn, 'jimu-state-disabled')){
445 this.clearGraphics();
446 }
447 },
448
449 destroy: function() {
450 if (this.measurement) {
451 this.measurement.destroy();
452 //destory layers
453 if(this.currentFeatureLayer){
454 this.currentFeatureLayer.clear();
455 this.map.removeLayer(this.currentFeatureLayer);
456 this.currentFeatureLayer = null;
457 }
458 if(this.linePicGraphicsLayer){
459 this.linePicGraphicsLayer.clear();
460 this.map.removeLayer(this.linePicGraphicsLayer);
461 this.linePicGraphicsLayer = null;
462 }
463 }
464 this.inherited(arguments);
465 }
466 });
467 return clazz;
468 });