123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- 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 * 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 {locationTooltipElement} from "@/components/easyMap/func/location";
- import {v4} from "uuid";
- import store from "@/store";
- const layerFlag = ['layerName', 'measureLayer']
- let measureTooltipElement;
- let helpTooltipElement;
- let helpTooltipMap = new Map()
- let measureTooltipMap = new Map()
- let dom: any = []
- const typeMapper = new Map([
- ['line', 'LineString'],
- ['rectangle', 'LineString'],
- ['polygon', 'Polygon'],
- ['circle', 'Circle'],
- ])
- /**
- *
- * @param map
- * @param typeSelect line线,rectangle矩形,polygon多边形,circle圆形
- */
- export default function Measure (map, typeSelect) {
- if (!measureTooltipElement && !store.state.gis.isTooling) {
- store.dispatch('gis/LOAD_IS_TOOLING', true)
- 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(255, 255, 255, 0.2)' //填充颜色
- }),
- stroke: new style.Stroke({
- color: '#f31a4a', //边框颜色
- width: 2 // 边框宽度
- }),
- image: new style.Circle({
- radius: 7,
- fill: new style.Fill({
- color: '#ffcc33'
- })
- })
- })
- });
- _vector.set(layerFlag[0], layerFlag[1])
- map.addLayer(_vector);
- }
- let sketch;
- const uuid = v4()
- let helpTooltip;
- let measureTooltip;
- let continueMsg = '双击结束测量';
- const geodesicCheckbox = true;//测地学方式对象
- const createMeasureTooltip = () => {
- const id = 'measureTooltipElementId'
- if (measureTooltipElement) {
- map.removeOverlay(map.getOverlayById(id))
- measureTooltipElement.parentNode.removeChild(measureTooltipElement);
- }
- measureTooltipElement = document.createElement('div');
- measureTooltipElement.className = 'tooltip tooltip-measure';
- measureTooltip = new ol.Overlay({
- id,
- element: measureTooltipElement,
- offset: [0, -15],
- positioning: 'bottom-center'
- });
- map.addOverlay(measureTooltip);
- measureTooltipMap.set(uuid, measureTooltip)
- }
- const createHelpTooltip = () => {
- const id = 'helpTooltipElementId'
- if (helpTooltipElement) {
- map.removeOverlay(map.getOverlayById(id))
- helpTooltipElement.parentNode.removeChild(helpTooltipElement);
- }
- helpTooltipElement = document.createElement('div');
- helpTooltipElement.className = 'tooltip hidden';
- helpTooltip = new ol.Overlay({
- id,
- element: helpTooltipElement,
- offset: [15, 0],
- positioning: 'center-left'
- });
- map.addOverlay(helpTooltip);
- helpTooltipMap.set(uuid, 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} 千米 <br>${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} 平方公里<br>${parseFloat(String(km * 0.38610)).toFixed(
- 2
- )} 平方英里`;
- } else {
- output = `${Math.round(area * 100) / 100} ` + " m<sup>2</sup>";
- }
- return output;
- };
- const addInteraction = () => {
- const id = 'measureName'
- 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(255, 255, 255, 0.2)",
- }),
- stroke: new style.Stroke({
- color: "#f3584a",
- width: 2,
- }),
- 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.commit('gis/SET_IS_DRAWING', 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()
- }
- measureTooltipElement.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.commit('gis/SET_IS_DRAWING', false)
- }, 300)
- map.removeInteraction(map.getInteractions().getArray().filter(v => v.get(id) === id)[0]);
- const del: any = document.createElement("div");
- del.className = "lineDel";
- measureTooltipElement.append(del);
- dom.push(del.parentElement.parentElement)
- 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)
- }
- };
- measureTooltipElement.className = 'tooltip tooltip-static'; //设置测量提示框的样式
- measureTooltip.setOffset([0, -7]);
- sketch = null; //置空当前绘制的要素对象
- measureTooltipElement = null; //置空测量工具提示框对象
- helpTooltipElement.parentNode.removeChild(helpTooltipElement);
- helpTooltipElement = 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)
- store.dispatch('gis/LOAD_IS_TOOLING', false)
- }
- 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; //绘制线时提示相应内容
- // }
- }
- helpTooltipElement.innerHTML = helpMsg; //将提示信息设置到对话框中显示
- helpTooltip.setPosition(evt.coordinate);//设置帮助提示框的位置
- helpTooltipElement.classList.remove('hidden');//移除帮助提示框的隐藏样式进行显示
- };
- map.on('pointermove', pointerMoveHandler); //地图容器绑定鼠标移动事件,动态显示帮助提示框内容
- //地图绑定鼠标移出事件,鼠标移出时为帮助提示框设置隐藏样式
- // map.getViewport().on('mouseout', () => {
- // helpTooltipElement.addClass('hidden');
- // });
- }
- }
- export const clearMeasureDom = (map) => {
- if (measureTooltipElement) {
- measureTooltipElement.parentNode.removeChild(measureTooltipElement);
- measureTooltipElement = null
- }
- if (helpTooltipElement) {
- helpTooltipElement.parentNode.removeChild(helpTooltipElement);
- helpTooltipElement = null
- }
- measureTooltipMap.forEach((v, k) => {
- map.removeOverlay(v)
- })
- helpTooltipMap.forEach((v, k) => {
- map.removeOverlay(v)
- })
- dom.forEach(v => {
- v?.parentElement?.removeChild(v)
- })
- }
|