feat: 新增测距和比例尺

This commit is contained in:
yarnom 2025-07-04 11:11:35 +08:00
parent a70852fdc9
commit 1336bb16e6

View File

@ -190,54 +190,6 @@
background: rgba(230, 230, 230, 0.6); background: rgba(230, 230, 230, 0.6);
} }
/* 比例尺样式 */
.map-scale {
position: absolute;
bottom: 20px;
left: 20px;
z-index: 1000;
background: rgba(255, 255, 255, 0.9);
padding: 8px 12px;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
font-size: 12px;
color: #333;
font-weight: bold;
border: 1px solid rgba(0, 0, 0, 0.1);
}
/* 测距工具样式 */
.measure-tooltip {
position: relative;
background: rgba(0, 0, 0, 0.8);
border-radius: 4px;
color: white;
padding: 4px 8px;
opacity: 0.8;
white-space: nowrap;
font-size: 12px;
}
.measure-tooltip-measure {
opacity: 1;
font-weight: bold;
}
.measure-tooltip-static {
background-color: #ffcc33;
color: black;
border: 1px solid white;
}
.help-tooltip {
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
}
.overview-stats { .overview-stats {
@ -416,6 +368,24 @@
padding: 2px 4px; padding: 2px 4px;
} }
} }
.ol-tooltip {
position: absolute;
background: rgba(255,255,255,0.8);
border-radius: 4px;
padding: 4px 8px;
border: 1px solid #d9d9d9;
color: #333;
font-size: 12px;
white-space: nowrap;
pointer-events: none;
z-index: 1001;
}
.ol-tooltip-static {
background: #ffcc33;
color: #222;
border: 1px solid #ffcc33;
}
</style> </style>
<script src="../js/ol.js"></script> <script src="../js/ol.js"></script>
@ -498,21 +468,20 @@
<div class="toolbar-item"> <div class="toolbar-item">
<select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()"> <select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()">
<option value="all" selected>全部设备</option> <option value="all">全部设备</option>
<option value="warning1">一般告警</option> <option value="warning1">一般告警</option>
<option value="warning2">严重告警</option> <option value="warning2" selected>严重告警</option>
</select> </select>
</div> </div>
<div class="toolbar-divider"></div> <div class="toolbar-divider"></div>
<div class="toolbar-item"> <div class="toolbar-item">
<select id="mapFeatures" class="toolbar-select" onchange="onMapFeaturesChange()"> <select id="displayOptions" class="toolbar-select" onchange="onDisplayOptionsChange()">
<option value="" selected>地图功能 ▼</option> <option value="both" selected>信息+集群</option>
<option value="toggle_labels">切换设备标签</option> <option value="device">仅设备信息</option>
<option value="toggle_cluster">切换设备集群</option> <option value="cluster">仅集群显示</option>
<option value="measure_distance">开始测距</option> <option value="none">隐藏标签</option>
<option value="clear_measure">清除测距</option>
</select> </select>
</div> </div>
@ -520,10 +489,15 @@
<span id="current-device-id-new" style="background: rgba(26, 160, 148, 0.1); padding: 4px 8px; border-radius: 4px; font-size: 12px; color: #1aa094; font-weight: bold;"></span> <span id="current-device-id-new" style="background: rgba(26, 160, 148, 0.1); padding: 4px 8px; border-radius: 4px; font-size: 12px; color: #1aa094; font-weight: bold;"></span>
<button class="toolbar-btn" onclick="clearDeviceSearch()" style="padding: 2px 6px; font-size: 11px;">清除</button> <button class="toolbar-btn" onclick="clearDeviceSearch()" style="padding: 2px 6px; font-size: 11px;">清除</button>
</div> </div>
<div class="toolbar-divider"></div>
<div class="toolbar-item">
<button class="toolbar-btn" id="measure-distance-btn" onclick="toggleMeasureDistance()">测距</button>
<button class="toolbar-btn" id="clear-measure-btn" onclick="clearMeasure()" style="margin-left:4px;">清除测距</button>
<span id="measure-result" style="margin-left:8px;color:#1aa094;font-size:12px;"></span>
</div>
</div> </div>
<!-- 比例尺 -->
<div id="map-scale" class="map-scale">比例尺 1:1000</div>
</div> </div>
</div> </div>
@ -541,7 +515,7 @@
var greenFeatures = []; var greenFeatures = [];
var orangeFeatures = []; var orangeFeatures = [];
var redFeatures = []; var redFeatures = [];
var marker_state = 1; // 1:all; 2:orange; 3:red var marker_state = 3; // 1:all; 2:orange; 3:red
var allFeatures = []; // 存储所有设备标记,用于搜索功能 var allFeatures = []; // 存储所有设备标记,用于搜索功能
var currentSearchedDevice = null; // 当前搜索的设备ID var currentSearchedDevice = null; // 当前搜索的设备ID
var myLocationFeature = null; // 存储"我的位置"标记 var myLocationFeature = null; // 存储"我的位置"标记
@ -552,16 +526,9 @@
var showCluster = true; var showCluster = true;
var minZoomForLabels = 4; var minZoomForLabels = 4;
var maxZoomForClustering = 8; var maxZoomForClustering = 8;
// 测距专用source和layer
// 测距相关变量
var measureSource; var measureSource;
var measureVector; var measureLayer;
var measureTooltipElement;
var measureTooltip;
var helpTooltipElement;
var helpTooltip;
var draw;
var measuring = false;
// 天地图 API 密钥fengyarnom@gmail.com // 天地图 API 密钥fengyarnom@gmail.com
var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac'; var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac';
@ -650,12 +617,38 @@
layers: [ layers: [
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}), }),
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}) })
] ]
@ -664,12 +657,38 @@
layers: [ layers: [
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}), }),
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}) })
] ]
@ -678,7 +697,20 @@
layers: [ layers: [
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图矢量图加载失败,已自动切换到高德矢量图');
layui.form.render('select');
}
};
}
}) })
}) })
] ]
@ -687,12 +719,38 @@
layers: [ layers: [
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}), }),
new ol.layer.Tile({ new ol.layer.Tile({
source: new ol.source.XYZ({ source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY url: 'https://t{0-7}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: function(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
// 天地图加载失败时切换到高德地图
var mapTypeSelect = document.getElementById('mapTypeSelect');
if(mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
}) })
}) })
] ]
@ -785,6 +843,28 @@
}) })
}); });
// 创建测距专用图层
measureSource = new ol.source.Vector();
measureLayer = new ol.layer.Vector({
source: measureSource,
style: new ol.style.Style({
fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }),
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }),
image: new ol.style.RegularShape({
points: 4,
radius: 8,
radius2: 0,
angle: Math.PI / 4,
stroke: new ol.style.Stroke({ color: '#ed8936', width: 2 })
})
})
});
map.addLayer(measureLayer);
// 添加比例尺控件
var scaleLineControl = new ol.control.ScaleLine();
map.addControl(scaleLineControl);
// 设置初始可见性状态 // 设置初始可见性状态
var initialZoom = map.getView().getZoom(); var initialZoom = map.getView().getZoom();
if (showCluster && initialZoom < maxZoomForClustering) { if (showCluster && initialZoom < maxZoomForClustering) {
@ -807,7 +887,6 @@
} }
} }
vectorLayer.changed(); vectorLayer.changed();
updateScale(); // 更新比例尺
}); });
map.on('click', function(evt) { map.on('click', function(evt) {
@ -845,7 +924,6 @@
addDeviceMarkers(); addDeviceMarkers();
myLocation(); myLocation();
startLocationUpdates(); startLocationUpdates();
updateScale(); // 初始化比例尺
} }
function switchMapType(mapType) { function switchMapType(mapType) {
@ -942,229 +1020,6 @@
// 新的地图功能事件处理
function onMapFeaturesChange() {
var selectElement = document.getElementById('mapFeatures');
var value = selectElement.value;
switch(value) {
case 'toggle_labels':
showDeviceId = !showDeviceId;
vectorLayer.changed();
break;
case 'toggle_cluster':
showCluster = !showCluster;
var zoom = map.getView().getZoom();
if (showCluster) {
if (zoom >= maxZoomForClustering) {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
} else {
clusterLayer.setVisible(true);
vectorLayer.setVisible(false);
}
} else {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
}
break;
case 'measure_distance':
startMeasuring();
break;
case 'clear_measure':
clearMeasurements();
break;
}
// 重置下拉框到默认状态
selectElement.value = '';
}
// 测距功能
function startMeasuring() {
if (measuring) return;
measuring = true;
// 创建测距图层
if (!measureSource) {
measureSource = new ol.source.Vector();
measureVector = new ol.layer.Vector({
source: measureSource,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
map.addLayer(measureVector);
}
// 创建绘制交互
draw = new ol.interaction.Draw({
source: measureSource,
type: 'LineString',
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.5)',
lineDash: [10, 10],
width: 2
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)'
}),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
})
})
})
});
map.addInteraction(draw);
createMeasureTooltip();
createHelpTooltip();
var listener;
draw.on('drawstart', function(evt) {
var sketch = evt.feature;
var tooltipCoord = evt.coordinate;
listener = sketch.getGeometry().on('change', function(evt) {
var geom = evt.target;
var output;
if (geom instanceof ol.geom.LineString) {
output = formatLength(geom);
tooltipCoord = geom.getLastCoordinate();
}
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(tooltipCoord);
});
});
draw.on('drawend', function() {
measureTooltipElement.className = 'measure-tooltip measure-tooltip-static';
measureTooltip.setOffset([0, -7]);
measureTooltipElement = null;
createMeasureTooltip();
ol.Observable.unByKey(listener);
// 结束测距
map.removeInteraction(draw);
measuring = false;
// 移除帮助提示
if (helpTooltip) {
map.removeOverlay(helpTooltip);
helpTooltip = null;
helpTooltipElement = null;
}
});
}
function clearMeasurements() {
if (measureSource) {
measureSource.clear();
}
if (draw) {
map.removeInteraction(draw);
draw = null;
}
measuring = false;
// 清除所有测距相关的覆盖物
var overlays = map.getOverlays().getArray().slice();
overlays.forEach(function(overlay) {
if (overlay.getElement() &&
(overlay.getElement().classList.contains('measure-tooltip') ||
overlay.getElement().classList.contains('help-tooltip'))) {
map.removeOverlay(overlay);
}
});
measureTooltip = null;
measureTooltipElement = null;
helpTooltip = null;
helpTooltipElement = null;
}
function createMeasureTooltip() {
if (measureTooltipElement) {
measureTooltipElement.parentNode.removeChild(measureTooltipElement);
}
measureTooltipElement = document.createElement('div');
measureTooltipElement.className = 'measure-tooltip measure-tooltip-measure';
measureTooltip = new ol.Overlay({
element: measureTooltipElement,
offset: [0, -15],
positioning: 'bottom-center'
});
map.addOverlay(measureTooltip);
}
function createHelpTooltip() {
if (helpTooltipElement) {
helpTooltipElement.parentNode.removeChild(helpTooltipElement);
}
helpTooltipElement = document.createElement('div');
helpTooltipElement.className = 'measure-tooltip help-tooltip';
helpTooltipElement.innerHTML = '点击开始测距,双击结束';
helpTooltip = new ol.Overlay({
element: helpTooltipElement,
offset: [15, 0],
positioning: 'center-left'
});
map.addOverlay(helpTooltip);
}
function formatLength(line) {
var length = ol.Sphere.getLength(line);
var output;
if (length > 100) {
output = (Math.round(length / 1000 * 100) / 100) + ' km';
} else {
output = (Math.round(length * 100) / 100) + ' m';
}
return output;
}
// 比例尺更新功能
function updateScale() {
var view = map.getView();
var resolution = view.getResolution();
var units = view.getProjection().getUnits();
var dpi = 25.4 / 0.28;
var mpu = ol.proj.METERS_PER_UNIT[units];
var scale = resolution * mpu * 39.37 * dpi;
if (scale >= 9500 && scale <= 950000) {
scale = Math.round(scale / 1000) * 1000;
} else if (scale >= 950000) {
scale = Math.round(scale / 100000) * 100000;
} else {
scale = Math.round(scale);
}
document.getElementById('map-scale').textContent = '比例尺 1:' + scale.toLocaleString();
}
function onMapTypeChange() { function onMapTypeChange() {
var mapType = document.getElementById('mapTypeSelectNew').value; var mapType = document.getElementById('mapTypeSelectNew').value;
switchMapType(mapType); switchMapType(mapType);
@ -1227,7 +1082,7 @@
navigator.geolocation.getCurrentPosition(function(position) { navigator.geolocation.getCurrentPosition(function(position) {
var lon = position.coords.longitude; var lon = position.coords.longitude;
var lat = position.coords.latitude; var lat = position.coords.latitude;
var currentMapType = document.getElementById('mapTypeSelectNew').value; var currentMapType = document.getElementById('mapTypeSelect').value;
var coordinates; var coordinates;
if (currentMapType === 'amap' || currentMapType === 'amap_satellite') { if (currentMapType === 'amap' || currentMapType === 'amap_satellite') {
@ -1435,10 +1290,17 @@
currentSearchedDevice = deviceId; currentSearchedDevice = deviceId;
filterByDeviceId(deviceId); filterByDeviceId(deviceId);
var layerIndex = layer.index; var layerIndex = layer.open({
layer.close(layerIndex); title: '',
type: 2,
layer.msg('已定位到设备: ' + deviceId); shade: 0.2,
maxmin: true,
shadeClose: true,
anim: 2,
offset: 'rb',
area: ['100%', '50%'],
content: '../page/gnss_q_status?query=' + deviceId,
});
} }
function updateFilterButtonsState(state) { function updateFilterButtonsState(state) {
@ -1585,6 +1447,168 @@
showWarning2(); showWarning2();
} }
} }
function onDisplayOptionsChange() {
var optionValue = document.getElementById('displayOptions').value;
switch(optionValue) {
case 'both':
showDeviceId = true;
showCluster = true;
break;
case 'device':
showDeviceId = true;
showCluster = false;
break;
case 'cluster':
showDeviceId = false;
showCluster = true;
break;
case 'none':
showDeviceId = false;
showCluster = false;
break;
}
// 更新图层可见性
var zoom = map.getView().getZoom();
if (showCluster) {
if (zoom >= maxZoomForClustering) {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
} else {
clusterLayer.setVisible(true);
vectorLayer.setVisible(false);
}
} else {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
}
// 强制更新样式
vectorLayer.changed();
}
// --- 测距相关变量 ---
var measureActive = false;
var measureDraw; // 当前测距交互
var measureTooltipElement;
var measureTooltip;
var measureTooltips = []; // 存储所有测距点的overlay
function toggleMeasureDistance() {
if (measureActive) {
deactivateMeasure();
} else {
activateMeasure();
}
}
function activateMeasure() {
measureSource.clear();
clearAllMeasureTooltips();
measureActive = true;
document.getElementById('measure-distance-btn').style.background = '#ed8936';
// 创建测距交互
measureDraw = new ol.interaction.Draw({
source: measureSource,
type: 'LineString',
style: new ol.style.Style({
fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }),
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }),
image: new ol.style.RegularShape({
points: 4,
radius: 8,
radius2: 0,
angle: Math.PI / 4,
stroke: new ol.style.Stroke({ color: '#ed8936', width: 2 })
})
})
});
map.addInteraction(measureDraw);
var sketch;
var listener;
measureDraw.on('drawstart', function(evt) {
sketch = evt.feature;
var coords = sketch.getGeometry().getCoordinates();
// 第一个点
addMeasureTooltip(coords[0], '0 m');
listener = sketch.getGeometry().on('change', function(e) {
var geom = e.target;
var coords = geom.getCoordinates();
clearAllMeasureTooltips();
var total = 0;
for (var i = 0; i < coords.length; i++) {
if (i === 0) {
addMeasureTooltip(coords[0], '0 m');
} else {
var seg = new ol.geom.LineString([coords[i-1], coords[i]]);
total += ol.sphere.getLength(seg);
var output = (total > 100 ? (Math.round(total / 100) / 10) + ' km' : (Math.round(total * 10) / 10) + ' m');
addMeasureTooltip(coords[i], output, i === coords.length-1);
}
}
});
});
measureDraw.on('drawend', function(evt) {
// 终点的tooltip样式特殊
if (measureTooltips.length > 0) {
var last = measureTooltips[measureTooltips.length-1];
last.getElement().className = 'ol-tooltip ol-tooltip-static';
}
ol.Observable.unByKey(listener);
measureDraw = null;
measureActive = false;
document.getElementById('measure-distance-btn').style.background = '';
});
}
function deactivateMeasure() {
measureActive = false;
document.getElementById('measure-distance-btn').style.background = '';
if (measureDraw) {
map.removeInteraction(measureDraw);
measureDraw = null;
}
if (measureTooltipElement) {
measureTooltipElement.parentNode.removeChild(measureTooltipElement);
measureTooltipElement = null;
}
document.getElementById('measure-result').innerHTML = '';
measureSource.clear();
clearAllMeasureTooltips();
}
// 添加测距tooltip
function addMeasureTooltip(coord, text, isLast) {
var elem = document.createElement('div');
elem.className = isLast ? 'ol-tooltip ol-tooltip-static' : 'ol-tooltip ol-tooltip-measure';
elem.innerHTML = text;
var overlay = new ol.Overlay({
element: elem,
offset: [0, -15],
positioning: 'bottom-center'
});
overlay.setPosition(coord);
map.addOverlay(overlay);
measureTooltips.push(overlay);
}
// 清除所有测距tooltip
function clearAllMeasureTooltips() {
for (var i = 0; i < measureTooltips.length; i++) {
map.removeOverlay(measureTooltips[i]);
}
measureTooltips = [];
}
// 清除测距按钮
function clearMeasure() {
measureSource.clear();
clearAllMeasureTooltips();
document.getElementById('measure-result').innerHTML = '';
}
</script> </script>
</body> </body>