金沙棋牌官方平台

当前位置:金沙棋牌 > 金沙棋牌官方平台 > 借助类库开发及框架介绍,JS使用前了解

借助类库开发及框架介绍,JS使用前了解

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-11-22 11:08

D3 力导向图和 WebGL 的整合使用

2017/07/14 · JavaScript · D3js, WebGL

原文出处: geekplux   

D3 是目前最流行的数据可视化库,WebGL 是目前 Web 端最快的绘制技术。由于性能问题的局限,将两者结合的尝试越来越多(如),本文将尝试用 D3 的力导向图 和 Three.js 和 PixiJS 结合。全文阅读完大概 5 分钟,因为你重点应该看代码。

做数据可视化时,必然会考虑性能的问题。早前数据可视化都是用 Qt 等 GUI,后来逐渐迁移到了迅猛发展的浏览器上展示,Web 的性能问题成了大多数可视化的局限,尤其是在三维可视化,或数据量特别大的时候。现在主流的 Web 可视化技术为三种:SVG、Canvas 和 WebGL,难易程度和性能如下图:

金沙棋牌官方平台 1Web visualization tech

SVG 的优点很多,编辑简单,交互便捷,灵活性极高,业内成熟的可视化工具(如 d3)都是用的 SVG。但是每个 SVG 都是一个 DOM 元素,随着它的数量上来之后,交互开始慢的难以忍受。这是因为每当修改一个 DOM 对象,只要这个对象在文档里,接着在浏览器里就会发生两个动作,一个叫 金沙棋牌官方平台,Reflow(重排,就是重新排版),另一个叫 Repaint(重绘,就是重新渲染页面)。这两个动作不一定都会发生,但如果被修改的 DOM 当前可见的话,那么就会先重排,后重绘。绘制性能上 canvas 和 SVG(DOM 元素)应该差不多,但前者可以省掉重排过程,因此性能更高。然而,WebGL 的性能更胜一筹,因为 WebGL 使用 GPU 加速渲染,GPU 在大规模计算方面有绝对优势(图像处理、深度学习都在用,显卡已经卖疯了)。例子:用 WebGL 绘制 200000 个点的动画()

WebGL 虽然威力无穷,但是写起来比较痛苦,画个三角形大致要 100 行代码。所以很多人对 WebGL 进行了封装。上面图中提到的两个 Three.js 和 PixiJS 是目前最流行的两款 WebGL 库,当然还有新兴的 regl 在今年的 OpenVis 上大放异彩。本文尝试用前两者和 d3-force 结合(项目代码在此),后面如果有时间的话,我会把使用 regl 和原生 WebGL 的例子也补充进去(我知道这是个 flag)。

Three.js是一个伟大的开源WebGL库,WebGL允许JavaScript操作GPU,在浏览器端实现真正意义的3D。但是目前这项技术还处在发展阶段,资料极为匮乏,爱好者学习基本要通过Demo源码和Three.js本身的源码来学习。

点评:前面我们看到了使用原生的WebGL API开发是多么的累,只因如此大量的WebGL框架被开发出来,这些框架不同程度的封装了创建3D场景的各种要素你可以快速创建需要的3D场景,感兴趣的朋友可以了解下,或许本文对你有所帮助

正文

首先我们要知道什么是力导向图和如何使用 d3-force。d3 4.0 之后,作者将其模块化,force 这个模块是基于 velocity Verlet 实现了物理粒子之间的作用力的仿真,常用于网络或关系结构数据。即你把网络中的节点想象成一个个粒子,它们之间互相有作用力,所以不停的拉扯,直到趋于一个稳定状态,具体可以看我 demo 中可视化出来的样子。

金沙棋牌官方平台 2Demo 效果图

仔细看 demo 中的源码可以发现,用 three.js 和用 pixi.js 实现起来非常类似,其中有关力导向图的关键代码是下面几句:

JavaScript

const simulation = d3.forceSimulation() // 创建一个作用力的仿真,但此时还没启动 .force('link', d3.forceLink().id((d) => d.id)) // 为边之间添加 Link 型作用力 .force('charge', d3.forceManyBody()) // 指定节点间的作用力类型为 Many-Body 型 .force('center', d3.forceCenter(width / 2, height / 2)) // Centering 作用力指定布局围绕的中心

1
2
3
4
const simulation = d3.forceSimulation() // 创建一个作用力的仿真,但此时还没启动
  .force('link', d3.forceLink().id((d) => d.id)) // 为边之间添加 Link 型作用力
  .force('charge', d3.forceManyBody()) // 指定节点间的作用力类型为 Many-Body 型
  .force('center', d3.forceCenter(width / 2, height / 2)) // Centering 作用力指定布局围绕的中心

d3-force 提供了五种作用力,分别是 Centering、Collision、Links、Many-Body、Positioning。此时我们已经创建好带有各种力的仿真器了,接下来需要启动它:

JavaScript

simulation .nodes(data.nodes) // 根据 data.nodes 数组来计算点之间的作用力,相当于不停计算节点的 xy 坐标 .on('tick', ticked) // 每次 tick 调用 ticked simulation.force('link') .links(data.links) // 根据 data.links 数据计算边之间的作用力

1
2
3
4
5
simulation
  .nodes(data.nodes) // 根据 data.nodes 数组来计算点之间的作用力,相当于不停计算节点的 xy 坐标
  .on('tick', ticked) // 每次 tick 调用 ticked
simulation.force('link')
  .links(data.links) // 根据 data.links 数据计算边之间的作用力

至此一个力导向图的仿真就开始了,那么怎么把这些节点和边显示出来呢?让我们继续看源码,以 three.js 为例:

JavaScript

const scene = new THREE.Scene() const camera = new THREE.OrthographicCamera(0, width, height, 0, 1, 1000) const renderer = new THREE.WebGLRenderer({alpha: true}) renderer.setSize(width, height) container.appendChild(renderer.domElement) // container 这里是 document.body

1
2
3
4
5
const scene = new THREE.Scene()
const camera = new THREE.OrthographicCamera(0, width, height, 0, 1, 1000)
const renderer = new THREE.WebGLRenderer({alpha: true})
renderer.setSize(width, height)
container.appendChild(renderer.domElement) // container 这里是 document.body

在 Three.js 中展示场景需要具备三要素:场景、照相机、渲染器。照相机就相当于我们的眼睛,它对着渲染好的场景就相当于把场景成像到了相机中,这里的照相机我们用的是平行投影相机,渲染器我们使用的是 WebGL 渲染器。设置好渲染器的大小,把它添加到页面的元素上,相当于添加了一个 <canvas> 元素。接下来,我们生成每个节点和边的样子:

JavaScript

data.nodes.forEach((node) => { node.geometry = new THREE.CircleBufferGeometry(5, 32) node.material = new THREE.MeshBasicMaterial({ color: colour(node.id) }) node.circle = new THREE.Mesh(node.geometry, node.material) scene.add(node.circle) }) data.links.forEach((link) => { link.material = new THREE.LineBasicMaterial({ color: 0xAAAAAA }) link.geometry = new THREE.Geometry() link.line = new THREE.Line(link.geometry, link.material) scene.add(link.line) })

1
2
3
4
5
6
7
8
9
10
11
12
data.nodes.forEach((node) => {
  node.geometry = new THREE.CircleBufferGeometry(5, 32)
  node.material = new THREE.MeshBasicMaterial({ color: colour(node.id) })
  node.circle = new THREE.Mesh(node.geometry, node.material)
  scene.add(node.circle)
})
data.links.forEach((link) => {
  link.material = new THREE.LineBasicMaterial({ color: 0xAAAAAA })
  link.geometry = new THREE.Geometry()
  link.line = new THREE.Line(link.geometry, link.material)
  scene.add(link.line)
})

套路都一样,都是先建一个几何体,然后设置材质的样式,添加到场景中就好了。接下来只要在刚才提到的 ticked 这个回调函数中把节点和边的坐标更新一下就好了:

JavaScript

function ticked () { data.nodes.forEach((node) => { const { x, y, circle } = node circle.position.set(x, y, 0) }) data.links.forEach((link) => { const { source, target, line } = link line.geometry.verticesNeedUpdate = true line.geometry.vertices[0] = new THREE.Vector3(source.x, source.y, -1) line.geometry.vertices[1] = new THREE.Vector3(target.x, target.y, -1) }) render(scene, camera) }

1
2
3
4
5
6
7
8
9
10
11
12
13
function ticked () {
  data.nodes.forEach((node) => {
    const { x, y, circle } = node
    circle.position.set(x, y, 0)
  })
  data.links.forEach((link) => {
    const { source, target, line } = link
    line.geometry.verticesNeedUpdate = true
    line.geometry.vertices[0] = new THREE.Vector3(source.x, source.y, -1)
    line.geometry.vertices[1] = new THREE.Vector3(target.x, target.y, -1)
  })
  render(scene, camera)
}

是不是比想象的简单多了?如果以上有什么地方看不懂,说明你可能对 Three.js 不是很了解,不过没关系,它的文档写的很好,入门很快。希望这篇文章能给你带来一些帮助,做了点微小的贡献,很惭愧 :)

1 赞 1 收藏 评论

金沙棋牌官方平台 3

国外网站 aerotwist.com 有六篇较为简单的入门教程,我尝试着将其翻译过来,与大家分享。
我在一些实验项目中使用了Three.js,我发现它对快速上手浏览器3D编程确实很有帮助。通过Three.js,你不仅可以创建相机、物体、光线、材质等等,还可以选择着色器,可以决定使用何种技术(WebGL、Canvas或SVG)在网页上渲染你的3D图形。Three.js是开源的,你甚至可以参与到这个项目中来。但现在,我将把重点放在基础的介绍上,我将向你展示如何使用这个引擎上。

前面我们看到了使用原生的WebGL API开发是多么的累,正因为如此,大量的WebGL框架被开发出来。使用这些框架,你可以快速创建需要的3D场景。这些框架不同程度的封装了创建3D场景的各种要素,例如场景,相机、模型、光照、材质等等;使用这些封装起来的对象,就可以很简单的创建需要的3D场景,这样你就只需要把更多精力放在逻辑方面就可以了。

尽管Three.js如此奇妙,但有时候它也会令人抓狂。比如,你将花费大量时间阅读例程,做一些逆向工程(在我的情形下)来确定某个函数的作用,有时还要去GitHub上提问。如果你需要提问,Mr. doob和AlteredQualia是极好的选择。

目前并没有哪一个具有能压倒其他框架的优势,选择什么样的框,还是看个人喜好吧,不过选择框架的时候,个人觉得还是多看看框架最后的更新时间,选择稳定更新的框架能让你始终能使用上最新的特性,使你的程序稳定性更好。

1.基础
我假定你的三维图形学知识过关,而且也在一定程度上掌握了JavaScript。如果不是这样,那先去学一点吧,否则直接看这篇教程,也许会感到困惑。

下面的例子就使用了Three.js框架进行开发。
Three.js是一个比较全面的开源框架,它良好的封装的3D场景的各种要素。你可以用它来很容易的去创建摄像机,模型,光照,材质等等。你还可以选择不同的渲染器,Three.js提供了多种渲染方式,你可以选择使用canvas来渲染,也可以使用WebGL或者SVG来进行渲染。

在我们的三维世界里,我们有以下这些东西。我会带你一步一步创建它们。
1.场景
2.渲染器
3.相机
4.物体(带有材质的)
当然,你也可以创造些其他的什么东西,我也希望你如此做。
2.浏览器支持
简单地看一下浏览器的支持情况吧。Google家的Chrome浏览器支持Three.js,在我的实验里,无论是对渲染器的支持程度还是JavaScript解释器的运行速度,Chrome都是做得最好的:它支持Canvas、WebGL和SVG,而且运行得非常快。FireFox浏览器排在第二位,它的JavaScript引擎的速度比Chrome慢了半拍,但是对渲染器的支持也很棒,而且FireFox的速度,随着版本更新也越来越快。Opera浏览器正在逐渐增加对WebGL的支持,Mac上的Safari浏览器有一个开启WebGL的选项。总体上,这两个浏览器仅仅支持Canvas渲染。微软家的IE9现在只支持Canvas渲染,而且微软似乎并不乐意支持WebGL这个新特性,所以我们现在肯定不会用IE9来做实验。
3.设置场景
假定你已经选择了一个支持所有渲染技术的浏览器,而且你准备通过Canvas或WebGL来渲染场景(这是更标准化的选择)。Canvas比WebGL有着更广泛地支持,但是WebGL可以直接在GPU上操作,这意味着你的CPU可以专注地处理非渲染类的工作,比如物理引擎或与用户交互等。

 此外,Three.js可以加载很多格式的3D文件,你的模型文件可以来自Blender,Maya,Chinema4D,3DMax等等。而且内置了比较基础的东西:(球体)Spheres, (飞机)Planes, (立方体) Cubes, (圆柱体)Cylinders。Three.js创建这些物体会非常的容易。

无论你选择何种渲染器,你都必须牢记在心的是:JavaScript代码需要优化。三维显示对浏览器来说不是一项轻松的工作(现在能够这样做就很伟大了),所以如果你的渲染太慢了,你需要知道你代码的瓶颈在何处,如果可能,改善它。

好了,不废话了,直接看代码:

说了这么多,我想你已经下载好Three.js源代码,而且将它引入了你的html文档了。那么如何开始创建一个场景呢?就像这样:

代码如下:

复制代码 代码如下:

<!DOCTYPE html>
<html>
<head>
<title>threeJSDemo </title>
<meta charset="utf-8">
<style>
body
{
margin:0px;
background-color:#B0B0B0;
overload:hidden;
}
</style>
</head>
<body>
<script src="Three.js"></script>
<script>
var camera,scene,renderer;
var mesh;
init();
animate();

// 设置场景大小
var WIDTH = 400,
HEIGHT = 300;
// 设置一些相机参数
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
// 获取DOM结构中的元素
// - 假设我们使用了JQuery
var $container = $('#container');
// 创建渲染器、相机和场景
var renderer = new THREE.WebGLRenderer();
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
// 将相机加入场景
scene.add(camera);
// 相机的初始位置为原点
// 将相机拉回来一些(译者注:这样才能看到原点)
camera.position.z = 300;
// 启动渲染器
renderer.setSize(WIDTH, HEIGHT);
// 将渲染器加到DOM结构中
$container.append(renderer.domElement);

function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70,window.innerWidth / window.innerHeight,1,1000);
camera.position.z = 400;
scene.add(camera);
geometry = new THREE.CubeGeometry(200,200,200);
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.05;
mesh.rotation.y += 0.05;
renderer.render( scene, camera );
}
</script>
</body>
</html>

你看,简单吧!
4.构建网格表面
现在我们有了一个场景,一个相机和一个渲染器(在我的例子里,当然是一个WebGL渲染器),但我们事实上什么还没画呢。事实上,Three.js提供了载入某几种标准格式3D文件的支持,如果你在Blender,Maya,Cinema4D或是什么其他工具中建模,这简直太棒了。为了简单(毕竟这才刚开始呢!)我们先来考虑基元。基元就是基本的几何表面,比如最基本的球体、平面、立方体、圆柱体。利用Three.js可以很方便地创建这些基元:

这个是全部的代码,相对于前面使用WebGL的API的代码,这个简直就是太简单了。
代码很直观,就那么几步:

复制代码 代码如下:

  1. 创建场景scene。
  2. 创建摄像机camera。
  3. 创建/加载模型geometry。
  4. 加载材质material。
  5. 渲染模型对象mesh(是由geometry和material组成)。
  6. 启用动画。

// 设置球体参数(译者注:球体被划分为16×16的网格,如果后两个参数取4、2,则生成一个八面体,请想象)
var radius = 50,
segments = 16,
rings = 16;
// material覆盖在geometry上,生成mesh
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings),
sphereMaterial);
// 将mesh加入到场景中
scene.add(sphere);

这是每个框架都提供的功能,使用不同的框架除了函数的名称可能不同以外,这些步骤基本都是一样的。下面的参考中列出了很多的框架学习文档,大家可以选几种学习一下。

好了,但是球体上的材质呢?在代码中我们使用了一个sphereMaterial变量,我们还没定义它呢。那我们就先来看看怎么创建材质吧。
5.材质
毫无疑问,这是Three.js最有用的部分了。这部分提供了几个非常易用的通用材质模型:
1.Basic材质:表示一种不考虑光照的材质,现在只能这么说了。
2.Lambert材质:(译者注:朗伯面,各向同性反射)。
3.Phong材质:(译者注:冯氏面,有光泽的表面,介于镜面反射和朗伯反射之间的反射,描述真实世界的反射)。

针对模型数据,我还想说一点,因为JSON短小精悍,所以比较适合网络传输。未来它可能成为最适合WebGL的模型数据格式,所以很多的框架都开始支持JSON格式的模型数据。

除此之外,还有一些其他类型材质,简单起见,就留给你自己探索。事实上,在使用WebGL类型的渲染器时,材质实在太好用了。为什么呢?因为在原生WebGL种你必须亲自为每个渲染编写着色器,而着色器本身就是个巨大的工程:简单地说着色器是使用GLSL语言(OpenGL的着色器语言)写的,用来操作GPU的程序,这意味着你要在数学上模拟光照,反射等等,这很快就变成一项极为复杂的工作。多亏有了Three.js你才可以不必去自己编写着色器,当然,如果你想亲自编写的话,你可以使用MeshShaderMaterial,可见这是很灵活的设定。

实用参考:
开发中心:

现在,让我们用朗伯面材质覆盖球体:

精品在线开发工具:
各种框架基础教程:
WebGL中文教程:
Oak3D中文教程:
CubicVR3D官网:
Three.js图形库:
各种框架的收集贴:

复制代码 代码如下:

// 创建球体表面的材质
var sphereMaterial =
new THREE.MeshLambertMaterial(
{
color: 0xCC0000
});

值得指出的是,创建材质的时候,除了颜色还有很多其他参数可以指定,比如光滑度和环境贴图。你可以需要检索这个Wiki页面来确认哪些是哪些属性可以设置在材质上,或Three.js引擎提供的任何对象上。
6.光
如果你现在就想渲染场景,你会看到一个红色的圆。虽然我们在球体上覆盖了朗伯面材质,但场景里没有光。所以按照默认设定,Three.js会恢复到满环境光,物体的看上去的颜色就是物体表面的颜色。让我们添加一个简单的点光源:

复制代码 代码如下:

// 创建一个点光源
var pointLight =
new THREE.PointLight(0xFFFFFF);
// 设置点光源的位置
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// 将点光源加入场景
scene.add(pointLight);

7.渲染循环
显然,关于渲染器的一切都设置好了。万事俱备,我们现在只需要:

复制代码 代码如下:

// 画!
renderer.render(scene, camera);

你很可能像多次渲染,而不是只渲染一次,所以如果你要去做一个循环,你应该使用requestAnimationFrame。这是目前最好的,在浏览器中处理动画的方法,虽然还没有得到最全面的支持,但我强烈建议你去看一看Paul Irish的博客。
8.通用的对象属性
如果你花点时间去浏览一遍Three.js的源代码,你会发现很多对象都继承自Object3D。这个基类包含了很多有用的属性,比如位置、旋转和缩放的信息。特别的,我们的球体是一个Mesh对象,而Mesh对象继承自Object3D对象,但是又增加了些自己的属性:geometry和material。为什么要说这些?因为你一定不会只满足于屏幕中一个什么都不做的圆球,而这些(译者注:基类中的)属性允许你操作Mesh对象更底层的细节和各种各样的材质。

复制代码 代码如下:

// sphere是一个mesh对象
sphere.geometry
// sphere包含了一些点和面的信息
sphere.geometry.vertices // 一个数组
sphere.geometry.faces // 另一个数组
// mesh对象继承自object3d对象
sphere.position // 包含x,y,z
sphere.rotation // 同上
sphere.scale // ... 同上

9.讨厌的秘密
我希望这样说你能很快弄明白:就是如果你修改了,比如说,一个mesh对象的顶点属性vertices,你会发现在渲染循环中,什么都没变。为什么?因为Three.js将mesh对象的信息缓存为某种优化结构了。你真正要做的是给Three.js一个标识,告诉它如果什么东西改变了,需要重新计算缓存中的结构:

复制代码 代码如下:

// 设置geometry为动态的,这样才允许改变其中的顶点
sphere.geometry.dynamic = true;
// 告诉Three.js,需要重新计算顶点
sphere.geometry.__dirtyVertices = true;
// 告诉Three.js,需要重新计算顶点
sphere.geometry.__dirtyNormals = true;

还有更多的标识,但我发现这两个是最有用的。你应该仅仅标识那些确实需要实时计算的属性来避免无谓的运算开销。
10.小结
我希望这篇简单的介绍对你有所帮助。没什么能比得上卷起袖子亲手实践了,我强烈建议你这样做。在浏览器里面运行3D程序很有意思,而且使用像Three.js这样一个引擎免去了很多麻烦,让你一开始就能专注于那些真正cool的事情。

我将这篇教程的源码打包了,你可以下载下来作为一份参考。

...

本文由金沙棋牌发布于金沙棋牌官方平台,转载请注明出处:借助类库开发及框架介绍,JS使用前了解

关键词:

上一篇:流程控制,异步流程控制

下一篇:没有了