deck.gl渲染IconLayer图标图层
目录
效果图
当前看到的头像和文字,是动态请求的网站贡献人的头像、用户名、贡献数
在线地址
deck.gl渲染IconLayer图标图层
https://tool.giserdqy.com/deckgl/icon-layer.html
功能说明
本文讲解了IconLayer渲染图标的两种方式;实例实现了deck.gl加载底图,基于IconLayer渲染自动请求的图片,动态设置图片宽高、位置,并增加图标鼠标事件。
API介绍
IconLayer加载图标有两种方式
- 提前制作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] // 图片颜色
});
- 动态生成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 // 图片位置
});
代码解析
- 此部分是引入在线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>
- 这部分初始化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}` // 格式化文本
});
- 这部分定义渲染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>