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 } }