空间数据可视化之ArcLayer详解
deck-overlay中
首先使用d3中的scaleQuantile将数据进行分类,scaleQuantile方法是d3中的一种数据分类方法(https://www.cnblogs.com/kidsitcn/p/7182274.html)
https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/arc/counties.json
_getArcs({data, selectedFeature}) {
if (!data || !selectedFeature) {
return null;
} const {flows, centroid} = selectedFeature.properties; const arcs = Object.keys(flows).map(toId => {
const f = data[toId];
return {
source: centroid,
target: f.properties.centroid,
value: flows[toId]
};
}); const scale = 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 arcs;
}
scaleQuantile是一种将连续的值转化成离散的方法,最终离散成这几种颜色分类
arc-layer中
这里还是使用了实例化的方法,先添加一堆实例化变量:
initializeState() {
const attributeManager = this.getAttributeManager(); /* eslint-disable max-len */
attributeManager.addInstanced({
instancePositions: {
size: 4,
transition: true,
accessor: ['getSourcePosition', 'getTargetPosition'],
update: this.calculateInstancePositions
},
instanceSourceColors: {
size: 4,
type: GL.UNSIGNED_BYTE,
transition: true,
accessor: 'getSourceColor',
update: this.calculateInstanceSourceColors
},
instanceTargetColors: {
size: 4,
type: GL.UNSIGNED_BYTE,
transition: true,
accessor: 'getTargetColor',
update: this.calculateInstanceTargetColors
}
});
/* eslint-enable max-len */
}
然后是制作图形,这里使用50个点来模拟一条抛物线的效果
_getModel(gl) {
let positions = [];
const NUM_SEGMENTS = 50; // 利用50个点来模拟曲线
/*
* (0, -1)-------------_(1, -1)
* | _,-" |
* o _,-" o
* | _,-" |
* (0, 1)"-------------(1, 1)
*/
for (let i = 0; i < NUM_SEGMENTS; i++) { // 使用三角带的方式来绘制三角形,同时这里的-1和1也是为了在绘制宽度的时候确定法向量的偏移
positions = positions.concat([i, -1, 0, i, 1, 0]);
} const model = new Model(
gl,
Object.assign({}, this.getShaders(), {
id: this.props.id,
geometry: new Geometry({
drawMode: GL.TRIANGLE_STRIP,
attributes: {
positions: new Float32Array(positions)
}
}),
isInstanced: true,
shaderCache: this.context.shaderCache // 缓存着色器,我怀疑自己写的hexagon偏慢也跟这个有关系
})// 绘制物体,这里是5.x的版本在新的版本中还要设定instanceCount参数,来控制绘制实例的数量
); model.setUniforms({numSegments: NUM_SEGMENTS}); return model;
}
下面是计算一些实例变量,根据data的数量来控制,但是luma好像会默认给实例变量的数组分配大小,实际的value中有一些多余的空间,如果数据量小的话,可能绘制不出来;比如:data有22条线,按照如下计算,instancePositions可用的value就只有88个元素。
calculateInstancePositions(attribute) {
const {data, getSourcePosition, getTargetPosition} = this.props;
const {value, size} = attribute;
let i = 0;
for (const object of data) {
const sourcePosition = getSourcePosition(object);
const targetPosition = getTargetPosition(object);
value[i + 0] = sourcePosition[0];
value[i + 1] = sourcePosition[1];
value[i + 2] = targetPosition[0];
value[i + 3] = targetPosition[1];
i += size;
}
} calculateInstancePositions64Low(attribute) {
const {data, getSourcePosition, getTargetPosition} = this.props;
const {value, size} = attribute;
let i = 0;
for (const object of data) {
const sourcePosition = getSourcePosition(object);
const targetPosition = getTargetPosition(object);
value[i + 0] = fp64LowPart(sourcePosition[0]);
value[i + 1] = fp64LowPart(sourcePosition[1]);
value[i + 2] = fp64LowPart(targetPosition[0]);
value[i + 3] = fp64LowPart(targetPosition[1]);
i += size;
}
} calculateInstanceSourceColors(attribute) {
const {data, getSourceColor} = this.props;
const {value, size} = attribute;
let i = 0;
for (const object of data) {
const color = getSourceColor(object);
value[i + 0] = color[0];
value[i + 1] = color[1];
value[i + 2] = color[2];
value[i + 3] = isNaN(color[3]) ? 255 : color[3];
i += size;
}
} calculateInstanceTargetColors(attribute) {
const {data, getTargetColor} = this.props;
const {value, size} = attribute;
let i = 0;
for (const object of data) {
const color = getTargetColor(object);
value[i + 0] = color[0];
value[i + 1] = color[1];
value[i + 2] = color[2];
value[i + 3] = isNaN(color[3]) ? 255 : color[3];
i += size;
}
}
着色器代码
#define SHADER_NAME arc-layer-vertex-shader attribute vec3 positions; // 几何图形的坐标,同时这里面也编码了一些信息,x代表线段索引,y可以代表偏移方向
// 本次可用的一些实例变量
attribute vec4 instanceSourceColors;// 起点的颜色
attribute vec4 instanceTargetColors; // 终点的颜色
attribute vec4 instancePositions; // 前两个值记录了起点经纬度,后两个值记录了终点经纬度
attribute vec3 instancePickingColors; uniform float numSegments; // 抛物线的线段数量
uniform float strokeWidth; // 线宽度
uniform float opacity; varying vec4 vColor; // source和target是在3d空间中的单位,ratio代表本此线段在总线段数目的比值范围在0~1,返回值时抛物线高度的平方
// 这里的方式决定高度单位与source/target的单位保持一致
float paraboloid(vec2 source, vec2 target, float ratio) { vec2 x = mix(source, target, ratio); // 获取该线段节点对应的直线位置
vec2 center = mix(source, target, 0.5);// 取中心点,充分利用glsl内建函数,提升性能 // 抛物线的公式应该是y * y = (source - center)^2 - (x - center)^2;
float dSourceCenter = distance(source, center);
float dXCenter = distance(x, center);
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
} // 在屏幕空间中计算偏移值,最后在反算到裁切空间,也就是ndc空间
// offset_direction在position的y坐标中记录
// offset vector by strokeWidth pixels
// offset_direction is -1 (left) or 1 (right)
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
// normalized direction of the line
// ndc空间中的坐标乘以屏幕宽高像素,转换成2维屏幕像素;然后归一化成单位向量
vec2 dir_screenspace = normalize(line_clipspace * project_uViewportSize);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); // 求法线向量 // 法向量乘以偏移方向乘以宽度一半获取在屏幕空间中的偏移值
vec2 offset_screenspace = dir_screenspace * offset_direction * strokeWidth / 2.0;
// 将屏幕坐标反算到ndc空间
vec2 offset_clipspace = project_pixel_to_clipspace(offset_screenspace).xy; return offset_clipspace; // 返回ndc空间的偏移量
} float getSegmentRatio(float index) { // 返回线段索引在总线段数目中的比值,转换成0~1之间
return smoothstep(0.0, 1.0, index / (numSegments - 1.0));
} vec3 getPos(vec2 source, vec2 target, float segmentRatio) { // 获取线段节点在三维空间中的位置
float vertex_height = paraboloid(source, target, segmentRatio); // 获取高度信息 return vec3(
mix(source, target, segmentRatio), // 获取节点的x/y坐标
sqrt(max(0.0, vertex_height))// 获取节点的高度坐标
);
} void main(void) {
// 将insance中编码的起终点的经纬度分别转换成瓦片像素单位
vec2 source = project_position(instancePositions.xy);
vec2 target = project_position(instancePositions.zw); float segmentIndex = positions.x;// 节点的线段索引
float segmentRatio = getSegmentRatio(segmentIndex);
// if it's the first point, use next - current as direction
// otherwise use current - prev
// 这里处理方式比较巧妙,充分利用内建函数优势;
// step(edge, x) 作用如: x>=edge ? 1.0 : 0.0
// 所以上面英文注释所说,如果是起点就使用next-curr,其他的都是用curr - prev
//float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
float indexDir = mix(-1.0, 1.0, (segmentIndex <= 0.0 ? 1.0 : 0.0));
// 根据indexDir获取下一段或者上一个线段节点的比值
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir); // 获取两个节点的3维世界坐标并转化成ndc坐标
vec3 currPos = getPos(source, target, segmentRatio);
vec3 nextPos = getPos(source, target, nextSegmentRatio);
vec4 curr = project_to_clipspace(vec4(currPos, 1.0));
vec4 next = project_to_clipspace(vec4(nextPos, 1.0)); // extrude
// 进行线宽拉伸,获取法线方向的偏移
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, positions.y);
gl_Position = curr + vec4(offset, 0.0, 0.0); // 获取最终节点的ndc位置 // 根据线段节点位置计算颜色插值
vec4 color = mix(instanceSourceColors, instanceTargetColors, segmentRatio) / 255.;
vColor = vec4(color.rgb, color.a * opacity);// 获取最终颜色 // Set color to be rendered to picking fbo (also used to check for selection highlight).
picking_setPickingColor(instancePickingColors);
}
空间数据可视化之ArcLayer详解的更多相关文章
- 每篇半小时1天入门MongoDB——3.MongoDB可视化及shell详解
本篇主要介绍MongoDB可视化操作以及shell使用及命令,备份恢复.数据导入导出. MongoVUE安装和简单使用 使用mongo.exe 管理数据库虽然可行,功能也挺强大,但每次都要敲命令,即繁 ...
- DoTween可视化编程用法详解
DoTween可视化编辑 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新 ...
- WPF (VisualChildren)可视化子元素详解
VisualChildrenCount 的 FrameworkElement 实现始终返回 0 或 1. 如果类所要维护的可视化子元素集合的成员数可能超过 1,则这样的类必须重写此属性和 Ge ...
- 眼球3D可视化解决方案——案例详解
医疗器械行业伴随着人类健康需求的增长而不断发展,是名副其实的朝阳行业,也是全球发达国家竞相争夺的领域. 一方面,行业门槛高,集中度低,外资企业挤占市场空间成了我国所有医疗器械行业入局者面临的共同挑战. ...
- Kibana可视化数据(Visualize)详解
可视化 (Visualize) 功能可以为您的 Elasticsearch 数据创建可视化控件.然后,您就可以创建仪表板将这些可视化控件整合到一起展示. Kibana 可视化控件基于 Elastics ...
- 可视化的Redis数据库管理工具redis-desktop-manager的初步使用(图文详解)
不多说,直接上干货! 无论是Linux 还是 Windows里安装Redis, Windows里如何正确安装Redis以服务运行(博主推荐)(图文详解) Windows下如何正确下载并安装可视化的Re ...
- Windows下如何正确下载并安装可视化的Redis数据库管理工具(redis-desktop-manager)(图文详解)
不多说,直接上干货! Redis Desktop Manager是一个可视化的Redis数据库管理工具,使用非常简单. 官网下载:https://redisdesktop.com/down ...
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...
- 给Clouderamanager集群里安装可视化分析利器工具Hue步骤(图文详解)
扩展博客 以下,是我在手动的CDH版本,安装Hue. CDH版本大数据集群下搭建Hue(hadoop-2.6.0-cdh5.5.4.gz + hue-3.9.0-cdh5.5.4.tar.gz)(博主 ...
随机推荐
- Activity,Window,View之间是什么关系?
Activity在onCreate之前调用attach方法,在attach方法中会创建window对象.window对象创建时并没有创建 Decor对象对象.用户在Activity中调用setCont ...
- centos7搭建postfix邮件服务器
在使用qq等邮件服务器厂商提供的邮件服务后,发现他们的邮件发送数量是有限制的,随着公司的业务的需求下,我们需要搭建一个邮件服务器,邮件服务器可以帮助我们在一些提醒方面和消息推送方面起到帮助. 理论性语 ...
- 详解vue的diff算法
前言 我的目标是写一个非常详细的关于diff的干货,所以本文有点长.也会用到大量的图片以及代码举例,目的让看这篇文章的朋友一定弄明白diff的边边角角. 先来了解几个点... 1. 当数据发生变化时, ...
- 唱吧DevOps的落地,微服务CI/CD的范本技术解读----最大的难点并不是实际业务代码的编写,而是服务的监控和调试以及容器的编排
1.业务架构:从单体式到微服务 K歌亭是唱吧的一条新业务线,旨在提供线下便捷的快餐式K歌方式,用户可以在一个电话亭大小的空间里完成K歌体验.K歌亭在客户端有VOD.微信和Web共三个交互入口,业务复杂 ...
- JAVA实现Base64编码的三种方式
摘要: Javabase64编码的三种方式 有如下三种方式: 方式一:commons-codec.jar Java代码 1. String base64String="whuang12 ...
- java.exe进程来源排查录
解决后的一个小结:此处是一个tomcat端口,这种情况下,可以先在浏览器访问下看看效果,就可以快速定位 又发现一个简单的办法: 下面的定位过程,适用于各种场合 无意中发现有个进程开了好多端口,很奇怪 ...
- ETCD相关介绍--整体概念及原理方面
etcd作为一个受到ZooKeeper与doozer启发而催生的项目,除了拥有与之类似的功能外,更专注于以下四点. 简单:基于HTTP+JSON的API让你用curl就可以轻松使用. 安全:可选SSL ...
- CSS3 :nth-child() 选择器---挖坑
E:nth-child(n) 语法: E:nth-child(n) { sRules } 说明: 匹配父元素的第n个子元素E,假设该子元素不是E,则选择符无效.(也就是说,会检查从body开始的每个元 ...
- Python 三级菜单 增强版
需要实现的功能是:三级菜单1.从文本内读出选项2.查询每一级的选项,并能对选项进行增/删/改功能3.每一级可以退出程序或者返回上一层 2018-5-14 更新内容 思路 实现过程中的BUG及解决方案: ...
- Tomcat 优化方案 和 配置详解(转)
转自 Tomcat 优化方案 和 配置详解 http://201605130349.iteye.com/blog/2298985 Server.xml配置文件用于对整个容器进行相关的配置. <S ...