本人并不是专业前端,所以写的不太好,但是应该拿来就可以用,方便小白学习,或者使用,现在还是有一点bug,就是测角度的时候,应该绘制两条线的时候就停止,但是还没时间研究, 用的时候别忘评论下,哈哈
measure.js
/**
*
* openlayer3测距离和面积(按钮版)
*
*/
/**
*
* tooltips相关css (就是包裹长度或者面积的气泡的样式) (这里是备用,防止以后找不到,可以从这里复制)
*
*.tooltip {
* position: relative;
* background: rgba(0, 0, 0, 0.5);
* border-radius: 4px;
* color: white;
* padding: 4px 8px;
* opacity: 0.7;
* white-space: nowrap;
* }
* .tooltip-measure {
* opacity: 1;
* font-weight: bold;
* }
* .tooltip-static {
* background-color: #ffcc33;
* color: black;
* border: 1px solid white;
* }
* .tooltip-measure:before,
* .tooltip-static:before {
* border-top: 6px solid rgba(0, 0, 0, 0.5);
* border-right: 6px solid transparent;
* border-left: 6px solid transparent;
* content: "";
* position: absolute;
* bottom: -6px;
* margin-left: -7px;
* left: 50%;
* }
* .tooltip-static:before {
* border-top-color: #ffcc33;
* }
*
* <div class="btnGroup" style="position: absolute;top: 50px;">
* <button id="measure-length">测量距离</button>
* <button id="measure-area">测量面积</button>
* <button id="stop-measure">停止测量</button>
* <label class="checkbox">
* <input type="checkbox" id="geodesic">
* 使用大地测量
* </label>
* </div>
*
*/
var measurementTool = (function () {
//**************全局配置******************/
// 绘制时线的颜色
var The_color_of_the_draw_line = 'rgba(0, 0, 0, 0.5)'
// 绘制时线的宽度
var The_width_of_the_draw_line = 2
// 绘制时虚线的间隔
var The_dash_of_the_draw_line = [10, 10]
// 绘制时鼠标小圆球边框颜色
var The_Small_ball_border_color = 'rgba(0, 0, 0, 0.7)'
// 绘制时鼠标小圆球填充颜色
var The_Small_ball_fill_color = 'rgba(255, 255, 255, 0.2)'
// 绘制时区域填充颜色
var The_fill_color_of_the_draw_area = 'rgba(255, 255, 255, 0.2)'
// 绘制后的线的颜色
var The_color_of_the_drawn_line = '#ffff00'
// 绘制后的线的宽度
var The_width_of_the_drawn_line = 2
// 绘制后的区域的填充颜色
var The_fill_color_of_the_drawn_area = 'rgba(255, 255, 255, 0.2)'
//********************************/
var wgs84Sphere = new ol.Sphere(6378137)
// 瓦片图层
// var raster = new ol.layer.Tile({
// source: new ol.source.OSM()
// });
// 矢量图层的源
var source = new ol.source.Vector()
// 矢量图层
var vector = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
// color: 'rgba(255, 255, 255, 0.2)'
color: The_fill_color_of_the_drawn_area
}),
stroke: new ol.style.Stroke({
color: The_color_of_the_drawn_line,
width: The_width_of_the_drawn_line
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: The_color_of_the_drawn_line
})
})
})
})
/**
* 当前绘制的特征。
* @type {ol.Feature}
*/
var sketch
/**
* 帮助工具提示元素。
* @type {Element}
*/
var helpTooltipElement
/**
* 显示帮助信息的覆盖层。
* @type {ol.Overlay}
*/
var helpTooltip
/**
* 测量工具提示元素。
* @type {Element}
*/
var measureTooltipElement
/**
* 显示测量结果的覆盖层。
* @type {ol.Overlay}
*/
var measureTooltip
/**
* 用户绘制多边形时显示的信息。
* @type {string}
*/
var continuePolygonMsg = '点击继续绘制多边形'
/**
* 用户绘制线条时显示的信息。
* @type {string}
*/
var continueLineMsg = '点击继续绘制线条'
// 进行角度绘制时的显示的信息
var continueAngleMsg = '点击继续绘制角度'
// 是否在测量角度? 测量角度和测量角度时候因为都是在绘制线,所以这里用一个变量来控制
var isAngleMeasurement = false; // 初始化标志变量
/**
* 处理指针移动事件。
* @param {ol.MapBrowserEvent} evt 事件。
*/
var pointerMoveHandler = function (evt) {
if (evt.dragging) {
return
}
/** @type {string} */
var helpMsg = '点击开始绘制'
if (sketch) {
var geom = sketch.getGeometry()
if (geom instanceof ol.geom.Polygon) {
helpMsg = continuePolygonMsg
} else if (geom instanceof ol.geom.LineString) {
// 判断是否在测量角度
if (isAngleMeasurement) {
helpMsg = continueAngleMsg
}else {
helpMsg = continueLineMsg
}
}
}
helpTooltipElement.innerHTML = helpMsg
helpTooltip.setPosition(evt.coordinate)
helpTooltipElement.classList.remove('hidden')
}
// map.addLayer(vector);
var typeSelect = document.getElementById('type')
var geodesicCheckbox = document.getElementById('geodesic')
var draw // 全局变量,以便稍后可以删除它
/**
* 格式化长度输出。
* @param {ol.geom.LineString} line 线。
* @return {string} 格式化的长度。
*/
var formatLength = function (line) {
var length
if (geodesicCheckbox.checked) {
var coordinates = line.getCoordinates()
length = 0
var sourceProj = map.getView().getProjection()
for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326')
var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326')
length += wgs84Sphere.haversineDistance(c1, c2)
}
} else {
length = Math.round(line.getLength() * 100) / 100
}
//todo 在这里修改长度单位
var output
if (length > 100) {
output = Math.round((length / 1000) * 100) / 100 + ' ' + '千米' // 单位改为千米
} else {
output = Math.round(length * 100) / 100 + ' ' + '米' // 单位改为米
}
return output
}
/**
* 格式化面积输出。
* @param {ol.geom.Polygon} polygon 多边形。
* @return {string} 格式化的面积。
*/
var formatArea = function (polygon) {
var area
if (geodesicCheckbox.checked) {
var sourceProj = map.getView().getProjection()
var geom = /** @type {ol.geom.Polygon} */ (
polygon.clone().transform(sourceProj, 'EPSG:4326')
)
var coordinates = geom.getLinearRing(0).getCoordinates()
area = Math.abs(wgs84Sphere.geodesicArea(coordinates))
} else {
area = polygon.getArea()
}
//todo 在这里修改面积单位
var output
if (area > 10000) {
output = Math.round((area / 1000000) * 100) / 100 + ' ' + '平方千米' // 单位改为平方千米
} else {
output = Math.round(area * 100) / 100 + ' ' + '平方米' // 单位改为平方米
}
return output
}
// 格式化角度
var formatAngle = function (line) {
var coordinates = line.getCoordinates();
var angle = 0;
var sourceProj = map.getView().getProjection();
if (coordinates.length < 3) {
return "0度";
}
// 获取三个点的坐标
var c1 = ol.proj.transform(coordinates[coordinates.length - 3], sourceProj, 'EPSG:4326');
var c2 = ol.proj.transform(coordinates[coordinates.length - 2], sourceProj, 'EPSG:4326');
var c3 = ol.proj.transform(coordinates[coordinates.length - 1], sourceProj, 'EPSG:4326');
// 计算两边的距离
var disa = wgs84Sphere.haversineDistance(c1, c2);
var disb = wgs84Sphere.haversineDistance(c2, c3);
var disc = wgs84Sphere.haversineDistance(c1, c3);
// 计算角度(使用余弦定理)
if (disa !== 0 && disb !== 0) {
var cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb);
angle = Math.acos(cos) * 180 / Math.PI; // 转为度
angle = angle.toFixed(2) + " 度";
}
return angle; // 返回角度
};
function addInteraction(type) {
draw = new ol.interaction.Draw({
source: source,
type: type,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: The_fill_color_of_the_draw_area
}),
stroke: new ol.style.Stroke({
color: The_color_of_the_draw_line,
lineDash: The_dash_of_the_draw_line,
width: The_width_of_the_draw_line
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: The_Small_ball_border_color
}),
fill: new ol.style.Fill({
color: The_Small_ball_fill_color
})
})
})
});
map.addInteraction(draw)
createMeasureTooltip()
createHelpTooltip()
var listener
draw.on(
'drawstart',
function (evt) {
// 设置当前草图
sketch = evt.feature
/** @type {ol.Coordinate|undefined} */
var tooltipCoord = evt.coordinate
listener = sketch.getGeometry().on('change', function (evt) {
var geom = evt.target
var output
// console.log("位置" + geom.getLastCoordinate());
// console.log("组" + geom.getCoordinates()[1]);
if (geom instanceof ol.geom.Polygon) {
output = formatArea(geom)
tooltipCoord = geom.getInteriorPoint().getCoordinates()
}
else if (geom instanceof ol.geom.LineString) {
// 判断是否在测量角度
if (isAngleMeasurement) {
output = formatAngle(geom); // 调用测量角度函数
tooltipCoord = geom.getCoordinates()[1];//角度显示在第二个点的位置i
} else {
output = formatLength(geom); // 调用测量长度函数
tooltipCoord = geom.getLastCoordinate();//长度显示在最后一个点的位置
}
}
// else if (geom instanceof ol.geom.LineString) {
// console.log(geom);
// output = formatLength(geom)
// tooltipCoord = geom.getLastCoordinate()
// }else{
// output = formatAngle(geom)
// tooltipCoord = geom.getLastCoordinate()
// }
measureTooltipElement.innerHTML = output
measureTooltip.setPosition(tooltipCoord)
})
},
this
)
draw.on(
'drawend',
function () {
measureTooltipElement.className = 'tooltip tooltip-static'
measureTooltip.setOffset([0, -7])
// 取消草图
sketch = null
// 取消工具提示,以便可以创建新的
measureTooltipElement = null
createMeasureTooltip()
ol.Observable.unByKey(listener)
},
this
)
}
/**
* 创建新的帮助工具提示
*/
function createHelpTooltip() {
if (helpTooltipElement) {
helpTooltipElement.parentNode.removeChild(helpTooltipElement)
}
helpTooltipElement = document.createElement('div')
helpTooltipElement.className = 'tooltip hidden'
helpTooltip = new ol.Overlay({
element: helpTooltipElement,
offset: [15, 0],
positioning: 'center-left'
})
map.addOverlay(helpTooltip)
}
/**
* 创建新的测量工具提示
*/
function createMeasureTooltip() {
if (measureTooltipElement) {
measureTooltipElement.parentNode.removeChild(measureTooltipElement)
}
measureTooltipElement = document.createElement('div')
measureTooltipElement.className = 'tooltip tooltip-measure'
measureTooltip = new ol.Overlay({
element: measureTooltipElement,
offset: [0, -15],
positioning: 'bottom-center'
})
map.addOverlay(measureTooltip)
}
return {
init: function () {
map.addLayer(vector)
// 绑定测量距离按钮
document.getElementById('measure-length').onclick = function () {
map.removeInteraction(draw)
map.on('pointermove', pointerMoveHandler)
map.getViewport().addEventListener('mouseout', function () {
helpTooltipElement.classList.add('hidden')
})
isAngleMeasurement = false; // 清除标志变量
addInteraction('LineString')
}
// 绑定测量面积按钮
document.getElementById('measure-area').onclick = function () {
map.removeInteraction(draw)
map.on('pointermove', pointerMoveHandler)
map.getViewport().addEventListener('mouseout', function () {
helpTooltipElement.classList.add('hidden')
})
addInteraction('Polygon')
}
// 绑定测量角度按钮
document.getElementById('measure-angle').onclick = function () {
map.removeInteraction(draw)
map.on('pointermove', pointerMoveHandler)
map.getViewport().addEventListener('mouseout', function () {
helpTooltipElement.classList.add('hidden')
})
isAngleMeasurement = true; // 设置标志变量
addInteraction('LineString')
}
// 绑定停止测量按钮
document.getElementById('stop-measure').onclick = function () {
map.removeInteraction(draw)
// helpTooltipElement.classList.add('hidden')
// 移除鼠标移动事件监听器,防止 `helpTooltip` 继续显示
map.un('pointermove', pointerMoveHandler);
// 显式隐藏并移除 `helpTooltip`
if (helpTooltip) {
map.removeOverlay(helpTooltip);
helpTooltipElement = null;
helpTooltip = null;
}
}
}
}
})()
measurementTool.init()