We need to customize the ESRI’s JavaScript Template as the following from ESRI's Github:
https://github.com/Esri/Viewer
I insert our own codes in two files: one is index.html and the other is main.js inside the js folder. What we want to do is to create our own draw tool in a separate pane on the left (see the image below), and control it from main.js; in addition we want to display the information in the datagrid at the bottom when users use the draw tool to select features on the map.
I put the source codes of index.html and main.js as below. In the viewer template, these are the only two files that we made modification. The debug of main.js always indicated that “Cannnot read property ‘graphics’ of undefined”. I post the question as the following before but still don’t understand where the map is loaded. https://community.esri.com/thread/113384
In main.js file, all the other codes are the same, our own customized codes are inserted all inside the addLayers: function (tool, toolbar, panelClass) {****}, this addLyers function is ESRI’s built-in function. Only this part is posted below:
_addLayers: function (tool, toolbar, panelClass) {
//Toggle layer visibility if web map has operational layers
var deferred = new Deferred();
var layers = this.config.response.itemInfo.itemData.operationalLayers;
//alert("The layer lable is " + layers[0].title)
if (layers.length === 0) {
deferred.resolve(false);
} else {
if (has("layers")) {
//Set up the query function *****************************************
//Build a feature layer
var j9t4 = new InfoTemplate("Current Land Use", "${*}");
var sUrlQuakesLayer = "http://arcgis02.h-gac.com/ArcGIS/rest/services/Land_Use/Current_Land_Use_New/MapServer/0";
var outFieldsQuakes = ["ParcelID", "Acres", "Current_Land_Use"];
var lyrQuakes = new FeatureLayer(sUrlQuakesLayer, {
id: "Current Land Use",
outFields: outFieldsQuakes
});
this.map.addLayer(lyrQuakes);
//Set up a single draw tool as Polygon for test purpose
var tbDraw = new Draw(this.map);
tbDraw.activate(Draw.POLYGON);
tbDraw.on("draw-end", displayPolygon);
function displayPolygon(evt) {
// Get the geometry from the event object
var geometryInput = evt.geometry;
// Define symbol for finished polygon
var tbDrawSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASHDOT, new Color([255, 255, 0]), 2), new Color([255, 255, 0, 0.2]));
// Clear the map's graphics layer
this.map.graphics.clear(); // Debug always indicated that graphics is not defined
//Step: Construct and add the polygon graphic
var graphicPolygon = new Graphic(geometryInput, tbDrawSymbol);
this.map.graphics.add(graphicPolygon); //Debug always indicated that graphics is not defined
// Call the next function
selectQuakes(geometryInput);
} //displayPolygon ends here
//Create a serial of the draw tool buttons as point, freehandpolyline and freehandpolygon
this.map.on("load", initToolbar); // Debug indicated initToolbar can not be called
var tb;
function initToolbar(evt) {
tb = new Draw(evt.map);
tb.on("draw-end", addGraphic);
// activate drawing tools on button click
registry.byId("point").on("click", function () {
tb.activate(this.id);
alert("You will start to use POINT drawing function");
tb.on("draw-end", addGraphic);//it can not be called
});
registry.byId("freehandpolyline").on("click", function () {
tb.activate(this.id);
alert("You will start to use POLYLINE drawing function");
tb.on("draw-end", addGraphic);//it can not be called
});
registry.byId("freehandpolygon").on("click", function () {
tb.activate(this.id);
alert("You will start to use POLYGON drawing function");
tb.on("draw-end", addGraphic);//it can not be called
});
registry.byId("stop").on("click", function () {
tb.deactivate(this.id);
alert("You have selected to STOP the drawing function");
});
}
function addGraphic(evt) {
//create a random color for the symbols
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var geometryInput = evt.geometry;//copy from displayPolygon(evt)
var type = evt.geometry.type;
var symbol;
if (type === "point" || type === "multipoint") {
symbol = new SimpleMarkerSymbol(
SimpleMarkerSymbol.STYLE_CIRCLE,
20, new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([r, g, b, 0.5]),
10
),
new Color([r, g, b, 0.9]));
} else if (type === "line" || type === "polyline") {
var symbol = new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([r, g, b, 0.85]),
6
); //selectQuakes(geometryInput);
} else {
symbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([r, g, b, 0.9]),
4
), new Color([r, g, b, 0.5]));
} // else Ends here
var graphic = new Graphic(evt.geometry, symbol);
this.map.graphics.add(graphic);
selectQuakes(geometryInput); //goes to the next function to call
}
//SelectQuakes set up
function selectQuakes(geometryInput) {
alert("Going into selectQuakes--2"); //------------------------
// Define symbol for selected features (using JSON syntax for improved readability!)
var symbolSelected = new SimpleMarkerSymbol({
"type": "esriSMS",
"style": "esriSMSCircle",
"color": [100, 100, 100, 128],
"size": 6,
"outline":
{
"color": [255, 0, 0, 214],
"width": 1
}
});
var sls = new SimpleLineSymbol({
"type": "esriSLS",
"style": "esriSLSSolid",
"color": [67, 0, 255, 40],
"width": 5
});
var sfs = new SimpleFillSymbol({
"type": "esriSFS",
"style": "esriSFSSolid",
"color": [255, 255, 0, 200],
"outline": {
"type": "esriSLS",
"style": "esriSLSSolid",
"color": [255, 0, 0, 215],
"width": 2
}
}); //LAST NUMBER AS A ALPHA VALUE
lyrQuakes.setSelectionSymbol(sfs);
/*
* Step: Initialize the query
*/
var queryQuakes = new Query();
queryQuakes.geometry = geometryInput;
lyrQuakes.on("selection-complete", populateGrid);
lyrQuakes.selectFeatures(queryQuakes, FeatureLayer.SELECTION_NEW);
registry.byId('cpBottom').selectChild(registry.byId('divGrid2'));
} // selectQuakes () ends here
//Create a datagrid
var gridQuakes = new (declare([Grid, Selection]))({
bufferRows: Infinity,
columns: {
ParcelID: "Parcel ID",
Acres: "Acres",
Current_Land_Use: "Current Land Use",
}
}, "divGrid2");
//Pop up to index div compoment
function populateGrid(results) {
var gridData;
dataQuakes = array.map(results.features, function (feature) {
var dateConvert = new Date(feature.attributes[outFieldsQuakes[2]]).toLocaleString();
return {
/*
* Step: Reference the attribute field values
*/
"ParcelID": feature.attributes[outFieldsQuakes[0]],
"Acres": feature.attributes[outFieldsQuakes[1]],
"Current_Land_Use": feature.attributes[outFieldsQuakes[2]],
}
});
// Pass the data to the grid
var memStore = new Memory({
data: dataQuakes
});
gridQuakes.set("store", memStore);
} //populateGrid fucntion ends here
//Use small panel class if layer layer is less than 5
if (layers.length < 5) {
panelClass = "small";
} else if (layers.length < 15) {
panelClass = "medium";
} else {
panelClass = "large";
}
var layersDiv = toolbar.createTool(tool, panelClass);
var toc = new TableOfContents({
map: this.map,
layers: layers
}, domConstruct.create("div", {}, layersDiv));
toc.startup();
deferred.resolve(true);
} else {
deferred.resolve(false);
}
}
return deferred.promise;
}, //999999999999999999999999999999999999999999999999999999999999999999999
Index.html source codes below:
<!DOCTYPE html>
<html>
<head>
<style>
#leftPane {
top: 200px;
background-color: #002f32;
color: #FFFFFF;
border: solid #97DCF2 1px;
height: 80%;
display: block;
width: 200px;
position: relative;
}
#cpBottom {
background-color: #deff89;
color: #FFFFFF;
border: solid #97DCF2 1px;
height: 250px;
display: block;
bottom: 0px;
width: 100%;
position: fixed;
}
#divGrid {
color: #061162;
height: 250px;
}
#divGrid2 {
color: #061162;
height: 250px;
}
#GridClose {
position: relative;
right: 0px;
height: 50px;
width: 50px;
background-color: #97DCF2;
}
</style>
<title></title> <!-- Define the versions of IE that will be used to render the page. See Microsoft documentation for details. Optional. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<!-- Responsive -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<!-- End Responsive -->
<!-- Use protocol relative urls that way if the browser is viewing the page via HTTPS the js/css file will be requested using the HTTPS protocol -->
<link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/esri/css/calcite/calcite.css">
<link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/esri/css/esri.css">
<!-- Load any application specific styles -->
<link rel="stylesheet" href="css/styles.css">
<!--[if IE 8]>
<link rel="stylesheet" href="css/ie.css">
<![endif]-->
</head>
<body class="calcite app-loading no-touch">
<!-- Loading Indicator -->
<div class="loading-indicator">
<div class="loading-message" id="loading_message"></div>
</div>
<!-- Map -->
<!-- The ArcGIS API for JavaScript provides bidirectional support. When viewing the application in an right to left (rtl) language like Hebrew and Arabic the map needs to remain in left-to-right (ltr) mode. Specify this by setting the dir attribute on the div to ltr. -->
<div id="mapDiv" dir="ltr" data-dojo-props="region:'top'">
</div>
<div id="leftPane"
data-dojo-type="dijit/layout/ContentPane"
data-dojo-props="region:'left', splitter:'true', gutters:false">
<b>This pane is for seleciton layers only</b>
<div>
<!--<p>
The custom operation inherits from esri/OperationBase.
<a target="_blank" href="./myModules/customoperation.js">This is a testing hyperlink</a>.
</p> -->
<p>
Please Select the Buttons Below to Activate the Drawing Tools
</p>
</div>
<button id="point" data-dojo-type="dijit/form/Button">
Point
</button>
<button id="freehandpolyline" data-dojo-type="dijit/form/Button">
Polyline
</button>
<button id="freehandpolygon" data-dojo-type="dijit/form/Button">
Polygon
</button>
<p>
Click "Stop Drawing" Button to Disable Drawing Tools;
<br />After Doing this, only Click-Pop-Up Function is Available
</p>
<button id="stop" data-dojo-type="dijit/form/Button">
Stop Drawing
</button>
</div>
<div id="cpBottom" data-dojo-type="dijit/layout/TabContainer" data-dojo-props="
splitter:'true', region:'bottom', closable:true">
<!--<div id="GridClose" class="GridCloseIcon" data-dojo-type="dijit/layout/ContentPane"
title="Close Grid" onclick="closeGrid();"></div> -->
<div id="divGrid2" data-dojo-props="title:'TAZs'" data-dojo-type="dijit/layout/ContentPane"></div>
<div id="divGrid" data-dojo-props="title:'Land Use'" data-dojo-type="dijit/layout/ContentPane"></div>
</div> <!-- cpBottom End -->
<!-- Panel Content -->
<div id="panelContent">
<div id="panelPages"></div>
</div>
<!-- Panel Top -->
<div id="panelTop" class="bg rounded shadow">
<!-- Panel Title -->
<div id="panelTitle">
<div class="fc" id="panelText">
</div>
<div id="panelSearch">
<div id="panelGeocoder"></div>
</div>
<div id="panelMenu" class="icon-menu icon-color"></div>
</div>
<!-- Panel Tools -->
<div id="panelTools">
<!--Tools are created programatically-->
</div>
</div> <!-- Panel Top End -->
<script type="text/javascript">
var package_path = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'));
var dojoConfig = {
// The locationPath logic below may look confusing but all its doing is
// enabling us to load the api from a CDN and load local modules from the correct location.
packages: [{
name: "application",
location: package_path + '/js'
}, {
name: "config",
location: package_path + '/config'
}]
};
</script>
<script type="text/javascript" src="//js.arcgis.com/3.10/"></script>
<script type="text/javascript">
require(["application/template", "application/main"],
function (Template, Main) {
// create the template. This will take care of all the logic required for template applications
var myTemplate = new Template();
var myApp = new Main();
//var mydrawTool = new DrawTool();//
myTemplate.startup().then(function (config) {
myApp.startup(config); //mydrawTool.startup();
}, function (error) {
// something went wrong. Let's report it.
myApp.reportError(error);
});
});
</script>
<!--<script type="text/javascript" src="js/drawTool.js"></script> -->
</body>
</html>
The other question is that the inserted codes in index.html seem very weird, e.g., <button id="point"…> and <button id="freehandpolyline"…>, <button id="freehandpolygon"…> do not display well. The TabContainer with two ContenPanes as divGrid and divGrid2, does not show the two Tabs in a row.
Thanks a lot for reading this and any hint will be very helpful!
Index.html codes are here:
<!DOCTYPE html>
<html>
<head>
<style>
#leftPane {
top: 200px;
background-color: #002f32;
color: #FFFFFF;
border: solid #97DCF2 1px;
height: 80%;
display: block;
width: 200px;
position: relative;
}
#cpBottom {
background-color: #deff89;
color: #FFFFFF;
border: solid #97DCF2 1px;
height: 250px;
display: block;
bottom: 0px;
width: 100%;
position: fixed;
}
#divGrid {
color: #061162;
height: 250px;
}
#divGrid2 {
color: #061162;
height: 250px;
}
#GridClose {
position: relative;
right: 0px;
height: 50px;
width: 50px;
background-color: #97DCF2;
}
</style>
<title></title> <!-- Define the versions of IE that will be used to render the page. See Microsoft documentation for details. Optional. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<!-- Responsive -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<!-- End Responsive -->
<!-- Use protocol relative urls that way if the browser is viewing the page via HTTPS the js/css file will be requested using the HTTPS protocol -->
<link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/esri/css/calcite/calcite.css">
<link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/esri/css/esri.css">
<!-- Load any application specific styles -->
<link rel="stylesheet" href="css/styles.css">
<!--[if IE 8]>
<link rel="stylesheet" href="css/ie.css">
<![endif]-->
</head>
<body class="calcite app-loading no-touch">
<!-- Loading Indicator -->
<div class="loading-indicator">
<div class="loading-message" id="loading_message"></div>
</div>
<!-- Map -->
<!-- The ArcGIS API for JavaScript provides bidirectional support. When viewing the application in an right to left (rtl) language like Hebrew and Arabic the map needs to remain in left-to-right (ltr) mode. Specify this by setting the dir attribute on the div to ltr. -->
<div id="mapDiv" dir="ltr" data-dojo-props="region:'top'">
</div>
<div id="leftPane"
data-dojo-type="dijit/layout/ContentPane"
data-dojo-props="region:'left', splitter:'true', gutters:false">
<b>This pane is for seleciton layers only</b>
<div>
<!--<p>
The custom operation inherits from esri/OperationBase.
<a target="_blank" href="./myModules/customoperation.js">This is a testing hyperlink</a>.
</p> -->
<p>
Please Select the Buttons Below to Activate the Drawing Tools
</p>
</div>
<button id="point" data-dojo-type="dijit/form/Button">
Point
</button>
<button id="freehandpolyline" data-dojo-type="dijit/form/Button">
Polyline
</button>
<button id="freehandpolygon" data-dojo-type="dijit/form/Button">
Polygon
</button>
<p>
Click "Stop Drawing" Button to Disable Drawing Tools;
<br />After Doing this, only Click-Pop-Up Function is Available
</p>
<button id="stop" data-dojo-type="dijit/form/Button">
Stop Drawing
</button>
</div>
<div id="cpBottom" data-dojo-type="dijit/layout/TabContainer" data-dojo-props="
splitter:'true', region:'bottom', closable:true">
<!--<div id="GridClose" class="GridCloseIcon" data-dojo-type="dijit/layout/ContentPane"
title="Close Grid" onclick="closeGrid();"></div> -->
<div id="divGrid2" data-dojo-props="title:'TAZs'" data-dojo-type="dijit/layout/ContentPane"></div>
<div id="divGrid" data-dojo-props="title:'Land Use'" data-dojo-type="dijit/layout/ContentPane"></div>
</div> <!-- cpBottom End -->
<!-- Panel Content -->
<div id="panelContent">
<div id="panelPages"></div>
</div>
<!-- Panel Top -->
<div id="panelTop" class="bg rounded shadow">
<!-- Panel Title -->
<div id="panelTitle">
<div class="fc" id="panelText">
</div>
<div id="panelSearch">
<div id="panelGeocoder"></div>
</div>
<div id="panelMenu" class="icon-menu icon-color"></div>
</div>
<!-- Panel Tools -->
<div id="panelTools">
<!--Tools are created programatically-->
</div>
</div> <!-- Panel Top End -->
<script type="text/javascript">
var package_path = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'));
var dojoConfig = {
// The locationPath logic below may look confusing but all its doing is
// enabling us to load the api from a CDN and load local modules from the correct location.
packages: [{
name: "application",
location: package_path + '/js'
}, {
name: "config",
location: package_path + '/config'
}]
};
</script>
<script type="text/javascript" src="//js.arcgis.com/3.10/"></script>
<script type="text/javascript">
require(["application/template", "application/main"],
function (Template, Main) {
// create the template. This will take care of all the logic required for template applications
var myTemplate = new Template();
var myApp = new Main();
//var mydrawTool = new DrawTool();//
myTemplate.startup().then(function (config) {
myApp.startup(config); //mydrawTool.startup();
}, function (error) {
// something went wrong. Let's report it.
myApp.reportError(error);
});
});
</script>
</body>
</html>