ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

时间:2022-11-06 16:28:07

一、前言

吐槽一下,百度在国内除了百度地图是良心产品外,其他的真的不敢恭维。在上一篇笔记里,我已经实现了自定义的地图测量模块。在百度地图里面(其他地图)都有一个周边搜索的功能,拖拽画一个圆,然后以圆半径进行搜索(也就是缓冲区╮(╯_╰)╭)。

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

这次的目标,就是要山寨这个拖拽画圆的功能,我先放一个效果图。

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

二、开始山寨

我们先想一想要实现这个功能需要哪些步骤。

  1. 拖拽
  2. 画圆
  3. 通知拖拽结束

2.1 实现拖拽

关于拖拽,有graphicslayer的拖拽事件和map的拖拽事件,如何选择呢?先来看一看官方文档。

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

graphicslayer 的鼠标事件

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

map的鼠标事件

在graphic的鼠标事件里面,鼠标事件触发的条件是鼠标必须在一个graphic上(红色标记处),但是graphicslayer的mouse-drag事件好像并不要这个条件,而且事件说明和map的一样。我们在仔细看一下文档,Arcgis文档在这个细节处理上特别值得学习。graphicslayer和map的鼠标事件文档中,开头都是mouse-down(mouse button is pressed down),结尾都是mouse-up(mouse button is released)。现在大家都发现了吧,两者的drag事件都是和mouse-down、mouse-up有关联的。首先,按下鼠标(mouse-down)是触发drag 的前提条件。然后,松开鼠标(mouse-up)是drag事件结束的标识。也就是说,如果要触发drag事件,就一定会触发mouse-down和mouse-up事件,所以graphicslayer的drag事件也需要鼠标在graphic上才能触发。

解释的不错,我选择map!下面先上两段代码来说一下为什么要选择map的drag事件原因。

map的鼠标事件,添加了一个graphicslayer和一个graphic

require([
"dojo/dom", "dojo/on",
"esri/map","esri/layers/GraphicsLayer", "esri/geometry/Point", "esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol", "esri/graphic", "esri/Color",
"dojo/domReady!"],
function (dom, on, Map, GraphicsLayer,Point,
SimpleMarkerSymbol, SimpleLineSymbol, Graphic, Color) {
var map = new Map("map", {
center: [103, 24.5],
zoom: 9,
basemap: "osm"
});
var graphicsLayer=new GraphicsLayer();
map.addLayer(graphicsLayer);
map.on("load", function () {
var sms = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE, 20,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
new Color([255, 0, 0]), 1),
new Color([0, 255, 0, 0.25]));
var point = new Point(103, 24.5);
var graphic = new Graphic(point, sms);
map.graphics.add(graphic);
graphicsLayer.add(graphic);
}); map.on("mouse-down", function (evt) {
console.log("map:mouse-down");
}); map.on("mouse-drag", function (evt) {
console.log("map:mouse-drag");
}); map.on("mouse-up", function (evt) {
console.log("map:mouse-up");
});
});

当在map上进行拖拽时,控制台的输出如下:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

当把鼠标移动到graphic上进行拖拽时,控制台输出如下:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

它也触发了地图的拖拽事件。

接着在看一看graphicslayer的鼠标事件,我添加了一个graphicslayer和一个graphic。

require([
"dojo/on",
"esri/map", "esri/layers/GraphicsLayer", "esri/geometry/Point", "esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol", "esri/graphic", "esri/Color",
"dojo/domReady!"],
function (on, Map, GraphicsLayer, Point,
SimpleMarkerSymbol, SimpleLineSymbol, Graphic, Color) {
var map = new Map("map", {
center: [102, 24.5],
zoom: 9,
basemap: "osm"
});
var graphicsLayer=new GraphicsLayer();
var graphic;
map.addLayer(graphicsLayer);
map.on("load", function () {
var sms = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE, 20,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
new Color([255, 0, 0]), 1),
new Color([0, 255, 0, 0.25]));
var point = new Point(102, 24.5);
graphic = new Graphic(point, sms);
graphicsLayer.add(graphic);
console.log(map.graphics)
});
graphicsLayer.on("mouse-down", function (evt) {
console.log("graphicslayer:mouse-down");
}); graphicsLayer.on("mouse-drag", function (evt) {
console.log("graphicslayer:mouse-drag");
}); graphicsLayer.on("mouse-up", function (evt) {
console.log("graphicslayer:mouse-up");
}); });

当在map上拖拽时候,这时候给人的感觉应该是,graphicslayer也在地图上,也应该会触发graphicslayer的拖拽事件,然而并没有,这时候控制台的输出为:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

当把鼠标移动到graphic上进行拖拽时,控制台输出如下:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

这时终于触发了graphicslayer的拖拽事件。

到现在为止,感觉好像二者区别不大。但是在进行拖拽时,移动的是地图,我们要实现的效果是移动graphic,这时就要用到如下方法:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

我们先来实现在graphicslayer上移动graphic。

graphicsLayer.on("mouse-down", function (evt) {
console.log("graphicslayer:mouse-down");
map.disableMapNavigation();
}); graphicsLayer.on("mouse-drag", function (evt) {
console.log("graphicslayer:mouse-drag");
graphic.setGeometry(evt.mapPoint);
}); graphicsLayer.on("mouse-up", function (evt) {
console.log("graphicslayer:mouse-up");
map.enableMapNavigation();
});

我们把graphic移动到昆明市,看看控制台的输出:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆 ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

这时在拖拽事件里移动了graphic,而且事件也按预期的顺序发生了。但是!但是!但是!这是鼠标一直在graphic上的时候才能触发的事件,当我们飞快的移动鼠标,使鼠标不在graphic上,这时就会有奇怪的行为发生了。

还是把graphic移动到昆明市(以很快的速度),看看控制台的输出:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

当鼠标移动到昆明市的时候,松开鼠标,并没有触发mous-up事件。现在在吧鼠标移到graphic上,你会发现不用点击鼠标graphic也会随着鼠标一起移动,要停止的话只有再次点击鼠标并松开,这时控制台输出如下:

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

所以如果选用graphiclayer的drag事件来实现拖拽按钮的话,用户体验会很糟糕,所以graphicslayer的drag事件不能用!

接下来实现map的drag事件,删除原来map的mouse-donw 事件,替换成graphicslayerdmouse-down。接着在graphic上加了个

isMouseDown属性,判断是否要拖拽这个graphic。

graphicsLayer.on("mouse-down", function (evt) {
console.log("graphicslayer:mouse-down");
graphic.isMouseDown=true;
map.disableMapNavigation();
}); map.on("mouse-drag", function (evt) {
console.log("map:mouse-drag");
if( graphic.isMouseDown){
graphic.setGeometry(evt.mapPoint);
}
}); map.on("mouse-up", function (evt) {
console.log("map:mouse-up");
map.enableMapNavigation();
graphic.isMouseDown=false;
});

这次就能很好的解决在graphicslayer上遇到的问题。

2.2画圆

解决了拖拽的问题,接下来就可以实现拖拽画圆了。我们传入中心点绘制制初始化圆,默认半径为500米,

startDrawCircle: function (centerPoint) {
this._unregistMapEvents();
this.centerPoint = centerPoint;
this.circle = this._createCircle(centerPoint, 500);
var dragPoint = this._createDragBtnPoint(this.circle, centerPoint); this.circleGraphic = new Graphic(this.circle, this.defaults.fillSymbol);
this.labelGraphic = new Graphic(dragPoint, this._createDistanceSymbol(500));
var dragGraphic = new Graphic(dragPoint, this.defaults.dragButtonSymbol); this._measureLayer.add(this.circleGraphic);
this._measureLayer.add(dragGraphic);
this._measureLayer.add(this.labelGraphic);
this._initialMapEvents();
},

第一步我们先取消上一次的画圆注册的map鼠标事件,第二步添加初始化圆,第三添加拖拽按钮和半径文描述。在计算拖拽按钮的为止时,可以用圆的extent来进行计算。

_createDragBtnPoint: function (geometry, center) {
var extent = geometry.getExtent();
var xmax = extent.xmax;
return new Point([xmax, center.y], center.spatialReference)
},

好了,现在所有的准备工作已经就绪,在结合前面的graphic拖拽,就可以轻松愉快的完成拖拽画圆了。

2.3通知拖拽结束

当每一次拖拽结束是,发出一次通知告诉用户绘制结束是很有必要的。这次就借助map的drag-end事件来通知用户

map.on("mouse-drag-end", lang.hitch(this, function (evt) {
if (this.dragGraphic && this.dragGraphic.isMouseDown) {
this.emit("drag-end", {circle: this.circle});
this.dragGraphic.isMouseDown = false;
this.defaults.map.enableMapNavigation();
this.defaults.map.setMapCursor("default");
}
})

通过 this.emit("drag-end", {circle: this.circle}); 我们就可以向外部发出拖拽结束的通知。

2.4 源码

/**
* Created by Extra
* Description:实现拖拽绘制圆,仿百度缓冲区搜索样式
* version: 1.0.0
*/
define("dextra/dijit/DrawDragCircle", [
"require",
"dojo/dom",
"dojo/query",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/Evented",
"dojo/on",
"esri/graphic",
"esri/layers/GraphicsLayer",
"esri/Color",
"esri/symbols/Font",
"esri/geometry/Point",
"esri/geometry/Circle",
"esri/geometry/Polyline",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/PictureMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/TextSymbol",
"esri/geometry/geometryEngine",
],
function (require, dom, query, declare, lang, Evented, on,
Graphic, GraphicsLayer,
Color, Font, Point, Circle, Polyline, MarkerSymbol, PictureMarkerSymbol, LineSymbol, FillSymbol, TextSymbol, geometryEngine) {
return declare(Evented, {
declaredClass: "dextra.dijit.DrawDragCircle",
defaults: {
map: null,
maxRadius: 5000,
markerSymbol: new MarkerSymbol(MarkerSymbol.STYLE_SQUARE, 20,
new LineSymbol(LineSymbol.STYLE_SOLID,
new Color("#DC143C"), 2),
new Color("#FFA500")),
dragButtonSymbol: new PictureMarkerSymbol({
"url": require.toUrl("./images/dragButton.png"),
"height": 21,
"width": 33
}),
lineSymbol: new LineSymbol(
LineSymbol.STYLE_SOLID,
new Color("#FFA500"), 2),
fillSymbol: new FillSymbol(FillSymbol.STYLE_SOLID,
new LineSymbol(LineSymbol.STYLE_SOLID,
new Color([0, 155, 255, 0.55]), 2), new Color([0, 155, 255, 0.55])),
},
circleGraphic: null,
circle: null,
labelGraphic: null,
dragGraphic: null,
_measureLayer: null,
_mapEvents: [], constructor: function (options) {
declare.safeMixin(this.defaults, options);
this._measureLayer = new GraphicsLayer();
this.defaults.map.addLayer(this._measureLayer);
this._initialMeasureLayer(); }, //初始化测量图层事件
_initialMeasureLayer: function () {
//开始拖拽绘制圆
this._measureLayer.on("mouse-down", lang.hitch(this, function (evt) {
var graphic = evt.graphic;
if (graphic.symbol.type == "picturemarkersymbol") {
this.dragGraphic = graphic;
this.dragGraphic.isMouseDown = true;
this.defaults.map.disableMapNavigation();
graphic.getDojoShape().moveToFront();
this.defaults.map.setMapCursor("pointer");
}
})); //提示可以拖拽
this._measureLayer.on("mouse-over", lang.hitch(this, function (evt) {
var graphic = evt.graphic;
if (graphic.symbol.type == "picturemarkersymbol") {
this.defaults.map.setMapCursor("pointer");
}
})); //恢复鼠标状态
this._measureLayer.on("mouse-out", lang.hitch(this, function (evt) {
this.defaults.map.setMapCursor("default");
}));
}, _initialMapEvents: function () {
this._mapEvents = [];
//拖拽绘制圆
this._mapEvents.push(this.defaults.map.on("mouse-drag", lang.hitch(this, function (evt) {
if (this.dragGraphic != null && this.dragGraphic.isMouseDown) {
var dragGraphic = this.dragGraphic;
var dragPoint = evt.mapPoint;
if (this.centerPoint.y != dragPoint.y) {
dragPoint.setY(this.centerPoint.y);
}
var radius = this._calDistance(this.centerPoint, dragPoint);
if (radius <= this.defaults.maxRadius) {
this._measureLayer.remove(this.circleGraphic);
this.circle = this._createCircle(this.centerPoint, radius);
this.circleGraphic = new Graphic(this.circle, this.defaults.fillSymbol);
dragGraphic.setGeometry(dragPoint); this.labelGraphic.setGeometry(dragPoint).setSymbol(this._createDistanceSymbol(radius))
this._measureLayer.add(this.circleGraphic);
this.circleGraphic.getDojoShape().moveToBack();
dragGraphic.getDojoShape().moveToFront();
}
}
}))); //触发"mouse-drag-end,通知拖拽结束
this._mapEvents.push(this.defaults.map.on("mouse-drag-end", lang.hitch(this, function (evt) {
if (this.dragGraphic && this.dragGraphic.isMouseDown) {
this.emit("drag-end", {circle: this.circle}); this.dragGraphic.isMouseDown = false;
this.defaults.map.enableMapNavigation();
this.defaults.map.setMapCursor("default");
}
})));
}, //取消上一次注册的map鼠标事件
_unregistMapEvents: function () {
for (var i = 0; i < this._mapEvents; i++) {
if (this._mapEvents[i]) {
this._mapEvents[i].remove();
}
}
this._mapEvents=[];
}, startDrawCircle: function (centerPoint) {
this._unregistMapEvents();
this.centerPoint = centerPoint;
this.circle = this._createCircle(centerPoint, 500);
var dragPoint = this._createDragBtnPoint(this.circle, centerPoint); this.circleGraphic = new Graphic(this.circle, this.defaults.fillSymbol);
this.labelGraphic = new Graphic(dragPoint, this._createDistanceSymbol(500));
var dragGraphic = new Graphic(dragPoint, this.defaults.dragButtonSymbol); this._measureLayer.add(this.circleGraphic);
this._measureLayer.add(dragGraphic);
this._measureLayer.add(this.labelGraphic);
this._initialMapEvents();
}, removeCircle: function () {
this.centerPoint = null;
this.circleGraphic = null;
this.labelGraphic = null;
this._measureLayer.clear();
}, _createCircle: function (point, distance) {
return new Circle(point, {
"radius": distance
});
}, _createDragBtnPoint: function (geometry, center) {
var extent = geometry.getExtent();
var xmax = extent.xmax;
return new Point([xmax, center.y], center.spatialReference)
}, _createDistanceSymbol: function (distance) {
distance = distance.toFixed(0) + "m";
var fontColor = new Color("#696969");
var holoColor = new Color("#fff");
var font = new Font("10pt", Font.STYLE_ITALIC, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Courier");
var textSymbol = new TextSymbol(distance, font, fontColor);
textSymbol.setOffset(10, 20).setHaloColor(holoColor).setHaloSize(2);
textSymbol.setAlign(TextSymbol.ALIGN_MIDDLE);
return textSymbol;
}, _calDistance: function (point1, point2) {
var line = new Polyline(this.defaults.map.spatialReference);
line.addPath([point1, point2]);
return geometryEngine.distance(point1, point2, "meters");
},
});
})

3.小结

本次功能最重要的地方就是实现graphic的拖拽。在拖拽graphic的时候,一定要关闭地图的导航,把graphic的geomtry设置成当前鼠标的位置。最后,如有不对的地方还请大家批评指正,欢迎转载!http://www.cnblogs.com/deliciousExtra/p/5503929.html

预告:下一期山寨百度的BubblePopupArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆的更多相关文章

  1. ArcGIS JS 学习笔记1 用ArcGIS JS 实现仿百度地图的距离量测和面积量测

    一.开篇 在博客注册了三年,今天才决定写第一篇博客,警告自己不要懒!!! 二.关于ArcGIS JS 版本选择 在写这篇博客时ArcGIS JS 4.0正式版已经发布.它和3.x版本的不同是,Map不 ...

  2. ArcGIS JS 学习笔记3 实现百度风格的BubblePopup

    1. 开篇 模仿是最好的学习,这次我们继续山寨百度,通过自定义Infowindow来实现百度风格的BubblePopup 2.准备 2.1 Copy模板 先打开百度地图,按下f12吧BubblePop ...

  3. ArcGIS JS 学习笔记4 实现地图联动

    1.开篇 守望屁股实在太好玩了,所以最近有点懒,这次就先写个简单的来凑一下数.这次我的模仿目标是天地图的地图联动. 天地的地图联动不仅地图有联动,而且鼠标也有联动,我就照着这个目标进行山寨. 2.准备 ...

  4. QML学习笔记(七)— 实现可拖拽、编辑、选中的ListView

    鼠标单击可选中当前项,头部呈绿色显示:按压当前项可进行拖拽更换列表项位置:点击数据可以进行编辑: GitHub:八至 作者:狐狸家的鱼 这里是自己定义的model,有些字体和颜色都是使用的全局属性, ...

  5. Chrome扩展&comma;应用开发学习笔记之2---恶搞百度一下

    Chrome扩展,应用开发学习笔记之2 恶搞百度一下 前面我们介绍了一个最简单的chrome扩展时钟,如今我来介绍一下一个恶搞百度一下的chrome扩展程序. 前面说过,manifest.json文件 ...

  6. WebGL three&period;js学习笔记 加载外部模型以及Tween&period;js动画

    WebGL three.js学习笔记 加载外部模型以及Tween.js动画 本文的程序实现了加载外部stl格式的模型,以及学习了如何把加载的模型变为一个粒子系统,并使用Tween.js对该粒子系统进行 ...

  7. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  8. Vue&period;js学习笔记(2)vue-router

    vue中vue-router的使用:

  9. JS 学习笔记--9---变量-作用域-内存相关

    JS 中变量和其它语言中变量最大的区别就是,JS 是松散型语言,决定了它只是在某一个特定时间保存某一特定的值的一个名字而已.由于在定义变量的时候不需要显示规定必须保存某种类型的值,故变量的值以及保存的 ...

随机推荐

  1. WindowsForm多窗体、多窗体传值、控件数据绑定--2016年12月8日

    多窗体 Show Form1 f1 = new Form1(); f1.Show(); ShowDialog--在父窗体之上 Form1 f1 = new Form1(); f1.ShowDialog ...

  2. VMware 安装虚拟机安装MAC (OSX10&lowbar;11)

    一.简述前言: 1.本案例是基于 VMware Workstation Pro(专业版)12 上创建一个MAC操作系统(版本 :OSX10_11),下面的步骤基本上和安装其他类型的虚拟机没有什么区别. ...

  3. pyqt5-为QListWidget添加右键菜单

    如何在pyqt5下为QListWidget添加右键菜单? 能百度到的均是pyqt4下的,有些貌似并不好用. 在尝试了很多方法后,下面贴出可用的方法: from PyQt4 import QtCore, ...

  4. Java NIO:浅析I&sol;O模型

    也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗.在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型.下面本文先从同步和异步的概念 说起, ...

  5. 【转】Doscommand-操作Cmd的第三方控件

    核心用法: Doscommand1.CommandLine := 'cmd /c' +[命令];Doscommand1.OutputLines :=Memo1.Lines;Doscommand1.Ex ...

  6. 【转】国内较快的maven镜像

    国内连接maven官方的仓库更新依赖库,网速一般很慢,收集一些国内快速的maven仓库镜像以备用. ====================国内OSChina提供的镜像,非常不错=========== ...

  7. Js特效总结

    1.//#hidediv2为一个需要隐藏的div  这个功能实现当点击hidediv2以外的其他任何位置时,隐藏该div $(document).click(function() {          ...

  8. v4l2视频采集摄像头

    v4l2 --是Linux内核中关于视频设备的内核驱动框架,为上层访问底层的视频设备提供了统一的接口./dev/vidioX 1.打开设备文件 fd=open("/dev/video3&qu ...

  9. PHP中利用DOM创建xml文档

    DOM创建xml文档 用dom创建如下文档: <booklist> <book id="1"> <title>天龙八部</title&gt ...

  10. angularjs 的ng-disabled属性操作

    ng-readonly:不可用,但是可以提交数据 ng-disabled: 属性是控制标签是否可用(不可用且无法传值) 表达式控制: <input class="col-md-2 fo ...