需要用到的类
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/Graphic",
"esri/widgets/Editor",
"esri/layers/GraphicsLayer",
"esri/geometry/support/webMercatorUtils"
], function (Map, MapView, FeatureLayer, Graphic, Editor, GraphicsLayer, webMercatorUtils) {
//这里面编写代码
})
①创建一个地图map
const map = new Map({
basemap: "streets-navigation-vector"; //地图的底图
});
②创建一个地图视图
const view = new MapView({
container: "viewDiv", //容器,可以认为是放置地图的地方
map: map, //地图
center: [-80, 35],
zoom: 3
});
③先创建一个图形要素(一个三角形)
// 创建一个图形
const polygon = {
type: "polygon", // autocasts as new Polygon()
rings: [
[-64.78, 32.3],
[-66.07, 18.45],
[-80.21, 25.78],
[-64.78, 32.3]
]
};
// Create a symbol for rendering the graphic
const fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: { // autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 1
}
};
// Add the geometry and symbol to a new graphic
const polygonGraphic = new Graphic({
geometry: polygon,
symbol: fillSymbol,
attributes: {
state: "hi~"
}
});
④现在我们再创建一个graphicsLayer图层,并且把此图层添加到地图上。
// 创建一个只有graphic要素的FeatureLayer图层
const graphicsLayer = new GraphicsLayer({ id: 'hello' })
// 将图层添加到地图上
map.add(graphicsLayer);
//将前面我们创建的三角形要素添加到graphicsLayer图层上
graphicsLayer.add(polygonGraphic)
此时地图上已经有一个图形要素了
⑤接下来实现拖拽移动图形
//先看如下两个移动要素的函数
//我们常用的要素有三种点、线、面。
//下面这个函数是移动面要素的,前面我们的三角形就是一个面要素。
function translatePolygon(startPoint, currPoint, polygon) {
let dx = currPoint.x - startPoint.x;
let dy = currPoint.y - startPoint.y;
polygon.rings.forEach(ring => {
if (Array.isArray(ring[0])) {
ring.forEach(coord => {
coord[0] += dx;
coord[1] += dy;
});
} else {
ring[0] += dx;
ring[1] += dy;
}
});
}
//下面这个函数是移动线要素的
function translatePolyline(startPoint, currPoint, polyline) {
let dx = currPoint.x - startPoint.x;
let dy = currPoint.y - startPoint.y;
polyline.paths.forEach(path => {
if (Array.isArray(path[0])) {
path.forEach(coord => {
coord[0] += dx;
coord[1] += dy;
});
} else {
path[0] += dx;
path[1] += dy;
}
});
}
//接下来监听视图的拖拽事件
view.on('drag', e => {
//e.action是用来判断拖拽过程的状态的,开始拖拽(按下鼠标刚开始),正在拖拽(按下鼠标拖拽中),结束拖拽(松开鼠标,结束拖拽)
if (e.action === 'start') {
view.hitTest(e).then(resp => {
if (resp.results.filter(item => item.graphic.geometry)[0]?.graphic) { //判断当前拖拽的是否是指定的要素
e.stopPropagation(); //这个方法是阻止默认行为的
selectedGraphic = resp.results.filter(item => item.graphic.geometry)[0]?.graphic; //获取到当前要素
// 判断是否是地理坐标系,转换坐标系
if (selectedGraphic.geometry.spatialReference.isWGS84) {
selectedGraphic.geometry = webMercatorUtils.geographicToWebMercator(selectedGraphic.geometry);
}
origin = view.toMap(e); //获取当前鼠标位置,这个是一开始的位置
}
})
} else if (e.action === 'update') { //这个if里面是正在拖拽(按下鼠标拖拽中)的过程
if (selectedGraphic) { //判断一开始拖拽获取的要素是否为空,不为空就要删掉这个要素,要不然拖拽后还有一个要素保留在原来的位置
e.stopPropagation(); //这个方法是阻止默认行为的
if (graphicsLayer.graphics.items.includes(selectedGraphic)) { //判断这个要素是否是在graphicsLayer图层上的
graphicsLayer.remove(selectedGraphic); //删除要素
}
if (tmpGraphic) { //这个tmpGraphic其实就是拖拽过程中的每一个要素,每到一个最新的位置,就要把之前的要素删掉
graphicsLayer.remove(tmpGraphic);
tmpGraphic = null;
}
tmpGraphic = selectedGraphic.clone(); //拷贝一个最初的位置的要素
switch (tmpGraphic.geometry.type) { //这个switch就是判断当前要素是那种类型的要素,会执行对应的移动方法
case "point":
tmpGraphic.geometry = view.toMap(e);
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic);
break;
case "polygon":
translatePolygon(origin, view.toMap(e), tmpGraphic.geometry); //开始执行移动方法传入参数(初始位置, 鼠标当前最新位置, 需要移动的要素的geometry)
//移动完后我们需要把要素的坐标转回地理坐标
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic); //添加这个移动后的要素到图层上
break;
case "polyline":
translatePolyline(origin, view.toMap(e), tmpGraphic.geometry);
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic);
break;
default:
break;
}
}
} else if (e.action === 'end') { //这里是移动的结束,就是鼠标松开的时候
selectedGraphic = null;
tmpGraphic = null;
origin = null;
}
});
⑥下面我们实现在鼠标点击的位置上添加一个要素,其实跟上面的拖拽同理,都可以通过移动要素来实现。
//监听视图的点击事件
view.on('click', (e) => {
view.hitTest(e).then(res => {
const new_graphic = new Graphic({ //新建一个要素,这个要素也是一个面要素,不过是一个正方形
symbol: {
type: "simple-fill",
color: 'rgba(102, 102, 102, .1)',
outline: {
color: [255, 255, 255],
width: 1,
},
},
geometry: {
type: "polygon",
rings: [
[-80.21, 18.45],
[-80.21, 32.3],
[-64.78, 32.3],
[-64.78, 18.45],
]
}
})
if (new_graphic.geometry.spatialReference.isWGS84) { //转换坐标系
new_graphic.geometry = webMercatorUtils.geographicToWebMercator(new_graphic.geometry);
}
translatePolygon(new_graphic.geometry.centroid, view.toMap(e), new_graphic.geometry) //移动要素new_graphic.geometry.centroid就是当前要素的中心位置
if (new_graphic.geometry.spatialReference.isWebMercator) { //转换回坐标系
new_graphic.geometry = webMercatorUtils.webMercatorToGeographic(new_graphic.geometry);
}
graphicsLayer.add(new_graphic)
})
})
最后
完整代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Creating a FeatureLayer with Graphics in ArcGIS JS 4</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.28/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.28/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/Graphic",
"esri/widgets/Editor",
"esri/layers/GraphicsLayer",
"esri/geometry/support/webMercatorUtils"
], function (Map, MapView, FeatureLayer, Graphic, Editor, GraphicsLayer, webMercatorUtils) {
//弹出框
let popup_template = {
title: "属性",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "座位号",
editable: true, // 设置可编辑
},
{
fieldName: "状态",
editable: true, // 设置可编辑
},
{
fieldName: "描述",
editable: true, // 设置可编辑
},
{
fieldName: "备注",
editable: true, // 设置可编辑
},
],
},
],
};
// 创建一个地图
const map = new Map({
basemap: "streets-navigation-vector"
});
// 创建一个地图视图
const view = new MapView({
container: "viewDiv",
map: map,
center: [-80, 35],
zoom: 3
});
// 创建一个图形
const polygon = {
type: "polygon", // autocasts as new Polygon()
rings: [
[-64.78, 32.3],
[-66.07, 18.45],
[-80.21, 25.78],
[-64.78, 32.3]
]
};
// Create a symbol for rendering the graphic
const fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: { // autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 1
}
};
// Add the geometry and symbol to a new graphic
const polygonGraphic = new Graphic({
geometry: polygon,
symbol: fillSymbol,
attributes: {
座位号: "hi~"
}
});
// 创建一个只有graphic要素的FeatureLayer图层
const graphicsLayer = new GraphicsLayer({ id: 'hello' })
// 将图层添加到地图中
graphicsLayer.add(polygonGraphic)
map.add(graphicsLayer);
let selectedGraphic = null;
let tmpGraphic = null;
let origin = null;
view.on('drag', e => {
if (e.action === 'start') {
view.hitTest(e).then(resp => {
if (resp.results.filter(item => item.graphic.geometry)[0]?.graphic) {
e.stopPropagation();
selectedGraphic = resp.results.filter(item => item.graphic.geometry)[0]?.graphic;
// doing this with web mercator or the spatial ref of the basemap, we don't want to use
// wgs84
if (selectedGraphic.geometry.spatialReference.isWGS84) {
selectedGraphic.geometry = webMercatorUtils.geographicToWebMercator(selectedGraphic.geometry);
}
origin = view.toMap(e);
}
})
} else if (e.action === 'update') {
if (selectedGraphic) {
e.stopPropagation();
if (graphicsLayer.graphics.items.includes(selectedGraphic)) {
graphicsLayer.remove(selectedGraphic);
}
if (tmpGraphic) {
graphicsLayer.remove(tmpGraphic);
tmpGraphic = null;
}
tmpGraphic = selectedGraphic.clone();
switch (tmpGraphic.geometry.type) {
case "point":
tmpGraphic.geometry = view.toMap(e);
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic);
break;
case "polygon":
translatePolygon(origin, view.toMap(e), tmpGraphic.geometry);
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic);
break;
case "polyline":
translatePolyline(origin, view.toMap(e), tmpGraphic.geometry);
if (selectedGraphic.geometry.spatialReference.isWebMercator) {
tmpGraphic.geometry = webMercatorUtils.webMercatorToGeographic(tmpGraphic.geometry);
}
graphicsLayer.add(tmpGraphic);
break;
default:
break;
}
}
} else if (e.action === 'end') {
selectedGraphic = null;
tmpGraphic = null;
origin = null;
}
});
function translatePolygon(startPoint, currPoint, polygon) {
let dx = currPoint.x - startPoint.x;
let dy = currPoint.y - startPoint.y;
polygon.rings.forEach(ring => {
if (Array.isArray(ring[0])) {
ring.forEach(coord => {
coord[0] += dx;
coord[1] += dy;
});
} else {
ring[0] += dx;
ring[1] += dy;
}
});
}
function translatePolyline(startPoint, currPoint, polyline) {
let dx = currPoint.x - startPoint.x;
let dy = currPoint.y - startPoint.y;
polyline.paths.forEach(path => {
if (Array.isArray(path[0])) {
path.forEach(coord => {
coord[0] += dx;
coord[1] += dy;
});
} else {
path[0] += dx;
path[1] += dy;
}
});
}
view.on('click', (e) => {
view.hitTest(e).then(res => {
const new_graphic = new Graphic({
symbol: {
type: "simple-fill",
color: 'rgba(102, 102, 102, .1)',
outline: {
color: [255, 255, 255],
width: 1,
},
},
geometry: {
type: "polygon",
rings: [
[-80.21, 18.45],
[-80.21, 32.3],
[-64.78, 32.3],
[-64.78, 18.45],
]
}
})
if (new_graphic.geometry.spatialReference.isWGS84) {
new_graphic.geometry = webMercatorUtils.geographicToWebMercator(new_graphic.geometry);
}
translatePolygon(new_graphic.geometry.centroid, view.toMap(e), new_graphic.geometry)
if (new_graphic.geometry.spatialReference.isWebMercator) {
new_graphic.geometry = webMercatorUtils.webMercatorToGeographic(new_graphic.geometry);
}
graphicsLayer.add(new_graphic)
})
})
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
结语
不想做前端牛马了~~~