deck.gl渲染ArcLayer弧线图层
目录
deck.gl渲染ArcLayer弧线图层
效果图
在线地址
deck.gl渲染ArcLayer弧线图层
https://tool.giserdqy.com/deckgl/arc-layer.html
功能说明
本实例实现了deck.gl加载底图,基于ArcLayer渲染海量弧线。实现了点击要素动态,动态更新渲染数据。可对比上一篇LineLayer https://www.giserdqy.com/#:~:text=deck.gl渲染LineLayer直线图层
数据结构
数据结构分为两部分,
- FeatureCollection是geojson数据,直接渲染为面图层,
- 另一部分是每个Feature附带的属性flows,centroid;centroid代表弧线的起点,flows存储的是多个终点要素的唯一id,可以在FeatureCollection中查询到
{"type":"Feature","properties":{"name":"Los Angeles, CA","flows":{"3":13,"8":-30,"22":-34,"23":259,"26":-336,"30":-20,"47":-17,"48":19,"53":-15,"54":-12,"67":-47,"69":-336,"70":-12,"71":-58,"72":-109,"73":-593,"74":-28,"77":12,"79":-14,"83":-13,"88":-32,"98":-67,"114":-20,"117":70,"119":-11,"123":131,"124":-12,"135":-100,"141":-17,"142":26,"148":-22,"149":17,"152":13,"160":-23,"172":45,"175":24,"176":-22,"178":-13,"182":-15,"186":26,"191":-13,"198":26,"202":12,"204":42,"212":-11,"214":-90,"224":-189,"234":-12,"247":13,"248":21,"253":25,"255":-32,"256":-13,"260":-40,"263":-58,"272":-166,"276":-23,"281":20,"285":153,"289":-39,"299":-17,"306":-76,"313":200,"325":313,"330":84,"333":-31,"334":-94,"336":-11,"338":-19,"340":20,"346":122,"355":-23,"362":-332,"364":-18,"370":-370,"382":-15,"391":-81,"394":-240,"405":-34,"420":-31,"447":-22,"449":14,"457":91,"460":-11,"465":-23,"466":-13,"467":-90,"478":111,"480":-123,"487":-38,"498":-59},"centroid":[-118.34921704225347,33.83014929577467,0]},"geometry":{"type":"MultiPolygon","coordinates":[[[[-118.59397,33.4672],[-118.48479,33.48748],[-118.37033,33.40928],[-118.28627,33.35146],[-118.32525,33.29907],[-118.37477,33.32006],[-118.46537,33.32605],[-118.48261,33.36991],[-118.56344,33.43438],[-118.59397,33.4672]]],[[[-118.59403,33.03595],[-118.54007,32.98093],[-118.44677,32.89542],[-118.3535,32.82196],[-118.42563,32.80059],[-118.4879,32.84458],[-118.5815,32.93166],[-118.64156,33.01712],[-118.59402,33.03594]]],[[[-118.9408,34.07497],[-118.85647,34.12677],[-118.78889,34.16822],[-118.69383,34.16856],[-118.66794,34.19917],[-118.6677,34.2367],[-118.63345,34.26953],[-118.65227,34.3234],[-118.7386,34.49898],[-118.88135,34.79064],[-118.89446,34.81798],[-118.32627,34.81973],[-117.77436,34.8233],[-117.66728,34.82253],[-117.65522,34.39723],[-117.64636,34.28918],[-117.67772,34.16506],[-117.69353,34.12163],[-117.70428,34.09506],[-117.71106,34.07954],[-117.74406,34.01981],[-117.76775,34.01943],[-117.80254,33.97555],[-117.78329,33.94641],[-117.91973,33.94767],[-117.9667,33.94606],[-117.9766,33.90281],[-118.02872,33.86624],[-118.05866,33.84613],[-118.06327,33.82422],[-118.0931,33.78615],[-118.11508,33.7438],[-118.1327,33.75321],[-118.1837,33.73611],[-118.23193,33.71529],[-118.25869,33.70374],[-118.31721,33.71282],[-118.3333,33.72119],[-118.35471,33.73232],[-118.39661,33.73592],[-118.42841,33.77472],[-118.39431,33.80432],[-118.41271,33.88392],[-118.46061,33.96912],[-118.51951,34.02752],[-118.60357,34.03906],[-118.67936,34.03327],[-118.74495,34.03212],[-118.80511,34.00126],[-118.85465,34.03424],[-118.94448,34.04676],[-118.9408,34.07499]]]]}}
代码解析
- 此部分是引入在线deck.gl包,d3js包用于csv数据读取格式处理,设置了基本的css样式
<head>
<title>deck.gl ArcLayer Example</title>
<script src="https://unpkg.com/deck.gl@^8.8.0/dist.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.13.0/mapbox-gl.js"></script>
<style type="text/css">
body {
width: 100vw;
height: 100vh;
margin: 0;
overflow: hidden;
}
.deck-tooltip {
font-family: Helvetica, Arial, sans-serif;
padding: 6px !important;
margin: 8px;
max-width: 300px;
font-size: 10px;
}
</style>
</head>
- 这部分是es6写法,引入需要的模块DeckGL、GeoJsonLayer、ArcLayer,并初始化DeckGL(GeoJsonLayer已经有过解释可参照deck.gl渲染GeoJsonLayer
https://www.giserdqy.com/secdev/deckgl/39849/
const {DeckGL, GeoJsonLayer, ArcLayer} = deck;
const deckgl = new DeckGL({
mapStyle: 'https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json',
initialViewState: {
longitude: -100,
latitude: 40.7,
zoom: 3,
maxZoom: 15,
pitch: 30,
bearing: 30
},
controller: true,
layers: [],
getTooltip: ({object}) => object && object.properties.name // 设置地图弹出框数据格式
});
</script>
- d3js读取数据,读取到数据后转为json,调用renderLayers方法渲染
fetch('https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/arc/counties.json')
.then(res => res.json())
.then(data => renderLayers(data))
- 渲染数据renderLayers方法封装,详情见注释
function renderLayers(data, selectedFeature) {
// 没有选中,默认设置选中Los Angeles, CA
selectedFeature = selectedFeature || data.features.find(f => f.properties.name === 'Los Angeles, CA');
const arcLayer = getArcLayer(data, selectedFeature);
const countyLayer = new GeoJsonLayer({ // 把geojson 多面数据直接渲染为GeoJSON图层
id: 'geojson',
data,
stroked: false,
filled: true,
autoHighlight: true,
pickable: true,
getFillColor: () => [0, 0, 0, 0],
onClick: info => renderLayers(data, info.object) // 点击面时,捕捉面对象属性,重新渲染该面存储的数据,渲染解释见5
});
deckgl.setProps({ layers: [countyLayer, arcLayer] });
}
- 封装初始化ArcLayer方法,具体配置见代码注释
// 定义颜色常量
const inFlowColors = [
[255, 255, 204],
[199, 233, 180],
[127, 205, 187],
[65, 182, 196],
[29, 145, 192],
[34, 94, 168],
[12, 44, 132]
];
const outFlowColors = [
[255, 255, 178],
[254, 217, 118],
[254, 178, 76],
[253, 141, 60],
[252, 78, 42],
[227, 26, 28],
[177, 0, 38]
];
// data 所有的数据
// selectedFeature 当前点击的面要素
function getArcLayer(data, selectedFeature) {
const {flows, centroid} = selectedFeature.properties; //读取选中面的中心点和目标位置id
// 遍历所有的终点id,并返回统一的数据结构
const arcs = Object.keys(flows).map(toId => {
const f = data.features[toId]; // 根据id获取到终点的geojson格式数据
return {// 调整成统一含有起点、终点、权重值结构的数据
source: centroid,
target: f.properties.centroid,
value: flows[toId]
};
});
// 通过d3js方法基于inFlowColors颜色值域排序并赋值gain、quantile属性,主要是为了确定渐变色值
const scale = d3.scaleQuantile()
.domain(arcs.map(a => Math.abs(a.value)))
.range(inFlowColors.map((c, i) => i));
arcs.forEach(a => {
a.gain = Math.sign(a.value);
a.quantile = scale(Math.abs(a.value));
});
// 初始化ArcLayer
return new ArcLayer({
id: 'arc', // 图层唯一id
data: arcs,// 绑定数据
getSourcePosition: d => d.source, // 动态获取起点geojson
getTargetPosition: d => d.target, // 动态获取终点geojson
getSourceColor: d => (d.gain > 0 ? inFlowColors : outFlowColors)[d.quantile],// 根据属性值设置起点颜色
getTargetColor: d => (d.gain > 0 ? outFlowColors : inFlowColors)[d.quantile],// 根据属性值设置终点颜色
strokeWidth: 4 // 边线颜色
});
}
源代码
拷贝到html文件中可直接用浏览器打开
<html>
<head>
<title>deck.gl ArcLayer Example</title>
<script src="https://unpkg.com/deck.gl@^8.8.0/dist.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.13.0/mapbox-gl.js"></script>
<style type="text/css">
body {
width: 100vw;
height: 100vh;
margin: 0;
overflow: hidden;
}
.deck-tooltip {
font-family: Helvetica, Arial, sans-serif;
padding: 6px !important;
margin: 8px;
max-width: 300px;
font-size: 10px;
}
</style>
</head>
<body>
</body>
<script type="text/javascript">
const {DeckGL, GeoJsonLayer, ArcLayer} = deck;
const inFlowColors = [
[255, 255, 204],
[199, 233, 180],
[127, 205, 187],
[65, 182, 196],
[29, 145, 192],
[34, 94, 168],
[12, 44, 132]
];
const outFlowColors = [
[255, 255, 178],
[254, 217, 118],
[254, 178, 76],
[253, 141, 60],
[252, 78, 42],
[227, 26, 28],
[177, 0, 38]
];
const deckgl = new DeckGL({
mapStyle: 'https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json',
initialViewState: {
longitude: -100,
latitude: 40.7,
zoom: 3,
maxZoom: 15,
pitch: 30,
bearing: 30
},
controller: true,
layers: [],
getTooltip: ({object}) => object && object.properties.name
});
function getArcLayer(data, selectedFeature) {
const {flows, centroid} = selectedFeature.properties;
const arcs = Object.keys(flows).map(toId => {
const f = data.features[toId];
return {
source: centroid,
target: f.properties.centroid,
value: flows[toId]
};
});
const scale = d3.scaleQuantile()
.domain(arcs.map(a => Math.abs(a.value)))
.range(inFlowColors.map((c, i) => i));
arcs.forEach(a => {
a.gain = Math.sign(a.value);
a.quantile = scale(Math.abs(a.value));
});
return new ArcLayer({
id: 'arc',
data: arcs,
getSourcePosition: d => d.source,
getTargetPosition: d => d.target,
getSourceColor: d => (d.gain > 0 ? inFlowColors : outFlowColors)[d.quantile],
getTargetColor: d => (d.gain > 0 ? outFlowColors : inFlowColors)[d.quantile],
strokeWidth: 4
});
}
function renderLayers(data, selectedFeature) {
selectedFeature = selectedFeature || data.features.find(f => f.properties.name === 'Los Angeles, CA');
const arcLayer = getArcLayer(data, selectedFeature);
const countyLayer = new GeoJsonLayer({
id: 'geojson',
data,
stroked: false,
filled: true,
autoHighlight: true,
pickable: true,
getFillColor: () => [0, 0, 0, 0],
onClick: info => renderLayers(data, info.object)
});
deckgl.setProps({ layers: [countyLayer, arcLayer] });
}
fetch('https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/arc/counties.json')
.then(res => res.json())
.then(data => renderLayers(data))
</script>
</html>