three.js 源码分析之FileLoader

//记录同一时间段中下载相同文件的标识,相同文件只下载一次

var loading = {};

    //封装文件下载类
    function FileLoader( manager ) {
        //使用默认的文件下载计数类
        this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;

    }

    Object.assign( FileLoader.prototype, {
        //下载
        load: function ( url, onLoad, onProgress, onError ) {
            //如果url为空
            if ( url === undefined ) url = '';
            //拼接url路径
            if ( this.path !== undefined ) url = this.path + url;
            //修改url
            url = this.manager.resolveURL( url );

            var scope = this;
            //在全局缓冲中查找文件
            var cached = Cache.get( url );
            //缓冲中找到了
            if ( cached !== undefined ) {
                //文件下载的计数类开始计数
                scope.manager.itemStart( url );
                //将下载回调放入到事件队列中,空闲时回调
                setTimeout( function () {
                    //单个文件下载完成
                    if ( onLoad ) onLoad( cached );
                    //所有文件其中一个下载完成
                    scope.manager.itemEnd( url );

                }, 0 );
                //返回文件
                return cached;

            }

            // Check if request is duplicate
            //查看是否有重复的下载项
            if ( loading[ url ] !== undefined ) {
                
                //设置同一个文件的回调队列
                loading[ url ].push( {

                    onLoad: onLoad,
                    onProgress: onProgress,
                    onError: onError

                } );

                return;

            }

            // Check for data: URI
            //url中已经带有base64的数据
            var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
            var dataUriRegexResult = url.match( dataUriRegex );

            // Safari can not handle Data URIs through XMLHttpRequest so process manually
            //不同浏览器的处理方式不同
            if ( dataUriRegexResult ) {

                var mimeType = dataUriRegexResult[ 1 ];        //数据的格式 png/jpeg
                var isBase64 = !! dataUriRegexResult[ 2 ];       //base64标志
                var data = dataUriRegexResult[ 3 ];                  //数据

                data = decodeURIComponent( data );              //解码数据,支持unicode编码

                if ( isBase64 ) data = atob( data );                     //解码base64        

                try {

                    var response;
                    var responseType = ( this.responseType || '' ).toLowerCase();     //响应的文件类型

                    switch ( responseType ) {

                        case 'arraybuffer':            //数组
                        case 'blob':                       //二进制文件              

                            var view = new Uint8Array( data.length );     //创建内存

                            for ( var i = 0; i < data.length; i ++ ) {

                                view[ i ] = data.charCodeAt( i );        //一个字节一个字节的赋值

                            }

                            if ( responseType === 'blob' ) {             //如果是二进制

                                response = new Blob( [ view.buffer ], { type: mimeType } );    //将文件转换为响应格式

                            } else {

                                response = view.buffer;       //

                            }

                            break;

                        case 'document':           //dom文档

                            var parser = new DOMParser();
                            response = parser.parseFromString( data, mimeType );

                            break;

                        case 'json':                    //json文件

                            response = JSON.parse( data );

                            break;

                        default: // 'text' or other       //文本文件

                            response = data;

                            break;

                    }

                    // Wait for next browser tick like standard XMLHttpRequest event dispatching does

                   //仿照XMLHttpRequest 的响应方式
                    setTimeout( function () {

                        if ( onLoad ) onLoad( response );

                        scope.manager.itemEnd( url );

                    }, 0 );

                } catch ( error ) {

                    // Wait for next browser tick like standard XMLHttpRequest event dispatching does
                    setTimeout( function () {

                        if ( onError ) onError( error );

                        scope.manager.itemError( url );
                        scope.manager.itemEnd( url );

                    }, 0 );

                }

            } else {

                // Initialise array for duplicate requests
                // 初始化这个url 的数组
                loading[ url ] = [];

                //添加响应函数
                loading[ url ].push( {

                    onLoad: onLoad,
                    onProgress: onProgress,
                    onError: onError

                } );

                //创建请求
                var request = new XMLHttpRequest();
                //设置请求类型
                request.open( 'GET', url, true );
                //添加下载完成监听
                request.addEventListener( 'load', function ( event ) {
                    //响应数据添加到缓冲中
                    var response = this.response;
                    
                    Cache.add( url, response );
                    //下载回调
                    var callbacks = loading[ url ];
                    
                    delete loading[ url ];

                    //下载状态
                    if ( this.status === 200 || this.status === 0 ) {
                        //本地文件状态为0
                        // Some browsers return HTTP Status 0 when using non-http protocol
                        // e.g. 'file://' or 'data://'. Handle as success.

                        if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
                        //调用回到
                        for ( var i = 0, il = callbacks.length; i < il; i ++ ) {

                            var callback = callbacks[ i ];
                            if ( callback.onLoad ) callback.onLoad( response );

                        }
                        //下载完成
                        scope.manager.itemEnd( url );

                    } else {

                        //下载错误,这是
                        for ( var i = 0, il = callbacks.length; i < il; i ++ ) {

                            var callback = callbacks[ i ];
                            if ( callback.onError ) callback.onError( event );

                        }

                        scope.manager.itemError( url );
                        scope.manager.itemEnd( url );

                    }

                }, false );

                //添加下载过程监听
                request.addEventListener( 'progress', function ( event ) {
                    //回调工程处理,主要是百分比
                    var callbacks = loading[ url ];

                    for ( var i = 0, il = callbacks.length; i < il; i ++ ) {

                        var callback = callbacks[ i ];
                        if ( callback.onProgress ) callback.onProgress( event );

                    }

                }, false );

                //添加错误监听
                request.addEventListener( 'error', function ( event ) {
                    
                    var callbacks = loading[ url ];

                    delete loading[ url ];

                    for ( var i = 0, il = callbacks.length; i < il; i ++ ) {

                        var callback = callbacks[ i ];
                        if ( callback.onError ) callback.onError( event );

                    }
                    //设置回调错误结束(manager所有文件的下载过程,不是单个文件的下载过程)
                    scope.manager.itemError( url );
                    scope.manager.itemEnd( url );

                }, false );

                //添加中断监听
                request.addEventListener( 'abort', function ( event ) {
                    //获取回调
                    var callbacks = loading[ url ];
                    //删除
                    delete loading[ url ];
                    //遍历回调
                    for ( var i = 0, il = callbacks.length; i < il; i ++ ) {

                        var callback = callbacks[ i ];
                        if ( callback.onError ) callback.onError( event );

                    }
                    //设置回调错误结束(manager所有文件的下载过程,不是单个文件的下载过程)
                    scope.manager.itemError( url );
                    scope.manager.itemEnd( url );

                }, false );

                //设置响应类型
                if ( this.responseType !== undefined ) request.responseType = this.responseType;
                //设置发送cookies
                if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
                //设置请求响应解析类型
                if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );

                //添加其他定义类型
                for ( var header in this.requestHeader ) {

                    request.setRequestHeader( header, this.requestHeader[ header ] );

                }

                //开始请求
                request.send( null );

            }
            //开始
            scope.manager.itemStart( url );

            return request;

        },

       //设置下载路径

        setPath: function ( value ) {

            this.path = value;
            return this;

        },

        setResponseType: function ( value ) {     //设置响应类型

            this.responseType = value;
            return this;

        },

        setWithCredentials: function ( value ) {    //设置携带的请求验证

            this.withCredentials = value;
            return this;

        },

        setMimeType: function ( value ) {          //设置mime类型

            this.mimeType = value;
            return this;

        },

        setRequestHeader: function ( value ) {     //设置请求头

            this.requestHeader = value;
            return this;

        }

    } );

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于Three.js的通过GeoJSON数据和灰度图生成3D地形图地图的代码示例: ```javascript // 创建场景、相机和渲染器 var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 50, 100); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 加载GeoJSON数据 var loader = new THREE.FileLoader(); loader.load('map.geojson', function(data) { var geojson = JSON.parse(data); // 创建平面面板 var width = 100; // 面板宽度 var height = 100; // 面板高度 var size = 256; // 面板像素数 var geometry = new THREE.PlaneGeometry(width, height, size - 1, size - 1); // 设置顶点高度 var grayData = new Uint8Array(size * size); var maxHeight = 10; // 最大高度值 for (var i = 0; i < size; i++) { for (var j = 0; j < size; j++) { var index = i * size + j; var coord = getCoord(j / size, i / size, geojson); var heightValue = coord ? coord.elevation : 0; geometry.vertices[index].z = heightValue; // 设置顶点的高度(z轴方向) grayData[index] = heightValue / maxHeight * 255; // 将高度值转换为0~255之间的像素值 } } // 创建灰度图像 var grayTexture = new THREE.DataTexture(grayData, size, size, THREE.LuminanceFormat); grayTexture.needsUpdate = true; // 创建材质和网格 var material = new THREE.MeshBasicMaterial({ map: grayTexture }); var mesh = new THREE.Mesh(geometry, material); scene.add(mesh); // 添加光源 var ambientLight = new THREE.AmbientLight(0x404040, 1); scene.add(ambientLight); var directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // 渲染场景 function render() { requestAnimationFrame(render); renderer.render(scene, camera); } render(); }); // 根据经纬度获取elevation值 function getCoord(lon, lat, geojson) { for (var i = 0; i < geojson.features.length; i++) { var feature = geojson.features[i]; if (feature.geometry.type == 'Polygon') { if (insidePolygon([lon, lat], feature.geometry.coordinates[0])) { return { elevation: feature.properties.elevation }; } } else if (feature.geometry.type == 'MultiPolygon') { for (var j = 0; j < feature.geometry.coordinates.length; j++) { if (insidePolygon([lon, lat], feature.geometry.coordinates[j][0])) { return { elevation: feature.properties.elevation }; } } } } return null; } // 判断一个点是否在多边形内部 function insidePolygon(point, polygon) { var x = point[0], y = point[1]; var inside = false; for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { var xi = polygon[i][0], yi = polygon[i][1]; var xj = polygon[j][0], yj = polygon[j][1]; var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; } ``` 在这个代码示例中,首先加载了一个GeoJSON数据文件`map.geojson`,可以根据实际情况修改文件名和路径。然后创建了一个100x100的平面面板,像素数为256x256,顶点高度根据GeoJSON数据中的经纬度坐标和elevation值设置。最终创建了一个基于灰度图像的3D地形网格,添加了环境光和定向光源,通过渲染器将场景渲染到屏幕上。 在设置顶点高度时,使用了`getCoord`函数来根据经纬度坐标获取elevation值,这个函数通过遍历GeoJSON数据中的所有Polygon和MultiPolygon,判断一个点是否在多边形内部,从而获取对应的elevation值。需要注意的是,这里使用了一个insidePolygon函数来判断一个点是否在多边形内部,这个函数可以通过射线法或者Winding Number算法来实现,这里使用的是射线法实现。 需要注意的是,在使用灰度图像作为材质贴图时,需要将高度值转换为0~255之间的像素值,并创建一个DataTexture对象来表示灰度图像。这里使用THREE.LuminanceFormat表示灰度图像的像素格式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值