<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ArcGIS for JavaScript Event Demo</title>
<!--JS imports-->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script type="text/javascript" src="script.js"></script>
<!--CSS imports-->
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="http://js.arcgis.com/3.14/esri/css/esri.css" />
<link rel="stylesheet" type="text/css" href="https://js.arcgis.com/3.14/dijit/themes/claro/claro.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="mainWrapper">
<div class="view">
<div class="header-block">
<h4 class="inline">ArcGIS for JavaScript Events</h4>
</div>
<div class="content">
<div class="row">
<div class="col-sm-4">
<div id="drawOptions">
<a class="btn btn-default btn-form btn-draw disabled"
title="Click and drag to draw a line" value="line">Line</a>
<a class="btn btn-default btn-form btn-draw disabled"
title="Click and drag to draw a circle" value="circle">Circle</a>
<a class="btn btn-default btn-form btn-draw disabled"
title="Click and release to draw a polygon side. Double-click to finish the shape" value="polygon">Polygon</a>
<a class="btn btn-default btn-form btn-draw disabled"
title="Click and drag to draw a freehand polygon" value="freehandpolygon">Freehand Polygon</a>
</div>
</div>
<div class="help-block col-sm-8">
Choose a shape then draw on the map.<br />
Click and drag to reposition vertices. Right-click a vertex to delete it.
Double-click the shape to toggle between <i>move</i> and <i>edit vertices</i>,
or right-click to open a context menu with more options.<br />
</div>
</div>
<div class="row">
<div class="col-sm-4">
<label for="vertices">Vertices</label>
<textarea id="vertices" rows="3" class="form-control form-group"></textarea>
</div>
</div>
</div>
</div>
<div id="map">
<a id="btnExpandMap" class="btn btn-primary" title="Click to maximize/minimize map">
<span class="glyphicon glyphicon-chevron-up"></span>
</a>
</div>
</div>
</body>
</html>
var DECIMAL_PRECISION = 5;
//Save a collection of event handlers. It is best practive to remove
//event handlers when the application closes (on map "unload")
var events = [];
function loadScript(src, callback) {
'use strict';
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
script.onreadystatechange = function() {
if (this.readyState === 'complete' || this.readyState === 'loaded') {
callback();
}
};
script.onload = callback;
var scriptTag = document.getElementsByTagName('script')[0];
scriptTag.parentNode.insertBefore(script, scriptTag);
}
loadScript('https://js.arcgis.com/3.14/init.js', function () {
onLoadGis(); //Initialize GIS components on ArcGIS load
});
$(document).ready(function () {
$("#btnExpandMap").click(function() {
$("#mainWrapper").toggleClass("maximized-map");
map.resize(); //Very important, must be called any time the map div is resized
var chevron = $(this).find("span");
chevron.toggleClass("glyphicon-chevron-down");
chevron.toggleClass("glyphicon-chevron-up");
});
});
function onLoadGis () {
require([
"esri/map",
"esri/toolbars/draw",
"esri/graphic",
"esri/Color",
"esri/toolbars/edit",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/CartographicLineSymbol",
"esri/geometry/Circle",
"esri/geometry/Polygon",
"esri/geometry/Polyline",
"esri/layers/GraphicsLayer",
"esri/geometry/webMercatorUtils",
"dijit/Menu",
"dijit/MenuItem",
"dojo/on"],
function (Map, Draw, Graphic, Color, Edit, SimpleLineSymbol, SimpleFillSymbol,
CartographicLineSymbol, Circle, Polygon, Polyline, GraphicsLayer,
WebMercatorUtils, Menu, MenuItem, on) {
var editToolBar, drawToolBar, drawingLayer, ctxMenuForGraphics, selectedGraphic = null;
var drawing = false, editing = false;
map = new Map("map", {
basemap: "streets",
center: [-79, 38],
zoom: 5,
minZoom: 2
});
events.push(map.on("load", function () {
initDrawing();
initEditing();
createGraphicsMenu();
}));
//Unload all the events when the application closes to prevent memory leaks
events.push(map.on("unload", function () {
for (var i = 0; i < events.length; i++) {
events[i].remove();
}
}));
//LineSymbol used for polylines
var lineSymbol = new CartographicLineSymbol(
CartographicLineSymbol.STYLE_SOLID,
new Color([255, 0, 0]), 10,
CartographicLineSymbol.CAP_ROUND,
CartographicLineSymbol.JOIN_MITER, 5
);
//FillSymbol for polygons drawn on the drawing layer
var drawFillSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
new Color([255, 0, 0]), 2), new Color([0, 0, 0, 0.25])
);
function initDrawing() {
drawToolBar = new Draw(map);
events.push(drawToolBar.on("draw-end", onDrawEnd));
//Create a dedicated drawing layer
//You could also just draw on map.graphics (built-in GraphicsLayer)
drawingLayer = new GraphicsLayer({
id: "drawingLayer"
});
map.addLayer(drawingLayer);
//Set the click event for the draw buttons
$(".btn-draw").click(function () {
//If the draw button clicked is already active, deactivate it
if ($(this).hasClass("active")) {
$(this).removeClass("active");
drawToolBar.deactivate();
drawing = false;
//Enable panning
map.enableMapNavigation();
} else {
//Activate Draw for the selected tool
$(".btn-draw.active").removeClass("active");
$(this).addClass("active");
var tool = $(this).attr('value');
//Disable panning
map.disableMapNavigation();
drawToolBar.activate(tool);
drawing = true;
}
});
//Enable the draw buttons
$(".btn-draw").removeClass("disabled");
}
function onDrawEnd(evt) {
//Deactivate the toolbar
drawToolBar.deactivate();
drawing = false;
//Enable panning
map.enableMapNavigation();
//Remove active style from draw button
$(".btn-draw.active").removeClass("active");
//Use the appropriate symbol depending on geometry type
var symbol;
if (evt.geometry.type === "polyline") {
symbol = lineSymbol;
} else {
symbol = drawFillSymbol;
}
var graphic = new Graphic(evt.geometry, symbol);
addGraphicToDrawingLayer(graphic);
}
function addGraphicToDrawingLayer(graphic) {
//For the purpose of this demo we only want one graphic at a time
drawingLayer.clear();
drawingLayer.add(graphic);
//Automatically activate editing
editToolBar.activate(Edit.EDIT_VERTICES, graphic);
editing = true;
postGraphic(graphic.geometry);
}
function initEditing() {
editToolBar = new Edit(map);
//Events to update vertex data after a shape is modified
events.push(editToolBar.on("vertex-move-stop", function (e) {
postGraphic(e.graphic.geometry);
}));
events.push(editToolBar.on("vertex-delete", function (e) {
postGraphic(e.graphic.geometry);
}));
events.push(editToolBar.on("graphic-move-stop", function (e) {
postGraphic(e.graphic.geometry);
}));
events.push(editToolBar.on("scale-stop", function (e) {
postGraphic(e.graphic.geometry);
}));
events.push(editToolBar.on("rotate-stop", function (e) {
postGraphic(e.graphic.geometry);
}));
//You can capture double clicks for the map itself or for a specific GraphicsLayer
//ex. drawingLayer.on("dbl-click", function (e) {...})
events.push(map.on("dbl-click", function (e) {
//If editing a graphic toggle the edit mode when that graphic is double-clicked
if (editing) {
var state = editToolBar.getCurrentState();
var editingGraphic = state.graphic;
if (editingGraphic != null) {
//There exists a method to check if a point is "in" a polygon, but no such thing for polylines
if ((editingGraphic.geometry.type === "polygon" && editingGraphic.geometry.contains(e.mapPoint))
|| (editingGraphic.geometry.type === "polyline" && e.graphic === editingGraphic)) {
if (state.tool == Edit.EDIT_VERTICES) {
editToolBar.activate(Edit.MOVE, editingGraphic);
} else if (state.tool == Edit.MOVE) {
editToolBar.activate(Edit.EDIT_VERTICES, editingGraphic);
}
map.infoWindow.hide();
}
}
}
}));
}
//Parse the vertices, convert them to a convenient format, then display
function postGraphic (geometry) {
$("#vertices").text("");
if (geometry.type === 'polygon') {
//Our polygons should have only one ring
var polygon = geometry.rings[0];
var vertices = "";
for (var i = 0; i < polygon.length; i++) {
if (geometry.spatialReference.isWebMercator()) {
//Convert to traditional decimal degrees
longLat = WebMercatorUtils.xyToLngLat(polygon[i][0], polygon[i][1]);
} else longLat = [polygon[i][0], polygon[i][1]];
x = round(longLat[0], DECIMAL_PRECISION);
y = round(longLat[1], DECIMAL_PRECISION);
//Convert the vertices to the format x,y;x,y;
vertices = vertices + x + ',' + y + ';';
}
$("#vertices").text(vertices);
}
else if (geometry.type === 'polyline') {
//Assuming one line
var path = geometry.paths[0];
var points = "";
for (var j = 0; j < path.length; j++) {
if (geometry.spatialReference.isWebMercator()) {
//Convert to traditional decimal degrees
longLat = WebMercatorUtils.xyToLngLat(path[j][0], path[j][1]);
} else longLat = [path[j][0], path[j][1]];
x = round(longLat[0], DECIMAL_PRECISION);
y = round(longLat[1], DECIMAL_PRECISION);
//Convert the vertices to the format x,y;x,y;
points = points + x + ',' + y + ';';
}
$("#vertices").text(points);
}
}
function round(num, places) {
var multiplier = Math.pow(10, places);
return Math.round((num + 0.00001) * multiplier) / multiplier;
}
//Creates right-click context menu for graphics on the drawingLayer
function createGraphicsMenu () {
ctxMenuForGraphics = new Menu({});
ctxMenuForGraphics.addChild(new MenuItem({
label: "Edit",
onClick: function() {
if (selectedGraphic != null && selectedGraphic.geometry.type !== "point") {
editToolBar.activate(Edit.EDIT_VERTICES, selectedGraphic);
editing = true;
}
}
}));
ctxMenuForGraphics.addChild(new MenuItem({
label: "Move",
onClick: function() {
if (selectedGraphic != null) {
editToolBar.activate(Edit.MOVE, selectedGraphic);
editing = true;
}
}
}));
ctxMenuForGraphics.addChild(new MenuItem({
label: "Rotate/Scale",
onClick: function() {
if (selectedGraphic != null && selectedGraphic.geometry.type !== "point" ) {
editToolBar.activate(Edit.ROTATE | Edit.SCALE, selectedGraphic);
editing = true;
}
}
}));
ctxMenuForGraphics.addChild(new MenuItem({
label: "Delete",
onClick: function() {
if (selectedGraphic != null) {
if (editing) {
editToolBar.deactivate();
editing = false;
}
drawingLayer.remove(selectedGraphic);
$("#vertices").text("");
}
}
}));
ctxMenuForGraphics.startup();
//Bind and unbind the context menu using the following two events
events.push(drawingLayer.on("mouse-over", function (e) {
selectedGraphic = e.graphic;
ctxMenuForGraphics.bindDomNode(e.graphic.getDojoShape().getNode());
}));
events.push(drawingLayer.on("mouse-out", function (e) {
ctxMenuForGraphics.unBindDomNode(e.graphic.getDojoShape().getNode());
}));
}
//Disable double-click zoom if a graphic is being clicked while editing
events.push(map.on("mouse-down", function (e) {
if (e.graphic !== undefined && editing) {
map.disableDoubleClickZoom();
} else {
map.enableDoubleClickZoom();
}
}));
//Prevent the infoWindow from opening while drawing
//Important if your app has drawing/editing and popup windows!
events.push(map.infoWindow.on("show", function () {
if (drawing) map.infoWindow.hide();
}));
});
}
html, body {
width: 100%;
height: 100%;
}
body {
overflow-y: hidden;
}
.inline {
display: inline-block;
}
.relative {
position: relative;
}
label {
font-weight: 600;
}
.help-block {
margin-bottom: 15px;
}
#mainWrapper {
height: calc(100% - 30px);
margin: 15px 15px 15px 15px;
}
.view {
width: 100%;
height: 270px;
}
.view .content {
height: calc(100% - 50px);
overflow-x: hidden;
}
#map {
width: 100%;
height: calc(100% - 270px);
position: relative;
background-color: lightblue;
}
.maximized-map #map {
height: 100%;
}
.maximized-map .view {
display: none;
}
.header-block {
position: relative;
}
.header-block h4 {
margin-right: 10px;
color: darkcyan;
}
.btn-form {
margin-bottom: 15px;
}
#btnExpandMap {
position: absolute;
right: 0;
top: 0;
font-size: 10px;
opacity: .6;
z-index: 1;
}
#btnExpandMap:hover {
opacity: 1;
}
#vertices {
min-width: 450px;
}
.dijitReset.dijitMenuItemIconCell {
padding: 0 5px 0 5px;
}
.dijitReset.dijitMenuItemLabel {
padding: 5px 5px 5px 0;
}
.dijitMenuItem:hover,
.dijitMenuItemSelected {
background-color: #444;
color: white;
}
@media (max-width: 450px) {
.view .content {
height: calc(100% - 85px);
}
}
Demonstrates many different ArcGIS for JavaScript events for Map, Edit, Draw, and more.
Also provides an example of polygon drawing/editing and context menus for graphics.
Visit http://info.easydynamics.com/blog/event-handling-in-arcgis-for-javascript to view the full blog post associated with this plunk.