符号图层(SymbolLayer)
用来加载点位信息,可设置icon以及text等属性,另还可实现点聚合功能,功能丰富。一般情况下,地图打点应该使用此图层。
非聚合示例
Selected Element Information:
lng: lat:
properties:{}
示例源码
vue
<template>
<div style="height: 500px">
<div style="height: 400px">
<mb-map
:zoom="mapZoom"
:center="mapCenter"
:glyphs="__RESOURCE_URL__ + 'fonts/{range}.pbf'"
:sprite="__RESOURCE_URL__ + 'sprites/sprite'"
@created="mapCreatedHandler"
>
<mb-tianditu-layer :types="['vec']" />
<mb-symbol-layer
:data="symbolDataSource"
text-field="label"
icon-image-field="icon"
text-halo-color="#9e9e9e"
:text-halo-width="1"
:text-offset="[0, -1]"
:cluster="false"
@mousemove="clickLayerHandler"
@mouseleave="leaveLayerHandler"
/>
</mb-map>
</div>
<div style="height: 60px; margin: 10px 10px">
<p>Selected Element Information:</p>
<p class="text-muted">lng:{{ lng }} lat:{{ lat }}</p>
<p class="text-muted">properties:{{ JSON.stringify(properties) }}</p>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import type { Map } from 'mapbox-gl'
const symbolDataSource = ref([])
const lng = ref('')
const lat = ref('')
const properties = ref<Record<string, any>>({})
const mapCenter = [107.5, 37.5]
const mapZoom = 3.5
function getRandomArbitrary(min: number, max: number) {
return Math.random() * (max - min) + min
}
const mapCreatedHandler = (map: Map) => {
map.rotateTo(180, { duration: 10000 })
}
const clickLayerHandler = (payload) => {
lng.value = payload.coordinates[0]
lat.value = payload.coordinates[1]
properties.value = payload.properties
}
const leaveLayerHandler = () => {
lng.value = ''
lat.value = ''
properties.value = {}
}
onMounted(() => {
const data = []
for (let i = 0; i < 2000; i++) {
data.push({
coordinates: [getRandomArbitrary(95, 120), getRandomArbitrary(30, 42)],
properties: {
label: `Airport-${i}`,
icon: 'airport-15',
},
})
}
symbolDataSource.value = data
})
</script>
聚合示例
示例源码
vue
<template>
<div style="height: 400px" class="vw-full vh-full">
<mb-map
:zoom="4"
:center="[107.5, 37.5]"
:glyphs="__RESOURCE_URL__ + 'fonts/{range}.pbf'"
:sprite="__RESOURCE_URL__ + 'sprites/sprite'"
>
<mb-tianditu-layer :types="['vec']" />
<mb-symbol-layer
:data="symbolDataSource"
text-field="label"
icon-image-field="icon"
:text-offset="[0, -1]"
:cluster="true"
:spiderify="true"
/>
</mb-map>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
const symbolDataSource = ref([])
function getRandomArbitrary(min: number, max: number) {
return Math.random() * (max - min) + min
}
onMounted(() => {
const data = []
for (let i = 0; i < 2000; i++) {
data.push({
coordinates: [getRandomArbitrary(95, 120), getRandomArbitrary(30, 42)],
properties: {
label: `Airport-${i}`,
icon: 'airport-15',
},
})
}
for (let i = 0; i < 13; i++) {
data.push({
coordinates: [116.678, 31.456],
properties: {
label: `same-${i}`,
icon: 'airport-15',
},
})
}
symbolDataSource.value = data
})
</script>
点避让示例
放大地图,在聚合点不能在散开以后,可以点击聚合点,聚合的点将以某个形状散开。
效果图
示例源码
vue
<template>
<div style="height: 400px" class="vw-full vh-full">
<mb-map
:zoom="5"
:center="[116.678, 31.456]"
:glyphs="__RESOURCE_URL__ + 'fonts/{range}.pbf'"
:sprite="__RESOURCE_URL__ + 'sprites/sprite'"
>
<mb-tianditu-layer :types="['vec']" />
<mb-image-loader :images="images" />
<mb-symbol-layer
:data="symbolDataSource"
text-field="label"
icon-image-field="icon"
:cluster-icons="clusterIcons"
:cluster-icon-size="0.5"
:cluster-icon-offset="[1, 5]"
:cluster="true"
:spiderify="true"
/>
<mb-symbol-layer
:data="symbolDataSource2"
text-field="label"
icon-image-field="icon"
:cluster-icons="clusterIcons2"
:cluster-icon-size="0.5"
:cluster-icon-offset="[1, 45]"
:cluster="true"
:spiderify="true"
/>
</mb-map>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
const images = [
{
name: 'cluster-icon',
type: 'link',
url: `${__RESOURCE_URL__}images/common_toget.png`,
},
{
name: 'cluster-icon2',
type: 'link',
url: `${__RESOURCE_URL__}images/eme_team_soc_toget.png`,
},
]
const clusterIcons = [
{
textColor: 'white',
textSize: 12,
iconName: 'cluster-icon',
},
]
const clusterIcons2 = [
{
textColor: 'white',
textSize: 16,
iconName: 'cluster-icon2',
},
]
const symbolDataSource = ref([])
const symbolDataSource2 = ref([])
onMounted(() => {
const data = [],
data2 = []
for (let i = 0; i < 13; i++) {
data.push({
coordinates: [116.678, 31.456],
properties: {
label: `same-${i}`,
icon: 'airport-15',
},
})
data2.push({
coordinates: [113.788, 31.956],
properties: {
label: `same2-${i}`,
icon: 'airport-15',
},
})
}
for (let i = 0; i < 5; i++) {
data.push({
coordinates: [116.688, 31.456],
properties: {
label: `same-2-${i}`,
icon: 'airport-15',
},
})
data2.push({
coordinates: [113.798, 31.956],
properties: {
label: `same-2-${i}`,
icon: 'airport-15',
},
})
}
symbolDataSource.value = data
symbolDataSource2.value = data2
})
</script>
动画示例
示例源码
vue
<template>
<div style="height: 400px" class="vw-full vh-full">
<mb-map
:zoom="11"
:center="[116.32, 39.9]"
:glyphs="__RESOURCE_URL__ + 'fonts/{range}.pbf'"
:sprite="__RESOURCE_URL__ + 'sprites/sprite'"
>
<div style="position: absolute; top: 5px; left: 5px">
<button class="primary" @click="start">Restart</button>
</div>
<mb-tianditu-layer :types="['vec']" />
<mb-image-loader :images="images" />
<mb-polyline-layer :data="polylineCoordinates" :width="3" color="blue" />
<mb-symbol-layer
:data="symbolDataSource"
icon-image-field="icon"
icon-anchor="center"
:icon-size="0.5"
icon-rotation-alignment="map"
icon-allow-overlap
:icon-rotate="['get', 'bearing']"
icon-ignore-placement
/>
</mb-map>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import * as turf from '@turf/turf'
const images = [
{
name: 'cluster-icon',
type: 'link',
url: `${__RESOURCE_URL__}images/common_toget.png`,
},
{
name: 'cluster-icon2',
type: 'link',
url: `${__RESOURCE_URL__}images/eme_team_soc_toget.png`,
},
]
let counter = 0
const steps = 9
const polylineCoordinates = [
{
coordinates: [
[116.28, 39.91],
[116.29, 39.91],
[116.32, 39.92],
[116.33, 39.91],
[116.32, 39.9],
[116.32, 39.89],
[116.3, 39.89],
[116.29, 39.89],
[116.27, 39.9],
],
},
]
const symbolDataSource = ref([
{
coordinates: [116.28, 39.91],
properties: {
label: ``,
icon: 'cluster-icon',
iconSize: 0.5,
bearing: 0,
},
},
])
const start = () => {
counter = 0
animate()
}
const animate = () => {
const start =
polylineCoordinates[0].coordinates[counter >= steps ? counter - 1 : counter]
const end =
polylineCoordinates[0].coordinates[counter >= steps ? counter : counter + 1]
if (!start || !end || counter > steps) {
counter = 0
return
}
// Update point geometry to a new position based on counter denoting
// the index to access the arc
symbolDataSource.value[0].coordinates =
polylineCoordinates[0].coordinates[counter]
// Calculate the bearing to ensure the icon is rotated to match the route arc
// The bearing is calculated between the current point and the next point, except
// at the end of the arc, which uses the previous point and the current point
symbolDataSource.value[0].properties.bearing = turf.bearing(
turf.point(start),
turf.point(end)
)
// Request the next frame of animation as long as the end has not been reached
if (counter < steps) {
// requestAnimationFrame(this.animate);
window.setTimeout(animate, 1500)
}
counter++
}
</script>
Popup示例
示例源码
vue
<template>
<div style="height: 400px">
<mb-map
:zoom="mapZoom"
:center="mapCenter"
:glyphs="__RESOURCE_URL__ + 'fonts/{range}.pbf'"
:sprite="__RESOURCE_URL__ + 'sprites/sprite'"
@created="mapCreatedHandler"
>
<mb-tianditu-layer :types="['vec']" />
<mb-symbol-layer
:data="symbolDataSource"
icon-image-field="icon"
:cluster="false"
/>
<mb-map-popup
v-for="s in symbolDataSource"
:key="s.properties.id"
:coordinates="s.coordinates"
:offset="[0, -10]"
:show-tip="false"
anchor="bottom"
>
<div
style="
padding: 4px;
background-color: white;
box-shadow: 10px 5px 10px grey;
"
>
{{ s.properties.label }}
</div>
</mb-map-popup>
</mb-map>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import type { Map } from 'mapbox-gl'
const symbolDataSource = ref([])
const mapCenter = [107.5, 37.5]
const mapZoom = 3.5
function getRandomArbitrary(min: number, max: number) {
return Math.random() * (max - min) + min
}
const mapCreatedHandler = (map: Map) => {
map.rotateTo(180, { duration: 10000 })
}
onMounted(() => {
const data = []
for (let i = 0; i < 10; i++) {
data.push({
coordinates: [getRandomArbitrary(95, 120), getRandomArbitrary(30, 42)],
properties: {
id: String(Math.random()),
label: `Airport-${i}`,
icon: 'airport-15',
},
})
}
symbolDataSource.value = data
})
</script>
API
PROPS
名称 | 描述 | 类型 | 默认值 |
---|---|---|---|
id | 图层id | string | - |
cluster | 是否聚合 | boolean | false |
cluster-icons | 聚合图层图标配置信息 | IndexAny[] | 见示例说明 |
cluster-max-zoom | 聚合效果可用的最大缩放级别 | number | 14 |
cluster-min-points | 聚合效果最小聚合点数 | number | 2 |
cluster-radius | 聚合半径,单位像素 | number | 50 |
cluster-icon-size | Icon放大倍数 | number | 1 |
cluster-icon-translate | Icon锚点平移量,正方向为右/下 | number[] | [0,0] |
cluster-icon-offset | Icon与其锚点的距离 正向为右/下 | number[] | [0,0] |
cluster-icon-anchor | Icon锚点位置 | string | center |
data | 矢量图层的数据 数组中每个对象需包含必需的coordinates属性以及可选的properties属性 每一个对象代表一个点/一条线/一个多边形 | SymbolLayerData | - |
geo-json-data-source | geojson数据源,可设为geojson数据链接或geojson数据对象;规范链接, 若设置了本属性,则data属性失效 | string / GeoJSONSource | - |
icon-allow-overlap | 是否允许重叠 | boolean | false |
icon-anchor | 锚点位置 | string("center", "left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right") | center |
icon-color | 图标颜色,仅在sdf icons生效 | string | #000000 |
icon-image | Icon资源,预加载好的图片名 | string / AnyArr | - |
ico-image-field | Icon图片字段名,将从dataSource properties中读取 覆盖iconImage属性 | string | - |
icon-offset | Icon与其锚点的距离 正向为右/下 | number[] | [0,0] |
icon-opacity | Icon透明度 | number | 1 |
icon-optional | 若为true,则icon与其他icon产生碰撞但Text未碰撞时,将只显示text | boolean | false |
icon-rotate | Icon旋转角度 | number | 0 |
icon-rotation-alignment | - | string | auto |
icon-ignore-placement | - | boolean | false |
icon-size | 图标放大倍数 | number | 1 |
icon-translate | 锚点平移量,正方向为右/下 | number[] | [0,0] |
maxzoom | 最大缩放级别 | number | 22 |
minzoom | 最小缩放级别 | number | 0 |
pickable | 图层是否响应拾取事件,若为false,则组件不会emit鼠标相关事件 | boolean | true |
show | 是否显示 | boolean | true |
source-id | 图层Source的id,若设置了本ID,则geoJsonDataSource与data属性都会失效 | string | - |
source-layer-name | 源数据中图层名称 设置sourceId时,此属性生效 | string | - |
text | 文本值,仅在textFiled未指定时生效 | string | - |
text-allow-overlap | 是否允许重叠 | boolean | false |
text-anchor | 锚定位置 | string("center", "left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right") | center |
text-color | 字体颜色 | string | #000000 |
text-field | 文本字段值/键值,将从dataSource properties中取值 | string | - |
text-font | 文字字体 Open Sans SemiBold | array | ["Open Sans SemiBold"] |
text-halo-blur | 文本边框炫光效果,以像素为单位 | number | 0 |
text-halo-color | 文本边框颜色 | string | rgba(0, 0, 0, 0) |
text-halo-width | 文本边框宽度,像素为单位 | number | 0 |
text-letter-spacing | 文字间距 em为单位 | number | 0 |
text-line-height | em为单位 | number | 1.2 |
text-max-width | em为单位 | number | 10 |
text-offset | text与其锚点的距离 正向为右/下 px | number[] | [0,0] |
text-opacity | 字体透明度 | number | 1 |
text-optional | 若为true,则text与其他text产生碰撞但icon未碰撞时,将只显示icon | boolean | false |
text-size | 文本字号大小,单位px | number | 16 |
text-translate | 锚点平移量,正方向为右/下 px | number[] | [0,0] |
text-padding | 文字间距 | number | 2 |
spiderify | 具有相同经纬度点是否可以展开 | boolean | false |
max-leafes-tospiderify | 最大展开数量 | number | 50 |
distance-between-spider-points | 展开点间距 | number | 50 |
spider-leg-color | 展开点线颜色 | string | #B6CBED |
spider-leg-width | 展开点线宽度 | number | 3 |
compare-precision | 聚合点比较相等时的小数位数,大于comparePrecision位的小数会被截掉 | number | 5 |
cluster-spiral-points | 聚合点形展开形式,大于是螺旋形,小于等于是圆形 | number | 10 |
TIP
clusterIcons
可以设置 iconName
使用 ImageLoader
中加载的图片。也可以设置functionName
,functionProps
属性,使用ImageLoader
中内置自定义的图形,内置函数可参考ImageLoader
中详细介绍。也支持functionName
为自定义函数,参考ImageLoader
中的functionName
方法。
默认值为:
js
[
{
count: 50,
textColor: "black",
textSize: 12,
functionName: "drawDynamicCircle",
functionProps: {
color: "#68B8EE",
radius: 50,
},
},
{
count: 100,
textColor: "black",
textSize: 14,
functionName: "drawDynamicCircle",
functionProps: {
color: "#B1E345",
radius: 75,
},
},
{
count: 200,
textColor: "white",
textSize: 18,
functionName: "drawDynamicCircle",
functionProps: {
color: "#F7DC00",
radius: 100,
},
},
{
count: 500,
textColor: "white",
textSize: 20,
functionName: "drawDynamicCircle",
functionProps: {
color: "#FA9800",
radius: 125,
},
},
{
textColor: "white",
textSize: 22,
functionName: "drawDynamicCircle",
functionProps: {
radius: 150,
color: "#F34A4A",
},
},
]
EVENTS
名称 | 描述 | 参数 |
---|---|---|
created | 地图初始化完成事件 | - |
click | 图层单击事件 | object — 包含屏幕坐标pixel、经纬度coordinate与选中元素的属性properties、originalEvent |
clusterclick | 单击图层不能在下钻聚合点事件 | object — 包含屏幕坐标pixel、经纬度coordinate与聚合数据data、originalEvent |
mousemove | 鼠标移动事件 | object — 包含屏幕坐标pixel、经纬度coordinate与选中元素的属性properties、originalEvent |
mouseenter | 鼠标移进事件 | object — 包含屏幕坐标pixel、经纬度coordinate与选中元素的属性properties、originalEvent |
mouseleave | 鼠标移出元素事件 | MapMouseEvent |
SLOTS
名称 | 描述 |
---|
METHODS
名称 | 描述 | 定义 |
---|---|---|
exportToGeoJson | 将本图层数据导出为geojson格式数据文本 若图层数据源来自source组件或为url,则输出null | ()=> object | null |