odoe

Be a drag

Blog Post created by odoe on Jun 3, 2015

esri-touch.jpg

 

Do you develop web apps that require editing? Maybe you have a feature that lets users add graphics to the map? Do you use the TemplatePicker to do your editing?

 

Why don't you try and spice things up a bit. We live in a world where we swipe and drag for everything on our devices. You may even swipe for your next date. But the idea is that users are becoming more sophisticated in their interactions with applications. They want something more intuitive.

 

A while ago, I did a writeup on this very subject, but I haven't really checked to see if the code would work in the current version of the ArcGIS JavaScript API. I was all deep into CoffeeScript at this time, so the code may not be the easiest to read.

 

So how could you accomplish something like this? Let's check out one solution.

require([
  "dojo/_base/declare",
  "esri/map",
  "dojo/Evented",
  "dojo/dom",
  "dojo/dom-geometry",
  "dojo/dom-attr",
  "dojo/on",
  "dojo/query",
  "esri/geometry/ScreenPoint",
  "esri/geometry/screenUtils",
  "esri/symbols/PictureMarkerSymbol",
  "esri/graphic"
], function(declare, Map, Evented, dom, domGeom, domAttr, on, query, ScreenPoint, screenUtils, PictureMarkerSymbol, Graphic) { 
  var cleanup = function(targets) {
    targets.map(function(x) {
      x.remove();
    });
  };
  var DragDropHandler = declare([Evented], {
    dragdrop: function(srcName, targetName) {
      var src = dom.byId(srcName);
      var target = dom.byId(targetName);
      var handlers = [];
      var self = this;
      handlers.push(on(target, 'dragenter', function(e) {e.preventDefault();}));
      handlers.push(on(target, 'dragover', function(e) {e.preventDefault();}));
      handlers.push(on(target, 'dragend', function(e) {cleanup(handlers);}));
      handlers.push(on(src, 'dragstart', function() {
        handlers.push(on(target, 'drop', function(e) {
          e.preventDefault();
          cleanup(handlers);
          var position = domGeom.position(e.currentTarget);
          var x = e.clientX - position.x; // in case the map does not take up whole page
          var y = e.clientY - position.y;// in case the map does not take up whole page
          self.emit('itemdrop', {
            bubbles: true,
            cancelable: true,
            dragsource: src,
            x:x,
            y:y
          });
        }));
      }));
    }
  });
  var handler = new DragDropHandler();
  var map = new Map("mapView", {
    center: [-118, 34.5],
    zoom: 8,
    basemap: "topo"
  });
  function addPoint(data) {
    var mp = screenUtils.toMapGeometry(map.extent, map.width, map.height, data.pt);
    var pms = new PictureMarkerSymbol(data.url, 24, 24);
    var graphic = new Graphic(mp, pms);
    map.graphics.add(graphic);
  }
  on(query('.drag-icon'), 'mousedown', function(e) {
    var srcName = domAttr.get(e.currentTarget, 'id');
    handler.dragdrop(srcName, 'mapView');
  });
  on(handler, 'itemdrop', function(e) {
    var data = {
      pt: new ScreenPoint(e.x, e.y),
      url: domAttr.get(e.dragsource, 'src')
    };
    addPoint(data);
  });
});

 

That's not really a whole lot of code. The workhorse is really the DragDropHandler. This DragDropHandler has a dragdrop method that will listen for drag events on an image, and sees when the image is dropped on the map. When this image is dropped on the map, you just need to emit an event with screen coordinates and what the dragged item was. The ArcGIS JS API provides some utilities for you to convert screen coordinates into map geometries and voila, you can quickly add graphics to the map and even copy the image src to display it on the map!

 

Here is an example on jsbin.

 

This sample just adds graphics to the map, but there is no reason it couldn't be applied to editing, so you could drag and drop features to add them to a FeatureService. So give it a shot and add some pazazz to your apps!

 

For more geodev tips and tricks, check out my blog.

Outcomes