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)' // 短时特大暴雨
    ]
  }
})
相关推荐
Carlos_sam6 分钟前
OpenLayers:封装Tooltip
前端·javascript
工呈士19 分钟前
MobX与响应式编程实践
前端·react.js·面试
嘉小华20 分钟前
Android Lifecycle 使用
前端
Sherry00722 分钟前
实时数据传输协议:WebSocket vs MQTT
前端·websocket
然我23 分钟前
JavaScript的OOP独特之道:从原型继承到class语法
前端·javascript·html
腹黑天蝎座25 分钟前
如何更好的实现业务中图片批量上传需求
前端
嘉小华25 分钟前
Android Lifecycle 源码解析
前端
不_喜26 分钟前
游戏开发零散知识点和优化记录
前端
去伪存真35 分钟前
提交规范靠吼没用,看我用“shell+husky螺丝刀”,一键给40多个项目上锁
前端·eslint
翠莲1 小时前
vue3+TS+eslint9配置
前端·代码规范