可变偏移标签放置
使用偏移量创建更灵活的标签放置;
<!DOCTYPE html>
<html lang="en">
<head>
<title>可变偏移标签放置</title>
<meta property="og:description" content="使用偏移量创建更灵活的标签放置" />
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.js'></script>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
.map-overlay {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 15px;
border-radius: 5px;
font-family: Arial, sans-serif;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);
max-width: 400px;
z-index: 100;
}
.map-overlay h3 {
margin: 0 0 10px 0;
font-size: 16px;
border-bottom: 1px solid #ddd;
padding-bottom: 5px;
}
.map-overlay p {
font-size: 13px;
line-height: 1.5;
margin: 0 0 8px 0;
color: #333;
}
.control-group {
margin: 12px 0;
}
.control-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
font-size: 12px;
color: #555;
}
input[type="range"] {
width: 100%;
margin: 0;
}
.control-display {
display: flex;
justify-content: space-between;
margin-top: 5px;
font-size: 11px;
color: #777;
}
.current-value {
display: block;
font-size: 14px;
font-weight: bold;
color: #3887be;
text-align: center;
margin-top: 5px;
}
.info-text {
font-size: 12px;
color: #666;
margin-top: 15px;
padding-top: 10px;
border-top: 1px solid #eee;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="map-overlay">
<h3>可变偏移标签放置</h3>
<p>调整滑块以更改地标标签偏移量。这种技术可用于创建自定义的标签放置方案,特别是当有多种类型的标记时。</p>
<div class="control-group">
<label>水平偏移</label>
<input type="range" id="horizontal-offset" min="-2" max="2" step="0.1" value="0">
<div class="control-display">
<span>左</span>
<span>右</span>
</div>
<div class="current-value">当前值: <span id="h-value">0</span></div>
</div>
<div class="control-group">
<label>垂直偏移</label>
<input type="range" id="vertical-offset" min="-2" max="2" step="0.1" value="0">
<div class="control-display">
<span>上</span>
<span>下</span>
</div>
<div class="current-value">当前值: <span id="v-value">0</span></div>
</div>
<div class="control-group">
<label>标签锚点位置</label>
<select id="text-anchor">
<option value="center">中心 (center)</option>
<option value="top">顶部 (top)</option>
<option value="bottom">底部 (bottom)</option>
<option value="left">左侧 (left)</option>
<option value="right">右侧 (right)</option>
<option value="top-left">左上 (top-left)</option>
<option value="top-right">右上 (top-right)</option>
<option value="bottom-left">左下 (bottom-left)</option>
<option value="bottom-right">右下 (bottom-right)</option>
</select>
</div>
<div class="info-text">
通过组合不同的锚点和偏移值,您可以实现几乎任何标签放置方案。这对于避免标签重叠或创建自定义地图样式非常有用。
</div>
</div>
<script>
// 初始化地图
const map = new maplibregl.Map({
container: 'map',
style: 'https://api.maptiler.com/maps/streets/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL',
center: [0, 30],
zoom: 2
});
// 添加导航控件
map.addControl(new maplibregl.NavigationControl());
// 获取控制元素
const hOffsetSlider = document.getElementById('horizontal-offset');
const vOffsetSlider = document.getElementById('vertical-offset');
const textAnchorSelect = document.getElementById('text-anchor');
const hValueDisplay = document.getElementById('h-value');
const vValueDisplay = document.getElementById('v-value');
let hOffset = 0;
let vOffset = 0;
let textAnchor = 'center';
map.on('load', () => {
// 添加一些示例点
const landmarks = [
{ name: '埃菲尔铁塔', coordinates: [2.2945, 48.8584] },
{ name: '自由女神像', coordinates: [-74.0445, 40.6892] },
{ name: '大本钟', coordinates: [-0.1246, 51.5007] },
{ name: '悉尼歌剧院', coordinates: [151.2153, -33.8568] },
{ name: '金字塔', coordinates: [31.1342, 29.9792] },
{ name: '泰姬陵', coordinates: [78.0422, 27.1751] },
{ name: '万里长城', coordinates: [116.5704, 40.4319] },
{ name: '佩特拉', coordinates: [35.4444, 30.3285] },
{ name: '马丘比丘', coordinates: [-72.5450, -13.1631] },
{ name: '科洛塞尔', coordinates: [12.4924, 41.8902] }
];
// 添加标记源
map.addSource('landmarks', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': landmarks.map(landmark => ({
'type': 'Feature',
'properties': {
'name': landmark.name
},
'geometry': {
'type': 'Point',
'coordinates': landmark.coordinates
}
}))
}
});
// 添加标记图层
map.addLayer({
'id': 'landmark-points',
'type': 'circle',
'source': 'landmarks',
'paint': {
'circle-radius': 8,
'circle-color': '#FF8C00',
'circle-stroke-width': 2,
'circle-stroke-color': 'white'
}
});
// 添加标签图层
map.addLayer({
'id': 'landmark-labels',
'type': 'symbol',
'source': 'landmarks',
'layout': {
'text-field': ['get', 'name'],
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
'text-size': 14,
'text-anchor': 'center',
'text-offset': [0, 0],
'text-variable-anchor': [
'center', 'top', 'bottom', 'left', 'right',
'top-left', 'top-right', 'bottom-left', 'bottom-right'
],
'text-justify': 'auto',
'text-radial-offset': 1,
'text-allow-overlap': false,
'text-ignore-placement': false
},
'paint': {
'text-color': '#333',
'text-halo-color': 'rgba(255, 255, 255, 0.9)',
'text-halo-width': 2
}
});
// 更新偏移量的函数
function updateOffset() {
map.setLayoutProperty('landmark-labels', 'text-offset', [hOffset, vOffset]);
map.setLayoutProperty('landmark-labels', 'text-anchor', textAnchor);
hValueDisplay.textContent = hOffset;
vValueDisplay.textContent = vOffset;
}
// 监听控制
hOffsetSlider.addEventListener('input', (e) => {
hOffset = parseFloat(e.target.value);
updateOffset();
});
vOffsetSlider.addEventListener('input', (e) => {
vOffset = parseFloat(e.target.value);
updateOffset();
});
textAnchorSelect.addEventListener('change', (e) => {
textAnchor = e.target.value;
updateOffset();
});
});
</script>
</body>
</html>