├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── ThreeMap.css
├── ThreeMap.js
├── assets
└── imgs
│ └── planets
│ ├── Earth.png
│ ├── EarthNormal.png
│ ├── EarthSpec.png
│ ├── Mars-normalmap_2k.png
│ ├── Mars_2k-050104.png
│ ├── earth-specular.gif
│ ├── earth.jpg
│ ├── land_ocean.jpg
│ ├── mars_1k_color.jpg
│ └── mars_1k_normal.jpg
├── common
└── threejslibs
│ ├── Projector.js
│ └── stats.min.js
├── index.css
├── index.js
├── logo.svg
└── registerServiceWorker.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 详细博客地址:
2 | > [使用React+Three.js 封装一个三维地球](https://zrysmt.github.io/2017/09/23/%E4%BD%BF%E7%94%A8React+Three.js%E5%B0%81%E8%A3%85%E4%B8%80%E4%B8%AA%E4%B8%89%E7%BB%B4%E5%9C%B0%E7%90%83/)
3 |
4 | ## 1.环境
5 | 使用facebook给出的脚手架工具[create-react-app](https://github.com/facebookincubator/create-react-app).
6 |
7 | ```bash
8 | npm install -g create-react-app
9 |
10 | create-react-app react-threejs-app
11 | cd react-threejs-app/
12 | ```
13 | 执行
14 | ```bash
15 | npm start
16 | ```
17 | 浏览器会自动打开`localhost:3000`。
18 |
19 | ## 2.一步一个脚印
20 | ### 2.1 准备一张高清的世界地图
21 | 这里在github仓库中已经给出。
22 | ### 2.2 定义一个组件`ThreeMap`
23 | 在`ThreeMap.js`定义组件`ThreeMap`,并且创建改组件的样式`ThreeMap.css`。css定义三维地球的容器的宽度和高度。
24 | ```css
25 | #WebGL-output{
26 | width: 100%;
27 | height: 700px;
28 | }
29 | ```
30 | 并且该组件在`App.js`引用。
31 | ### 2.2 引入库和样式
32 | ```js
33 | import './ThreeMap.css';
34 | import React, { Component } from 'react';
35 | import * as THREE from 'three';
36 | import Orbitcontrols from 'three-orbitcontrols';
37 | import Stats from './common/threejslibs/stats.min.js';
38 | ```
39 | ### 2.3 初始化方法入口和要渲染的虚拟DOM
40 | ```js
41 | componentDidMount(){
42 | this.initThree();
43 | }
44 | ```
45 | 要渲染的虚拟DOM设定好
46 | ```js
47 | render(){
48 | return(
49 |
50 | )
51 | }
52 | ```
53 | ### 2.4 initThree方法
54 | - 创建场景
55 |
56 | ```js
57 | let scene;
58 | scene = new THREE.Scene();
59 | ```
60 | - 创建Group
61 |
62 | ```js
63 | let group;
64 | group = new THREE.Group();
65 | scene.add( group );
66 | ```
67 | - 创建相机
68 |
69 | ```js
70 | camera = new THREE.PerspectiveCamera( 60, width / height, 1, 2000 );
71 | camera.position.x = -10;
72 | camera.position.y = 15;
73 | camera.position.z = 500;
74 | camera.lookAt( scene.position );
75 | ```
76 | - 相机作为`Orbitcontrols`的参数,支持鼠标交互
77 |
78 | ```js
79 | let orbitControls = new Orbitcontrols(camera);
80 | orbitControls.autoRotate = false;
81 | ```
82 | - 添加光源:环境光和点光源
83 |
84 | ```js
85 | let ambi = new THREE.AmbientLight(0x686868); //环境光
86 | scene.add(ambi);
87 | let spotLight = new THREE.DirectionalLight(0xffffff); //点光源
88 | spotLight.position.set(550, 100, 550);
89 | spotLight.intensity = 0.6;
90 | scene.add(spotLight);
91 | ```
92 | - 创建模型和材质
93 |
94 | ```js
95 | let loader = new THREE.TextureLoader();
96 | let planetTexture = require("./assets/imgs/planets/Earth.png");
97 |
98 | loader.load( planetTexture, function ( texture ) {
99 | let geometry = new THREE.SphereGeometry( 200, 20, 20 );
100 | let material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
101 | let mesh = new THREE.Mesh( geometry, material );
102 | group.add( mesh );
103 | } );
104 | ```
105 | - 渲染
106 |
107 | ```js
108 | let renderer;
109 | renderer = new THREE.WebGLRenderer();
110 | renderer.setClearColor( 0xffffff );
111 | renderer.setPixelRatio( window.devicePixelRatio );
112 | renderer.setSize( width, height );
113 | container.appendChild( renderer.domElement );
114 | ```
115 | - 增加监控的信息状态
116 |
117 | ```js
118 | stats = new Stats();
119 | container.appendChild( stats.dom );
120 | ```
121 | **将以上封装到`init`函数中**
122 | - 动态渲染,地球自转
123 |
124 | ```js
125 | function animate() {
126 | requestAnimationFrame( animate );
127 | render();
128 | stats.update();
129 | }
130 | function render() {
131 | group.rotation.y -= 0.005; //这行可以控制地球自转
132 | renderer.render( scene, camera );
133 | }
134 | ```
135 | 调用的顺序是:
136 | ```js
137 | init();
138 | animate();
139 |
140 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-threejs-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^15.6.1",
7 | "react-dom": "^15.6.1",
8 | "react-scripts": "1.0.13",
9 | "three": "^0.87.1",
10 | "three-orbitcontrols": "^1.2.1"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "react-scripts build",
15 | "test": "react-scripts test --env=jsdom",
16 | "eject": "react-scripts eject"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 30px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 30px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-intro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes App-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 | import ThreeMap from './ThreeMap';
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |

12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | });
9 |
--------------------------------------------------------------------------------
/src/ThreeMap.css:
--------------------------------------------------------------------------------
1 | #WebGL-output{
2 | width: 100%;
3 | height: 700px;
4 | }
--------------------------------------------------------------------------------
/src/ThreeMap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * React+Three.js 三维地球
3 | */
4 | import './ThreeMap.css';
5 | import React, { Component } from 'react';
6 | import * as THREE from 'three';
7 | import Orbitcontrols from 'three-orbitcontrols';
8 | import Stats from './common/threejslibs/stats.min.js';
9 |
10 | class ThreeMap extends Component{
11 | componentDidMount(){
12 | this.initThree();
13 | }
14 | initThree(){
15 | let stats;
16 | let camera, scene, renderer;
17 | let group;
18 | let container = document.getElementById('WebGL-output');
19 | let width = container.clientWidth,height = container.clientHeight;
20 |
21 | init();
22 | animate();
23 |
24 | function init() {
25 | scene = new THREE.Scene();
26 | group = new THREE.Group();
27 | scene.add( group );
28 |
29 | camera = new THREE.PerspectiveCamera( 60, width / height, 1, 2000 );
30 | camera.position.x = -10;
31 | camera.position.y = 15;
32 | camera.position.z = 500;
33 | camera.lookAt( scene.position );
34 |
35 | //控制地球
36 | let orbitControls = new /*THREE.OrbitControls*/Orbitcontrols(camera);
37 | orbitControls.autoRotate = false;
38 | // let clock = new THREE.Clock();
39 | //光源
40 | let ambi = new THREE.AmbientLight(0x686868);
41 | scene.add(ambi);
42 |
43 | let spotLight = new THREE.DirectionalLight(0xffffff);
44 | spotLight.position.set(550, 100, 550);
45 | spotLight.intensity = 0.6;
46 |
47 | scene.add(spotLight);
48 | // Texture
49 | let loader = new THREE.TextureLoader();
50 | let planetTexture = require("./assets/imgs/planets/Earth.png");
51 |
52 | loader.load( planetTexture, function ( texture ) {
53 | let geometry = new THREE.SphereGeometry( 200, 20, 20 );
54 | let material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
55 | let mesh = new THREE.Mesh( geometry, material );
56 | group.add( mesh );
57 | } );
58 |
59 | renderer = new THREE.WebGLRenderer();
60 | renderer.setClearColor( 0xffffff );
61 | renderer.setPixelRatio( window.devicePixelRatio );
62 | renderer.setSize( width, height );
63 | container.appendChild( renderer.domElement );
64 | stats = new Stats();
65 | container.appendChild( stats.dom ); //增加状态信息
66 |
67 | }
68 |
69 | function animate() {
70 | requestAnimationFrame( animate );
71 | render();
72 | stats.update();
73 | }
74 | function render() {
75 | group.rotation.y -= 0.005; //这行可以控制地球自转
76 | renderer.render( scene, camera );
77 | }
78 | }
79 | render(){
80 | return(
81 |
82 | )
83 | }
84 | }
85 |
86 | export default ThreeMap;
--------------------------------------------------------------------------------
/src/assets/imgs/planets/Earth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/Earth.png
--------------------------------------------------------------------------------
/src/assets/imgs/planets/EarthNormal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/EarthNormal.png
--------------------------------------------------------------------------------
/src/assets/imgs/planets/EarthSpec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/EarthSpec.png
--------------------------------------------------------------------------------
/src/assets/imgs/planets/Mars-normalmap_2k.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/Mars-normalmap_2k.png
--------------------------------------------------------------------------------
/src/assets/imgs/planets/Mars_2k-050104.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/Mars_2k-050104.png
--------------------------------------------------------------------------------
/src/assets/imgs/planets/earth-specular.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/earth-specular.gif
--------------------------------------------------------------------------------
/src/assets/imgs/planets/earth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/earth.jpg
--------------------------------------------------------------------------------
/src/assets/imgs/planets/land_ocean.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/land_ocean.jpg
--------------------------------------------------------------------------------
/src/assets/imgs/planets/mars_1k_color.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/mars_1k_color.jpg
--------------------------------------------------------------------------------
/src/assets/imgs/planets/mars_1k_normal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/react-threejs-app/6bcafa341a0b3ffbfc223b2f124397f558a236f0/src/assets/imgs/planets/mars_1k_normal.jpg
--------------------------------------------------------------------------------
/src/common/threejslibs/Projector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | * @author supereggbert / http://www.paulbrunt.co.uk/
4 | * @author julianwa / https://github.com/julianwa
5 | */
6 | import * as THREE from 'three';
7 |
8 | THREE.RenderableObject = function () {
9 |
10 | this.id = 0;
11 |
12 | this.object = null;
13 | this.z = 0;
14 | this.renderOrder = 0;
15 |
16 | };
17 |
18 | //
19 |
20 | THREE.RenderableFace = function () {
21 |
22 | this.id = 0;
23 |
24 | this.v1 = new THREE.RenderableVertex();
25 | this.v2 = new THREE.RenderableVertex();
26 | this.v3 = new THREE.RenderableVertex();
27 |
28 | this.normalModel = new THREE.Vector3();
29 |
30 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
31 | this.vertexNormalsLength = 0;
32 |
33 | this.color = new THREE.Color();
34 | this.material = null;
35 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
36 |
37 | this.z = 0;
38 | this.renderOrder = 0;
39 |
40 | };
41 |
42 | //
43 |
44 | THREE.RenderableVertex = function () {
45 |
46 | this.position = new THREE.Vector3();
47 | this.positionWorld = new THREE.Vector3();
48 | this.positionScreen = new THREE.Vector4();
49 |
50 | this.visible = true;
51 |
52 | };
53 |
54 | THREE.RenderableVertex.prototype.copy = function ( vertex ) {
55 |
56 | this.positionWorld.copy( vertex.positionWorld );
57 | this.positionScreen.copy( vertex.positionScreen );
58 |
59 | };
60 |
61 | //
62 |
63 | THREE.RenderableLine = function () {
64 |
65 | this.id = 0;
66 |
67 | this.v1 = new THREE.RenderableVertex();
68 | this.v2 = new THREE.RenderableVertex();
69 |
70 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
71 | this.material = null;
72 |
73 | this.z = 0;
74 | this.renderOrder = 0;
75 |
76 | };
77 |
78 | //
79 |
80 | THREE.RenderableSprite = function () {
81 |
82 | this.id = 0;
83 |
84 | this.object = null;
85 |
86 | this.x = 0;
87 | this.y = 0;
88 | this.z = 0;
89 |
90 | this.rotation = 0;
91 | this.scale = new THREE.Vector2();
92 |
93 | this.material = null;
94 | this.renderOrder = 0;
95 |
96 | };
97 |
98 | //
99 |
100 | THREE.Projector = function () {
101 |
102 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
103 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
104 | _face, _faceCount, _facePool = [], _facePoolLength = 0,
105 | _line, _lineCount, _linePool = [], _linePoolLength = 0,
106 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
107 |
108 | _renderData = { objects: [], lights: [], elements: [] },
109 |
110 | _vector3 = new THREE.Vector3(),
111 | _vector4 = new THREE.Vector4(),
112 |
113 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
114 | _boundingBox = new THREE.Box3(),
115 | _points3 = new Array( 3 ),
116 |
117 | _viewMatrix = new THREE.Matrix4(),
118 | _viewProjectionMatrix = new THREE.Matrix4(),
119 |
120 | _modelMatrix,
121 | _modelViewProjectionMatrix = new THREE.Matrix4(),
122 |
123 | _normalMatrix = new THREE.Matrix3(),
124 |
125 | _frustum = new THREE.Frustum(),
126 |
127 | _clippedVertex1PositionScreen = new THREE.Vector4(),
128 | _clippedVertex2PositionScreen = new THREE.Vector4();
129 |
130 | //
131 |
132 | this.projectVector = function ( vector, camera ) {
133 |
134 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
135 | vector.project( camera );
136 |
137 | };
138 |
139 | this.unprojectVector = function ( vector, camera ) {
140 |
141 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
142 | vector.unproject( camera );
143 |
144 | };
145 |
146 | this.pickingRay = function () {
147 |
148 | console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
149 |
150 | };
151 |
152 | //
153 |
154 | var RenderList = function () {
155 |
156 | var normals = [];
157 | var colors = [];
158 | var uvs = [];
159 |
160 | var object = null;
161 | var material = null;
162 |
163 | var normalMatrix = new THREE.Matrix3();
164 |
165 | function setObject( value ) {
166 |
167 | object = value;
168 | material = object.material;
169 |
170 | normalMatrix.getNormalMatrix( object.matrixWorld );
171 |
172 | normals.length = 0;
173 | colors.length = 0;
174 | uvs.length = 0;
175 |
176 | }
177 |
178 | function projectVertex( vertex ) {
179 |
180 | var position = vertex.position;
181 | var positionWorld = vertex.positionWorld;
182 | var positionScreen = vertex.positionScreen;
183 |
184 | positionWorld.copy( position ).applyMatrix4( _modelMatrix );
185 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
186 |
187 | var invW = 1 / positionScreen.w;
188 |
189 | positionScreen.x *= invW;
190 | positionScreen.y *= invW;
191 | positionScreen.z *= invW;
192 |
193 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
194 | positionScreen.y >= - 1 && positionScreen.y <= 1 &&
195 | positionScreen.z >= - 1 && positionScreen.z <= 1;
196 |
197 | }
198 |
199 | function pushVertex( x, y, z ) {
200 |
201 | _vertex = getNextVertexInPool();
202 | _vertex.position.set( x, y, z );
203 |
204 | projectVertex( _vertex );
205 |
206 | }
207 |
208 | function pushNormal( x, y, z ) {
209 |
210 | normals.push( x, y, z );
211 |
212 | }
213 |
214 | function pushColor( r, g, b ) {
215 |
216 | colors.push( r, g, b );
217 |
218 | }
219 |
220 | function pushUv( x, y ) {
221 |
222 | uvs.push( x, y );
223 |
224 | }
225 |
226 | function checkTriangleVisibility( v1, v2, v3 ) {
227 |
228 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
229 |
230 | _points3[ 0 ] = v1.positionScreen;
231 | _points3[ 1 ] = v2.positionScreen;
232 | _points3[ 2 ] = v3.positionScreen;
233 |
234 | return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) );
235 |
236 | }
237 |
238 | function checkBackfaceCulling( v1, v2, v3 ) {
239 |
240 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
241 | ( v2.positionScreen.y - v1.positionScreen.y ) -
242 | ( v3.positionScreen.y - v1.positionScreen.y ) *
243 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
244 |
245 | }
246 |
247 | function pushLine( a, b ) {
248 |
249 | var v1 = _vertexPool[ a ];
250 | var v2 = _vertexPool[ b ];
251 |
252 | // Clip
253 |
254 | v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );
255 | v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );
256 |
257 | if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {
258 |
259 | // Perform the perspective divide
260 | v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );
261 | v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );
262 |
263 | _line = getNextLineInPool();
264 | _line.id = object.id;
265 | _line.v1.copy( v1 );
266 | _line.v2.copy( v2 );
267 | _line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );
268 | _line.renderOrder = object.renderOrder;
269 |
270 | _line.material = object.material;
271 |
272 | if ( object.material.vertexColors === THREE.VertexColors ) {
273 |
274 | _line.vertexColors[ 0 ].fromArray( colors, a * 3 );
275 | _line.vertexColors[ 1 ].fromArray( colors, b * 3 );
276 |
277 | }
278 |
279 | _renderData.elements.push( _line );
280 |
281 | }
282 |
283 | }
284 |
285 | function pushTriangle( a, b, c ) {
286 |
287 | var v1 = _vertexPool[ a ];
288 | var v2 = _vertexPool[ b ];
289 | var v3 = _vertexPool[ c ];
290 |
291 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
292 |
293 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
294 |
295 | _face = getNextFaceInPool();
296 |
297 | _face.id = object.id;
298 | _face.v1.copy( v1 );
299 | _face.v2.copy( v2 );
300 | _face.v3.copy( v3 );
301 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
302 | _face.renderOrder = object.renderOrder;
303 |
304 | // use first vertex normal as face normal
305 |
306 | _face.normalModel.fromArray( normals, a * 3 );
307 | _face.normalModel.applyMatrix3( normalMatrix ).normalize();
308 |
309 | for ( var i = 0; i < 3; i ++ ) {
310 |
311 | var normal = _face.vertexNormalsModel[ i ];
312 | normal.fromArray( normals, arguments[ i ] * 3 );
313 | normal.applyMatrix3( normalMatrix ).normalize();
314 |
315 | var uv = _face.uvs[ i ];
316 | uv.fromArray( uvs, arguments[ i ] * 2 );
317 |
318 | }
319 |
320 | _face.vertexNormalsLength = 3;
321 |
322 | _face.material = object.material;
323 |
324 | _renderData.elements.push( _face );
325 |
326 | }
327 |
328 | }
329 |
330 | return {
331 | setObject: setObject,
332 | projectVertex: projectVertex,
333 | checkTriangleVisibility: checkTriangleVisibility,
334 | checkBackfaceCulling: checkBackfaceCulling,
335 | pushVertex: pushVertex,
336 | pushNormal: pushNormal,
337 | pushColor: pushColor,
338 | pushUv: pushUv,
339 | pushLine: pushLine,
340 | pushTriangle: pushTriangle
341 | };
342 |
343 | };
344 |
345 | var renderList = new RenderList();
346 |
347 | function projectObject( object ) {
348 |
349 | if ( object.visible === false ) return;
350 |
351 | if ( object instanceof THREE.Light ) {
352 |
353 | _renderData.lights.push( object );
354 |
355 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) {
356 |
357 | if ( object.material.visible === false ) return;
358 | if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;
359 |
360 | addObject( object );
361 |
362 | } else if ( object instanceof THREE.Sprite ) {
363 |
364 | if ( object.material.visible === false ) return;
365 | if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;
366 |
367 | addObject( object );
368 |
369 | }
370 |
371 | var children = object.children;
372 |
373 | for ( var i = 0, l = children.length; i < l; i ++ ) {
374 |
375 | projectObject( children[ i ] );
376 |
377 | }
378 |
379 | }
380 |
381 | function addObject( object ) {
382 |
383 | _object = getNextObjectInPool();
384 | _object.id = object.id;
385 | _object.object = object;
386 |
387 | _vector3.setFromMatrixPosition( object.matrixWorld );
388 | _vector3.applyMatrix4( _viewProjectionMatrix );
389 | _object.z = _vector3.z;
390 | _object.renderOrder = object.renderOrder;
391 |
392 | _renderData.objects.push( _object );
393 |
394 | }
395 |
396 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
397 |
398 | _faceCount = 0;
399 | _lineCount = 0;
400 | _spriteCount = 0;
401 |
402 | _renderData.elements.length = 0;
403 |
404 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
405 | if ( camera.parent === null ) camera.updateMatrixWorld();
406 |
407 | _viewMatrix.copy( camera.matrixWorldInverse );
408 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
409 |
410 | _frustum.setFromMatrix( _viewProjectionMatrix );
411 |
412 | //
413 |
414 | _objectCount = 0;
415 |
416 | _renderData.objects.length = 0;
417 | _renderData.lights.length = 0;
418 |
419 | projectObject( scene );
420 |
421 | if ( sortObjects === true ) {
422 |
423 | _renderData.objects.sort( painterSort );
424 |
425 | }
426 |
427 | //
428 |
429 | var objects = _renderData.objects;
430 |
431 | for ( var o = 0, ol = objects.length; o < ol; o ++ ) {
432 |
433 | var object = objects[ o ].object;
434 | var geometry = object.geometry;
435 |
436 | renderList.setObject( object );
437 |
438 | _modelMatrix = object.matrixWorld;
439 |
440 | _vertexCount = 0;
441 |
442 | if ( object instanceof THREE.Mesh ) {
443 |
444 | if ( geometry instanceof THREE.BufferGeometry ) {
445 |
446 | var attributes = geometry.attributes;
447 | var groups = geometry.groups;
448 |
449 | if ( attributes.position === undefined ) continue;
450 |
451 | var positions = attributes.position.array;
452 |
453 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
454 |
455 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
456 |
457 | }
458 |
459 | if ( attributes.normal !== undefined ) {
460 |
461 | var normals = attributes.normal.array;
462 |
463 | for ( var i = 0, l = normals.length; i < l; i += 3 ) {
464 |
465 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
466 |
467 | }
468 |
469 | }
470 |
471 | if ( attributes.uv !== undefined ) {
472 |
473 | var uvs = attributes.uv.array;
474 |
475 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
476 |
477 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
478 |
479 | }
480 |
481 | }
482 |
483 | if ( geometry.index !== null ) {
484 |
485 | var indices = geometry.index.array;
486 |
487 | if ( groups.length > 0 ) {
488 |
489 | for ( var g = 0; g < groups.length; g ++ ) {
490 |
491 | var group = groups[ g ];
492 |
493 | for ( var i = group.start, l = group.start + group.count; i < l; i += 3 ) {
494 |
495 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
496 |
497 | }
498 |
499 | }
500 |
501 | } else {
502 |
503 | for ( var i = 0, l = indices.length; i < l; i += 3 ) {
504 |
505 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
506 |
507 | }
508 |
509 | }
510 |
511 | } else {
512 |
513 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
514 |
515 | renderList.pushTriangle( i, i + 1, i + 2 );
516 |
517 | }
518 |
519 | }
520 |
521 | } else if ( geometry instanceof THREE.Geometry ) {
522 |
523 | var vertices = geometry.vertices;
524 | var faces = geometry.faces;
525 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
526 |
527 | _normalMatrix.getNormalMatrix( _modelMatrix );
528 |
529 | var material = object.material;
530 |
531 | var isMultiMaterial = Array.isArray( material );
532 |
533 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
534 |
535 | var vertex = vertices[ v ];
536 |
537 | _vector3.copy( vertex );
538 |
539 | if ( material.morphTargets === true ) {
540 |
541 | var morphTargets = geometry.morphTargets;
542 | var morphInfluences = object.morphTargetInfluences;
543 |
544 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
545 |
546 | var influence = morphInfluences[ t ];
547 |
548 | if ( influence === 0 ) continue;
549 |
550 | var target = morphTargets[ t ];
551 | var targetVertex = target.vertices[ v ];
552 |
553 | _vector3.x += ( targetVertex.x - vertex.x ) * influence;
554 | _vector3.y += ( targetVertex.y - vertex.y ) * influence;
555 | _vector3.z += ( targetVertex.z - vertex.z ) * influence;
556 |
557 | }
558 |
559 | }
560 |
561 | renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );
562 |
563 | }
564 |
565 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
566 |
567 | var face = faces[ f ];
568 |
569 | material = isMultiMaterial === true
570 | ? object.material[ face.materialIndex ]
571 | : object.material;
572 |
573 | if ( material === undefined ) continue;
574 |
575 | var side = material.side;
576 |
577 | var v1 = _vertexPool[ face.a ];
578 | var v2 = _vertexPool[ face.b ];
579 | var v3 = _vertexPool[ face.c ];
580 |
581 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
582 |
583 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
584 |
585 | if ( side !== THREE.DoubleSide ) {
586 |
587 | if ( side === THREE.FrontSide && visible === false ) continue;
588 | if ( side === THREE.BackSide && visible === true ) continue;
589 |
590 | }
591 |
592 | _face = getNextFaceInPool();
593 |
594 | _face.id = object.id;
595 | _face.v1.copy( v1 );
596 | _face.v2.copy( v2 );
597 | _face.v3.copy( v3 );
598 |
599 | _face.normalModel.copy( face.normal );
600 |
601 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
602 |
603 | _face.normalModel.negate();
604 |
605 | }
606 |
607 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
608 |
609 | var faceVertexNormals = face.vertexNormals;
610 |
611 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
612 |
613 | var normalModel = _face.vertexNormalsModel[ n ];
614 | normalModel.copy( faceVertexNormals[ n ] );
615 |
616 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
617 |
618 | normalModel.negate();
619 |
620 | }
621 |
622 | normalModel.applyMatrix3( _normalMatrix ).normalize();
623 |
624 | }
625 |
626 | _face.vertexNormalsLength = faceVertexNormals.length;
627 |
628 | var vertexUvs = faceVertexUvs[ f ];
629 |
630 | if ( vertexUvs !== undefined ) {
631 |
632 | for ( var u = 0; u < 3; u ++ ) {
633 |
634 | _face.uvs[ u ].copy( vertexUvs[ u ] );
635 |
636 | }
637 |
638 | }
639 |
640 | _face.color = face.color;
641 | _face.material = material;
642 |
643 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
644 | _face.renderOrder = object.renderOrder;
645 |
646 | _renderData.elements.push( _face );
647 |
648 | }
649 |
650 | }
651 |
652 | } else if ( object instanceof THREE.Line ) {
653 |
654 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
655 |
656 | if ( geometry instanceof THREE.BufferGeometry ) {
657 |
658 | var attributes = geometry.attributes;
659 |
660 | if ( attributes.position !== undefined ) {
661 |
662 | var positions = attributes.position.array;
663 |
664 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
665 |
666 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
667 |
668 | }
669 |
670 | if ( attributes.color !== undefined ) {
671 |
672 | var colors = attributes.color.array;
673 |
674 | for ( var i = 0, l = colors.length; i < l; i += 3 ) {
675 |
676 | renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
677 |
678 | }
679 |
680 | }
681 |
682 | if ( geometry.index !== null ) {
683 |
684 | var indices = geometry.index.array;
685 |
686 | for ( var i = 0, l = indices.length; i < l; i += 2 ) {
687 |
688 | renderList.pushLine( indices[ i ], indices[ i + 1 ] );
689 |
690 | }
691 |
692 | } else {
693 |
694 | var step = object instanceof THREE.LineSegments ? 2 : 1;
695 |
696 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
697 |
698 | renderList.pushLine( i, i + 1 );
699 |
700 | }
701 |
702 | }
703 |
704 | }
705 |
706 | } else if ( geometry instanceof THREE.Geometry ) {
707 |
708 | var vertices = object.geometry.vertices;
709 |
710 | if ( vertices.length === 0 ) continue;
711 |
712 | v1 = getNextVertexInPool();
713 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
714 |
715 | var step = object instanceof THREE.LineSegments ? 2 : 1;
716 |
717 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
718 |
719 | v1 = getNextVertexInPool();
720 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
721 |
722 | if ( ( v + 1 ) % step > 0 ) continue;
723 |
724 | v2 = _vertexPool[ _vertexCount - 2 ];
725 |
726 | _clippedVertex1PositionScreen.copy( v1.positionScreen );
727 | _clippedVertex2PositionScreen.copy( v2.positionScreen );
728 |
729 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
730 |
731 | // Perform the perspective divide
732 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
733 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
734 |
735 | _line = getNextLineInPool();
736 |
737 | _line.id = object.id;
738 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
739 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
740 |
741 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
742 | _line.renderOrder = object.renderOrder;
743 |
744 | _line.material = object.material;
745 |
746 | if ( object.material.vertexColors === THREE.VertexColors ) {
747 |
748 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
749 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
750 |
751 | }
752 |
753 | _renderData.elements.push( _line );
754 |
755 | }
756 |
757 | }
758 |
759 | }
760 |
761 | } else if ( object instanceof THREE.Points ) {
762 |
763 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
764 |
765 | if ( geometry instanceof THREE.Geometry ) {
766 |
767 | var vertices = object.geometry.vertices;
768 |
769 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
770 |
771 | var vertex = vertices[ v ];
772 |
773 | _vector4.set( vertex.x, vertex.y, vertex.z, 1 );
774 | _vector4.applyMatrix4( _modelViewProjectionMatrix );
775 |
776 | pushPoint( _vector4, object, camera );
777 |
778 | }
779 |
780 | } else if ( geometry instanceof THREE.BufferGeometry ) {
781 |
782 | var attributes = geometry.attributes;
783 |
784 | if ( attributes.position !== undefined ) {
785 |
786 | var positions = attributes.position.array;
787 |
788 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
789 |
790 | _vector4.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ], 1 );
791 | _vector4.applyMatrix4( _modelViewProjectionMatrix );
792 |
793 | pushPoint( _vector4, object, camera );
794 |
795 | }
796 |
797 | }
798 |
799 | }
800 |
801 | } else if ( object instanceof THREE.Sprite ) {
802 |
803 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
804 | _vector4.applyMatrix4( _viewProjectionMatrix );
805 |
806 | pushPoint( _vector4, object, camera );
807 |
808 | }
809 |
810 | }
811 |
812 | if ( sortElements === true ) {
813 |
814 | _renderData.elements.sort( painterSort );
815 |
816 | }
817 |
818 | return _renderData;
819 |
820 | };
821 |
822 | function pushPoint( _vector4, object, camera ) {
823 |
824 | var invW = 1 / _vector4.w;
825 |
826 | _vector4.z *= invW;
827 |
828 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
829 |
830 | _sprite = getNextSpriteInPool();
831 | _sprite.id = object.id;
832 | _sprite.x = _vector4.x * invW;
833 | _sprite.y = _vector4.y * invW;
834 | _sprite.z = _vector4.z;
835 | _sprite.renderOrder = object.renderOrder;
836 | _sprite.object = object;
837 |
838 | _sprite.rotation = object.rotation;
839 |
840 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
841 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
842 |
843 | _sprite.material = object.material;
844 |
845 | _renderData.elements.push( _sprite );
846 |
847 | }
848 |
849 | }
850 |
851 | // Pools
852 |
853 | function getNextObjectInPool() {
854 |
855 | if ( _objectCount === _objectPoolLength ) {
856 |
857 | var object = new THREE.RenderableObject();
858 | _objectPool.push( object );
859 | _objectPoolLength ++;
860 | _objectCount ++;
861 | return object;
862 |
863 | }
864 |
865 | return _objectPool[ _objectCount ++ ];
866 |
867 | }
868 |
869 | function getNextVertexInPool() {
870 |
871 | if ( _vertexCount === _vertexPoolLength ) {
872 |
873 | var vertex = new THREE.RenderableVertex();
874 | _vertexPool.push( vertex );
875 | _vertexPoolLength ++;
876 | _vertexCount ++;
877 | return vertex;
878 |
879 | }
880 |
881 | return _vertexPool[ _vertexCount ++ ];
882 |
883 | }
884 |
885 | function getNextFaceInPool() {
886 |
887 | if ( _faceCount === _facePoolLength ) {
888 |
889 | var face = new THREE.RenderableFace();
890 | _facePool.push( face );
891 | _facePoolLength ++;
892 | _faceCount ++;
893 | return face;
894 |
895 | }
896 |
897 | return _facePool[ _faceCount ++ ];
898 |
899 |
900 | }
901 |
902 | function getNextLineInPool() {
903 |
904 | if ( _lineCount === _linePoolLength ) {
905 |
906 | var line = new THREE.RenderableLine();
907 | _linePool.push( line );
908 | _linePoolLength ++;
909 | _lineCount ++;
910 | return line;
911 |
912 | }
913 |
914 | return _linePool[ _lineCount ++ ];
915 |
916 | }
917 |
918 | function getNextSpriteInPool() {
919 |
920 | if ( _spriteCount === _spritePoolLength ) {
921 |
922 | var sprite = new THREE.RenderableSprite();
923 | _spritePool.push( sprite );
924 | _spritePoolLength ++;
925 | _spriteCount ++;
926 | return sprite;
927 |
928 | }
929 |
930 | return _spritePool[ _spriteCount ++ ];
931 |
932 | }
933 |
934 | //
935 |
936 | function painterSort( a, b ) {
937 |
938 | if ( a.renderOrder !== b.renderOrder ) {
939 |
940 | return a.renderOrder - b.renderOrder;
941 |
942 | } else if ( a.z !== b.z ) {
943 |
944 | return b.z - a.z;
945 |
946 | } else if ( a.id !== b.id ) {
947 |
948 | return a.id - b.id;
949 |
950 | } else {
951 |
952 | return 0;
953 |
954 | }
955 |
956 | }
957 |
958 | function clipLine( s1, s2 ) {
959 |
960 | var alpha1 = 0, alpha2 = 1,
961 |
962 | // Calculate the boundary coordinate of each vertex for the near and far clip planes,
963 | // Z = -1 and Z = +1, respectively.
964 |
965 | bc1near = s1.z + s1.w,
966 | bc2near = s2.z + s2.w,
967 | bc1far = - s1.z + s1.w,
968 | bc2far = - s2.z + s2.w;
969 |
970 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
971 |
972 | // Both vertices lie entirely within all clip planes.
973 | return true;
974 |
975 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
976 |
977 | // Both vertices lie entirely outside one of the clip planes.
978 | return false;
979 |
980 | } else {
981 |
982 | // The line segment spans at least one clip plane.
983 |
984 | if ( bc1near < 0 ) {
985 |
986 | // v1 lies outside the near plane, v2 inside
987 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
988 |
989 | } else if ( bc2near < 0 ) {
990 |
991 | // v2 lies outside the near plane, v1 inside
992 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
993 |
994 | }
995 |
996 | if ( bc1far < 0 ) {
997 |
998 | // v1 lies outside the far plane, v2 inside
999 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
1000 |
1001 | } else if ( bc2far < 0 ) {
1002 |
1003 | // v2 lies outside the far plane, v2 inside
1004 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
1005 |
1006 | }
1007 |
1008 | if ( alpha2 < alpha1 ) {
1009 |
1010 | // The line segment spans two boundaries, but is outside both of them.
1011 | // (This can't happen when we're only clipping against just near/far but good
1012 | // to leave the check here for future usage if other clip planes are added.)
1013 | return false;
1014 |
1015 | } else {
1016 |
1017 | // Update the s1 and s2 vertices to match the clipped line segment.
1018 | s1.lerp( s2, alpha1 );
1019 | s2.lerp( s1, 1 - alpha2 );
1020 |
1021 | return true;
1022 |
1023 | }
1024 |
1025 | }
1026 |
1027 | }
1028 |
1029 | };
1030 |
--------------------------------------------------------------------------------
/src/common/threejslibs/stats.min.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats = function() {
3 | function h(a) { c.appendChild(a.dom); return a }
4 |
5 | function k(a) { for (var d = 0; d < c.children.length; d++) c.children[d].style.display = d === a ? "block" : "none";
6 | l = a }
7 | var l = 0,
8 | c = document.createElement("div");
9 | c.style.cssText = "position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
10 | c.addEventListener("click", function(a) { a.preventDefault();
11 | k(++l % c.children.length) }, !1);
12 | var g = (performance || Date).now(),
13 | e = g,
14 | a = 0,
15 | r = h(new Stats.Panel("FPS", "#0ff", "#002")),
16 | f = h(new Stats.Panel("MS", "#0f0", "#020"));
17 | if (this.performance && this.performance.memory) var t = h(new Stats.Panel("MB", "#f08", "#201"));
18 | k(0);
19 | return { REVISION: 16, dom: c, addPanel: h, showPanel: k, begin: function() { g = (performance || Date).now() }, end: function() { a++; var c = (performance || Date).now();
20 | f.update(c - g, 200); if (c > e + 1E3 && (r.update(1E3 * a / (c - e), 100), e = c, a = 0, t)) { var d = performance.memory;
21 | t.update(d.usedJSHeapSize / 1048576, d.jsHeapSizeLimit / 1048576) } return c }, update: function() { g = this.end() }, domElement: c, setMode: k }
22 | };
23 | Stats.Panel = function(h, k, l) {
24 | var c = Infinity,
25 | g = 0,
26 | e = Math.round,
27 | a = e(window.devicePixelRatio || 1),
28 | r = 80 * a,
29 | f = 48 * a,
30 | t = 3 * a,
31 | u = 2 * a,
32 | d = 3 * a,
33 | m = 15 * a,
34 | n = 74 * a,
35 | p = 30 * a,
36 | q = document.createElement("canvas");
37 | q.width = r;
38 | q.height = f;
39 | q.style.cssText = "width:80px;height:48px";
40 | var b = q.getContext("2d");
41 | b.font = "bold " + 9 * a + "px Helvetica,Arial,sans-serif";
42 | b.textBaseline = "top";
43 | b.fillStyle = l;
44 | b.fillRect(0, 0, r, f);
45 | b.fillStyle = k;
46 | b.fillText(h, t, u);
47 | b.fillRect(d, m, n, p);
48 | b.fillStyle = l;
49 | b.globalAlpha = .9;
50 | b.fillRect(d, m, n, p);
51 | return {
52 | dom: q,
53 | update: function(f,
54 | v) { c = Math.min(c, f);
55 | g = Math.max(g, f);
56 | b.fillStyle = l;
57 | b.globalAlpha = 1;
58 | b.fillRect(0, 0, r, m);
59 | b.fillStyle = k;
60 | b.fillText(e(f) + " " + h + " (" + e(c) + "-" + e(g) + ")", t, u);
61 | b.drawImage(q, d + a, m, n - a, p, d, m, n - a, p);
62 | b.fillRect(d + n - a, m, a, p);
63 | b.fillStyle = l;
64 | b.globalAlpha = .9;
65 | b.fillRect(d + n - a, m, a, e((1 - f / v) * p)) }
66 | }
67 | };
68 | export default Stats;
69 | // "object" === typeof module && (module.exports = Stats);
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 | registerServiceWorker();
9 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (!isLocalhost) {
36 | // Is not local host. Just register service worker
37 | registerValidSW(swUrl);
38 | } else {
39 | // This is running on localhost. Lets check if a service worker still exists or not.
40 | checkValidServiceWorker(swUrl);
41 | }
42 | });
43 | }
44 | }
45 |
46 | function registerValidSW(swUrl) {
47 | navigator.serviceWorker
48 | .register(swUrl)
49 | .then(registration => {
50 | registration.onupdatefound = () => {
51 | const installingWorker = registration.installing;
52 | installingWorker.onstatechange = () => {
53 | if (installingWorker.state === 'installed') {
54 | if (navigator.serviceWorker.controller) {
55 | // At this point, the old content will have been purged and
56 | // the fresh content will have been added to the cache.
57 | // It's the perfect time to display a "New content is
58 | // available; please refresh." message in your web app.
59 | console.log('New content is available; please refresh.');
60 | } else {
61 | // At this point, everything has been precached.
62 | // It's the perfect time to display a
63 | // "Content is cached for offline use." message.
64 | console.log('Content is cached for offline use.');
65 | }
66 | }
67 | };
68 | };
69 | })
70 | .catch(error => {
71 | console.error('Error during service worker registration:', error);
72 | });
73 | }
74 |
75 | function checkValidServiceWorker(swUrl) {
76 | // Check if the service worker can be found. If it can't reload the page.
77 | fetch(swUrl)
78 | .then(response => {
79 | // Ensure service worker exists, and that we really are getting a JS file.
80 | if (
81 | response.status === 404 ||
82 | response.headers.get('content-type').indexOf('javascript') === -1
83 | ) {
84 | // No service worker found. Probably a different app. Reload the page.
85 | navigator.serviceWorker.ready.then(registration => {
86 | registration.unregister().then(() => {
87 | window.location.reload();
88 | });
89 | });
90 | } else {
91 | // Service worker found. Proceed as normal.
92 | registerValidSW(swUrl);
93 | }
94 | })
95 | .catch(() => {
96 | console.log(
97 | 'No internet connection found. App is running in offline mode.'
98 | );
99 | });
100 | }
101 |
102 | export function unregister() {
103 | if ('serviceWorker' in navigator) {
104 | navigator.serviceWorker.ready.then(registration => {
105 | registration.unregister();
106 | });
107 | }
108 | }
109 |
--------------------------------------------------------------------------------