import * as ol from 'ol'
import * as style from 'ol/style'
import * as layer from 'ol/layer'
import * as source from 'ol/source'
import * as geom from 'ol/geom'
import {fromCircle} from 'ol/geom/Polygon';
import * as proj from 'ol/proj'
import * as interaction from 'ol/interaction'
import * as coordinate from 'ol/coordinate'
import * as control from 'ol/control'
import * as sphere from 'ol/sphere'
import { unByKey } from 'ol/Observable'
import './dom.scss'
import {createBox} from "ol/interaction/Draw";
import {Circle, LineString, Polygon} from "ol/geom";
import {formatPosition} from '@/utils/easyMap'
import store from "@/store";
const layerFlag = ['layerName', 'drawLayer']
let drawTooltipElement;
let drawHelpTooltipElement;
const typeMapper = new Map([
['line', 'LineString'],
['rectangle', 'LineString'],
['polygon', 'Polygon'],
['circle', 'Circle'],
])
let oldDrawFeature
/**
*
* @param map
* @param typeSelect line线,rectangle矩形,polygon多边形,circle圆形
*/
export default function Draw (map, typeSelect) {
return new Promise((resolve, reject) => {
if (!drawTooltipElement) {
let _source
const realLayer = map.getLayers().getArray().filter(v => v.get(layerFlag[0]) === layerFlag[1])
if (realLayer[0]) {
_source = realLayer[0].getSource()
} else {
_source = new source.Vector(); //图层数据源
const _vector = new layer.Vector({
zIndex: 9999,
source: _source,
style: new style.Style({ //图层样式
fill: new style.Fill({
color: 'rgba(46,129,255,0.15)' //填充颜色
}),
stroke: new style.Stroke({
color: '#2E81FF', //边框颜色
width: 2, // 边框宽度
lineDash: [10, 10]
}),
image: new style.Circle({
radius: 7,
fill: new style.Fill({
color: '#ffcc33'
})
})
})
});
_vector.set(layerFlag[0], layerFlag[1])
map.addLayer(_vector);
}
let sketch;
let helpTooltip;
let measureTooltip;
let continueMsg = '双击结束标绘';
const geodesicCheckbox = true;//测地学方式对象
const createMeasureTooltip = () => {
const id = 'drawTooltipElementId'
if (drawTooltipElement) {
map.removeOverlay(map.getOverlayById(id))
drawTooltipElement.parentNode.removeChild(drawTooltipElement);
}
drawTooltipElement = document.createElement('div');
drawTooltipElement.className = 'tooltip tooltip-measure';
measureTooltip = new ol.Overlay({
id,
element: drawTooltipElement,
offset: [0, -15],
positioning: 'bottom-center'
});
map.addOverlay(measureTooltip);
}
const createHelpTooltip = () => {
const id = 'drawHelpTooltipElementId'
if (drawHelpTooltipElement) {
map.removeOverlay(map.getOverlayById(id))
drawHelpTooltipElement.parentNode.removeChild(drawHelpTooltipElement);
}
drawHelpTooltipElement = document.createElement('div');
drawHelpTooltipElement.className = 'tooltip hidden';
helpTooltip = new ol.Overlay({
id,
element: drawHelpTooltipElement,
offset: [15, 0],
positioning: 'center-left'
});
map.addOverlay(helpTooltip);
}
const formatLength = (line) => {
// 获取投影坐标系
const sourceProj = map.getView().getProjection();
// ol/sphere里有getLength()和getArea()用来测量距离和区域面积,默认的投影坐标系是EPSG:3857, 其中有个options的参数,可以设置投影坐标系
const length = sphere.getLength(line, {projection: sourceProj});
// const length = getLength(line);
let output;
if (length > 100) {
const km = Math.round((length / 1000) * 100) / 100;
output = `${km} 千米
${parseFloat(String(km * 0.53995)).toFixed(2)} 海里`;
} else {
output = `${Math.round(length * 100) / 100} m`;
}
return output;
};
//获取圆的面积
const getCircleArea = (circle, projection) => {
const P = 3.14
const radius = getCircleRadius(circle, projection)
return P * radius * radius
}
//获取圆的半径
const getCircleRadius = (circle, projection) => {
return circle.getRadius() * projection.getMetersPerUnit()
}
const formatArea = (polygon, type= 'polygon') => {
let area
const sourceProj = map.getView().getProjection();
// 获取投影坐标系
if (type === 'polygon') {
area = sphere.getArea(polygon, {
projection: sourceProj,
});
} else if (type === 'circle') {
area = getCircleArea(polygon, sourceProj)
}
let output;
if (area > 10000) {
const km = Math.round((area / 1000000) * 100) / 100;
output = `${km} 平方公里
${parseFloat(String(km * 0.38610)).toFixed(
2
)} 平方英里`;
} else {
output = `${Math.round(area * 100) / 100} ` + " m2";
}
return output;
};
const addInteraction = () => {
const id = 'drawName'
const draw = new interaction.Draw({
source: _source,//测量绘制层数据源
// @ts-ignore
type: typeMapper.get(typeSelect), //几何图形类型
// @ts-ignore
geometryFunction: typeSelect === 'rectangle' ? createBox() : null,
style: new style.Style({
fill: new style.Fill({
color: "rgba(46,129,255,0.15)",
}),
stroke: new style.Stroke({
color: "#2E81FF",
width: 2,
lineDash: [10, 10]
}),
image: new style.Circle({
radius: 5,
stroke: new style.Stroke({
color: "rgba(0, 0, 0, 0.7)",
}),
fill: new style.Fill({
color: "rgba(255, 255, 255, 0.2)",
}),
}),
}),
});
draw.set(id, id)
createMeasureTooltip(); //创建测量工具提示框
createHelpTooltip(); //创建帮助提示框
map.addInteraction(draw);
let listener;
//绑定交互绘制工具开始绘制的事件
const drawstartHandle = (evt) => {
store.dispatch('gis/LOAD_IS_TOOLING', true)
sketch = evt.feature; //绘制的要素
let tooltipCoord = evt.coordinate;// 绘制的坐标
//绑定change事件,根据绘制几何类型得到测量长度值或面积值,并将其设置到测量工具提示框中显示
listener = sketch.getGeometry().on('change', function (evt) {
const geom = evt.target
let output;
if (geom.getType() === 'LineString') {
output = formatLength(geom);//长度值
tooltipCoord = geom.getLastCoordinate();//坐标
} else if (geom.getType() === 'Polygon') {
output = formatArea(geom);//面积值
tooltipCoord = geom.getInteriorPoint().getCoordinates();//坐标
} else if (geom.getType() === 'Circle') {
output = formatArea(geom, 'circle');//面积值
tooltipCoord = geom.getCenter()
}
drawTooltipElement.innerHTML = output;//将测量值设置到测量工具提示框中显示
measureTooltip.setPosition(tooltipCoord);//设置测量工具提示框的显示位置
});
}
draw.on('drawstart', drawstartHandle);
//绑定交互绘制工具结束绘制的事件
const copy = (value) => {
const str = document.createElement('input')
str.setAttribute('value', value)
document.body.appendChild(str)
str.select()
document.execCommand('copy')
document.body.removeChild(str)
}
const drawendHandle = (evt) => {
setTimeout(() => {
store.dispatch('gis/LOAD_IS_TOOLING', false)
}, 300)
map.removeInteraction(map.getInteractions().getArray().filter(v => v.get(id) === id)[0]);
// const del = document.createElement("div");
// del.className = "lineDel";
// drawTooltipElement.append(del);
// del.onclick = () => {
// _source.removeFeature(evt.feature)
// const b = del.parentElement.parentElement
// b.parentElement.removeChild(b);
// const g = evt.feature.getGeometry()
// if (g.getType() === 'LineString') {
// const w = `LINESTRING(${g.getCoordinates().map(v => v[0] + ' ' + v[1]).join(',')})`
// copy(w)
// } else if (g.getType() === 'Polygon') {
// const w = `POLYGON(${g.getCoordinates().map(v => '(' + v.map(c => c[0] + ' ' + c[1]) + ')').join(',')})`
// copy(w)
// }
// };
// drawTooltipElement.className = 'tooltip tooltip-static'; //设置测量提示框的样式
// measureTooltip.setOffset([0, -7]);
// 标绘的时候不需要最终结果dom
map.removeOverlay(map.getOverlayById('drawHelpTooltipElementId'))
drawTooltipElement.parentNode.removeChild(drawTooltipElement);
sketch = null; //置空当前绘制的要素对象
drawTooltipElement = null; //置空测量工具提示框对象
drawHelpTooltipElement.parentNode.removeChild(drawHelpTooltipElement);
drawHelpTooltipElement = null; //置空测量工具提示框对象
unByKey(listener);
draw.un('drawstart', drawstartHandle);
draw.un('drawend', drawendHandle);
map.removeInteraction(map.getInteractions().getArray().filter(v => v.get(id) === id)[0]);
map.un('pointermove', pointerMoveHandler)
if (oldDrawFeature) {
_source.removeFeature(oldDrawFeature)
}
oldDrawFeature = evt.feature
const gm = oldDrawFeature.getGeometry()
let wkt = ''
const gType = gm.getType()
if (gType === 'Polygon') {
wkt = formatPosition.cpnTwpn(gm.getCoordinates())
} else if (gType === 'LineString') {
wkt = formatPosition.clTwl(gm.getCoordinates())
} else if (gType === 'Circle') {
const circlePoly = fromCircle(gm, 128)
oldDrawFeature.setGeometry(circlePoly)
wkt = formatPosition.cpnTwpn(circlePoly.getCoordinates())
}
resolve({feature: oldDrawFeature, wkt: wkt})
}
draw.on('drawend', drawendHandle);
}
addInteraction(); //调用加载绘制交互控件方法,添加绘图进行测量
const pointerMoveHandler = (evt) => {
if (evt.dragging) {
return;
}
let helpMsg = '单击开始标绘';//当前默认提示信息
//判断绘制几何类型设置相应的帮助提示信息
if (sketch) {
const geom = sketch.getGeometry()
helpMsg = continueMsg;
// if (geom.getType() === 'Polygon') {
// helpMsg = continueMsg; //绘制多边形时提示相应内容
// } else if (geom.getType() === 'LineString') {
// helpMsg = continueMsg; //绘制线时提示相应内容
// }
}
drawHelpTooltipElement.innerHTML = helpMsg; //将提示信息设置到对话框中显示
helpTooltip.setPosition(evt.coordinate);//设置帮助提示框的位置
drawHelpTooltipElement.classList.remove('hidden');//移除帮助提示框的隐藏样式进行显示
};
map.on('pointermove', pointerMoveHandler); //地图容器绑定鼠标移动事件,动态显示帮助提示框内容
//地图绑定鼠标移出事件,鼠标移出时为帮助提示框设置隐藏样式
try {
map.getViewport().on('mouseout', () => {
drawHelpTooltipElement.addClass('hidden');
});
} catch (e) {
}
} else {
reject('正在标绘中,请勿重复操作!')
}
})
}
export const DrawClear = (map) => {
const realLayer = map.getLayers().getArray().filter(v => v.get(layerFlag[0]) === layerFlag[1])
if (realLayer[0]) {
realLayer[0].getSource().clear()
oldDrawFeature = null
}
}