基于mapbox立柱图效果,附示例源码

567 阅读2分钟

需求

希望热力图的效果,能以3d柱子的方式立在地图上

参考资料

核心插件deck.gl官网地址

插件demo源码地址:点击查看

插件效果预览地址:点击查看

在线编辑器预览地址:点击查看

博客案例参考地址: 点击查看

图层数据源

使用官方提供的数据源进行调试,线上地址。由于是csv格式,前端使用d3插件,处理资源转成图层需要的格式(二位数组,经纬度坐标集合),数据格式如下:

[    [-0.198465, 51.505538]
    [-0.178838, 51.491836]
    [-0.20559, 51.51491]
    [-0.208327, 51.514952]
    [-0.206022, 51.496572]
    [-0.19361, 51.500788]
    [-0.173519, 51.495171]
]

截图: image.png 该数据用于渲染热力图,相当于每个点位的权重都是1,越密集柱子颜色越深。

实现源码(vue2)

实现方式一

(MapboxOverlay),图层缩放存在抖动,不推荐使用,请使用方式二开发

      
<template>
  <div>
    <div id="map" ref="map"></div>
    <div id="info"></div> <!--  坐标提示框 -->
  </div>
</template>

<script>
// 3d立体图层效果
import mapboxgl from "mapbox-gl";
import { AmbientLight, PointLight, LightingEffect } from '@deck.gl/core';
import { HexagonLayer } from '@deck.gl/aggregation-layers';
import { MapboxOverlay } from '@deck.gl/mapbox';
import * as d3 from 'd3';
export default {
  name: "Home",

  data() {
    return {
      map: "", //地图
      time: 0, //时间
      loopLength: 1800, // 线圈长度
      animationSpeed: 1, //动画速度
    };
  },
  mounted() {
    this.initMap();
  },
  methods: {
    // 用mapbox的方式初始化底层地图
    initMap() {
      this.map = new mapboxgl.Map({
        accessToken: "your-token",
        container: this.$refs.map,
        style: "https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json",
        center: [-0.198465,51.505538],
        zoom: 5,
        pitch: 45,
        bearing: 0,
        // antialias: true, // 平滑曲线
      });
      // 添加图层
      this.addLayers();
    },

    // 添加图层
    async addLayers() {
      const ambientLight = new AmbientLight({
        color: [255, 255, 255],
        intensity: 1.0
      });

      const pointLight1 = new PointLight({
        color: [255, 255, 255],
        intensity: 0.8,
        position: [-0.144528, 49.739968, 80000]
      });

      const pointLight2 = new PointLight({
        color: [255, 255, 255],
        intensity: 0.8,
        position: [-3.807751, 54.104682, 8000]
      });

      const lightingEffect = new LightingEffect({ ambientLight, pointLight1, pointLight2 });

      const material = {
        ambient: 0.64,
        diffuse: 0.6,
        shininess: 32,
        specularColor: [51, 51, 51]
      };

      const INITIAL_VIEW_STATE = {
        longitude: -1.415727,
        latitude: 52.232395,
        zoom: 6.6,
        minZoom: 5,
        maxZoom: 15,
        pitch: 40.5,
        bearing: -27
      };
      const colorRange = [
        [1, 152, 189],
        [73, 227, 206],
        [216, 254, 181],
        [254, 237, 177],
        [254, 173, 84],
        [209, 55, 78]
      ];
      const radius = 1000,
        upperPercentile = 100,
        coverage = 1;
      const url = "https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv"
      let data = []

      await d3.csv(url, (response, index) => {
        // console.log("解析在线文件得到数据: ", response, index,response.lng,response.lat);
        data.push([Number(response.lng), Number(response.lat)])
      });
      console.log("最终的data:  ", data);
      let hexagonLayer = new HexagonLayer({
        id: 'heatmap',
        colorRange,
        coverage,
        data,
        elevationRange: [0, 3000],
        elevationScale: data && data.length ? 50 : 0,
        extruded: true,
        getPosition: d => d,
        pickable: true,
        radius,
        upperPercentile,
        material,

        transitions: {
          elevationScale: 3000
        }
      })
      const mapboxOverlay = new MapboxOverlay({
        layers: [
        hexagonLayer
        ],
      })
      this.map.addControl(mapboxOverlay); //将deckGL的Layers作为mapbox的control添加到mapbox上
      this.map.addControl(new mapboxgl.NavigationControl());
    },
  },
};
</script>

<style scoped lang="scss">
#map {
  width: 100%;
  height: 800px;
  background: #e5e9ec;
}

</style>

    

实现方式二【推荐】

(MapboxLayer)

      
<template>
  <div>
    <div id="map" ref="map"></div>
    <div id="info"></div> <!--  坐标提示框 -->
  </div>
</template>

<script>
// 3d立体图层效果
import mapboxgl from "mapbox-gl";
import { AmbientLight, PointLight, LightingEffect } from '@deck.gl/core';
import { HexagonLayer } from '@deck.gl/aggregation-layers';
import { MapboxLayer } from '@deck.gl/mapbox';
import * as d3 from 'd3';
export default {
  name: "Home",

  data() {
    return {
      map: "", //地图
    };
  },
  mounted() {
    this.initMap();
  },
  methods: {
    initMap() {
      this.map = new mapboxgl.Map({
        accessToken: "your-token",
        container: this.$refs.map,
        style: "https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json",
        center: [-1.415727, 52.232395],
        zoom: 5,
        pitch: 45,
        bearing: 0,
        antialias: true, // 平滑曲线
      });
      // 添加图层
      this.addLayers();
    },

    // 添加图层
    async addLayers() {
      // const ambientLight = new AmbientLight({
      //   color: [255, 255, 255],
      //   intensity: 1.0
      // });

      // const pointLight1 = new PointLight({
      //   color: [255, 255, 255],
      //   intensity: 0.8,
      //   position: [-0.144528, 49.739968, 80000]
      // });

      // const pointLight2 = new PointLight({
      //   color: [255, 255, 255],
      //   intensity: 0.8,
      //   position: [-3.807751, 54.104682, 8000]
      // });

      // const lightingEffect = new LightingEffect({ ambientLight, pointLight1, pointLight2 });

      const material = {
        ambient: 0.64,
        diffuse: 0.6,
        shininess: 32,
        specularColor: [51, 51, 51]
      };

      // const INITIAL_VIEW_STATE = {
      //   longitude: -1.415727,
      //   latitude: 52.232395,
      //   zoom: 6.6,
      //   minZoom: 5,
      //   maxZoom: 15,
      //   pitch: 40.5,
      //   bearing: -27
      // };
      const colorRange = [
        [1, 152, 189],
        [73, 227, 206],
        [216, 254, 181],
        [254, 237, 177],
        [254, 173, 84],
        [209, 55, 78]
      ];
      const radius = 1000,
        upperPercentile = 100,
        coverage = 1;
      const url = "https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv"
      let data = []

      await d3.csv(url, (response, index) => {
        // console.log("解析在线文件得到数据: ", response, index,response.lng,response.lat);
        data.push([Number(response.lng), Number(response.lat)])
      });
      console.log("最终的data:  ", data);

      let hexagonLayer = new MapboxLayer({
        id: 'heatmap',
        type: HexagonLayer,
        colorRange,
        coverage,
        data,
        elevationRange: [0, 3000],
        elevationScale: data && data.length ? 50 : 0,
        extruded: true,
        getPosition: d => d,
        pickable: true,
        radius,
        upperPercentile,
        material,

        transitions: {
          elevationScale: 3000
        }
      });

      this.map.on('load', () => {
        this.map.addLayer(hexagonLayer);
      });
    },
  },
};
</script>

<style scoped lang="scss">
#map {
  width: 100%;
  height: 800px;
  background: #e5e9ec;
}
</style>