gmap-ol
Version:
A set of helper classes for working with openLayers.
269 lines (254 loc) • 7.78 kB
JavaScript
import Feature from 'ol/Feature';
import { Draw, Modify } from 'ol/interaction';
import { LineString, Point } from 'ol/geom';
import { Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';
import { getArea, getLength } from 'ol/sphere';
import { style, labelStyle, tipStyle, modifyStyle, segmentStyle, clearStyle } from './StyleConfig.js';
let globalMap = null;
let draw; // global so we can remove it later
let drawType = 'LineString'; // 测量类型: LineString, Polygon
let showSegments = true; // 显示段长度
let clearPrevious = true; // 清除先前的测量数据
const segmentStyles = [segmentStyle];
const source = new VectorSource();
let modify = new Modify({ source: source, style: modifyStyle });
let tipPoint;
// 初始调用一次,加载绘制图层。
let isFirst = true;
function onceFunction() {
if (isFirst) {
globalMap.addLayer(drawLayer);
globalMap.addLayer(clearLayer);
globalMap.addInteraction(modify);
isFirst = false;
}
}
/**
* 测量距离
*
* @param {import("ol/Map").default} map An OlMap.
*
* @return {number} The length of line in meters.
*/
export function measureLength(olmap, measureOption, measureCallbackFn) {
if (olmap === null || olmap === undefined) {
return; // 终止函数执行
}
globalMap = olmap;
drawType = 'LineString';
onceFunction();
if (draw) {
let drawInteraction;
olmap.getInteractions().forEach((interaction) => {
if (interaction instanceof Draw) {
drawInteraction = interaction;
}
});
// 从地图上移除该交互。
if (drawInteraction) {
olmap.removeInteraction(drawInteraction);
}
}
addInteractionFn(measureCallbackFn);
if (measureOption) {
showSegments = measureOption?.showSegments;
clearPrevious = measureOption?.clearPrevious;
}
}
/**
* 测量面积
*
* @param {import("ol/Map").default} map An OlMap.
*
* @return {number} The area of the polygon in square meter.
*/
export function measureArea(olmap, measureOption, measureCallbackFn) {
globalMap = olmap;
drawType = 'Polygon';
onceFunction();
if (draw) {
let drawInteraction;
olmap.getInteractions().forEach((interaction) => {
if (interaction instanceof Draw) {
drawInteraction = interaction;
}
});
// 从地图上移除该交互。
if (drawInteraction) {
olmap.removeInteraction(drawInteraction);
}
}
addInteractionFn(measureCallbackFn);
if (measureOption) {
showSegments = measureOption?.showSegments;
clearPrevious = measureOption?.clearPrevious;
}
}
/**
* 清除测量
*
* @param {import("ol/Map").default} map An OlMap.
*
* @return {number} The area of the polygon in square meter.
*/
export function clearMeasure() {
source.clear();
drawLayer.getSource().clear();
clearLayer.getSource().clear();
}
// 清除按钮
const clearLayer = new VectorLayer({
source: new VectorSource(),
zIndex: 1100,
});
// 绘制图层
const drawLayer = new VectorLayer({
source: new VectorSource(),
style: function (feature) {
return styleFunction(feature, showSegments);
},
zIndex: 1000,
});
const addInteractionFn = (measureCallbackFn) => {
const activeTip = '单击以继续绘制' + (drawType === 'Polygon' ? '多边形' : '线');
const idleTip = '点击开始测量';
let tip = idleTip;
draw = new Draw({
source: source,
type: drawType,
style: (feature) => {
return styleFunction(feature, showSegments, drawType, tip);
},
});
draw.on('drawstart', () => {
if (clearPrevious) {
clearMeasure();
}
modify.setActive(false);
tip = activeTip;
});
draw.on('drawend', (event) => {
drawLayer.getSource().addFeature(event.feature);
modifyStyle.setGeometry(tipPoint);
modify.setActive(true);
globalMap.once('pointermove', () => {
modifyStyle.setGeometry();
});
tip = idleTip;
// 结束绘制,清除draw
globalMap.once('dblclick', (event) => {
event.map.removeInteraction(draw);
});
globalMap.on('singleclick', (event) => {
const pixel = event.map.getEventPixel(event.originalEvent);
const feature = event.map.forEachFeatureAtPixel(pixel, (feature) => {
return feature.getProperties();
});
if (feature?.name === 'ClearPoint') {
clearMeasure();
}
});
globalMap.on('pointermove', (event) => {
const pixel = event.map.getEventPixel(event.originalEvent);
const feature = event.map.forEachFeatureAtPixel(pixel, (feature) => {
return feature.getProperties();
});
event.map.getTargetElement().style.cursor = 'auto';
if (feature?.name === 'ClearPoint') {
event.map.getTargetElement().style.cursor = 'pointer';
}
});
// 回调函数,返回测量的数据
setTimeout(() => {
const features = drawLayer.getSource().getFeatures();
const geometryData = features[features.length - 1].getGeometry();
let measure = '';
if (drawType === 'LineString') {
measure = formatLength(geometryData);
} else {
measure = formatArea(geometryData);
}
return measureCallbackFn ? measureCallbackFn(measure) : null;
}, 100);
});
modify.setActive(true);
globalMap.addInteraction(draw);
};
// 计算距离
const formatLength = (line) => {
let sourceProj = globalMap.getView().getProjection(); //获取投影坐标系
const length = getLength(line, { projection: sourceProj });
let output;
if (length > 100) {
output = Math.round((length / 1000) * 100) / 100 + ' km';
} else {
output = Math.round(length * 100) / 100 + ' m';
}
return output;
};
// 计算面积
const formatArea = (polygon) => {
let sourceProj = globalMap.getView().getProjection(); //获取投影坐标系
const area = getArea(polygon, { projection: sourceProj });
let output;
if (area > 10000) {
output = Math.round((area / 1000000) * 100) / 100 + ' km\xB2';
} else {
output = Math.round(area * 100) / 100 + ' m\xB2';
}
return output;
};
const styleFunction = (feature, segments, drawType, tip) => {
const styles = [style];
const geometry = feature.getGeometry();
const type = geometry.getType();
let point, label, line;
if (!drawType || drawType === type) {
if (type === 'Polygon') {
point = geometry.getInteriorPoint();
label = formatArea(geometry);
line = new LineString(geometry.getCoordinates()[0]);
} else if (type === 'LineString') {
point = new Point(geometry.getLastCoordinate());
label = formatLength(geometry);
line = geometry;
}
}
if (segments && line) {
let count = 0;
line.forEachSegment((a, b) => {
const segment = new LineString([a, b]);
const label = formatLength(segment);
if (segmentStyles.length - 1 < count) {
segmentStyles.push(segmentStyle.clone());
}
const segmentPoint = new Point(segment.getCoordinateAt(0.5));
segmentStyles[count].setGeometry(segmentPoint);
segmentStyles[count].getText().setText(label);
styles.push(segmentStyles[count]);
count++;
});
}
if (label) {
labelStyle.setGeometry(point);
labelStyle.getText().setText(label);
styles.push(labelStyle);
}
if (tip && type === 'Point' && !modify.getOverlay().getSource().getFeatures().length) {
tipPoint = geometry;
tipStyle.getText().setText(tip);
styles.push(tipStyle);
}
// 添加删除按钮
if (!drawType) {
clearLayer.getSource().clear();
const iconFeature = new Feature({
geometry: new Point(point.flatCoordinates),
name: 'ClearPoint',
});
iconFeature.setStyle(clearStyle);
clearLayer.getSource().addFeature(iconFeature);
}
return styles;
};