deck.gl渲染IconLayer图标图层

效果图


当前看到的头像和文字,是动态请求的网站贡献人的头像、用户名、贡献数

在线地址

deck.gl渲染IconLayer图标图层
https://tool.giserdqy.com/deckgl/icon-layer.html

功能说明

本文讲解了IconLayer渲染图标的两种方式;实例实现了deck.gl加载底图,基于IconLayer渲染自动请求的图片,动态设置图片宽高、位置,并增加图标鼠标事件。

API介绍

IconLayer加载图标有两种方式

  1. 提前制作sprite 图像 ( iconAtlas),把所有图片打包到一张图中;附带一个JSON描述(iconMapping),他描述每个图片在sprite中的位置和大小;优点是速度快,预加载,缺点也是不需要的图标也会加载
// 图标描述信息
const ICON_MAPPING = {
  marker: {x: 0, y: 0, width: 128, height: 128, mask: true}
};
/**
   * Data format:
   * [
   *   {name: 'Colma (COLM)', address: '365 D Street, Colma CA 94014', exits: 4214, coordinates: [-122.466233, 37.684638]},
   *   ...
   * ]
   */
  const layer = new IconLayer({
    id: 'icon-layer',
    data, // 图层数据
    pickable: true, // 可捕捉
    // iconAtlas and iconMapping are required
    // getIcon: return a string
    iconAtlas: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/icon-atlas.png', // sprite图片url
    iconMapping: ICON_MAPPING, // 图标描述配置
    getIcon: d => 'marker', // 获取图标

    sizeScale: 15, // 图片大小放大级别
    getPosition: d => d.coordinates,// 每张图片位置
    getSize: d => 5,// 图片大小
    getColor: d => [Math.sqrt(d.exits), 140, 0] // 图片颜色
  });
  1. 动态生成iconAtlas,有点是图片是动态加载设置,灵活度更高;缺点是相对来说效率慢,每张图都需要网络加载
/**
   * Data format:
   * [
   *   {
   *     avatar_url: "https://avatars1.githubusercontent.com/u/7025232?v=4",
   *     contributions: 620,
   *     id: 7025232,
   *     login: "ibgreen",
   *     type: "User",
   *     ...
   *   }
   * ]
   */
  const layer = new IconLayer({
    id: 'icon-layer',
    // 动态请求图片
    data: octokit.repos.getContributors({
      owner: 'visgl',
      repo: 'deck.gl'
    }).then(result => result.data),
    // iconAtlas and iconMapping should not be provided
    // getIcon return an object which contains url to fetch icon of each data point
    getIcon: d => ({
      url: d.avatar_url, // 图片地址
      width: 128, // 宽
      height: 128, // 高
      anchorY: 128 //Y偏移量
    }),// 根据请求到的图片信息动态设置属性
    // icon size is based on data point's contributions, between 2 - 25
    getSize: d => Math.max(2, Math.min(d.contributions / 1000 * 25, 25)),// 图片大小
    pickable: true, // 可捕捉
    sizeScale: 15,// 大小放大级别
    getPosition: d => d.coordinates // 图片位置
  });

代码解析

  1. 此部分是引入在线deck.gl包,mapboxgl底图,d3js数据请求,图片服务api,设置了基本的css样式
 <head>
    <title>deck.gl IconLayer Example</title>

    <script src="https://unpkg.com/deck.gl@^8.8.0/dist.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rest.js/15.2.6/octokit-rest.min.js"></script>
    <script src="https://d3js.org/d3.v7.min.js"></script>

    <style type="text/css">
      body {
        width: 100vw;
        height: 100vh;
        margin: 0;
        background: #f7f7f7;
        overflow: hidden;
      }
      .deck-tooltip {
        font-family: Helvetica, Arial, sans-serif;
        padding: 6px !important;
        margin: 8px;
        max-width: 300px;
        font-size: 10px;
      }
    </style>
  </head>

  <body>
    <div id="tooltip"></div>
  </body>
  1. 这部分初始化DeckGL对象,设置第一视角视图和初始状态;设置鼠标捕捉格式化文本
const {DeckGL, OrthographicView, IconLayer, LineLayer, ScatterplotLayer, TextLayer, COORDINATE_SYSTEM} = deck;

    const deckgl =  new DeckGL({
      views: new OrthographicView(), // 第一人称视图
      initialViewState: { target: [0, 0, 0], zoom: 3 }, // 视图初始状态
      controller: true,
      getTooltip: ({object}) => object && `${object.login}nContributions: ${object.contributions}` // 格式化文本
    });
  1. 这部分定义渲染IconLayer方法;动态请求接口,解析数据后调用渲染方法动态渲染用户头像。
// 定义渲染IconLayer方法
   function renderLayers(data) {
      const iconLayer = new IconLayer({
        id: 'users',
        data,
        getIcon: d => ({
          url: d.avatar_url,
          width: 128,
          height: 128
        }),
        getSize : d => d.r * 1.4,
        getPosition: d => [d.x, d.y],
        sizeUnits: 'common',
        pickable: true
      });

      deckgl.setProps({ layers: [iconLayer] });
    }
        // 定义获取用户信息接口
    async function getContributors() {
      const octokit = new Octokit();
      const perPage = 100;
      let page = 1;
      let result = [];
      while (true) {
        const {data} = await octokit.repos.getContributors({ owner: 'visgl', repo: 'deck.gl', per_page: perPage, page: page++});
        result = result.concat(data);
        if (data.length < perPage) return result;
      }
    }
        // 获取用户信息后提取格式化成需要的格式,并调用渲染方法,渲染到图上
    getContributors()
    .then(data => {
      const circles = data.map((d, i) => {
        return {
          login: d.login,
          avatar_url: d.avatar_url,
          contributions: d.contributions,
          // For d3.pack
          r: Math.log(d.contributions + 1)
        };
      });

      d3.packSiblings(circles);

      renderLayers(circles);
    })

源代码

拷贝到html文件中可直接用浏览器打开

<html>
  <head>
    <title>deck.gl IconLayer Example</title>

    <script src="https://unpkg.com/deck.gl@^8.8.0/dist.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rest.js/15.2.6/octokit-rest.min.js"></script>
    <script src="https://d3js.org/d3.v7.min.js"></script>

    <style type="text/css">
      body {
        width: 100vw;
        height: 100vh;
        margin: 0;
        background: #f7f7f7;
        overflow: hidden;
      }
      .deck-tooltip {
        font-family: Helvetica, Arial, sans-serif;
        padding: 6px !important;
        margin: 8px;
        max-width: 300px;
        font-size: 10px;
      }
    </style>
  </head>

  <body>
    <div id="tooltip"></div>
  </body>

  <script type="text/javascript">

    const {DeckGL, OrthographicView, IconLayer, LineLayer, ScatterplotLayer, TextLayer, COORDINATE_SYSTEM} = deck;

    const deckgl =  new DeckGL({
      views: new OrthographicView(),
      initialViewState: { target: [0, 0, 0], zoom: 3 },
      controller: true,
      getTooltip: ({object}) => object && `${object.login}nContributions: ${object.contributions}`
    });

    function renderLayers(data) {
      const iconLayer = new IconLayer({
        id: 'users',
        data,
        getIcon: d => ({
          url: d.avatar_url,
          width: 128,
          height: 128
        }),
        getSize : d => d.r * 1.4,
        getPosition: d => [d.x, d.y],
        sizeUnits: 'common',
        pickable: true
      });

      deckgl.setProps({ layers: [iconLayer] });
    }

    async function getContributors() {
      const octokit = new Octokit();
      const perPage = 100;
      let page = 1;
      let result = [];
      while (true) {
        const {data} = await octokit.repos.getContributors({ owner: 'visgl', repo: 'deck.gl', per_page: perPage, page: page++});
        result = result.concat(data);
        if (data.length < perPage) return result;
      }
    }

    getContributors()
    .then(data => {
      const circles = data.map((d, i) => {
        return {
          login: d.login,
          avatar_url: d.avatar_url,
          contributions: d.contributions,
          // For d3.pack
          r: Math.log(d.contributions + 1)
        };
      });

      d3.packSiblings(circles);

      renderLayers(circles);
    })

  </script>
</html>

You may also like...