mapbox开发小技巧

自定义图标

js 复制代码
// 1、单个图标
const url = './static/assets/symbols/code24x24/VIDEO.png' // 图标路径
map.loadImage(url ,(error, image) => {
  if (error) throw error
  map.addImage('video-icon', image)
})

// 2、雪碧图利用canvas
// json和png图片
function getStyleImage(fileName: any) {
  return new URL('/json/style/' + fileName + '.png', import.meta.url).href;
}

fetch(new URL('/json/style/' + fileName + '.json', import.meta.url).href)
	.then(response => response.json())
	.then(spriteJson => {
	  var img = new Image()
	  img.crossOrigin = 'anonymous'
	  img.src = getStyleImage(spriteName)
	  img.onload = function () {
	    Object.keys(spriteJson).forEach((key: any) => {
	      let spriteItem = spriteJson[key]
	      let { X, Y, Width, Height } = spriteItem
	      let canvas = createCavans(Width, Height)
	      let context: any = canvas.getContext('2d') || ''
	      context.drawImage(img, X, Y, Width, Height, 0, 0, Width, Height)
	      // 单位雪碧图项,转base64字符串
	      map.addImage(key, canvas.toDataURL('image/png'))
	    })
	    console.log(spriteName, '完成加载...')
	  }
});

vue2.0中自定义弹窗(核心代码)

样式文件

css 复制代码
// 地图弹窗
.mapbox-msgBox {
  position: relative;
  border: 0;
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
    'Microsoft YaHei', '微软雅黑', Arial, sans-serif;

  // 弹窗内容
  .mapboxgl-popup-content {
    padding: 0 !important;
  }
  
  // 弹窗标题
  h2 {
    width: 100%;
    height: 40px !important;
    line-height: 40px !important;
    font-size: 18px !important;
    color: #fff;
    background: #0057a7;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0 15px;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
  }

  // 关闭按钮
  .mapboxgl-popup-close-button {
    height: 40px;
    font-size: 3em;
    padding: 0 5px;
    color: white;
    cursor: pointer;
    &:hover {
      color: #aaaaaa;
    }
  }
}

vue文件

vue 复制代码
<template>
  <div>
    <h2>{{ title }}</h2>
  </div>
</template>
<script>

export default {
  name: 'popTemplate',
  components: {},
  props: ['attrs', 'title'],
  data() {
    return {}
  },
  mounted() {
    console.log('props:', this.attrs)
  },
  methods: {
    callback(attrs) {
      this.$emit('callback', attrs)
    }
}
</script>

实现代码

javascript 复制代码
const location = [110,30]
// 初始化弹窗
const mapboxPopup = new mapboxgl.Popup({
        closeButton: true,
        closeOnClick: false,
        className: 'mapbox-msgBox',
        maxWidth: '450px',
        offset: [0, 0]
      })
// popTemplate为引用的vue文件
const popDetail = Vue.extend(popTemplate)
const vm = new popDetail({
        propsData: {
          title,
          attrs
        },
        methods: {
          callback(config) {
            console.log('🚀 ~ callback ~ config:', config)
          }
        }
      })
      vm.$mount() // 挂载
      mapboxPopupLayer
        .setLngLat(location)
        .setDOMContent(vm.$el)
        .addTo(map)

创建自定义标签(核心代码)

定义样式为扩散圆

css 复制代码
/* 标签选择器之属性匹配选择 */
.mapbox-marker span[class^='pulse'] {
  /* 保证小盒子水平垂直居中 */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 8px;
  height: 8px;
  box-shadow: 0 0 5px #ff0000;
  border-radius: 50%;
  animation: pulse 3s linear infinite;
}

.mapbox-marker .pulse1 {
  animation-delay: 0s !important;
}

.mapbox-marker .pulse2 {
  animation-delay: 1s !important;
}

.mapbox-marker .pulse3 {
  animation-delay: 2s !important;
}

@keyframes pulse {
  0% {
    width: 8px;
    height: 8px;
  }
  40% {
    width: 40px;
    height: 40px;
    opamapbox-marker: 1;
  }
  100% {
    width: 70px;
    height: 70px;
    opamapbox-marker: 0;
  }
}

实现代码

js 复制代码
 // 创建一个新的标记并添加到地图上
 const location = [110,30]
 const el = document.createElement('div')
 el.className = 'mapbox-marker'

 const el1 = document.createElement('span')
 el1.className = 'pulse1'
 el.appendChild(el1)

 const el2 = document.createElement('span')
 el2.className = 'pulse2'
 el1.appendChild(el2)

 const el3 = document.createElement('span')
 el3.className = 'pulse3'
 el1.appendChild(el3)

 const currentMarker = new mapboxgl.Marker(el).setLngLat(location).addTo(map)
 map.setCenter(location)

 // 实现扩散效果(例如放大到特定区域)
 map.flyTo({
   center: location,
   zoom: 18,
   speed: 1, // 动画速度
   curve: 1, // 动画曲线类型
   easing: function (t) {
     return t
   } // 动画缓动函数
 })
 
 // 5s之后移除
 setTimeout(() => {
   // 如果已存在标记,则移除它
   if (currentMarker) {
     currentMarker.remove()
   }
 }, 5000)

聚合图层

bash 复制代码
// 添加数据源
map.addSource('videoLayer', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: videoListFeatures
  },
  cluster: true,
  clusterMaxZoom: 14, // 最大缩放级别,超过该级别不再聚合
  clusterRadius: 50 // 聚合半径,单位为像素
})

// 添加聚合图层
map.addLayer({
  id: 'videoLayer-cluster',
  type: 'circle',
  source: 'videoLayer',
  filter: ['has', 'point_count'],
  paint: {
    'circle-color': [
      'step',
      ['get', 'point_count'],
      '#51bbd6',
      100,
      '#f1f075',
      750,
      '#f28cb1'
    ],
    'circle-radius': [
      'step',
      ['get', 'point_count'],
      20,
      100,
      30,
      750,
      40
    ]
  }
})

// 添加聚合点计数图层
map.addLayer({
  id: 'videoLayer-cluster-count',
  type: 'symbol',
  source: 'videoLayer',
  filter: ['has', 'point_count'],
  layout: {
    'text-field': ['get', 'point_count_abbreviated'],
    'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
    'text-size': 12
  }
})

// 添加非聚合点图层
map.addLayer({
  id: 'videoLayer-unclustered-point',
  source: 'videoLayer',
  filter: ['!', ['has', 'point_count']],
  type: 'symbol',
  layout: {
    'icon-image': 'video-icon',
    'icon-size': 1
  }
})

分类渲染降雨等值面事例

js 复制代码
map.addLayer({
  id: 'grid_line',
  type: 'fill',
  source: {
    type: 'geojson',
    data: { type: 'FeatureCollection', features }
  },
  paint: {
    'fill-opacity': 1,
    'fill-outline-color': 'rgba(255, 255, 255, 0)',
    'fill-color': [
      'step',
      ['get', 'rain'],
      'rgba(255, 255, 255, 0)', // 无降雨
      0.000001,
      'rgb(165, 243, 141)', // 短时小雨
      0.25,
      'rgb(61, 185, 63)', // 短时中雨
      0.5,
      'rgb(99, 184, 249)', // 短时大雨
      1,
      'rgb(0, 0, 254)', // 短时暴雨
      2.5,
      'rgb(243, 5, 238)', // 短时大暴雨
      7.5,
      'rgb(129, 0, 64)' // 短时特大暴雨
    ]
  }
})
相关推荐
@PHARAOH2 分钟前
WHAT - Tree Shaking 的前提是 ES Module
前端·webpack·ecmascript
鱼樱前端9 分钟前
📚 Vue Router 4 核心知识点(Vue3技术栈)面试指南
前端·javascript·vue.js
食指Shaye15 分钟前
Chrome 中清理缓存的方法
前端·chrome·缓存
午后书香26 分钟前
一天三场面试,口干舌燥要晕倒(二)
前端·javascript·面试
Book_熬夜!41 分钟前
CSS—补充:CSS计数器、单位、@media媒体查询
前端·css·html·媒体
几度泥的菜花2 小时前
如何禁用移动端页面的多点触控和手势缩放
前端·javascript
狼性书生2 小时前
electron + vue3 + vite 渲染进程到主进程的双向通信
前端·javascript·electron
肥肠可耐的西西公主2 小时前
前端(AJAX)学习笔记(CLASS 4):进阶
前端·笔记·学习
拉不动的猪2 小时前
Node.js(Express)
前端·javascript·面试
Re.不晚2 小时前
Web前端开发——HTML基础下
前端·javascript·html