├── index.js
├── .gitignore
├── assets
├── logo.png
├── wifi.png
├── 3dline.png
├── scatter.png
├── border-top.png
├── policecar.png
├── policehat.png
├── border-bottom.png
├── border-left.png
├── border-right.png
├── policestation.png
├── circle.svg
├── heatLinesRoad.json
└── loader
│ ├── MTLLoader.js
│ ├── OBJLoader2.js
│ └── LoaderSupport.js
├── src
├── amap.js
├── AMapModel.js
├── AMapView.js
└── AMapCoordSys.js
├── webpack.config.js
├── package.json
├── LICENSE
├── examples
├── index.2.html
├── index.4.html
├── index.3.html
├── amap3d-bus-line.html
└── index.1.html
├── README.md
├── dist
├── echarts-amap.min.js
└── echarts-amap.min.js.map
└── index.html
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./dist/echarts-amap.min.js')
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | assets/model/
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/logo.png
--------------------------------------------------------------------------------
/assets/wifi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/wifi.png
--------------------------------------------------------------------------------
/assets/3dline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/3dline.png
--------------------------------------------------------------------------------
/assets/scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/scatter.png
--------------------------------------------------------------------------------
/assets/border-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/border-top.png
--------------------------------------------------------------------------------
/assets/policecar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/policecar.png
--------------------------------------------------------------------------------
/assets/policehat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/policehat.png
--------------------------------------------------------------------------------
/assets/border-bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/border-bottom.png
--------------------------------------------------------------------------------
/assets/border-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/border-left.png
--------------------------------------------------------------------------------
/assets/border-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/border-right.png
--------------------------------------------------------------------------------
/assets/policestation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfEric/echarts-amap/HEAD/assets/policestation.png
--------------------------------------------------------------------------------
/src/amap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * BMap component extension
3 | */
4 | require('echarts').registerCoordinateSystem(
5 | 'amap', require('./AMapCoordSys')
6 | );
7 | require('./AMapModel');
8 | require('./AMapView');
9 |
10 | // Action
11 | require('echarts').registerAction({
12 | type: 'amapRoam',
13 | event: 'amapRoam',
14 | update: 'updateLayout'
15 | }, function (payload, ecModel) {
16 | ecModel.eachComponent('amap', function (aMapModel) {
17 | var amap = aMapModel.getAMap();
18 | var center = amap.getCenter();
19 | aMapModel.setCenterAndZoom([center.lng, center.lat], amap.getZoom());
20 | });
21 | });
22 |
23 | module.exports = {
24 | version: process.env.VERSION
25 | };
26 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var packagejson = require('./package.json');
3 | var PROD = process.argv.indexOf('-p') >= 0;
4 |
5 | console.log('building package version ' + packagejson.version)
6 | module.exports = {
7 | entry: {
8 | 'amap': __dirname + '/src/amap.js',
9 | },
10 | output: {
11 | libraryTarget: 'umd',
12 | library: ['echarts', '[name]'],
13 | path: __dirname + '/dist',
14 | filename: PROD ? 'echarts-[name].min.js' : 'echarts-[name].js'
15 | },
16 | externals: {
17 | 'echarts': 'echarts'
18 | },
19 | devtool: PROD ? '#source-map' : '#eval-source-map',
20 | plugins: [
21 | new webpack.DefinePlugin({
22 | 'process.env.VERSION': JSON.stringify(packagejson.version)
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/src/AMapModel.js:
--------------------------------------------------------------------------------
1 | function v2Equal(a, b) {
2 | return a && b && a[0] === b[0] && a[1] === b[1];
3 | }
4 |
5 | module.exports = require('echarts').extendComponentModel({
6 | type: 'amap',
7 |
8 | getAMap: function () {
9 | // __amap is injected when creating AMapCoordSys
10 | return this.__amap;
11 | },
12 |
13 | getLayer: function() {
14 | // __layer is injected when creating AMapCoordSys
15 | return this.__layer;
16 | },
17 |
18 | getMapOptions: function() {
19 | return this.__options;
20 | },
21 |
22 | setCenterAndZoom: function (center, zoom) {
23 | this.option.center = center;
24 | this.option.zoom = zoom;
25 | },
26 | centerOrZoomChanged: function (center, zoom) {
27 | var option = this.option;
28 | return !(v2Equal(center, option.center) && zoom === option.zoom);
29 | },
30 |
31 | defaultOption: {
32 | center: [116.397475,39.908695],
33 | zoom: 4,
34 | }
35 | });
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "echarts-amap",
3 | "version": "1.0.0-rc.6",
4 | "description": "\u0016an echarts extension to support AMap(http://lbs.amap.com/)",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "webpack-dev-server --open --hot",
8 | "build": "webpack -p",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/billy-poon/echarts-amap.git"
14 | },
15 | "keywords": [
16 | "echarts",
17 | "amap",
18 | "alimap",
19 | "autonavi"
20 | ],
21 | "author": "Billy Poon",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/billy-poon/echarts-amap/issues"
25 | },
26 | "homepage": "https://github.com/billy-poon/echarts-amap#readme",
27 | "devDependencies": {
28 | "webpack": "^2.2.1",
29 | "webpack-dev-server": "^2.4.1"
30 | },
31 | "dependencies": {
32 | "echarts": "^4.0.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 billy-poon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/heatLinesRoad.json:
--------------------------------------------------------------------------------
1 | [
2 | [
3 | "河南中路-泗泾路-东南角",
4 | "河南中路-昭通路-西南角",
5 | "河南中路-福州路-东南角",
6 | "河南中路-汉口路-南向中间隔离带",
7 | "河南中路-九江路西-南角",
8 | "河南中路-天津路-西北角",
9 | "河南中路-宁波路-西南角",
10 | "河南中路-北京东路(河南路桥口)-西南角"
11 | ],
12 | [
13 | "延安东路-江西中路-东北角",
14 | "江西中路-广东路-西南角",
15 | "江西中路-福州路-东北角",
16 | "江西中路-福州路-西北角",
17 | "江西中路-江西中路222号-对面(劳动局信访办)",
18 | "江西中路-九江路-东南角",
19 | "江西中路-滇池路-东南角",
20 | "江西中路-宁波路-东南角"
21 | ],
22 | [
23 | "四川中路-广东路-东南角",
24 | "四川中路-福州路-东南角",
25 | "四川中路-汉口路-东北角",
26 | "四川中路-九江路-西南角",
27 | "南京东路-四川中路-东北角",
28 | "四川中路-滇池路-西北角",
29 | "北京东路-四川中路-西北角",
30 | "四川中路-四川中路590号-门口"
31 | ],
32 | [
33 | "中山东一路-广东路-东侧",
34 | "中山东一路-气象广场-北侧",
35 | "中山东一路-福州路-东侧",
36 | "中山东一路-汉口路-东侧",
37 | "中山东一路-九江路-东侧",
38 | "中山东一路-九江路-西北角",
39 | "中山东一路-陈毅广场-南侧",
40 | "中山东一路-南京东路-东侧",
41 | "中山东一路-滇池路-东侧",
42 | "中山东一路-陈毅广场-北侧",
43 | "中山东一路-北京东路-东北角",
44 | "中山东一路-延安东路(水文站)-东侧"
45 | ],
46 | [
47 | "中山东一路-北京东路-东北角",
48 | "北京东路-圆明园路-西南角",
49 | "北京东路-虎丘路-东北角",
50 | "北京东路-江西中路-东北角",
51 | "北京东路-江西中路-东北角",
52 | "河南中路-北京东路(河南路桥口)-西南角"
53 | ],
54 | [
55 | "中山东一路-滇池路-东侧",
56 | "圆明园路-滇池路-东北角",
57 | "中山东一路-滇池路-东侧",
58 | "江西中路-滇池路-东南角",
59 | "河南中路-天津路-西北角"
60 | ],
61 | [
62 | "中山东一路-南京东路-东侧",
63 | "南京东路-四川中路-东北角",
64 | "南京东路-江西中路-东北角"
65 | ],
66 | [
67 | "中山东一路-九江路-东侧",
68 | "中山东一路-九江路-西北角",
69 | "四川中路-九江路-西南角",
70 | "江西中路-九江路-东南角",
71 | "河南中路-九江路西-南角"
72 | ],
73 | [
74 | "中山东一路-汉口路-东侧",
75 | "四川中路-汉口路-东北角",
76 | "江西中路-汉口路-西北角",
77 | "汉口路-193号对面",
78 | "河南中路-汉口路-南向中间隔离带"
79 | ],
80 | [
81 | "中山东一路-福州路-东侧",
82 | "四川中路-福州路-东南角",
83 | "江西中路-福州路-西北角",
84 | "江西中路-福州路-东北角",
85 | "福州路-185号-北侧",
86 | "河南中路-福州路-东南角"
87 | ],
88 | ["中山东一路-广东路-东侧", "四川中路-广东路-东南角", "江西中路-广东路-西南角"]
89 | ]
90 |
--------------------------------------------------------------------------------
/examples/index.2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Echarts plugin to support AMap
7 |
8 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/examples/index.4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 点是否在多边形内
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
73 |
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ECharts Extension AMap
2 |
3 | An echarts extension to support AMap(http://lbs.amap.com/), Ported from the offical echarts `extension-bmap`
4 |
5 | > https://github.com/ecomfe/echarts/tree/master/extension/bmap
6 |
7 | ## Install
8 |
9 | ```bash
10 | npm install -S echarts-amap
11 | ```
12 |
13 | ## Get Started
14 |
15 | **Using Script Tag**
16 |
17 | ```html
18 |
19 |
20 |
21 |
22 | ECharts AMap Test
23 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
77 |
78 |
79 | ```
80 |
81 | **Using Webpack**
82 |
83 | ```javascript
84 | var echarts = require('echarts')
85 | require('echarts-amap')
86 |
87 | var echart = echarts.init(document.getElementById('map'))
88 | echart.setOption({
89 | ... // see the example above
90 | })
91 | ```
92 |
93 | ###20180417更新日志
94 |
95 | >支持高德地图3D地图,可以实现更多炫酷效果,部分截图如下:
96 |
97 |
98 | 
99 |
100 | 
101 |
102 |
--------------------------------------------------------------------------------
/src/AMapView.js:
--------------------------------------------------------------------------------
1 | /*
2 | * this function bollowed from:
3 | * https://github.com/Leaflet/Leaflet/blob/master/src/core/Util.js
4 | */
5 | function throttle(fn, time, context) {
6 | var lock, args, wrapperFn, later;
7 |
8 | later = function () {
9 | // reset lock and call if queued
10 | lock = false;
11 | if (args) {
12 | wrapperFn.apply(context, args);
13 | args = false;
14 | }
15 | };
16 |
17 | wrapperFn = function () {
18 | if (lock) {
19 | // called too soon, queue to call later
20 | args = arguments;
21 |
22 | } else {
23 | // call and lock until later
24 | fn.apply(context, arguments);
25 | setTimeout(later, time);
26 | lock = true;
27 | }
28 | };
29 |
30 | return wrapperFn;
31 | }
32 |
33 | var echarts = require('echarts');
34 |
35 | module.exports = require('echarts').extendComponentView({
36 | type: 'amap',
37 | render: function (aMapModel, ecModel, api) {
38 | var rendering = true;
39 |
40 | var amap = aMapModel.getAMap();
41 | var viewportRoot = api.getZr().painter.getViewportRoot();
42 | var coordSys = aMapModel.coordinateSystem;
43 | var moveHandler = function (e) {
44 | if (rendering) {
45 | return;
46 | }
47 | var offsetEl = viewportRoot.parentNode.parentNode.parentNode;
48 | var mapOffset = [
49 | -parseInt(offsetEl.style.left, 10) || 0,
50 | -parseInt(offsetEl.style.top, 10) || 0
51 | ];
52 | viewportRoot.style.left = mapOffset[0] + 'px';
53 | viewportRoot.style.top = mapOffset[1] + 'px';
54 |
55 | coordSys.setMapOffset(mapOffset);
56 | aMapModel.__mapOffset = mapOffset;
57 |
58 | api.dispatchAction({
59 | type: 'amapRoam'
60 | });
61 | };
62 |
63 | function zoomEndHandler() {
64 | if (rendering) {
65 | return;
66 | }
67 | api.dispatchAction({
68 | type: 'amapRoam'
69 | });
70 | }
71 |
72 | function resizeHandler(e) {
73 | echarts.getInstanceByDom(api.getDom()).resize();
74 | moveHandler.call(this, e)
75 | }
76 |
77 | var throttledResizeHandler = throttle(resizeHandler, 300, amap);
78 |
79 | amap.off('movestart', this._oldMoveHandler);
80 | amap.off('zoomend', this._oldZoomEndHandler);
81 | amap.off('moveend', this._oldZoomEndHandler);
82 | amap.off('complete', this._oldZoomEndHandler);
83 | aMapModel.get('resizeEnable') && amap.off('resize', this._oldResizeHandler);
84 |
85 | amap.on('movestart', moveHandler);
86 | amap.on('zoomend', zoomEndHandler);
87 | amap.on('moveend', zoomEndHandler);
88 | amap.on('complete', zoomEndHandler);
89 | aMapModel.get('resizeEnable') && amap.on('resize', throttledResizeHandler);
90 |
91 | this._oldMoveHandler = moveHandler;
92 | this._oldZoomEndHandler = zoomEndHandler;
93 | this._oldResizeHandler = throttledResizeHandler;
94 |
95 | // var roam = aMapModel.get('roam');
96 | // if (roam && roam !== 'scale') {
97 | // amap.enableDragging();
98 | // }
99 | // else {
100 | // amap.disableDragging();
101 | // }
102 | // if (roam && roam !== 'move') {
103 | // amap.enableScrollWheelZoom();
104 | // amap.enableDoubleClickZoom();
105 | // amap.enablePinchToZoom();
106 | // }
107 | // else {
108 | // amap.disableScrollWheelZoom();
109 | // amap.disableDoubleClickZoom();
110 | // amap.disablePinchToZoom();
111 | // }
112 |
113 | rendering = false;
114 | }
115 | });
116 |
--------------------------------------------------------------------------------
/examples/index.3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 | 自定义图层
18 |
19 |
20 |
21 |
22 |
23 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/src/AMapCoordSys.js:
--------------------------------------------------------------------------------
1 | var echarts = require('echarts');
2 |
3 | function AMapCoordSys(amap, api) {
4 | this._amap = amap;
5 | this.dimensions = ['lng', 'lat'];
6 | this._mapOffset = [0, 0];
7 |
8 | this._api = api;
9 | }
10 |
11 | AMapCoordSys.prototype.dimensions = ['lng', 'lat'];
12 |
13 | AMapCoordSys.prototype.setZoom = function (zoom) {
14 | this._zoom = zoom;
15 | };
16 |
17 | AMapCoordSys.prototype.setCenter = function (center) {
18 | this._center = this._amap.lnglatToPixel(center);//, 10)
19 | };
20 |
21 | AMapCoordSys.prototype.setMapOffset = function (mapOffset) {
22 | this._mapOffset = mapOffset;
23 | };
24 |
25 | AMapCoordSys.prototype.getAMap = function () {
26 | return this._amap;
27 | };
28 |
29 | AMapCoordSys.prototype.dataToPoint = function (data) {
30 | var point = new AMap.LngLat(data[0], data[1]);
31 | var px = this._amap.lngLatToContainer(point);//, this._zoom);
32 | var mapOffset = this._mapOffset;
33 | return [px.x - mapOffset[0], px.y - mapOffset[1]];
34 | };
35 |
36 | AMapCoordSys.prototype.pointToData = function (pt) {
37 | var mapOffset = this._mapOffset;
38 | var pt = this._amap.containerToLngLat({
39 | x: pt[0] + mapOffset[0],
40 | y: pt[1] + mapOffset[1]
41 | });
42 | return [pt.lng, pt.lat];
43 | };
44 |
45 | AMapCoordSys.prototype.getViewRect = function () {
46 | var api = this._api;
47 | return new echarts.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight());
48 | };
49 |
50 | AMapCoordSys.prototype.getRoamTransform = function () {
51 | return echarts.matrix.create();
52 | };
53 |
54 | var Overlay;
55 |
56 | // For deciding which dimensions to use when creating list data
57 | AMapCoordSys.dimensions = AMapCoordSys.prototype.dimensions;
58 |
59 | AMapCoordSys.create = function (ecModel, api) {
60 | var amapCoordSys;
61 | var root = api.getDom();
62 |
63 | // TODO Dispose
64 | ecModel.eachComponent('amap', function (amapModel) {
65 | var viewportRoot = api.getZr().painter.getViewportRoot();
66 | if (typeof AMap === 'undefined') {
67 | throw new Error('AMap api is not loaded');
68 | }
69 |
70 | if (amapCoordSys) {
71 | throw new Error('Only one amap component can exist');
72 | }
73 | if (!amapModel.__amap) {
74 | // Not support IE8
75 | var amapRoot = root.querySelector('.ec-extension-amap');
76 | if (amapRoot) {
77 | // Reset viewport left and top, which will be changed
78 | // in moving handler in AMapView
79 | viewportRoot.style.left = '0px';
80 | viewportRoot.style.top = '0px';
81 | root.removeChild(amapRoot);
82 | }
83 | amapRoot = document.createElement('div');
84 | amapRoot.style.cssText = 'width:100%;height:100%';
85 | // Not support IE8
86 | amapRoot.classList.add('ec-extension-amap');
87 | root.appendChild(amapRoot);
88 |
89 | var options = amapModel.get() || {};
90 | options = amapModel.__options = echarts.util.clone(options);
91 | var amap = amapModel.__amap = new AMap.Map(amapRoot, options);
92 |
93 | var layer = amapModel.__layer = new AMap.CustomLayer(viewportRoot);
94 | layer.setMap(amap);
95 | }
96 | var amap = amapModel.getAMap();
97 | var layer = amapModel.getLayer();
98 | layer.hide();
99 |
100 | var zoom = amap.getZoom();
101 | var center = amap.getCenter();
102 |
103 | amapCoordSys = new AMapCoordSys(amap, api);
104 | amapCoordSys.setMapOffset(amapModel.__mapOffset || [0, 0]);
105 | amapCoordSys.setZoom(zoom);
106 | amapCoordSys.setCenter([center.lng, center.lat]);
107 |
108 | amapModel.coordinateSystem = amapCoordSys;
109 | layer.show();
110 | });
111 |
112 | ecModel.eachSeries(function (seriesModel) {
113 | if (seriesModel.get('coordinateSystem') === 'amap') {
114 | seriesModel.coordinateSystem = amapCoordSys;
115 | }
116 | });
117 | };
118 |
119 | module.exports = AMapCoordSys;
120 |
--------------------------------------------------------------------------------
/dist/echarts-amap.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("echarts")):"function"==typeof define&&define.amd?define(["echarts"],e):"object"==typeof exports?exports.amap=e(require("echarts")):(t.echarts=t.echarts||{},t.echarts.amap=e(t.echarts))}(this,function(t){return function(t){function e(n){if(o[n])return o[n].exports;var a=o[n]={i:n,l:!1,exports:{}};return t[n].call(a.exports,a,a.exports,e),a.l=!0,a.exports}var o={};return e.m=t,e.c=o,e.i=function(t){return t},e.d=function(t,o,n){e.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(o,"a",o),o},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=4)}([function(e,o){e.exports=t},function(t,e,o){function n(t,e){this._amap=t,this.dimensions=["lng","lat"],this._mapOffset=[0,0],this._api=e}var a=o(0);n.prototype.dimensions=["lng","lat"],n.prototype.setZoom=function(t){this._zoom=t},n.prototype.setCenter=function(t){this._center=this._amap.lnglatToPixel(t)},n.prototype.setMapOffset=function(t){this._mapOffset=t},n.prototype.getAMap=function(){return this._amap},n.prototype.dataToPoint=function(t){var e=new AMap.LngLat(t[0],t[1]),o=this._amap.lngLatToContainer(e),n=this._mapOffset;return[o.x-n[0],o.y-n[1]]},n.prototype.pointToData=function(t){var e=this._mapOffset,t=this._amap.containerToLngLat({x:t[0]+e[0],y:t[1]+e[1]});return[t.lng,t.lat]},n.prototype.getViewRect=function(){var t=this._api;return new a.graphic.BoundingRect(0,0,t.getWidth(),t.getHeight())},n.prototype.getRoamTransform=function(){return a.matrix.create()};n.dimensions=n.prototype.dimensions,n.create=function(t,e){var o,r=e.getDom();t.eachComponent("amap",function(t){var i=e.getZr().painter.getViewportRoot();if("undefined"==typeof AMap)throw new Error("AMap api is not loaded");if(o)throw new Error("Only one amap component can exist");if(!t.__amap){var p=r.querySelector(".ec-extension-amap");p&&(i.style.left="0px",i.style.top="0px",r.removeChild(p)),p=document.createElement("div"),p.style.cssText="width:100%;height:100%",p.classList.add("ec-extension-amap"),r.appendChild(p);var s=t.get()||{};s=t.__options=a.util.clone(s);var c=t.__amap=new AMap.Map(p,s),f=t.__layer=new AMap.CustomLayer(i);f.setMap(c)}var c=t.getAMap(),f=t.getLayer();f.hide();var m=c.getZoom(),u=c.getCenter();o=new n(c,e),o.setMapOffset(t.__mapOffset||[0,0]),o.setZoom(m),o.setCenter([u.lng,u.lat]),t.coordinateSystem=o,f.show()}),t.eachSeries(function(t){"amap"===t.get("coordinateSystem")&&(t.coordinateSystem=o)})},t.exports=n},function(t,e,o){function n(t,e){return t&&e&&t[0]===e[0]&&t[1]===e[1]}t.exports=o(0).extendComponentModel({type:"amap",getAMap:function(){return this.__amap},getLayer:function(){return this.__layer},getMapOptions:function(){return this.__options},setCenterAndZoom:function(t,e){this.option.center=t,this.option.zoom=e},centerOrZoomChanged:function(t,e){var o=this.option;return!(n(t,o.center)&&e===o.zoom)},defaultOption:{center:[116.397475,39.908695],zoom:4}})},function(t,e,o){function n(t,e,o){var n,a,r,i;return i=function(){n=!1,a&&(r.apply(o,a),a=!1)},r=function(){n?a=arguments:(t.apply(o,arguments),setTimeout(i,e),n=!0)}}var a=o(0);t.exports=o(0).extendComponentView({type:"amap",render:function(t,e,o){function r(){p||o.dispatchAction({type:"amapRoam"})}function i(t){a.getInstanceByDom(o.getDom()).resize(),m.call(this,t)}var p=!0,s=t.getAMap(),c=o.getZr().painter.getViewportRoot(),f=t.coordinateSystem,m=function(e){if(!p){var n=c.parentNode.parentNode.parentNode,a=[-parseInt(n.style.left,10)||0,-parseInt(n.style.top,10)||0];c.style.left=a[0]+"px",c.style.top=a[1]+"px",f.setMapOffset(a),t.__mapOffset=a,o.dispatchAction({type:"amapRoam"})}},u=n(i,300,s);s.off("movestart",this._oldMoveHandler),s.off("zoomend",this._oldZoomEndHandler),s.off("moveend",this._oldZoomEndHandler),s.off("complete",this._oldZoomEndHandler),t.get("resizeEnable")&&s.off("resize",this._oldResizeHandler),s.on("movestart",m),s.on("zoomend",r),s.on("moveend",r),s.on("complete",r),t.get("resizeEnable")&&s.on("resize",u),this._oldMoveHandler=m,this._oldZoomEndHandler=r,this._oldResizeHandler=u,p=!1}})},function(t,e,o){o(0).registerCoordinateSystem("amap",o(1)),o(2),o(3),o(0).registerAction({type:"amapRoam",event:"amapRoam",update:"updateLayout"},function(t,e){e.eachComponent("amap",function(t){var e=t.getAMap(),o=e.getCenter();t.setCenterAndZoom([o.lng,o.lat],e.getZoom())})}),t.exports={version:"1.0.0-rc.6"}}])});
2 | //# sourceMappingURL=echarts-amap.min.js.map
--------------------------------------------------------------------------------
/examples/amap3d-bus-line.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Echarts plugin to support AMap
7 |
8 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/assets/loader/MTLLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Loads a Wavefront .mtl file specifying materials
3 | *
4 | * @author angelxuanchang
5 | */
6 |
7 | THREE.MTLLoader = function ( manager ) {
8 |
9 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
10 |
11 | };
12 |
13 | THREE.MTLLoader.prototype = {
14 |
15 | constructor: THREE.MTLLoader,
16 |
17 | /**
18 | * Loads and parses a MTL asset from a URL.
19 | *
20 | * @param {String} url - URL to the MTL file.
21 | * @param {Function} [onLoad] - Callback invoked with the loaded object.
22 | * @param {Function} [onProgress] - Callback for download progress.
23 | * @param {Function} [onError] - Callback for download errors.
24 | *
25 | * @see setPath setTexturePath
26 | *
27 | * @note In order for relative texture references to resolve correctly
28 | * you must call setPath and/or setTexturePath explicitly prior to load.
29 | */
30 | load: function ( url, onLoad, onProgress, onError ) {
31 |
32 | var scope = this;
33 |
34 | var loader = new THREE.FileLoader( this.manager );
35 | loader.setPath( this.path );
36 | loader.load( url, function ( text ) {
37 |
38 | onLoad( scope.parse( text ) );
39 |
40 | }, onProgress, onError );
41 |
42 | },
43 |
44 | /**
45 | * Set base path for resolving references.
46 | * If set this path will be prepended to each loaded and found reference.
47 | *
48 | * @see setTexturePath
49 | * @param {String} path
50 | *
51 | * @example
52 | * mtlLoader.setPath( 'assets/obj/' );
53 | * mtlLoader.load( 'my.mtl', ... );
54 | */
55 | setPath: function ( path ) {
56 |
57 | this.path = path;
58 |
59 | },
60 |
61 | /**
62 | * Set base path for resolving texture references.
63 | * If set this path will be prepended found texture reference.
64 | * If not set and setPath is, it will be used as texture base path.
65 | *
66 | * @see setPath
67 | * @param {String} path
68 | *
69 | * @example
70 | * mtlLoader.setPath( 'assets/obj/' );
71 | * mtlLoader.setTexturePath( 'assets/textures/' );
72 | * mtlLoader.load( 'my.mtl', ... );
73 | */
74 | setTexturePath: function ( path ) {
75 |
76 | this.texturePath = path;
77 |
78 | },
79 |
80 | setBaseUrl: function ( path ) {
81 |
82 | console.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' );
83 |
84 | this.setTexturePath( path );
85 |
86 | },
87 |
88 | setCrossOrigin: function ( value ) {
89 |
90 | this.crossOrigin = value;
91 |
92 | },
93 |
94 | setMaterialOptions: function ( value ) {
95 |
96 | this.materialOptions = value;
97 |
98 | },
99 |
100 | /**
101 | * Parses a MTL file.
102 | *
103 | * @param {String} text - Content of MTL file
104 | * @return {THREE.MTLLoader.MaterialCreator}
105 | *
106 | * @see setPath setTexturePath
107 | *
108 | * @note In order for relative texture references to resolve correctly
109 | * you must call setPath and/or setTexturePath explicitly prior to parse.
110 | */
111 | parse: function ( text ) {
112 |
113 | var lines = text.split( '\n' );
114 | var info = {};
115 | var delimiter_pattern = /\s+/;
116 | var materialsInfo = {};
117 |
118 | for ( var i = 0; i < lines.length; i ++ ) {
119 |
120 | var line = lines[ i ];
121 | line = line.trim();
122 |
123 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
124 |
125 | // Blank line or comment ignore
126 | continue;
127 |
128 | }
129 |
130 | var pos = line.indexOf( ' ' );
131 |
132 | var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
133 | key = key.toLowerCase();
134 |
135 | var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';
136 | value = value.trim();
137 |
138 | if ( key === 'newmtl' ) {
139 |
140 | // New material
141 |
142 | info = { name: value };
143 | materialsInfo[ value ] = info;
144 |
145 | } else if ( info ) {
146 |
147 | if ( key === 'ka' || key === 'kd' || key === 'ks' ) {
148 |
149 | var ss = value.split( delimiter_pattern, 3 );
150 | info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
151 |
152 | } else {
153 |
154 | info[ key ] = value;
155 |
156 | }
157 |
158 | }
159 |
160 | }
161 |
162 | var materialCreator = new THREE.MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions );
163 | materialCreator.setCrossOrigin( this.crossOrigin );
164 | materialCreator.setManager( this.manager );
165 | materialCreator.setMaterials( materialsInfo );
166 | return materialCreator;
167 |
168 | }
169 |
170 | };
171 |
172 | /**
173 | * Create a new THREE-MTLLoader.MaterialCreator
174 | * @param baseUrl - Url relative to which textures are loaded
175 | * @param options - Set of options on how to construct the materials
176 | * side: Which side to apply the material
177 | * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
178 | * wrap: What type of wrapping to apply for textures
179 | * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
180 | * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
181 | * Default: false, assumed to be already normalized
182 | * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
183 | * Default: false
184 | * @constructor
185 | */
186 |
187 | THREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) {
188 |
189 | this.baseUrl = baseUrl || '';
190 | this.options = options;
191 | this.materialsInfo = {};
192 | this.materials = {};
193 | this.materialsArray = [];
194 | this.nameLookup = {};
195 |
196 | this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
197 | this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
198 |
199 | };
200 |
201 | THREE.MTLLoader.MaterialCreator.prototype = {
202 |
203 | constructor: THREE.MTLLoader.MaterialCreator,
204 |
205 | crossOrigin: 'Anonymous',
206 |
207 | setCrossOrigin: function ( value ) {
208 |
209 | this.crossOrigin = value;
210 |
211 | },
212 |
213 | setManager: function ( value ) {
214 |
215 | this.manager = value;
216 |
217 | },
218 |
219 | setMaterials: function ( materialsInfo ) {
220 |
221 | this.materialsInfo = this.convert( materialsInfo );
222 | this.materials = {};
223 | this.materialsArray = [];
224 | this.nameLookup = {};
225 |
226 | },
227 |
228 | convert: function ( materialsInfo ) {
229 |
230 | if ( ! this.options ) return materialsInfo;
231 |
232 | var converted = {};
233 |
234 | for ( var mn in materialsInfo ) {
235 |
236 | // Convert materials info into normalized form based on options
237 |
238 | var mat = materialsInfo[ mn ];
239 |
240 | var covmat = {};
241 |
242 | converted[ mn ] = covmat;
243 |
244 | for ( var prop in mat ) {
245 |
246 | var save = true;
247 | var value = mat[ prop ];
248 | var lprop = prop.toLowerCase();
249 |
250 | switch ( lprop ) {
251 |
252 | case 'kd':
253 | case 'ka':
254 | case 'ks':
255 |
256 | // Diffuse color (color under white light) using RGB values
257 |
258 | if ( this.options && this.options.normalizeRGB ) {
259 |
260 | value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
261 |
262 | }
263 |
264 | if ( this.options && this.options.ignoreZeroRGBs ) {
265 |
266 | if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {
267 |
268 | // ignore
269 |
270 | save = false;
271 |
272 | }
273 |
274 | }
275 |
276 | break;
277 |
278 | default:
279 |
280 | break;
281 |
282 | }
283 |
284 | if ( save ) {
285 |
286 | covmat[ lprop ] = value;
287 |
288 | }
289 |
290 | }
291 |
292 | }
293 |
294 | return converted;
295 |
296 | },
297 |
298 | preload: function () {
299 |
300 | for ( var mn in this.materialsInfo ) {
301 |
302 | this.create( mn );
303 |
304 | }
305 |
306 | },
307 |
308 | getIndex: function ( materialName ) {
309 |
310 | return this.nameLookup[ materialName ];
311 |
312 | },
313 |
314 | getAsArray: function () {
315 |
316 | var index = 0;
317 |
318 | for ( var mn in this.materialsInfo ) {
319 |
320 | this.materialsArray[ index ] = this.create( mn );
321 | this.nameLookup[ mn ] = index;
322 | index ++;
323 |
324 | }
325 |
326 | return this.materialsArray;
327 |
328 | },
329 |
330 | create: function ( materialName ) {
331 |
332 | if ( this.materials[ materialName ] === undefined ) {
333 |
334 | this.createMaterial_( materialName );
335 |
336 | }
337 |
338 | return this.materials[ materialName ];
339 |
340 | },
341 |
342 | createMaterial_: function ( materialName ) {
343 |
344 | // Create material
345 |
346 | var scope = this;
347 | var mat = this.materialsInfo[ materialName ];
348 | var params = {
349 |
350 | name: materialName,
351 | side: this.side
352 |
353 | };
354 |
355 | function resolveURL( baseUrl, url ) {
356 |
357 | if ( typeof url !== 'string' || url === '' )
358 | return '';
359 |
360 | // Absolute URL
361 | if ( /^https?:\/\//i.test( url ) ) return url;
362 |
363 | return baseUrl + url;
364 |
365 | }
366 |
367 | function setMapForType( mapType, value ) {
368 |
369 | if ( params[ mapType ] ) return; // Keep the first encountered texture
370 |
371 | var texParams = scope.getTextureParams( value, params );
372 | var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );
373 |
374 | map.repeat.copy( texParams.scale );
375 | map.offset.copy( texParams.offset );
376 |
377 | map.wrapS = scope.wrap;
378 | map.wrapT = scope.wrap;
379 |
380 | params[ mapType ] = map;
381 |
382 | }
383 |
384 | for ( var prop in mat ) {
385 |
386 | var value = mat[ prop ];
387 | var n;
388 |
389 | if ( value === '' ) continue;
390 |
391 | switch ( prop.toLowerCase() ) {
392 |
393 | // Ns is material specular exponent
394 |
395 | case 'kd':
396 |
397 | // Diffuse color (color under white light) using RGB values
398 |
399 | params.color = new THREE.Color().fromArray( value );
400 |
401 | break;
402 |
403 | case 'ks':
404 |
405 | // Specular color (color when light is reflected from shiny surface) using RGB values
406 | params.specular = new THREE.Color().fromArray( value );
407 |
408 | break;
409 |
410 | case 'map_kd':
411 |
412 | // Diffuse texture map
413 |
414 | setMapForType( "map", value );
415 |
416 | break;
417 |
418 | case 'map_ks':
419 |
420 | // Specular map
421 |
422 | setMapForType( "specularMap", value );
423 |
424 | break;
425 |
426 | case 'norm':
427 |
428 | setMapForType( "normalMap", value );
429 |
430 | break;
431 |
432 | case 'map_bump':
433 | case 'bump':
434 |
435 | // Bump texture map
436 |
437 | setMapForType( "bumpMap", value );
438 |
439 | break;
440 |
441 | case 'ns':
442 |
443 | // The specular exponent (defines the focus of the specular highlight)
444 | // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
445 |
446 | params.shininess = parseFloat( value );
447 |
448 | break;
449 |
450 | case 'd':
451 | n = parseFloat( value );
452 |
453 | if ( n < 1 ) {
454 |
455 | params.opacity = n;
456 | params.transparent = true;
457 |
458 | }
459 |
460 | break;
461 |
462 | case 'tr':
463 | n = parseFloat( value );
464 |
465 | if ( n > 0 ) {
466 |
467 | params.opacity = 1 - n;
468 | params.transparent = true;
469 |
470 | }
471 |
472 | break;
473 |
474 | default:
475 | break;
476 |
477 | }
478 |
479 | }
480 |
481 | this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
482 | return this.materials[ materialName ];
483 |
484 | },
485 |
486 | getTextureParams: function ( value, matParams ) {
487 |
488 | var texParams = {
489 |
490 | scale: new THREE.Vector2( 1, 1 ),
491 | offset: new THREE.Vector2( 0, 0 )
492 |
493 | };
494 |
495 | var items = value.split( /\s+/ );
496 | var pos;
497 |
498 | pos = items.indexOf( '-bm' );
499 |
500 | if ( pos >= 0 ) {
501 |
502 | matParams.bumpScale = parseFloat( items[ pos + 1 ] );
503 | items.splice( pos, 2 );
504 |
505 | }
506 |
507 | pos = items.indexOf( '-s' );
508 |
509 | if ( pos >= 0 ) {
510 |
511 | texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
512 | items.splice( pos, 4 ); // we expect 3 parameters here!
513 |
514 | }
515 |
516 | pos = items.indexOf( '-o' );
517 |
518 | if ( pos >= 0 ) {
519 |
520 | texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
521 | items.splice( pos, 4 ); // we expect 3 parameters here!
522 |
523 | }
524 |
525 | texParams.url = items.join( ' ' ).trim();
526 | return texParams;
527 |
528 | },
529 |
530 | loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
531 |
532 | var texture;
533 | var loader = THREE.Loader.Handlers.get( url );
534 | var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;
535 |
536 | if ( loader === null ) {
537 |
538 | loader = new THREE.TextureLoader( manager );
539 |
540 | }
541 |
542 | if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
543 | texture = loader.load( url, onLoad, onProgress, onError );
544 |
545 | if ( mapping !== undefined ) texture.mapping = mapping;
546 |
547 | return texture;
548 |
549 | }
550 |
551 | };
552 |
--------------------------------------------------------------------------------
/examples/index.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Echarts plugin to support AMap
7 |
8 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
413 |
414 |
415 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Echarts plugin to support AMap
7 |
8 |
17 |
18 |
19 |
20 |
21 |
22 |
24 | -->
25 |
26 |
27 |
28 |
32 |
33 |
422 |
423 |
424 |
--------------------------------------------------------------------------------
/dist/echarts-amap.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///echarts-amap.min.js","webpack:///webpack/bootstrap 6491c7555f12406ee575","webpack:///external \"echarts\"","webpack:///./src/AMapCoordSys.js","webpack:///./src/AMapModel.js","webpack:///./src/AMapView.js","webpack:///./src/amap.js"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE_0__","modules","__webpack_require__","moduleId","installedModules","i","l","call","m","c","value","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s","AMapCoordSys","amap","api","_amap","dimensions","_mapOffset","_api","echarts","setZoom","zoom","_zoom","setCenter","center","_center","lnglatToPixel","setMapOffset","mapOffset","getAMap","dataToPoint","data","point","AMap","LngLat","px","lngLatToContainer","x","y","pointToData","pt","containerToLngLat","lng","lat","getViewRect","graphic","BoundingRect","getWidth","getHeight","getRoamTransform","matrix","create","ecModel","amapCoordSys","getDom","eachComponent","amapModel","viewportRoot","getZr","painter","getViewportRoot","Error","__amap","amapRoot","querySelector","style","left","top","removeChild","document","createElement","cssText","classList","add","appendChild","options","__options","util","clone","Map","layer","__layer","CustomLayer","setMap","getLayer","hide","getZoom","getCenter","__mapOffset","coordinateSystem","show","eachSeries","seriesModel","v2Equal","a","b","extendComponentModel","type","getMapOptions","setCenterAndZoom","option","centerOrZoomChanged","defaultOption","throttle","fn","time","context","lock","args","wrapperFn","later","apply","arguments","setTimeout","extendComponentView","render","aMapModel","zoomEndHandler","rendering","dispatchAction","resizeHandler","e","getInstanceByDom","resize","moveHandler","coordSys","offsetEl","parentNode","parseInt","throttledResizeHandler","off","_oldMoveHandler","_oldZoomEndHandler","_oldResizeHandler","on","registerCoordinateSystem","registerAction","event","update","payload","version"],"mappings":"CAAA,SAAAA,EAAAC,GACA,gBAAAC,UAAA,gBAAAC,QACAA,OAAAD,QAAAD,EAAAG,QAAA,YACA,kBAAAC,gBAAAC,IACAD,QAAA,WAAAJ,GACA,gBAAAC,SACAA,QAAA,KAAAD,EAAAG,QAAA,aAEAJ,EAAA,QAAAA,EAAA,YAAyCA,EAAA,aAAAC,EAAAD,EAAA,WACxCO,KAAA,SAAAC,GACD,MCAgB,UAAUC,GCN1B,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAT,OAGA,IAAAC,GAAAS,EAAAD,IACAE,EAAAF,EACAG,GAAA,EACAZ,WAUA,OANAO,GAAAE,GAAAI,KAAAZ,EAAAD,QAAAC,IAAAD,QAAAQ,GAGAP,EAAAW,GAAA,EAGAX,EAAAD,QAvBA,GAAAU,KA+DA,OAnCAF,GAAAM,EAAAP,EAGAC,EAAAO,EAAAL,EAGAF,EAAAG,EAAA,SAAAK,GAA2C,MAAAA,IAG3CR,EAAAS,EAAA,SAAAjB,EAAAkB,EAAAC,GACAX,EAAAY,EAAApB,EAAAkB,IACAG,OAAAC,eAAAtB,EAAAkB,GACAK,cAAA,EACAC,YAAA,EACAC,IAAAN,KAMAX,EAAAkB,EAAA,SAAAzB,GACA,GAAAkB,GAAAlB,KAAA0B,WACA,WAA2B,MAAA1B,GAAA,SAC3B,WAAiC,MAAAA,GAEjC,OADAO,GAAAS,EAAAE,EAAA,IAAAA,GACAA,GAIAX,EAAAY,EAAA,SAAAQ,EAAAC,GAAsD,MAAAR,QAAAS,UAAAC,eAAAlB,KAAAe,EAAAC,IAGtDrB,EAAAwB,EAAA,GAGAxB,IAAAyB,EAAA,KDgBM,SAAUhC,EAAQD,GEhFxBC,EAAAD,QAAAM,GFsFM,SAAUL,EAAQD,EAASQ,GGpFjC,QAAA0B,GAAAC,EAAAC,GACA/B,KAAAgC,MAAAF,EACA9B,KAAAiC,YAAA,aACAjC,KAAAkC,YAAA,KAEAlC,KAAAmC,KAAAJ,EAPA,GAAAK,GAAAjC,EAAA,EAUA0B,GAAAJ,UAAAQ,YAAA,aAEAJ,EAAAJ,UAAAY,QAAA,SAAAC,GACAtC,KAAAuC,MAAAD,GAGAT,EAAAJ,UAAAe,UAAA,SAAAC,GACAzC,KAAA0C,QAAA1C,KAAAgC,MAAAW,cAAAF,IAGAZ,EAAAJ,UAAAmB,aAAA,SAAAC,GACA7C,KAAAkC,WAAAW,GAGAhB,EAAAJ,UAAAqB,QAAA,WACA,MAAA9C,MAAAgC,OAGAH,EAAAJ,UAAAsB,YAAA,SAAAC,GACA,GAAAC,GAAA,GAAAC,MAAAC,OAAAH,EAAA,GAAAA,EAAA,IACAI,EAAApD,KAAAgC,MAAAqB,kBAAAJ,GACAJ,EAAA7C,KAAAkC,UACA,QAAAkB,EAAAE,EAAAT,EAAA,GAAAO,EAAAG,EAAAV,EAAA,KAGAhB,EAAAJ,UAAA+B,YAAA,SAAAC,GACA,GAAAZ,GAAA7C,KAAAkC,WACAuB,EAAAzD,KAAAgC,MAAA0B,mBACAJ,EAAAG,EAAA,GAAAZ,EAAA,GACAU,EAAAE,EAAA,GAAAZ,EAAA,IAEA,QAAAY,EAAAE,IAAAF,EAAAG,MAGA/B,EAAAJ,UAAAoC,YAAA,WACA,GAAA9B,GAAA/B,KAAAmC,IACA,WAAAC,GAAA0B,QAAAC,aAAA,IAAAhC,EAAAiC,WAAAjC,EAAAkC,cAGApC,EAAAJ,UAAAyC,iBAAA,WACA,MAAA9B,GAAA+B,OAAAC,SAMAvC,GAAAI,WAAAJ,EAAAJ,UAAAQ,WAEAJ,EAAAuC,OAAA,SAAAC,EAAAtC,GACA,GAAAuC,GACA7E,EAAAsC,EAAAwC,QAGAF,GAAAG,cAAA,gBAAAC,GACA,GAAAC,GAAA3C,EAAA4C,QAAAC,QAAAC,iBACA,uBAAA3B,MACA,SAAA4B,OAAA,yBAGA,IAAAR,EACA,SAAAQ,OAAA,oCAEA,KAAAL,EAAAM,OAAA,CAEA,GAAAC,GAAAvF,EAAAwF,cAAA,qBACAD,KAGAN,EAAAQ,MAAAC,KAAA,MACAT,EAAAQ,MAAAE,IAAA,MACA3F,EAAA4F,YAAAL,IAEAA,EAAAM,SAAAC,cAAA,OACAP,EAAAE,MAAAM,QAAA,yBAEAR,EAAAS,UAAAC,IAAA,qBACAjG,EAAAkG,YAAAX,EAEA,IAAAY,GAAAnB,EAAArD,SACAwE,GAAAnB,EAAAoB,UAAAzD,EAAA0D,KAAAC,MAAAH,EACA,IAAA9D,GAAA2C,EAAAM,OAAA,GAAA7B,MAAA8C,IAAAhB,EAAAY,GAEAK,EAAAxB,EAAAyB,QAAA,GAAAhD,MAAAiD,YAAAzB,EACAuB,GAAAG,OAAAtE,GAEA,GAAAA,GAAA2C,EAAA3B,UACAmD,EAAAxB,EAAA4B,UACAJ,GAAAK,MAEA,IAAAhE,GAAAR,EAAAyE,UACA9D,EAAAX,EAAA0E,WAEAlC,GAAA,GAAAzC,GAAAC,EAAAC,GACAuC,EAAA1B,aAAA6B,EAAAgC,cAAA,MACAnC,EAAAjC,QAAAC,GACAgC,EAAA9B,WAAAC,EAAAkB,IAAAlB,EAAAmB,MAEAa,EAAAiC,iBAAApC,EACA2B,EAAAU,SAGAtC,EAAAuC,WAAA,SAAAC,GACA,SAAAA,EAAAzF,IAAA,sBACAyF,EAAAH,iBAAApC,MAKA1E,EAAAD,QAAAkC,GH6FM,SAAUjC,EAAQD,EAASQ,GInNjC,QAAA2G,GAAAC,EAAAC,GACA,MAAAD,IAAAC,GAAAD,EAAA,KAAAC,EAAA,IAAAD,EAAA,KAAAC,EAAA,GAGApH,EAAAD,QAAAQ,EAAA,GAAA8G,sBACAC,KAAA,OAEApE,QAAA,WAEA,MAAA9C,MAAA+E,QAGAsB,SAAA,WAEA,MAAArG,MAAAkG,SAGAiB,cAAA,WACA,MAAAnH,MAAA6F,WAGAuB,iBAAA,SAAA3E,EAAAH,GACAtC,KAAAqH,OAAA5E,SACAzC,KAAAqH,OAAA/E,QAEAgF,oBAAA,SAAA7E,EAAAH,GACA,GAAA+E,GAAArH,KAAAqH,MACA,SAAAP,EAAArE,EAAA4E,EAAA5E,SAAAH,IAAA+E,EAAA/E,OAGAiF,eACA9E,QAAA,sBACAH,KAAA,MJ4NM,SAAU1C,EAAQD,EAASQ,GKxPjC,QAAAqH,GAAAC,EAAAC,EAAAC,GACA,GAAAC,GAAAC,EAAAC,EAAAC,CAwBA,OAtBAA,GAAA,WAEAH,GAAA,EACAC,IACAC,EAAAE,MAAAL,EAAAE,GACAA,GAAA,IAIAC,EAAA,WACAF,EAEAC,EAAAI,WAIAR,EAAAO,MAAAL,EAAAM,WACAC,WAAAH,EAAAL,GACAE,GAAA,IAOA,GAAAxF,GAAAjC,EAAA,EAEAP,GAAAD,QAAAQ,EAAA,GAAAgI,qBACAjB,KAAA,OACAkB,OAAA,SAAAC,EAAAhE,EAAAtC,GA0BA,QAAAuG,KACAC,GAGAxG,EAAAyG,gBACAtB,KAAA,aAIA,QAAAuB,GAAAC,GACAtG,EAAAuG,iBAAA5G,EAAAwC,UAAAqE,SACAC,EAAArI,KAAAR,KAAA0I,GApCA,GAAAH,IAAA,EAEAzG,EAAAuG,EAAAvF,UACA4B,EAAA3C,EAAA4C,QAAAC,QAAAC,kBACAiE,EAAAT,EAAA3B,iBACAmC,EAAA,SAAAH,GACA,IAAAH,EAAA,CAGA,GAAAQ,GAAArE,EAAAsE,iCACAnG,IACAoG,SAAAF,EAAA7D,MAAAC,KAAA,QACA8D,SAAAF,EAAA7D,MAAAE,IAAA,OAEAV,GAAAQ,MAAAC,KAAAtC,EAAA,QACA6B,EAAAQ,MAAAE,IAAAvC,EAAA,QAEAiG,EAAAlG,aAAAC,GACAwF,EAAA5B,YAAA5D,EAEAd,EAAAyG,gBACAtB,KAAA,eAkBAgC,EAAA1B,EAAAiB,EAAA,IAAA3G,EAEAA,GAAAqH,IAAA,YAAAnJ,KAAAoJ,iBACAtH,EAAAqH,IAAA,UAAAnJ,KAAAqJ,oBACAvH,EAAAqH,IAAA,UAAAnJ,KAAAqJ,oBACAvH,EAAAqH,IAAA,WAAAnJ,KAAAqJ,oBACAhB,EAAAjH,IAAA,iBAAAU,EAAAqH,IAAA,SAAAnJ,KAAAsJ,mBAEAxH,EAAAyH,GAAA,YAAAV,GACA/G,EAAAyH,GAAA,UAAAjB,GACAxG,EAAAyH,GAAA,UAAAjB,GACAxG,EAAAyH,GAAA,WAAAjB,GACAD,EAAAjH,IAAA,iBAAAU,EAAAyH,GAAA,SAAAL,GAEAlJ,KAAAoJ,gBAAAP,EACA7I,KAAAqJ,mBAAAf,EACAtI,KAAAsJ,kBAAAJ,EAoBAX,GAAA,MLqQM,SAAU3I,EAAQD,EAASQ,GMlXjCA,EAAA,GAAAqJ,yBACA,OAAArJ,EAAA,IAEAA,EAAA,GACAA,EAAA,GAGAA,EAAA,GAAAsJ,gBACAvC,KAAA,WACAwC,MAAA,WACAC,OAAA,gBACC,SAAAC,EAAAvF,GACDA,EAAAG,cAAA,gBAAA6D,GACA,GAAAvG,GAAAuG,EAAAvF,UACAL,EAAAX,EAAA0E,WACA6B,GAAAjB,kBAAA3E,EAAAkB,IAAAlB,EAAAmB,KAAA9B,EAAAyE,eAIA3G,EAAAD,SACAkK,QAAA","file":"echarts-amap.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"echarts\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"echarts\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"amap\"] = factory(require(\"echarts\"));\n\telse\n\t\troot[\"echarts\"] = root[\"echarts\"] || {}, root[\"echarts\"][\"amap\"] = factory(root[\"echarts\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"echarts\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"echarts\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"amap\"] = factory(require(\"echarts\"));\n\telse\n\t\troot[\"echarts\"] = root[\"echarts\"] || {}, root[\"echarts\"][\"amap\"] = factory(root[\"echarts\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__webpack_require__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 4);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE_0__;\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar echarts = __webpack_require__(0);\r\n\r\nfunction AMapCoordSys(amap, api) {\r\n this._amap = amap;\r\n this.dimensions = ['lng', 'lat'];\r\n this._mapOffset = [0, 0];\r\n\r\n this._api = api;\r\n}\r\n\r\nAMapCoordSys.prototype.dimensions = ['lng', 'lat'];\r\n\r\nAMapCoordSys.prototype.setZoom = function (zoom) {\r\n this._zoom = zoom;\r\n};\r\n\r\nAMapCoordSys.prototype.setCenter = function (center) {\r\n this._center = this._amap.lnglatToPixel(center);//, 10)\r\n};\r\n\r\nAMapCoordSys.prototype.setMapOffset = function (mapOffset) {\r\n this._mapOffset = mapOffset;\r\n};\r\n\r\nAMapCoordSys.prototype.getAMap = function () {\r\n return this._amap;\r\n};\r\n\r\nAMapCoordSys.prototype.dataToPoint = function (data) {\r\n var point = new AMap.LngLat(data[0], data[1]);\r\n var px = this._amap.lngLatToContainer(point);//, this._zoom);\r\n var mapOffset = this._mapOffset;\r\n return [px.x - mapOffset[0], px.y - mapOffset[1]];\r\n};\r\n\r\nAMapCoordSys.prototype.pointToData = function (pt) {\r\n var mapOffset = this._mapOffset;\r\n var pt = this._amap.containerToLngLat({\r\n x: pt[0] + mapOffset[0],\r\n y: pt[1] + mapOffset[1]\r\n });\r\n return [pt.lng, pt.lat];\r\n};\r\n\r\nAMapCoordSys.prototype.getViewRect = function () {\r\n var api = this._api;\r\n return new echarts.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight());\r\n};\r\n\r\nAMapCoordSys.prototype.getRoamTransform = function () {\r\n return echarts.matrix.create();\r\n};\r\n\r\nvar Overlay;\r\n\r\n// For deciding which dimensions to use when creating list data\r\nAMapCoordSys.dimensions = AMapCoordSys.prototype.dimensions;\r\n\r\nAMapCoordSys.create = function (ecModel, api) {\r\n var amapCoordSys;\r\n var root = api.getDom();\r\n\r\n // TODO Dispose\r\n ecModel.eachComponent('amap', function (amapModel) {\r\n var viewportRoot = api.getZr().painter.getViewportRoot();\r\n if (typeof AMap === 'undefined') {\r\n throw new Error('AMap api is not loaded');\r\n }\r\n\r\n if (amapCoordSys) {\r\n throw new Error('Only one amap component can exist');\r\n }\r\n if (!amapModel.__amap) {\r\n // Not support IE8\r\n var amapRoot = root.querySelector('.ec-extension-amap');\r\n if (amapRoot) {\r\n // Reset viewport left and top, which will be changed\r\n // in moving handler in AMapView\r\n viewportRoot.style.left = '0px';\r\n viewportRoot.style.top = '0px';\r\n root.removeChild(amapRoot);\r\n }\r\n amapRoot = document.createElement('div');\r\n amapRoot.style.cssText = 'width:100%;height:100%';\r\n // Not support IE8\r\n amapRoot.classList.add('ec-extension-amap');\r\n root.appendChild(amapRoot);\r\n\r\n var options = amapModel.get() || {};\r\n options = amapModel.__options = echarts.util.clone(options);\r\n var amap = amapModel.__amap = new AMap.Map(amapRoot, options);\r\n\r\n var layer = amapModel.__layer = new AMap.CustomLayer(viewportRoot);\r\n layer.setMap(amap);\r\n }\r\n var amap = amapModel.getAMap();\r\n var layer = amapModel.getLayer();\r\n layer.hide();\r\n\r\n var zoom = amap.getZoom();\r\n var center = amap.getCenter();\r\n\r\n amapCoordSys = new AMapCoordSys(amap, api);\r\n amapCoordSys.setMapOffset(amapModel.__mapOffset || [0, 0]);\r\n amapCoordSys.setZoom(zoom);\r\n amapCoordSys.setCenter([center.lng, center.lat]);\r\n\r\n amapModel.coordinateSystem = amapCoordSys;\r\n layer.show();\r\n });\r\n\r\n ecModel.eachSeries(function (seriesModel) {\r\n if (seriesModel.get('coordinateSystem') === 'amap') {\r\n seriesModel.coordinateSystem = amapCoordSys;\r\n }\r\n });\r\n};\r\n\r\nmodule.exports = AMapCoordSys;\r\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __webpack_require__) {\n\nfunction v2Equal(a, b) {\r\n return a && b && a[0] === b[0] && a[1] === b[1];\r\n}\r\n\r\nmodule.exports = __webpack_require__(0).extendComponentModel({\r\n type: 'amap',\r\n\r\n getAMap: function () {\r\n // __amap is injected when creating AMapCoordSys\r\n return this.__amap;\r\n },\r\n\r\n getLayer: function() {\r\n // __layer is injected when creating AMapCoordSys\r\n return this.__layer;\r\n },\r\n\r\n getMapOptions: function() {\r\n return this.__options;\r\n },\r\n\r\n setCenterAndZoom: function (center, zoom) {\r\n this.option.center = center;\r\n this.option.zoom = zoom;\r\n },\r\n centerOrZoomChanged: function (center, zoom) {\r\n var option = this.option;\r\n return !(v2Equal(center, option.center) && zoom === option.zoom);\r\n },\r\n\r\n defaultOption: {\r\n center: [116.397475,39.908695],\r\n zoom: 4,\r\n }\r\n});\r\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/*\r\n * this function bollowed from:\r\n * https://github.com/Leaflet/Leaflet/blob/master/src/core/Util.js\r\n */\r\nfunction throttle(fn, time, context) {\r\n\tvar lock, args, wrapperFn, later;\r\n\r\n\tlater = function () {\r\n\t\t// reset lock and call if queued\r\n\t\tlock = false;\r\n\t\tif (args) {\r\n\t\t\twrapperFn.apply(context, args);\r\n\t\t\targs = false;\r\n\t\t}\r\n\t};\r\n\r\n\twrapperFn = function () {\r\n\t\tif (lock) {\r\n\t\t\t// called too soon, queue to call later\r\n\t\t\targs = arguments;\r\n\r\n\t\t} else {\r\n\t\t\t// call and lock until later\r\n\t\t\tfn.apply(context, arguments);\r\n\t\t\tsetTimeout(later, time);\r\n\t\t\tlock = true;\r\n\t\t}\r\n\t};\r\n\r\n\treturn wrapperFn;\r\n}\r\n\r\nvar echarts = __webpack_require__(0);\r\n\r\nmodule.exports = __webpack_require__(0).extendComponentView({\r\n type: 'amap',\r\n render: function (aMapModel, ecModel, api) {\r\n var rendering = true;\r\n\r\n var amap = aMapModel.getAMap();\r\n var viewportRoot = api.getZr().painter.getViewportRoot();\r\n var coordSys = aMapModel.coordinateSystem;\r\n var moveHandler = function (e) {\r\n if (rendering) {\r\n return;\r\n }\r\n var offsetEl = viewportRoot.parentNode.parentNode.parentNode;\r\n var mapOffset = [\r\n -parseInt(offsetEl.style.left, 10) || 0,\r\n -parseInt(offsetEl.style.top, 10) || 0\r\n ];\r\n viewportRoot.style.left = mapOffset[0] + 'px';\r\n viewportRoot.style.top = mapOffset[1] + 'px';\r\n\r\n coordSys.setMapOffset(mapOffset);\r\n aMapModel.__mapOffset = mapOffset;\r\n\r\n api.dispatchAction({\r\n type: 'amapRoam'\r\n });\r\n };\r\n\r\n function zoomEndHandler() {\r\n if (rendering) {\r\n return;\r\n }\r\n api.dispatchAction({\r\n type: 'amapRoam'\r\n });\r\n }\r\n\r\n function resizeHandler(e) {\r\n echarts.getInstanceByDom(api.getDom()).resize();\r\n moveHandler.call(this, e)\r\n }\r\n\r\n var throttledResizeHandler = throttle(resizeHandler, 300, amap);\r\n\r\n amap.off('movestart', this._oldMoveHandler);\r\n amap.off('zoomend', this._oldZoomEndHandler);\r\n amap.off('moveend', this._oldZoomEndHandler);\r\n amap.off('complete', this._oldZoomEndHandler);\r\n aMapModel.get('resizeEnable') && amap.off('resize', this._oldResizeHandler);\r\n\r\n amap.on('movestart', moveHandler);\r\n amap.on('zoomend', zoomEndHandler);\r\n amap.on('moveend', zoomEndHandler);\r\n amap.on('complete', zoomEndHandler);\r\n aMapModel.get('resizeEnable') && amap.on('resize', throttledResizeHandler);\r\n\r\n this._oldMoveHandler = moveHandler;\r\n this._oldZoomEndHandler = zoomEndHandler;\r\n this._oldResizeHandler = throttledResizeHandler;\r\n\r\n // var roam = aMapModel.get('roam');\r\n // if (roam && roam !== 'scale') {\r\n // amap.enableDragging();\r\n // }\r\n // else {\r\n // amap.disableDragging();\r\n // }\r\n // if (roam && roam !== 'move') {\r\n // amap.enableScrollWheelZoom();\r\n // amap.enableDoubleClickZoom();\r\n // amap.enablePinchToZoom();\r\n // }\r\n // else {\r\n // amap.disableScrollWheelZoom();\r\n // amap.disableDoubleClickZoom();\r\n // amap.disablePinchToZoom();\r\n // }\r\n\r\n rendering = false;\r\n }\r\n});\r\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\r\n * BMap component extension\r\n */\r\n__webpack_require__(0).registerCoordinateSystem(\r\n 'amap', __webpack_require__(1)\r\n);\r\n__webpack_require__(2);\r\n__webpack_require__(3);\r\n\r\n// Action\r\n__webpack_require__(0).registerAction({\r\n type: 'amapRoam',\r\n event: 'amapRoam',\r\n update: 'updateLayout'\r\n}, function (payload, ecModel) {\r\n ecModel.eachComponent('amap', function (aMapModel) {\r\n var amap = aMapModel.getAMap();\r\n var center = amap.getCenter();\r\n aMapModel.setCenterAndZoom([center.lng, center.lat], amap.getZoom());\r\n });\r\n});\r\n\r\nmodule.exports = {\r\n version: \"1.0.0-rc.6\"\r\n};\r\n\n\n/***/ })\n/******/ ]);\n});\n\n\n// WEBPACK FOOTER //\n// echarts-amap.min.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 4);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 6491c7555f12406ee575","module.exports = __WEBPACK_EXTERNAL_MODULE_0__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"echarts\"\n// module id = 0\n// module chunks = 0","var echarts = require('echarts');\r\n\r\nfunction AMapCoordSys(amap, api) {\r\n this._amap = amap;\r\n this.dimensions = ['lng', 'lat'];\r\n this._mapOffset = [0, 0];\r\n\r\n this._api = api;\r\n}\r\n\r\nAMapCoordSys.prototype.dimensions = ['lng', 'lat'];\r\n\r\nAMapCoordSys.prototype.setZoom = function (zoom) {\r\n this._zoom = zoom;\r\n};\r\n\r\nAMapCoordSys.prototype.setCenter = function (center) {\r\n this._center = this._amap.lnglatToPixel(center);//, 10)\r\n};\r\n\r\nAMapCoordSys.prototype.setMapOffset = function (mapOffset) {\r\n this._mapOffset = mapOffset;\r\n};\r\n\r\nAMapCoordSys.prototype.getAMap = function () {\r\n return this._amap;\r\n};\r\n\r\nAMapCoordSys.prototype.dataToPoint = function (data) {\r\n var point = new AMap.LngLat(data[0], data[1]);\r\n var px = this._amap.lngLatToContainer(point);//, this._zoom);\r\n var mapOffset = this._mapOffset;\r\n return [px.x - mapOffset[0], px.y - mapOffset[1]];\r\n};\r\n\r\nAMapCoordSys.prototype.pointToData = function (pt) {\r\n var mapOffset = this._mapOffset;\r\n var pt = this._amap.containerToLngLat({\r\n x: pt[0] + mapOffset[0],\r\n y: pt[1] + mapOffset[1]\r\n });\r\n return [pt.lng, pt.lat];\r\n};\r\n\r\nAMapCoordSys.prototype.getViewRect = function () {\r\n var api = this._api;\r\n return new echarts.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight());\r\n};\r\n\r\nAMapCoordSys.prototype.getRoamTransform = function () {\r\n return echarts.matrix.create();\r\n};\r\n\r\nvar Overlay;\r\n\r\n// For deciding which dimensions to use when creating list data\r\nAMapCoordSys.dimensions = AMapCoordSys.prototype.dimensions;\r\n\r\nAMapCoordSys.create = function (ecModel, api) {\r\n var amapCoordSys;\r\n var root = api.getDom();\r\n\r\n // TODO Dispose\r\n ecModel.eachComponent('amap', function (amapModel) {\r\n var viewportRoot = api.getZr().painter.getViewportRoot();\r\n if (typeof AMap === 'undefined') {\r\n throw new Error('AMap api is not loaded');\r\n }\r\n\r\n if (amapCoordSys) {\r\n throw new Error('Only one amap component can exist');\r\n }\r\n if (!amapModel.__amap) {\r\n // Not support IE8\r\n var amapRoot = root.querySelector('.ec-extension-amap');\r\n if (amapRoot) {\r\n // Reset viewport left and top, which will be changed\r\n // in moving handler in AMapView\r\n viewportRoot.style.left = '0px';\r\n viewportRoot.style.top = '0px';\r\n root.removeChild(amapRoot);\r\n }\r\n amapRoot = document.createElement('div');\r\n amapRoot.style.cssText = 'width:100%;height:100%';\r\n // Not support IE8\r\n amapRoot.classList.add('ec-extension-amap');\r\n root.appendChild(amapRoot);\r\n\r\n var options = amapModel.get() || {};\r\n options = amapModel.__options = echarts.util.clone(options);\r\n var amap = amapModel.__amap = new AMap.Map(amapRoot, options);\r\n\r\n var layer = amapModel.__layer = new AMap.CustomLayer(viewportRoot);\r\n layer.setMap(amap);\r\n }\r\n var amap = amapModel.getAMap();\r\n var layer = amapModel.getLayer();\r\n layer.hide();\r\n\r\n var zoom = amap.getZoom();\r\n var center = amap.getCenter();\r\n\r\n amapCoordSys = new AMapCoordSys(amap, api);\r\n amapCoordSys.setMapOffset(amapModel.__mapOffset || [0, 0]);\r\n amapCoordSys.setZoom(zoom);\r\n amapCoordSys.setCenter([center.lng, center.lat]);\r\n\r\n amapModel.coordinateSystem = amapCoordSys;\r\n layer.show();\r\n });\r\n\r\n ecModel.eachSeries(function (seriesModel) {\r\n if (seriesModel.get('coordinateSystem') === 'amap') {\r\n seriesModel.coordinateSystem = amapCoordSys;\r\n }\r\n });\r\n};\r\n\r\nmodule.exports = AMapCoordSys;\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/AMapCoordSys.js\n// module id = 1\n// module chunks = 0","function v2Equal(a, b) {\r\n return a && b && a[0] === b[0] && a[1] === b[1];\r\n}\r\n\r\nmodule.exports = require('echarts').extendComponentModel({\r\n type: 'amap',\r\n\r\n getAMap: function () {\r\n // __amap is injected when creating AMapCoordSys\r\n return this.__amap;\r\n },\r\n\r\n getLayer: function() {\r\n // __layer is injected when creating AMapCoordSys\r\n return this.__layer;\r\n },\r\n\r\n getMapOptions: function() {\r\n return this.__options;\r\n },\r\n\r\n setCenterAndZoom: function (center, zoom) {\r\n this.option.center = center;\r\n this.option.zoom = zoom;\r\n },\r\n centerOrZoomChanged: function (center, zoom) {\r\n var option = this.option;\r\n return !(v2Equal(center, option.center) && zoom === option.zoom);\r\n },\r\n\r\n defaultOption: {\r\n center: [116.397475,39.908695],\r\n zoom: 4,\r\n }\r\n});\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/AMapModel.js\n// module id = 2\n// module chunks = 0","/*\r\n * this function bollowed from:\r\n * https://github.com/Leaflet/Leaflet/blob/master/src/core/Util.js\r\n */\r\nfunction throttle(fn, time, context) {\r\n\tvar lock, args, wrapperFn, later;\r\n\r\n\tlater = function () {\r\n\t\t// reset lock and call if queued\r\n\t\tlock = false;\r\n\t\tif (args) {\r\n\t\t\twrapperFn.apply(context, args);\r\n\t\t\targs = false;\r\n\t\t}\r\n\t};\r\n\r\n\twrapperFn = function () {\r\n\t\tif (lock) {\r\n\t\t\t// called too soon, queue to call later\r\n\t\t\targs = arguments;\r\n\r\n\t\t} else {\r\n\t\t\t// call and lock until later\r\n\t\t\tfn.apply(context, arguments);\r\n\t\t\tsetTimeout(later, time);\r\n\t\t\tlock = true;\r\n\t\t}\r\n\t};\r\n\r\n\treturn wrapperFn;\r\n}\r\n\r\nvar echarts = require('echarts');\r\n\r\nmodule.exports = require('echarts').extendComponentView({\r\n type: 'amap',\r\n render: function (aMapModel, ecModel, api) {\r\n var rendering = true;\r\n\r\n var amap = aMapModel.getAMap();\r\n var viewportRoot = api.getZr().painter.getViewportRoot();\r\n var coordSys = aMapModel.coordinateSystem;\r\n var moveHandler = function (e) {\r\n if (rendering) {\r\n return;\r\n }\r\n var offsetEl = viewportRoot.parentNode.parentNode.parentNode;\r\n var mapOffset = [\r\n -parseInt(offsetEl.style.left, 10) || 0,\r\n -parseInt(offsetEl.style.top, 10) || 0\r\n ];\r\n viewportRoot.style.left = mapOffset[0] + 'px';\r\n viewportRoot.style.top = mapOffset[1] + 'px';\r\n\r\n coordSys.setMapOffset(mapOffset);\r\n aMapModel.__mapOffset = mapOffset;\r\n\r\n api.dispatchAction({\r\n type: 'amapRoam'\r\n });\r\n };\r\n\r\n function zoomEndHandler() {\r\n if (rendering) {\r\n return;\r\n }\r\n api.dispatchAction({\r\n type: 'amapRoam'\r\n });\r\n }\r\n\r\n function resizeHandler(e) {\r\n echarts.getInstanceByDom(api.getDom()).resize();\r\n moveHandler.call(this, e)\r\n }\r\n\r\n var throttledResizeHandler = throttle(resizeHandler, 300, amap);\r\n\r\n amap.off('movestart', this._oldMoveHandler);\r\n amap.off('zoomend', this._oldZoomEndHandler);\r\n amap.off('moveend', this._oldZoomEndHandler);\r\n amap.off('complete', this._oldZoomEndHandler);\r\n aMapModel.get('resizeEnable') && amap.off('resize', this._oldResizeHandler);\r\n\r\n amap.on('movestart', moveHandler);\r\n amap.on('zoomend', zoomEndHandler);\r\n amap.on('moveend', zoomEndHandler);\r\n amap.on('complete', zoomEndHandler);\r\n aMapModel.get('resizeEnable') && amap.on('resize', throttledResizeHandler);\r\n\r\n this._oldMoveHandler = moveHandler;\r\n this._oldZoomEndHandler = zoomEndHandler;\r\n this._oldResizeHandler = throttledResizeHandler;\r\n\r\n // var roam = aMapModel.get('roam');\r\n // if (roam && roam !== 'scale') {\r\n // amap.enableDragging();\r\n // }\r\n // else {\r\n // amap.disableDragging();\r\n // }\r\n // if (roam && roam !== 'move') {\r\n // amap.enableScrollWheelZoom();\r\n // amap.enableDoubleClickZoom();\r\n // amap.enablePinchToZoom();\r\n // }\r\n // else {\r\n // amap.disableScrollWheelZoom();\r\n // amap.disableDoubleClickZoom();\r\n // amap.disablePinchToZoom();\r\n // }\r\n\r\n rendering = false;\r\n }\r\n});\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/AMapView.js\n// module id = 3\n// module chunks = 0","/**\r\n * BMap component extension\r\n */\r\nrequire('echarts').registerCoordinateSystem(\r\n 'amap', require('./AMapCoordSys')\r\n);\r\nrequire('./AMapModel');\r\nrequire('./AMapView');\r\n\r\n// Action\r\nrequire('echarts').registerAction({\r\n type: 'amapRoam',\r\n event: 'amapRoam',\r\n update: 'updateLayout'\r\n}, function (payload, ecModel) {\r\n ecModel.eachComponent('amap', function (aMapModel) {\r\n var amap = aMapModel.getAMap();\r\n var center = amap.getCenter();\r\n aMapModel.setCenterAndZoom([center.lng, center.lat], amap.getZoom());\r\n });\r\n});\r\n\r\nmodule.exports = {\r\n version: process.env.VERSION\r\n};\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/amap.js\n// module id = 4\n// module chunks = 0"],"sourceRoot":""}
--------------------------------------------------------------------------------
/assets/loader/OBJLoader2.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Kai Salmen / https://kaisalmen.de
3 | * Development repository: https://github.com/kaisalmen/WWOBJLoader
4 | */
5 |
6 | 'use strict';
7 |
8 | if (THREE.OBJLoader2 === undefined) {
9 | THREE.OBJLoader2 = {}
10 | }
11 |
12 | if (THREE.LoaderSupport === undefined) console.error('"THREE.LoaderSupport" is not available. "THREE.OBJLoader2" requires it. Please include "LoaderSupport.js" in your HTML.');
13 |
14 | /**
15 | * Use this class to load OBJ data from files or to parse OBJ data from an arraybuffer
16 | * @class
17 | *
18 | * @param {THREE.DefaultLoadingManager} [manager] The loadingManager for the loader to use. Default is {@link THREE.DefaultLoadingManager}
19 | * @param {THREE.LoaderSupport.ConsoleLogger} logger logger to be used
20 | */
21 | THREE.OBJLoader2 = (function() {
22 |
23 | var OBJLOADER2_VERSION = '2.2.1';
24 | var LoaderBase = THREE.LoaderSupport.LoaderBase;
25 | var Validator = THREE.LoaderSupport.Validator;
26 | var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
27 |
28 | OBJLoader2.prototype = Object.create(THREE.LoaderSupport.LoaderBase.prototype);
29 | OBJLoader2.prototype.constructor = OBJLoader2;
30 |
31 | function OBJLoader2(manager, logger) {
32 | THREE.LoaderSupport.LoaderBase.call(this, manager, logger);
33 | this.logger.logInfo('Using THREE.OBJLoader2 version: ' + OBJLOADER2_VERSION);
34 |
35 | this.materialPerSmoothingGroup = false;
36 | this.fileLoader = Validator.verifyInput(this.fileLoader, new THREE.FileLoader(this.manager));
37 |
38 | this.workerSupport = null;
39 | this.terminateWorkerOnLoad = true;
40 | };
41 |
42 | /**
43 | * Tells whether a material shall be created per smoothing group.
44 | * @memberOf THREE.OBJLoader2
45 | *
46 | * @param {boolean} materialPerSmoothingGroup=false
47 | */
48 | OBJLoader2.prototype.setMaterialPerSmoothingGroup = function(materialPerSmoothingGroup) {
49 | this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
50 | };
51 |
52 | /**
53 | * Use this convenient method to load an OBJ file at the given URL. By default the fileLoader uses an arraybuffer.
54 | * @memberOf THREE.OBJLoader2
55 | *
56 | * @param {string} url A string containing the path/URL of the .obj file.
57 | * @param {callback} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument.
58 | * @param {callback} [onProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes.
59 | * @param {callback} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument.
60 | * @param {callback} [onMeshAlter] A function to be called after a new mesh raw data becomes available for alteration.
61 | * @param {boolean} [useAsync] If true, uses async loading with worker, if false loads data synchronously.
62 | */
63 | OBJLoader2.prototype.load = function(url, onLoad, onProgress, onError, onMeshAlter, useAsync) {
64 | var scope = this;
65 | if (!Validator.isValid(onProgress)) {
66 | var numericalValueRef = 0;
67 | var numericalValue = 0;
68 | onProgress = function(event) {
69 | if (!event.lengthComputable) return;
70 |
71 | numericalValue = event.loaded / event.total;
72 | if (numericalValue > numericalValueRef) {
73 |
74 | numericalValueRef = numericalValue;
75 | var output = 'Download of "' + url + '": ' + (numericalValue * 100).toFixed(2) + '%';
76 | scope.onProgress('progressLoad', output, numericalValue);
77 |
78 | }
79 | };
80 | }
81 |
82 | if (!Validator.isValid(onError)) {
83 | onError = function(event) {
84 | var output = 'Error occurred while downloading "' + url + '"';
85 | scope.logger.logError(output + ': ' + event);
86 | scope.onProgress('error', output, -1);
87 | };
88 | }
89 |
90 | this.fileLoader.setPath(this.path);
91 | this.fileLoader.setResponseType('arraybuffer');
92 | this.fileLoader.load(url, function(content) {
93 | if (useAsync) {
94 |
95 | scope.parseAsync(content, onLoad);
96 |
97 | } else {
98 |
99 | var callbacks = new THREE.LoaderSupport.Callbacks();
100 | callbacks.setCallbackOnMeshAlter(onMeshAlter);
101 | scope._setCallbacks(callbacks);
102 | onLoad({
103 | detail: {
104 | loaderRootNode: scope.parse(content),
105 | modelName: scope.modelName,
106 | instanceNo: scope.instanceNo
107 | }
108 | });
109 |
110 | }
111 |
112 | }, onProgress, onError);
113 |
114 | };
115 |
116 | /**
117 | * Run the loader according the provided instructions.
118 | * @memberOf THREE.OBJLoader2
119 | *
120 | * @param {THREE.LoaderSupport.PrepData} prepData All parameters and resources required for execution
121 | * @param {THREE.LoaderSupport.WorkerSupport} [workerSupportExternal] Use pre-existing WorkerSupport
122 | */
123 | OBJLoader2.prototype.run = function(prepData, workerSupportExternal) {
124 | this._applyPrepData(prepData);
125 | var available = this._checkFiles(prepData.resources);
126 | if (Validator.isValid(workerSupportExternal)) {
127 |
128 | this.terminateWorkerOnLoad = false;
129 | this.workerSupport = workerSupportExternal;
130 | this.logger = workerSupportExternal.logger;
131 |
132 | }
133 | var scope = this;
134 | var onMaterialsLoaded = function(materials) {
135 | scope.builder.setMaterials(materials);
136 |
137 | if (Validator.isValid(available.obj.content)) {
138 |
139 | if (prepData.useAsync) {
140 |
141 | scope.parseAsync(available.obj.content, scope.callbacks.onLoad);
142 |
143 | } else {
144 |
145 | scope.parse(available.obj.content);
146 |
147 | }
148 | } else {
149 |
150 | scope.setPath(available.obj.path);
151 | scope.load(available.obj.name, scope.callbacks.onLoad, null, null, scope.callbacks.onMeshAlter, prepData.useAsync);
152 |
153 | }
154 | };
155 |
156 | this._loadMtl(available.mtl, onMaterialsLoaded, prepData.crossOrigin);
157 | };
158 |
159 | OBJLoader2.prototype._applyPrepData = function(prepData) {
160 | THREE.LoaderSupport.LoaderBase.prototype._applyPrepData.call(this, prepData);
161 |
162 | if (Validator.isValid(prepData)) {
163 |
164 | this.setMaterialPerSmoothingGroup(prepData.materialPerSmoothingGroup);
165 |
166 | }
167 | };
168 |
169 | /**
170 | * Parses OBJ data synchronously from arraybuffer or string.
171 | * @memberOf THREE.OBJLoader2
172 | *
173 | * @param {arraybuffer|string} content OBJ data as Uint8Array or String
174 | */
175 | OBJLoader2.prototype.parse = function(content) {
176 | this.logger.logTimeStart('OBJLoader2 parse: ' + this.modelName);
177 |
178 | var parser = new Parser();
179 | parser.setLogConfig(this.logger.enabled, this.logger.debug);
180 | parser.setMaterialPerSmoothingGroup(this.materialPerSmoothingGroup);
181 | parser.setUseIndices(this.useIndices);
182 | parser.setDisregardNormals(this.disregardNormals);
183 | // sync code works directly on the material references
184 | parser.setMaterials(this.builder.getMaterials());
185 |
186 | var scope = this;
187 | var onMeshLoaded = function(payload) {
188 | var meshes = scope.builder.processPayload(payload);
189 | var mesh;
190 | for (var i in meshes) {
191 | mesh = meshes[i];
192 | scope.loaderRootNode.add(mesh);
193 | }
194 | };
195 | parser.setCallbackBuilder(onMeshLoaded);
196 | var onProgressScoped = function(text, numericalValue) {
197 | scope.onProgress('progressParse', text, numericalValue);
198 | };
199 | parser.setCallbackProgress(onProgressScoped);
200 |
201 | if (content instanceof ArrayBuffer || content instanceof Uint8Array) {
202 |
203 | this.logger.logInfo('Parsing arrayBuffer...');
204 | parser.parse(content);
205 |
206 | } else if (typeof(content) === 'string' || content instanceof String) {
207 |
208 | this.logger.logInfo('Parsing text...');
209 | parser.parseText(content);
210 |
211 | } else {
212 |
213 | throw 'Provided content was neither of type String nor Uint8Array! Aborting...';
214 |
215 | }
216 | this.logger.logTimeEnd('OBJLoader2 parse: ' + this.modelName);
217 |
218 | return this.loaderRootNode;
219 | };
220 |
221 | /**
222 | * Parses OBJ content asynchronously from arraybuffer.
223 | * @memberOf THREE.OBJLoader2
224 | *
225 | * @param {arraybuffer} content OBJ data as Uint8Array
226 | * @param {callback} onLoad Called after worker successfully completed loading
227 | */
228 | OBJLoader2.prototype.parseAsync = function(content, onLoad) {
229 | this.logger.logTimeStart('OBJLoader2 parseAsync: ' + this.modelName);
230 |
231 | var scope = this;
232 | var scopedOnLoad = function() {
233 | onLoad({
234 | detail: {
235 | loaderRootNode: scope.loaderRootNode,
236 | modelName: scope.modelName,
237 | instanceNo: scope.instanceNo
238 | }
239 | });
240 | scope.logger.logTimeEnd('OBJLoader2 parseAsync: ' + scope.modelName);
241 | };
242 | var scopedOnMeshLoaded = function(payload) {
243 | var meshes = scope.builder.processPayload(payload);
244 | var mesh;
245 | for (var i in meshes) {
246 | mesh = meshes[i];
247 | scope.loaderRootNode.add(mesh);
248 | }
249 | };
250 |
251 | this.workerSupport = Validator.verifyInput(this.workerSupport, new THREE.LoaderSupport.WorkerSupport(this.logger));
252 | var buildCode = function(funcBuildObject, funcBuildSingelton) {
253 | var workerCode = '';
254 | workerCode += '/**\n';
255 | workerCode += ' * This code was constructed by OBJLoader2 buildCode.\n';
256 | workerCode += ' */\n\n';
257 | workerCode += funcBuildObject('Validator', Validator);
258 | workerCode += funcBuildSingelton('ConsoleLogger', 'ConsoleLogger', ConsoleLogger);
259 | workerCode += funcBuildSingelton('LoaderBase', 'LoaderBase', LoaderBase);
260 | workerCode += funcBuildObject('Consts', Consts);
261 | workerCode += funcBuildSingelton('Parser', 'Parser', Parser);
262 | workerCode += funcBuildSingelton('RawMesh', 'RawMesh', RawMesh);
263 | workerCode += funcBuildSingelton('RawMeshSubGroup', 'RawMeshSubGroup', RawMeshSubGroup);
264 |
265 | return workerCode;
266 | };
267 | this.workerSupport.validate(buildCode, false);
268 | this.workerSupport.setCallbacks(scopedOnMeshLoaded, scopedOnLoad);
269 | if (scope.terminateWorkerOnLoad) this.workerSupport.setTerminateRequested(true);
270 |
271 | var materialNames = {};
272 | var materials = this.builder.getMaterials();
273 | for (var materialName in materials) {
274 |
275 | materialNames[materialName] = materialName;
276 |
277 | }
278 | this.workerSupport.run({
279 | params: {
280 | useAsync: true,
281 | materialPerSmoothingGroup: this.materialPerSmoothingGroup,
282 | useIndices: this.useIndices,
283 | disregardNormals: this.disregardNormals
284 | },
285 | logger: {
286 | debug: this.logger.debug,
287 | enabled: this.logger.enabled
288 | },
289 | materials: {
290 | // in async case only material names are supplied to parser
291 | materials: materialNames
292 | },
293 | data: {
294 | input: content,
295 | options: null
296 | }
297 | });
298 | };
299 |
300 | /**
301 | * Constants used by THREE.OBJLoader2
302 | */
303 | var Consts = {
304 | CODE_LF: 10,
305 | CODE_CR: 13,
306 | CODE_SPACE: 32,
307 | CODE_SLASH: 47,
308 | STRING_LF: '\n',
309 | STRING_CR: '\r',
310 | STRING_SPACE: ' ',
311 | STRING_SLASH: '/',
312 | LINE_F: 'f',
313 | LINE_G: 'g',
314 | LINE_L: 'l',
315 | LINE_O: 'o',
316 | LINE_S: 's',
317 | LINE_V: 'v',
318 | LINE_VT: 'vt',
319 | LINE_VN: 'vn',
320 | LINE_MTLLIB: 'mtllib',
321 | LINE_USEMTL: 'usemtl'
322 | };
323 |
324 | /**
325 | * Parse OBJ data either from ArrayBuffer or string
326 | * @class
327 | */
328 | var Parser = (function() {
329 |
330 | var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
331 |
332 | function Parser() {
333 | this.callbackProgress = null;
334 | this.callbackBuilder = null;
335 |
336 | this.materials = {};
337 | this.rawMesh = null;
338 | this.useAsync = false;
339 | this.materialPerSmoothingGroup = false;
340 | this.useIndices = false;
341 | this.disregardNormals = false;
342 |
343 | this.inputObjectCount = 1;
344 | this.outputObjectCount = 1;
345 | this.counts = {
346 | vertices: 0,
347 | faces: 0,
348 | doubleIndicesCount: 0
349 | };
350 | this.logger = new ConsoleLogger();
351 | this.totalBytes = 0;
352 | };
353 |
354 | Parser.prototype.setUseAsync = function(useAsync) {
355 | this.useAsync = useAsync;
356 | };
357 |
358 | Parser.prototype.setMaterialPerSmoothingGroup = function(materialPerSmoothingGroup) {
359 | this.materialPerSmoothingGroup = materialPerSmoothingGroup;
360 | };
361 |
362 | Parser.prototype.setUseIndices = function(useIndices) {
363 | this.useIndices = useIndices;
364 | };
365 |
366 | Parser.prototype.setDisregardNormals = function(disregardNormals) {
367 | this.disregardNormals = disregardNormals;
368 | };
369 |
370 | Parser.prototype.setMaterials = function(materials) {
371 | this.materials = Validator.verifyInput(materials, this.materials);
372 | this.materials = Validator.verifyInput(this.materials, {});
373 | };
374 |
375 | Parser.prototype.setCallbackBuilder = function(callbackBuilder) {
376 | this.callbackBuilder = callbackBuilder;
377 | if (!Validator.isValid(this.callbackBuilder)) throw 'Unable to run as no "builder" callback is set.';
378 | };
379 |
380 | Parser.prototype.setCallbackProgress = function(callbackProgress) {
381 | this.callbackProgress = callbackProgress;
382 | };
383 |
384 | Parser.prototype.setLogConfig = function(enabled, debug) {
385 | this.logger.setEnabled(enabled);
386 | this.logger.setDebug(debug);
387 | };
388 |
389 | Parser.prototype.configure = function() {
390 | this.rawMesh = new RawMesh(this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals);
391 |
392 | if (this.logger.isEnabled()) {
393 |
394 | var matKeys = Object.keys(this.materials);
395 | var matNames = (matKeys.length > 0) ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join('\n\t\t- ') : '\n\tmaterialNames: None';
396 | var printedConfig = 'OBJLoader2.Parser configuration:' +
397 | matNames +
398 | '\n\tuseAsync: ' + this.useAsync +
399 | '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup +
400 | '\n\tuseIndices: ' + this.useIndices +
401 | '\n\tdisregardNormals: ' + this.disregardNormals +
402 | '\n\tcallbackBuilderName: ' + this.callbackBuilder.name +
403 | '\n\tcallbackProgressName: ' + this.callbackProgress.name;
404 | this.logger.logInfo(printedConfig);
405 | }
406 | };
407 |
408 | /**
409 | * Parse the provided arraybuffer
410 | * @memberOf Parser
411 | *
412 | * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array
413 | */
414 | Parser.prototype.parse = function(arrayBuffer) {
415 | this.logger.logTimeStart('OBJLoader2.Parser.parse');
416 | this.configure();
417 |
418 | var arrayBufferView = new Uint8Array(arrayBuffer);
419 | var length = arrayBufferView.byteLength;
420 | this.totalBytes = length;
421 | var buffer = new Array(128);
422 | var bufferPointer = 0;
423 | var slashSpacePattern = new Array(16);
424 | var slashSpacePatternPointer = 0;
425 | var code;
426 | var word = '';
427 | var i = 0;
428 | for (; i < length; i++) {
429 |
430 | code = arrayBufferView[i];
431 | switch (code) {
432 | case Consts.CODE_SPACE:
433 | if (word.length > 0) buffer[bufferPointer++] = word;
434 | slashSpacePattern[slashSpacePatternPointer++] = 0;
435 | word = '';
436 | break;
437 |
438 | case Consts.CODE_SLASH:
439 | if (word.length > 0) buffer[bufferPointer++] = word;
440 | slashSpacePattern[slashSpacePatternPointer++] = 1;
441 | word = '';
442 | break;
443 |
444 | case Consts.CODE_LF:
445 | if (word.length > 0) buffer[bufferPointer++] = word;
446 | word = '';
447 | this.processLine(buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i);
448 | bufferPointer = 0;
449 | slashSpacePatternPointer = 0;
450 | break;
451 |
452 | case Consts.CODE_CR:
453 | break;
454 |
455 | default:
456 | word += String.fromCharCode(code);
457 | break;
458 | }
459 | }
460 | this.finalize(i);
461 | this.logger.logTimeEnd('OBJLoader2.Parser.parse');
462 | };
463 |
464 | /**
465 | * Parse the provided text
466 | * @memberOf Parser
467 | *
468 | * @param {string} text OBJ data as string
469 | */
470 | Parser.prototype.parseText = function(text) {
471 | this.logger.logTimeStart('OBJLoader2.Parser.parseText');
472 | this.configure();
473 |
474 | var length = text.length;
475 | this.totalBytes = length;
476 | var buffer = new Array(128);
477 | var bufferPointer = 0;
478 | var slashSpacePattern = new Array(16);
479 | var slashSpacePatternPointer = 0;
480 | var char;
481 | var word = '';
482 | var i = 0;
483 | for (; i < length; i++) {
484 |
485 | char = text[i];
486 | switch (char) {
487 | case Consts.STRING_SPACE:
488 | if (word.length > 0) buffer[bufferPointer++] = word;
489 | slashSpacePattern[slashSpacePatternPointer++] = 0;
490 | word = '';
491 | break;
492 |
493 | case Consts.STRING_SLASH:
494 | if (word.length > 0) buffer[bufferPointer++] = word;
495 | slashSpacePattern[slashSpacePatternPointer++] = 1;
496 | word = '';
497 | break;
498 |
499 | case Consts.STRING_LF:
500 | if (word.length > 0) buffer[bufferPointer++] = word;
501 | word = '';
502 | this.processLine(buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i);
503 | bufferPointer = 0;
504 | slashSpacePatternPointer = 0;
505 | break;
506 |
507 | case Consts.STRING_CR:
508 | break;
509 |
510 | default:
511 | word += char;
512 | }
513 | }
514 | this.finalize(i);
515 | this.logger.logTimeEnd('OBJLoader2.Parser.parseText');
516 | };
517 |
518 | Parser.prototype.processLine = function(buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, currentByte) {
519 | if (bufferPointer < 1) return;
520 |
521 | var countSlashes = function(slashSpacePattern, slashSpacePatternPointer) {
522 | var slashesCount = 0;
523 | for (var i = 0; i < slashSpacePatternPointer; i++) {
524 | slashesCount += slashSpacePattern[i];
525 | }
526 | return slashesCount;
527 | };
528 |
529 | var concatStringBuffer = function(buffer, bufferPointer, slashSpacePattern) {
530 | var concatBuffer = '';
531 | if (bufferPointer === 2) {
532 |
533 | concatBuffer = buffer[1];
534 |
535 | } else {
536 |
537 | var bufferLength = bufferPointer - 1;
538 | for (var i = 1; i < bufferLength; i++) {
539 |
540 | concatBuffer += buffer[i] + (slashSpacePattern[i] === 0 ? ' ' : '/');
541 |
542 | }
543 | concatBuffer += buffer[bufferLength];
544 |
545 | }
546 | return concatBuffer;
547 | };
548 |
549 | var flushStringBuffer = function(buffer, bufferPointer) {
550 | for (var i = 0; i < bufferPointer; i++) {
551 | buffer[i] = '';
552 | }
553 | };
554 |
555 | switch (buffer[0]) {
556 | case Consts.LINE_V:
557 | this.rawMesh.pushVertex(buffer, bufferPointer > 4);
558 | break;
559 |
560 | case Consts.LINE_VT:
561 | this.rawMesh.pushUv(buffer);
562 | break;
563 |
564 | case Consts.LINE_VN:
565 | this.rawMesh.pushNormal(buffer);
566 | break;
567 |
568 | case Consts.LINE_F:
569 | this.rawMesh.processFaces(buffer, bufferPointer, countSlashes(slashSpacePattern, slashSpacePatternPointer));
570 | break;
571 |
572 | case Consts.LINE_L:
573 | this.rawMesh.processLines(buffer, bufferPointer, countSlashes(slashSpacePattern, slashSpacePatternPointer));
574 | break;
575 |
576 | case Consts.LINE_S:
577 | this.rawMesh.pushSmoothingGroup(buffer[1]);
578 | flushStringBuffer(buffer, bufferPointer);
579 | break;
580 |
581 | case Consts.LINE_G:
582 | // 'g' leads to creation of mesh if valid data (faces declaration was done before), otherwise only groupName gets set
583 | this.processCompletedMesh(currentByte);
584 | this.rawMesh.pushGroup(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
585 | flushStringBuffer(buffer, bufferPointer);
586 | break;
587 |
588 | case Consts.LINE_O:
589 | // 'o' is pure meta-information and does not result in creation of new meshes
590 | this.rawMesh.pushObject(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
591 | flushStringBuffer(buffer, bufferPointer);
592 | break;
593 |
594 | case Consts.LINE_MTLLIB:
595 | this.rawMesh.pushMtllib(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
596 | flushStringBuffer(buffer, bufferPointer);
597 | break;
598 |
599 | case Consts.LINE_USEMTL:
600 | this.rawMesh.pushUsemtl(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
601 | flushStringBuffer(buffer, bufferPointer);
602 | break;
603 |
604 | default:
605 | break;
606 | }
607 | };
608 |
609 | Parser.prototype.createRawMeshReport = function(rawMesh, inputObjectCount) {
610 | var report = rawMesh.createReport(inputObjectCount);
611 | return 'Input Object number: ' + inputObjectCount +
612 | '\n\tObject name: ' + report.objectName +
613 | '\n\tGroup name: ' + report.groupName +
614 | '\n\tMtllib name: ' + report.mtllibName +
615 | '\n\tVertex count: ' + report.vertexCount +
616 | '\n\tNormal count: ' + report.normalCount +
617 | '\n\tUV count: ' + report.uvCount +
618 | '\n\tSmoothingGroup count: ' + report.smoothingGroupCount +
619 | '\n\tMaterial count: ' + report.mtlCount +
620 | '\n\tReal RawMeshSubGroup count: ' + report.subGroups;
621 | };
622 |
623 | Parser.prototype.processCompletedMesh = function(currentByte) {
624 | var result = this.rawMesh.finalize();
625 | if (Validator.isValid(result)) {
626 |
627 | if (this.rawMesh.colors.length > 0 && this.rawMesh.colors.length !== this.rawMesh.vertices.length) {
628 |
629 | throw 'Vertex Colors were detected, but vertex count and color count do not match!';
630 |
631 | }
632 | if (this.logger.isDebug()) this.logger.logDebug(this.createRawMeshReport(this.rawMesh, this.inputObjectCount));
633 | this.inputObjectCount++;
634 |
635 | this.buildMesh(result, currentByte);
636 | var progressBytesPercent = currentByte / this.totalBytes;
637 | this.callbackProgress('Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '] Total progress: ' + (progressBytesPercent * 100).toFixed(2) + '%', progressBytesPercent);
638 | this.rawMesh.reset(this.rawMesh.smoothingGroup.splitMaterials);
639 |
640 | return true;
641 |
642 | } else {
643 |
644 | return false;
645 | }
646 | };
647 |
648 | Parser.prototype.finalize = function(currentByte) {
649 | this.logger.logInfo('Global output object count: ' + this.outputObjectCount);
650 | if (this.processCompletedMesh(currentByte) && this.logger.isEnabled()) {
651 |
652 | var parserFinalReport = 'Overall counts: ' +
653 | '\n\tVertices: ' + this.counts.vertices +
654 | '\n\tFaces: ' + this.counts.faces +
655 | '\n\tMultiple definitions: ' + this.counts.doubleIndicesCount;
656 | this.logger.logInfo(parserFinalReport);
657 |
658 | }
659 | };
660 |
661 | /**
662 | * RawObjectDescriptions are transformed to too intermediate format that is forwarded to the Builder.
663 | * It is ensured that rawObjectDescriptions only contain objects with vertices (no need to check).
664 | *
665 | * @param result
666 | */
667 | Parser.prototype.buildMesh = function(result, currentByte) {
668 | var rawObjectDescriptions = result.subGroups;
669 |
670 | var vertexFA = new Float32Array(result.absoluteVertexCount);
671 | this.counts.vertices += result.absoluteVertexCount / 3;
672 | this.counts.faces += result.faceCount;
673 | this.counts.doubleIndicesCount += result.doubleIndicesCount;
674 | var indexUA = (result.absoluteIndexCount > 0) ? new Uint32Array(result.absoluteIndexCount) : null;
675 | var colorFA = (result.absoluteColorCount > 0) ? new Float32Array(result.absoluteColorCount) : null;
676 | var normalFA = (result.absoluteNormalCount > 0) ? new Float32Array(result.absoluteNormalCount) : null;
677 | var uvFA = (result.absoluteUvCount > 0) ? new Float32Array(result.absoluteUvCount) : null;
678 | var haveVertexColors = Validator.isValid(colorFA);
679 |
680 | var rawObjectDescription;
681 | var materialNames = [];
682 |
683 | var createMultiMaterial = (rawObjectDescriptions.length > 1);
684 | var materialIndex = 0;
685 | var materialIndexMapping = [];
686 | var selectedMaterialIndex;
687 | var materialGroup;
688 | var materialGroups = [];
689 |
690 | var vertexFAOffset = 0;
691 | var indexUAOffset = 0;
692 | var colorFAOffset = 0;
693 | var normalFAOffset = 0;
694 | var uvFAOffset = 0;
695 | var materialGroupOffset = 0;
696 | var materialGroupLength = 0;
697 |
698 | var materialOrg, material, materialName, materialNameOrg;
699 | for (var oodIndex in rawObjectDescriptions) {
700 |
701 | if (!rawObjectDescriptions.hasOwnProperty(oodIndex)) continue;
702 | rawObjectDescription = rawObjectDescriptions[oodIndex];
703 |
704 | materialNameOrg = rawObjectDescription.materialName;
705 | materialName = materialNameOrg + (haveVertexColors ? '_vertexColor' : '') + (rawObjectDescription.smoothingGroup === 0 ? '_flat' : '');
706 | materialOrg = this.materials[materialNameOrg];
707 | material = this.materials[materialName];
708 |
709 | // both original and derived names do not lead to an existing material => need to use a default material
710 | if (!Validator.isValid(materialOrg) && !Validator.isValid(material)) {
711 |
712 | var defaultMaterialName = haveVertexColors ? 'vertexColorMaterial' : 'defaultMaterial';
713 | materialOrg = this.materials[defaultMaterialName];
714 | this.logger.logWarn('object_group "' + rawObjectDescription.objectName + '_' +
715 | rawObjectDescription.groupName + '" was defined with unresolvable material "' +
716 | materialNameOrg + '"! Assigning "' + defaultMaterialName + '".');
717 | materialNameOrg = defaultMaterialName;
718 |
719 | // if names are identical then there is no need for later manipulation
720 | if (materialNameOrg === materialName) {
721 |
722 | material = materialOrg;
723 | materialName = defaultMaterialName;
724 |
725 | }
726 |
727 | }
728 | if (!Validator.isValid(material)) {
729 |
730 | var materialCloneInstructions = {
731 | materialNameOrg: materialNameOrg,
732 | materialName: materialName,
733 | materialProperties: {
734 | vertexColors: haveVertexColors ? 2 : 0,
735 | flatShading: rawObjectDescription.smoothingGroup === 0
736 | }
737 | };
738 | var payload = {
739 | cmd: 'materialData',
740 | materials: {
741 | materialCloneInstructions: materialCloneInstructions
742 | }
743 | };
744 | this.callbackBuilder(payload);
745 |
746 | // fake entry for async; sync Parser always works on material references (Builder update directly visible here)
747 | if (this.useAsync) this.materials[materialName] = materialCloneInstructions;
748 |
749 | }
750 |
751 | if (createMultiMaterial) {
752 |
753 | // re-use material if already used before. Reduces materials array size and eliminates duplicates
754 | selectedMaterialIndex = materialIndexMapping[materialName];
755 | if (!selectedMaterialIndex) {
756 |
757 | selectedMaterialIndex = materialIndex;
758 | materialIndexMapping[materialName] = materialIndex;
759 | materialNames.push(materialName);
760 | materialIndex++;
761 |
762 | }
763 | materialGroupLength = this.useIndices ? rawObjectDescription.indices.length : rawObjectDescription.vertices.length / 3;
764 | materialGroup = {
765 | start: materialGroupOffset,
766 | count: materialGroupLength,
767 | index: selectedMaterialIndex
768 | };
769 | materialGroups.push(materialGroup);
770 | materialGroupOffset += materialGroupLength;
771 |
772 | } else {
773 |
774 | materialNames.push(materialName);
775 |
776 | }
777 |
778 | vertexFA.set(rawObjectDescription.vertices, vertexFAOffset);
779 | vertexFAOffset += rawObjectDescription.vertices.length;
780 |
781 | if (indexUA) {
782 |
783 | indexUA.set(rawObjectDescription.indices, indexUAOffset);
784 | indexUAOffset += rawObjectDescription.indices.length;
785 |
786 | }
787 |
788 | if (colorFA) {
789 |
790 | colorFA.set(rawObjectDescription.colors, colorFAOffset);
791 | colorFAOffset += rawObjectDescription.colors.length;
792 |
793 | }
794 |
795 | if (normalFA) {
796 |
797 | normalFA.set(rawObjectDescription.normals, normalFAOffset);
798 | normalFAOffset += rawObjectDescription.normals.length;
799 |
800 | }
801 | if (uvFA) {
802 |
803 | uvFA.set(rawObjectDescription.uvs, uvFAOffset);
804 | uvFAOffset += rawObjectDescription.uvs.length;
805 |
806 | }
807 |
808 | if (this.logger.isDebug()) {
809 | var materialIndexLine = Validator.isValid(selectedMaterialIndex) ? '\n\t\tmaterialIndex: ' + selectedMaterialIndex : '';
810 | var createdReport = 'Output Object no.: ' + this.outputObjectCount +
811 | '\n\t\tgroupName: ' + rawObjectDescription.groupName +
812 | materialIndexLine +
813 | '\n\t\tmaterialName: ' + rawObjectDescription.materialName +
814 | '\n\t\tsmoothingGroup: ' + rawObjectDescription.smoothingGroup +
815 | '\n\t\tobjectName: ' + rawObjectDescription.objectName +
816 | '\n\t\t#vertices: ' + rawObjectDescription.vertices.length / 3 +
817 | '\n\t\t#indices: ' + rawObjectDescription.indices.length +
818 | '\n\t\t#colors: ' + rawObjectDescription.colors.length / 3 +
819 | '\n\t\t#uvs: ' + rawObjectDescription.uvs.length / 2 +
820 | '\n\t\t#normals: ' + rawObjectDescription.normals.length / 3;
821 | this.logger.logDebug(createdReport);
822 | }
823 |
824 | }
825 |
826 | this.outputObjectCount++;
827 | this.callbackBuilder({
828 | cmd: 'meshData',
829 | progress: {
830 | numericalValue: currentByte / this.totalBytes
831 | },
832 | params: {
833 | meshName: result.name
834 | },
835 | materials: {
836 | multiMaterial: createMultiMaterial,
837 | materialNames: materialNames,
838 | materialGroups: materialGroups
839 | },
840 | buffers: {
841 | vertices: vertexFA,
842 | indices: indexUA,
843 | colors: colorFA,
844 | normals: normalFA,
845 | uvs: uvFA
846 | }
847 | }, [vertexFA.buffer],
848 | Validator.isValid(indexUA) ? [indexUA.buffer] : null,
849 | Validator.isValid(colorFA) ? [colorFA.buffer] : null,
850 | Validator.isValid(normalFA) ? [normalFA.buffer] : null,
851 | Validator.isValid(uvFA) ? [uvFA.buffer] : null
852 | );
853 | };
854 |
855 | return Parser;
856 | })();
857 |
858 | /**
859 | * {@link RawMesh} is only used by {@link Parser}.
860 | * The user of OBJLoader2 does not need to care about this class.
861 | * It is defined publicly for inclusion in web worker based OBJ loader ({@link THREE.OBJLoader2.WWOBJLoader2})
862 | */
863 | var RawMesh = (function() {
864 |
865 | function RawMesh(materialPerSmoothingGroup, useIndices, disregardNormals) {
866 | this.vertices = [];
867 | this.colors = [];
868 | this.normals = [];
869 | this.uvs = [];
870 |
871 | this.useIndices = useIndices === true;
872 | this.disregardNormals = disregardNormals === true;
873 |
874 | this.objectName = '';
875 | this.groupName = '';
876 | this.activeMtlName = '';
877 | this.mtllibName = '';
878 | this.reset(materialPerSmoothingGroup);
879 | }
880 |
881 | RawMesh.prototype.reset = function(materialPerSmoothingGroup) {
882 | // faces are stored according combined index of group, material and smoothingGroup (0 or not)
883 | this.subGroups = [];
884 | this.subGroupInUse = null;
885 | this.smoothingGroup = {
886 | splitMaterials: materialPerSmoothingGroup === true,
887 | normalized: -1,
888 | real: -1
889 | };
890 | // this default index is required as it is possible to define faces without 'g' or 'usemtl'
891 | this.pushSmoothingGroup(1);
892 |
893 | this.doubleIndicesCount = 0;
894 | this.faceCount = 0;
895 | this.mtlCount = 0;
896 | this.smoothingGroupCount = 0;
897 | };
898 |
899 | RawMesh.prototype.pushVertex = function(buffer, haveVertexColors) {
900 | this.vertices.push(parseFloat(buffer[1]));
901 | this.vertices.push(parseFloat(buffer[2]));
902 | this.vertices.push(parseFloat(buffer[3]));
903 | if (haveVertexColors) {
904 |
905 | this.colors.push(parseFloat(buffer[4]));
906 | this.colors.push(parseFloat(buffer[5]));
907 | this.colors.push(parseFloat(buffer[6]));
908 |
909 | }
910 | };
911 |
912 | RawMesh.prototype.pushUv = function(buffer) {
913 | this.uvs.push(parseFloat(buffer[1]));
914 | this.uvs.push(parseFloat(buffer[2]));
915 | };
916 |
917 | RawMesh.prototype.pushNormal = function(buffer) {
918 | this.normals.push(parseFloat(buffer[1]));
919 | this.normals.push(parseFloat(buffer[2]));
920 | this.normals.push(parseFloat(buffer[3]));
921 | };
922 |
923 | RawMesh.prototype.pushGroup = function(groupName) {
924 | this.groupName = Validator.verifyInput(groupName, '');
925 | };
926 |
927 | RawMesh.prototype.pushObject = function(objectName) {
928 | this.objectName = Validator.verifyInput(objectName, '');
929 | };
930 |
931 | RawMesh.prototype.pushMtllib = function(mtllibName) {
932 | this.mtllibName = Validator.verifyInput(mtllibName, '');
933 | };
934 |
935 | RawMesh.prototype.pushUsemtl = function(mtlName) {
936 | if (this.activeMtlName === mtlName || !Validator.isValid(mtlName)) return;
937 | this.activeMtlName = mtlName;
938 | this.mtlCount++;
939 |
940 | this.verifyIndex();
941 | };
942 |
943 | RawMesh.prototype.pushSmoothingGroup = function(smoothingGroup) {
944 | var smoothingGroupInt = parseInt(smoothingGroup);
945 | if (isNaN(smoothingGroupInt)) {
946 | smoothingGroupInt = smoothingGroup === "off" ? 0 : 1;
947 | }
948 |
949 | var smoothCheck = this.smoothingGroup.normalized;
950 | this.smoothingGroup.normalized = this.smoothingGroup.splitMaterials ? smoothingGroupInt : (smoothingGroupInt === 0) ? 0 : 1;
951 | this.smoothingGroup.real = smoothingGroupInt;
952 |
953 | if (smoothCheck !== smoothingGroupInt) {
954 |
955 | this.smoothingGroupCount++;
956 | this.verifyIndex();
957 |
958 | }
959 | };
960 |
961 | RawMesh.prototype.verifyIndex = function() {
962 | var index = this.activeMtlName + '|' + this.smoothingGroup.normalized;
963 | this.subGroupInUse = this.subGroups[index];
964 | if (!Validator.isValid(this.subGroupInUse)) {
965 |
966 | this.subGroupInUse = new RawMeshSubGroup(this.objectName, this.groupName, this.activeMtlName, this.smoothingGroup.normalized);
967 | this.subGroups[index] = this.subGroupInUse;
968 |
969 | }
970 | };
971 |
972 | RawMesh.prototype.processFaces = function(buffer, bufferPointer, slashesCount) {
973 | var bufferLength = bufferPointer - 1;
974 | var i, length;
975 |
976 | // "f vertex ..."
977 | if (slashesCount === 0) {
978 |
979 | for (i = 2, length = bufferLength; i < length; i++) {
980 |
981 | this.buildFace(buffer[1]);
982 | this.buildFace(buffer[i]);
983 | this.buildFace(buffer[i + 1]);
984 |
985 | }
986 |
987 | // "f vertex/uv ..."
988 | } else if (bufferLength === slashesCount * 2) {
989 |
990 | for (i = 3, length = bufferLength - 2; i < length; i += 2) {
991 |
992 | this.buildFace(buffer[1], buffer[2]);
993 | this.buildFace(buffer[i], buffer[i + 1]);
994 | this.buildFace(buffer[i + 2], buffer[i + 3]);
995 |
996 | }
997 |
998 | // "f vertex/uv/normal ..."
999 | } else if (bufferLength * 2 === slashesCount * 3) {
1000 |
1001 | for (i = 4, length = bufferLength - 3; i < length; i += 3) {
1002 |
1003 | this.buildFace(buffer[1], buffer[2], buffer[3]);
1004 | this.buildFace(buffer[i], buffer[i + 1], buffer[i + 2]);
1005 | this.buildFace(buffer[i + 3], buffer[i + 4], buffer[i + 5]);
1006 |
1007 | }
1008 |
1009 | // "f vertex//normal ..."
1010 | } else {
1011 |
1012 | for (i = 3, length = bufferLength - 2; i < length; i += 2) {
1013 |
1014 | this.buildFace(buffer[1], undefined, buffer[2]);
1015 | this.buildFace(buffer[i], undefined, buffer[i + 1]);
1016 | this.buildFace(buffer[i + 2], undefined, buffer[i + 3]);
1017 |
1018 | }
1019 |
1020 | }
1021 | };
1022 |
1023 |
1024 | RawMesh.prototype.buildFace = function(faceIndexV, faceIndexU, faceIndexN) {
1025 | var sgiu = this.subGroupInUse;
1026 | if (this.disregardNormals) faceIndexN = undefined;
1027 | var scope = this;
1028 | var updateRawObjectDescriptionInUse = function() {
1029 |
1030 | var faceIndexVi = parseInt(faceIndexV);
1031 | var indexPointerV = 3 * (faceIndexVi > 0 ? faceIndexVi - 1 : faceIndexVi + scope.vertices.length / 3);
1032 |
1033 | var vertices = sgiu.vertices;
1034 | vertices.push(scope.vertices[indexPointerV++]);
1035 | vertices.push(scope.vertices[indexPointerV++]);
1036 | vertices.push(scope.vertices[indexPointerV]);
1037 |
1038 | var indexPointerC = scope.colors.length > 0 ? indexPointerV : null;
1039 | if (indexPointerC !== null) {
1040 |
1041 | var colors = sgiu.colors;
1042 | colors.push(scope.colors[indexPointerC++]);
1043 | colors.push(scope.colors[indexPointerC++]);
1044 | colors.push(scope.colors[indexPointerC]);
1045 |
1046 | }
1047 |
1048 | if (faceIndexU) {
1049 |
1050 | var faceIndexUi = parseInt(faceIndexU);
1051 | var indexPointerU = 2 * (faceIndexUi > 0 ? faceIndexUi - 1 : faceIndexUi + scope.uvs.length / 2);
1052 | var uvs = sgiu.uvs;
1053 | uvs.push(scope.uvs[indexPointerU++]);
1054 | uvs.push(scope.uvs[indexPointerU]);
1055 |
1056 | }
1057 | if (faceIndexN) {
1058 |
1059 | var faceIndexNi = parseInt(faceIndexN);
1060 | var indexPointerN = 3 * (faceIndexNi > 0 ? faceIndexNi - 1 : faceIndexNi + scope.normals.length / 3);
1061 | var normals = sgiu.normals;
1062 | normals.push(scope.normals[indexPointerN++]);
1063 | normals.push(scope.normals[indexPointerN++]);
1064 | normals.push(scope.normals[indexPointerN]);
1065 |
1066 | }
1067 | };
1068 |
1069 | if (this.useIndices) {
1070 |
1071 | var mappingName = faceIndexV + (faceIndexU ? '_' + faceIndexU : '_n') + (faceIndexN ? '_' + faceIndexN : '_n');
1072 | var indicesPointer = sgiu.indexMappings[mappingName];
1073 | if (Validator.isValid(indicesPointer)) {
1074 |
1075 | this.doubleIndicesCount++;
1076 |
1077 | } else {
1078 |
1079 | indicesPointer = sgiu.vertices.length / 3;
1080 | updateRawObjectDescriptionInUse();
1081 | sgiu.indexMappings[mappingName] = indicesPointer;
1082 | sgiu.indexMappingsCount++;
1083 |
1084 | }
1085 | sgiu.indices.push(indicesPointer);
1086 |
1087 | } else {
1088 |
1089 | updateRawObjectDescriptionInUse();
1090 |
1091 | }
1092 | this.faceCount++;
1093 | };
1094 |
1095 | /*
1096 | * Support for lines with or without texture. First element in indexArray is the line identification
1097 | * 0: "f vertex/uv vertex/uv ..."
1098 | * 1: "f vertex vertex ..."
1099 | */
1100 | RawMesh.prototype.processLines = function(buffer, bufferPointer, slashCount) {
1101 | var i = 1;
1102 | var length;
1103 | var bufferLength = bufferPointer - 1;
1104 |
1105 | if (bufferLength === slashCount * 2) {
1106 |
1107 | for (length = bufferLength - 2; i < length; i += 2) {
1108 |
1109 | this.vertices.push(parseInt(buffer[i]));
1110 | this.uvs.push(parseInt(buffer[i + 1]));
1111 |
1112 | }
1113 |
1114 | } else {
1115 |
1116 | for (length = bufferLength - 1; i < length; i++) {
1117 |
1118 | this.vertices.push(parseInt(buffer[i]));
1119 |
1120 | }
1121 |
1122 | }
1123 | };
1124 |
1125 | /**
1126 | * Clear any empty rawObjectDescription and calculate absolute vertex, normal and uv counts
1127 | */
1128 | RawMesh.prototype.finalize = function() {
1129 | var rawObjectDescriptionsTemp = [];
1130 | var rawObjectDescription;
1131 | var absoluteVertexCount = 0;
1132 | var absoluteIndexMappingsCount = 0;
1133 | var absoluteIndexCount = 0;
1134 | var absoluteColorCount = 0;
1135 | var absoluteNormalCount = 0;
1136 | var absoluteUvCount = 0;
1137 | var indices;
1138 | for (var name in this.subGroups) {
1139 |
1140 | rawObjectDescription = this.subGroups[name];
1141 | if (rawObjectDescription.vertices.length > 0) {
1142 |
1143 | indices = rawObjectDescription.indices;
1144 | if (indices.length > 0 && absoluteIndexMappingsCount > 0) {
1145 |
1146 | for (var i in indices) indices[i] = indices[i] + absoluteIndexMappingsCount;
1147 |
1148 | }
1149 | rawObjectDescriptionsTemp.push(rawObjectDescription);
1150 | absoluteVertexCount += rawObjectDescription.vertices.length;
1151 | absoluteIndexMappingsCount += rawObjectDescription.indexMappingsCount;
1152 | absoluteIndexCount += rawObjectDescription.indices.length;
1153 | absoluteColorCount += rawObjectDescription.colors.length;
1154 | absoluteUvCount += rawObjectDescription.uvs.length;
1155 | absoluteNormalCount += rawObjectDescription.normals.length;
1156 |
1157 | }
1158 | }
1159 |
1160 | // do not continue if no result
1161 | var result = null;
1162 | if (rawObjectDescriptionsTemp.length > 0) {
1163 |
1164 | result = {
1165 | name: this.groupName !== '' ? this.groupName : this.objectName,
1166 | subGroups: rawObjectDescriptionsTemp,
1167 | absoluteVertexCount: absoluteVertexCount,
1168 | absoluteIndexCount: absoluteIndexCount,
1169 | absoluteColorCount: absoluteColorCount,
1170 | absoluteNormalCount: absoluteNormalCount,
1171 | absoluteUvCount: absoluteUvCount,
1172 | faceCount: this.faceCount,
1173 | doubleIndicesCount: this.doubleIndicesCount
1174 | };
1175 |
1176 | }
1177 | return result;
1178 | };
1179 |
1180 | RawMesh.prototype.createReport = function() {
1181 | var report = {
1182 | objectName: this.objectName,
1183 | groupName: this.groupName,
1184 | mtllibName: this.mtllibName,
1185 | vertexCount: this.vertices.length / 3,
1186 | normalCount: this.normals.length / 3,
1187 | uvCount: this.uvs.length / 2,
1188 | smoothingGroupCount: this.smoothingGroupCount,
1189 | mtlCount: this.mtlCount,
1190 | subGroups: this.subGroups.length
1191 | };
1192 |
1193 | return report;
1194 | };
1195 |
1196 | return RawMesh;
1197 | })();
1198 |
1199 | /**
1200 | * Descriptive information and data (vertices, normals, uvs) to passed on to mesh building function.
1201 | * @class
1202 | *
1203 | * @param {string} objectName Name of the mesh
1204 | * @param {string} groupName Name of the group
1205 | * @param {string} materialName Name of the material
1206 | * @param {number} smoothingGroup Normalized smoothingGroup (0: flat shading, 1: smooth shading)
1207 | */
1208 | var RawMeshSubGroup = (function() {
1209 |
1210 | function RawMeshSubGroup(objectName, groupName, materialName, smoothingGroup) {
1211 | this.objectName = objectName;
1212 | this.groupName = groupName;
1213 | this.materialName = materialName;
1214 | this.smoothingGroup = smoothingGroup;
1215 | this._init();
1216 | }
1217 |
1218 | RawMeshSubGroup.prototype._init = function() {
1219 | this.vertices = [];
1220 | this.indexMappingsCount = 0;
1221 | this.indexMappings = [];
1222 | this.indices = [];
1223 | this.colors = [];
1224 | this.uvs = [];
1225 | this.normals = [];
1226 | };
1227 |
1228 | return RawMeshSubGroup;
1229 | })();
1230 |
1231 | OBJLoader2.prototype._checkFiles = function(resources) {
1232 | var resource;
1233 | var result = {
1234 | mtl: null,
1235 | obj: null
1236 | };
1237 | for (var index in resources) {
1238 |
1239 | resource = resources[index];
1240 | if (!Validator.isValid(resource.name)) continue;
1241 | if (Validator.isValid(resource.content)) {
1242 |
1243 | if (resource.extension === 'OBJ') {
1244 |
1245 | // fast-fail on bad type
1246 | if (!(resource.content instanceof Uint8Array)) throw 'Provided content is not of type arraybuffer! Aborting...';
1247 | result.obj = resource;
1248 |
1249 | } else if (resource.extension === 'MTL' && Validator.isValid(resource.name)) {
1250 |
1251 | if (!(typeof(resource.content) === 'string' || resource.content instanceof String)) throw 'Provided content is not of type String! Aborting...';
1252 | result.mtl = resource;
1253 |
1254 | } else if (resource.extension === "ZIP") {
1255 | // ignore
1256 |
1257 | } else {
1258 |
1259 | throw 'Unidentified resource "' + resource.name + '": ' + resource.url;
1260 |
1261 | }
1262 |
1263 | } else {
1264 |
1265 | // fast-fail on bad type
1266 | if (!(typeof(resource.name) === 'string' || resource.name instanceof String)) throw 'Provided file is not properly defined! Aborting...';
1267 | if (resource.extension === 'OBJ') {
1268 |
1269 | result.obj = resource;
1270 |
1271 | } else if (resource.extension === 'MTL') {
1272 |
1273 | result.mtl = resource;
1274 |
1275 | } else if (resource.extension === "ZIP") {
1276 | // ignore
1277 |
1278 | } else {
1279 |
1280 | throw 'Unidentified resource "' + resource.name + '": ' + resource.url;
1281 |
1282 | }
1283 | }
1284 | }
1285 |
1286 | return result;
1287 | };
1288 |
1289 | /**
1290 | * Utility method for loading an mtl file according resource description.
1291 | * @memberOf THREE.OBJLoader2
1292 | *
1293 | * @param {string} url URL to the file
1294 | * @param {Object} content The file content as arraybuffer or text
1295 | * @param {function} callbackOnLoad
1296 | * @param {string} [crossOrigin] CORS value
1297 | */
1298 | OBJLoader2.prototype.loadMtl = function(url, content, callbackOnLoad, crossOrigin) {
1299 | var resource = new THREE.LoaderSupport.ResourceDescriptor(url, 'MTL');
1300 | resource.setContent(content);
1301 | this._loadMtl(resource, callbackOnLoad, crossOrigin);
1302 | };
1303 |
1304 | /**
1305 | * Utility method for loading an mtl file according resource description.
1306 | * @memberOf THREE.OBJLoader2
1307 | *
1308 | * @param {THREE.LoaderSupport.ResourceDescriptor} resource
1309 | * @param {function} callbackOnLoad
1310 | * @param {string} [crossOrigin] CORS value
1311 | */
1312 | OBJLoader2.prototype._loadMtl = function(resource, callbackOnLoad, crossOrigin) {
1313 | if (THREE.MTLLoader === undefined) console.error('"THREE.MTLLoader" is not available. "THREE.OBJLoader2" requires it for loading MTL files.');
1314 | if (Validator.isValid(resource)) this.logger.logTimeStart('Loading MTL: ' + resource.name);
1315 |
1316 | var materials = [];
1317 | var scope = this;
1318 | var processMaterials = function(materialCreator) {
1319 | var materialCreatorMaterials = [];
1320 | if (Validator.isValid(materialCreator)) {
1321 |
1322 | materialCreator.preload();
1323 | materialCreatorMaterials = materialCreator.materials;
1324 | for (var materialName in materialCreatorMaterials) {
1325 |
1326 | if (materialCreatorMaterials.hasOwnProperty(materialName)) {
1327 |
1328 | materials[materialName] = materialCreatorMaterials[materialName];
1329 |
1330 | }
1331 | }
1332 | }
1333 |
1334 | if (Validator.isValid(resource)) scope.logger.logTimeEnd('Loading MTL: ' + resource.name);
1335 | callbackOnLoad(materials);
1336 | };
1337 |
1338 | var mtlLoader = new THREE.MTLLoader();
1339 | crossOrigin = Validator.verifyInput(crossOrigin, 'anonymous');
1340 | mtlLoader.setCrossOrigin(crossOrigin);
1341 |
1342 | // fast-fail
1343 | if (!Validator.isValid(resource) || (!Validator.isValid(resource.content) && !Validator.isValid(resource.url))) {
1344 |
1345 | processMaterials();
1346 |
1347 | } else {
1348 |
1349 | mtlLoader.setPath(resource.path);
1350 | if (Validator.isValid(resource.content)) {
1351 |
1352 | processMaterials(Validator.isValid(resource.content) ? mtlLoader.parse(resource.content) : null);
1353 |
1354 | } else if (Validator.isValid(resource.url)) {
1355 |
1356 | var onError = function(event) {
1357 | var output = 'Error occurred while downloading "' + resource.url + '"';
1358 | scope.logger.logError(output + ': ' + event);
1359 | throw output;
1360 | };
1361 |
1362 | mtlLoader.load(resource.name, processMaterials, undefined, onError);
1363 |
1364 | }
1365 | }
1366 | };
1367 |
1368 | return OBJLoader2;
1369 | })();
--------------------------------------------------------------------------------
/assets/loader/LoaderSupport.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Kai Salmen / https://kaisalmen.de
3 | * Development repository: https://github.com/kaisalmen/WWOBJLoader
4 | */
5 |
6 | 'use strict';
7 |
8 | if ( THREE.LoaderSupport === undefined ) { THREE.LoaderSupport = {} }
9 |
10 | /**
11 | * Validation functions.
12 | * @class
13 | */
14 | THREE.LoaderSupport.Validator = {
15 | /**
16 | * If given input is null or undefined, false is returned otherwise true.
17 | *
18 | * @param input Can be anything
19 | * @returns {boolean}
20 | */
21 | isValid: function( input ) {
22 | return ( input !== null && input !== undefined );
23 | },
24 | /**
25 | * If given input is null or undefined, the defaultValue is returned otherwise the given input.
26 | *
27 | * @param input Can be anything
28 | * @param defaultValue Can be anything
29 | * @returns {*}
30 | */
31 | verifyInput: function( input, defaultValue ) {
32 | return ( input === null || input === undefined ) ? defaultValue : input;
33 | }
34 | };
35 |
36 |
37 | /**
38 | * Logging wrapper for console.
39 | * @class
40 | *
41 | * @param {boolean} enabled=true Tell if logger is enabled.
42 | * @param {boolean} debug=false Toggle debug logging.
43 | */
44 | THREE.LoaderSupport.ConsoleLogger = (function () {
45 |
46 | function ConsoleLogger( enabled, debug ) {
47 | this.enabled = enabled !== false;
48 | this.debug = debug === true;
49 | }
50 |
51 | /**
52 | * Enable or disable debug logging.
53 | * @memberOf THREE.LoaderSupport.ConsoleLogger
54 | *
55 | * @param {boolean} debug True or False
56 | */
57 | ConsoleLogger.prototype.setDebug = function ( debug ) {
58 | this.debug = debug === true;
59 | };
60 |
61 | /**
62 | * Returns if is enabled and debug.
63 | * @memberOf THREE.LoaderSupport.ConsoleLogger
64 | *
65 | * @returns {boolean}
66 | */
67 | ConsoleLogger.prototype.isDebug = function () {
68 | return this.isEnabled() && this.debug;
69 | };
70 |
71 | /**
72 | * Enable or disable info, debug and time logging.
73 | * @memberOf THREE.LoaderSupport.ConsoleLogger
74 | *
75 | * @param {boolean} enabled True or False
76 | */
77 | ConsoleLogger.prototype.setEnabled = function ( enabled ) {
78 | this.enabled = enabled === true;
79 | };
80 |
81 | /**
82 | * Returns if is enabled.
83 | * @memberOf THREE.LoaderSupport.ConsoleLogger
84 | *
85 | * @returns {boolean}
86 | */
87 | ConsoleLogger.prototype.isEnabled = function () {
88 | return this.enabled;
89 | };
90 |
91 | /**
92 | * Log a debug message if enabled and debug is set.
93 | * @memberOf THREE.LoaderSupport.ConsoleLogger
94 | *
95 | * @param {string} message Message to log
96 | */
97 | ConsoleLogger.prototype.logDebug = function ( message ) {
98 | if ( this.enabled && this.debug ) console.log( message );
99 | };
100 |
101 | /**
102 | * Log an info message if enabled.
103 | * @memberOf THREE.LoaderSupport.ConsoleLogger
104 | *
105 | * @param {string} message Message to log
106 | */
107 | ConsoleLogger.prototype.logInfo = function ( message ) {
108 | if ( this.enabled ) console.log( message );
109 | };
110 |
111 | /**
112 | * Log a warn message (always).
113 | * @memberOf THREE.LoaderSupport.ConsoleLogger
114 | *
115 | * @param {string} message Message to log
116 | */
117 | ConsoleLogger.prototype.logWarn = function ( message ) {
118 | console.warn( message );
119 | };
120 |
121 | /**
122 | * Log an error message (always).
123 | * @memberOf THREE.LoaderSupport.ConsoleLogger
124 | *
125 | * @param {string} message Message to log
126 | */
127 | ConsoleLogger.prototype.logError = function ( message ) {
128 | console.error( message );
129 | };
130 |
131 | /**
132 | * Start time measurement with provided id.
133 | * @memberOf THREE.LoaderSupport.ConsoleLogger
134 | *
135 | * @param {string} id Time identification
136 | */
137 | ConsoleLogger.prototype.logTimeStart = function ( id ) {
138 | // if ( this.enabled ) console.time( id );
139 | };
140 |
141 | /**
142 | * Stop time measurement started with provided id.
143 | * @memberOf THREE.LoaderSupport.ConsoleLogger
144 | *
145 | * @param {string} id Time identification
146 | */
147 | ConsoleLogger.prototype.logTimeEnd = function ( id ) {
148 | // if ( this.enabled ) console.timeEnd( id );
149 | };
150 |
151 | return ConsoleLogger;
152 | })();
153 |
154 | /**
155 | * Callbacks utilized by loaders and builder.
156 | * @class
157 | */
158 | THREE.LoaderSupport.Callbacks = (function () {
159 |
160 | var Validator = THREE.LoaderSupport.Validator;
161 |
162 | function Callbacks() {
163 | this.onProgress = null;
164 | this.onMeshAlter = null;
165 | this.onLoad = null;
166 | this.onLoadMaterials = null;
167 | }
168 |
169 | /**
170 | * Register callback function that is invoked by internal function "announceProgress" to print feedback.
171 | * @memberOf THREE.LoaderSupport.Callbacks
172 | *
173 | * @param {callback} callbackOnProgress Callback function for described functionality
174 | */
175 | Callbacks.prototype.setCallbackOnProgress = function ( callbackOnProgress ) {
176 | this.onProgress = Validator.verifyInput( callbackOnProgress, this.onProgress );
177 | };
178 |
179 | /**
180 | * Register callback function that is called every time a mesh was loaded.
181 | * Use {@link THREE.LoaderSupport.LoadedMeshUserOverride} for alteration instructions (geometry, material or disregard mesh).
182 | * @memberOf THREE.LoaderSupport.Callbacks
183 | *
184 | * @param {callback} callbackOnMeshAlter Callback function for described functionality
185 | */
186 | Callbacks.prototype.setCallbackOnMeshAlter = function ( callbackOnMeshAlter ) {
187 | this.onMeshAlter = Validator.verifyInput( callbackOnMeshAlter, this.onMeshAlter );
188 | };
189 |
190 | /**
191 | * Register callback function that is called once loading of the complete OBJ file is completed.
192 | * @memberOf THREE.LoaderSupport.Callbacks
193 | *
194 | * @param {callback} callbackOnLoad Callback function for described functionality
195 | */
196 | Callbacks.prototype.setCallbackOnLoad = function ( callbackOnLoad ) {
197 | this.onLoad = Validator.verifyInput( callbackOnLoad, this.onLoad );
198 | };
199 |
200 | /**
201 | * Register callback function that is called when materials have been loaded.
202 | * @memberOf THREE.LoaderSupport.Callbacks
203 | *
204 | * @param {callback} callbackOnLoadMaterials Callback function for described functionality
205 | */
206 | Callbacks.prototype.setCallbackOnLoadMaterials = function ( callbackOnLoadMaterials ) {
207 | this.onLoadMaterials = Validator.verifyInput( callbackOnLoadMaterials, this.onLoadMaterials );
208 | };
209 |
210 | return Callbacks;
211 | })();
212 |
213 |
214 | /**
215 | * Object to return by callback onMeshAlter. Used to disregard a certain mesh or to return one to many meshes.
216 | * @class
217 | *
218 | * @param {boolean} disregardMesh=false Tell implementation to completely disregard this mesh
219 | * @param {boolean} disregardMesh=false Tell implementation that mesh(es) have been altered or added
220 | */
221 | THREE.LoaderSupport.LoadedMeshUserOverride = (function () {
222 |
223 | function LoadedMeshUserOverride( disregardMesh, alteredMesh ) {
224 | this.disregardMesh = disregardMesh === true;
225 | this.alteredMesh = alteredMesh === true;
226 | this.meshes = [];
227 | }
228 |
229 | /**
230 | * Add a mesh created within callback.
231 | *
232 | * @memberOf THREE.OBJLoader2.LoadedMeshUserOverride
233 | *
234 | * @param {THREE.Mesh} mesh
235 | */
236 | LoadedMeshUserOverride.prototype.addMesh = function ( mesh ) {
237 | this.meshes.push( mesh );
238 | this.alteredMesh = true;
239 | };
240 |
241 | /**
242 | * Answers if mesh shall be disregarded completely.
243 | *
244 | * @returns {boolean}
245 | */
246 | LoadedMeshUserOverride.prototype.isDisregardMesh = function () {
247 | return this.disregardMesh;
248 | };
249 |
250 | /**
251 | * Answers if new mesh(es) were created.
252 | *
253 | * @returns {boolean}
254 | */
255 | LoadedMeshUserOverride.prototype.providesAlteredMeshes = function () {
256 | return this.alteredMesh;
257 | };
258 |
259 | return LoadedMeshUserOverride;
260 | })();
261 |
262 |
263 | /**
264 | * A resource description used by {@link THREE.LoaderSupport.PrepData} and others.
265 | * @class
266 | *
267 | * @param {string} url URL to the file
268 | * @param {string} extension The file extension (type)
269 | */
270 | THREE.LoaderSupport.ResourceDescriptor = (function () {
271 |
272 | var Validator = THREE.LoaderSupport.Validator;
273 |
274 | function ResourceDescriptor( url, extension ) {
275 | var urlParts = url.split( '/' );
276 |
277 | if ( urlParts.length < 2 ) {
278 |
279 | this.path = null;
280 | this.name = url;
281 | this.url = url;
282 |
283 | } else {
284 |
285 | this.path = Validator.verifyInput( urlParts.slice( 0, urlParts.length - 1).join( '/' ) + '/', null );
286 | this.name = Validator.verifyInput( urlParts[ urlParts.length - 1 ], null );
287 | this.url = url;
288 |
289 | }
290 | this.extension = Validator.verifyInput( extension, "default" );
291 | this.extension = this.extension.trim();
292 | this.content = null;
293 | }
294 |
295 | /**
296 | * Set the content of this resource (String)
297 | * @memberOf THREE.LoaderSupport.ResourceDescriptor
298 | *
299 | * @param {Object} content The file content as arraybuffer or text
300 | */
301 | ResourceDescriptor.prototype.setContent = function ( content ) {
302 | this.content = Validator.verifyInput( content, null );
303 | };
304 |
305 | return ResourceDescriptor;
306 | })();
307 |
308 |
309 | /**
310 | * Configuration instructions to be used by run method.
311 | * @class
312 | */
313 | THREE.LoaderSupport.PrepData = (function () {
314 |
315 | var Validator = THREE.LoaderSupport.Validator;
316 |
317 | function PrepData( modelName ) {
318 | this.modelName = Validator.verifyInput( modelName, '' );
319 | this.resources = [];
320 | this.streamMeshesTo = null;
321 | this.materialPerSmoothingGroup = false;
322 | this.useIndices = false;
323 | this.disregardNormals = false;
324 | this.callbacks = new THREE.LoaderSupport.Callbacks();
325 | this.crossOrigin;
326 | this.useAsync = false;
327 | }
328 |
329 | /**
330 | * Set the node where the loaded objects will be attached directly.
331 | * @memberOf THREE.LoaderSupport.PrepData
332 | *
333 | * @param {THREE.Object3D} streamMeshesTo Object already attached to scenegraph where new meshes will be attached to
334 | */
335 | PrepData.prototype.setStreamMeshesTo = function ( streamMeshesTo ) {
336 | this.streamMeshesTo = Validator.verifyInput( streamMeshesTo, null );
337 | };
338 |
339 | /**
340 | * Tells whether a material shall be created per smoothing group.
341 | * @memberOf THREE.LoaderSupport.PrepData
342 | *
343 | * @param {boolean} materialPerSmoothingGroup=false
344 | */
345 | PrepData.prototype.setMaterialPerSmoothingGroup = function ( materialPerSmoothingGroup ) {
346 | this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
347 | };
348 |
349 | /**
350 | * Tells whether indices should be used
351 | * @memberOf THREE.LoaderSupport.PrepData
352 | *
353 | * @param {boolean} useIndices=false
354 | */
355 | PrepData.prototype.setUseIndices = function ( useIndices ) {
356 | this.useIndices = useIndices === true;
357 | };
358 |
359 | /**
360 | * Tells whether normals should be completely disregarded and regenerated.
361 | * @memberOf THREE.LoaderSupport.PrepData
362 | *
363 | * @param {boolean} disregardNormals=false
364 | */
365 | PrepData.prototype.setDisregardNormals = function ( disregardNormals ) {
366 | this.disregardNormals = disregardNormals === true;
367 | };
368 |
369 | /**
370 | * Returns all callbacks as {@link THREE.LoaderSupport.Callbacks}
371 | * @memberOf THREE.LoaderSupport.PrepData
372 | *
373 | * @returns {THREE.LoaderSupport.Callbacks}
374 | */
375 | PrepData.prototype.getCallbacks = function () {
376 | return this.callbacks;
377 | };
378 |
379 | /**
380 | * Sets the CORS string to be used.
381 | * @memberOf THREE.LoaderSupport.PrepData
382 | *
383 | * @param {string} crossOrigin CORS value
384 | */
385 | PrepData.prototype.setCrossOrigin = function ( crossOrigin ) {
386 | this.crossOrigin = crossOrigin;
387 | };
388 |
389 | /**
390 | * Add a resource description.
391 | * @memberOf THREE.LoaderSupport.PrepData
392 | *
393 | * @param {THREE.LoaderSupport.ResourceDescriptor}
394 | */
395 | PrepData.prototype.addResource = function ( resource ) {
396 | this.resources.push( resource );
397 | };
398 |
399 | /**
400 | * If true uses async loading with worker, if false loads data synchronously.
401 | * @memberOf THREE.LoaderSupport.PrepData
402 | *
403 | * @param {boolean} useAsync
404 | */
405 | PrepData.prototype.setUseAsync = function ( useAsync ) {
406 | this.useAsync = useAsync === true;
407 | };
408 |
409 | /**
410 | * Clones this object and returns it afterwards.
411 | * @memberOf THREE.LoaderSupport.PrepData
412 | *
413 | * @returns {@link THREE.LoaderSupport.PrepData}
414 | */
415 | PrepData.prototype.clone = function () {
416 | var clone = new THREE.LoaderSupport.PrepData( this.modelName );
417 | clone.resources = this.resources;
418 | clone.streamMeshesTo = this.streamMeshesTo;
419 | clone.materialPerSmoothingGroup = this.materialPerSmoothingGroup;
420 | clone.useIndices = this.useIndices;
421 | clone.disregardNormals = this.disregardNormals;
422 | clone.callbacks = this.callbacks;
423 | clone.crossOrigin = this.crossOrigin;
424 | clone.useAsync = this.useAsync;
425 | return clone;
426 | };
427 |
428 | return PrepData;
429 | })();
430 |
431 | /**
432 | * Builds one or many THREE.Mesh from one raw set of Arraybuffers, materialGroup descriptions and further parameters.
433 | * Supports vertex, vertexColor, normal, uv and index buffers.
434 | * @class
435 | */
436 | THREE.LoaderSupport.Builder = (function () {
437 |
438 | var LOADER_BUILDER_VERSION = '1.1.1';
439 |
440 | var Validator = THREE.LoaderSupport.Validator;
441 | var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
442 |
443 | function Builder( logger ) {
444 | this.logger = Validator.verifyInput( logger, new ConsoleLogger() );
445 | this.logger.logInfo( 'Using THREE.LoaderSupport.Builder version: ' + LOADER_BUILDER_VERSION );
446 | this.callbacks = new THREE.LoaderSupport.Callbacks();
447 | this.materials = [];
448 | }
449 |
450 | /**
451 | * Set materials loaded by any supplier of an Array of {@link THREE.Material}.
452 | * @memberOf THREE.LoaderSupport.Builder
453 | *
454 | * @param {THREE.Material[]} materials Array of {@link THREE.Material}
455 | */
456 | Builder.prototype.setMaterials = function ( materials ) {
457 | var payload = {
458 | cmd: 'materialData',
459 | materials: {
460 | materialCloneInstructions: null,
461 | serializedMaterials: null,
462 | runtimeMaterials: Validator.isValid( this.callbacks.onLoadMaterials ) ? this.callbacks.onLoadMaterials( materials ) : materials
463 | }
464 | };
465 | this.updateMaterials( payload );
466 | };
467 |
468 | Builder.prototype._setCallbacks = function ( callbacks ) {
469 | if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
470 | if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
471 | if ( Validator.isValid( callbacks.onLoad ) ) this.callbacks.setCallbackOnLoad( callbacks.onLoad );
472 | if ( Validator.isValid( callbacks.onLoadMaterials ) ) this.callbacks.setCallbackOnLoadMaterials( callbacks.onLoadMaterials );
473 | };
474 |
475 | /**
476 | * Delegates processing of the payload (mesh building or material update) to the corresponding functions (BW-compatibility).
477 | * @memberOf THREE.LoaderSupport.Builder
478 | *
479 | * @param {Object} payload Raw Mesh or Material descriptions.
480 | * @returns {THREE.Mesh[]} mesh Array of {@link THREE.Mesh} or null in case of material update
481 | */
482 | Builder.prototype.processPayload = function ( payload ) {
483 | if ( payload.cmd === 'meshData' ) {
484 |
485 | return this.buildMeshes( payload );
486 |
487 | } else if ( payload.cmd === 'materialData' ) {
488 |
489 | this.updateMaterials( payload );
490 | return null;
491 |
492 | }
493 | };
494 |
495 | /**
496 | * Builds one or multiple meshes from the data described in the payload (buffers, params, material info).
497 | * @memberOf THREE.LoaderSupport.Builder
498 | *
499 | * @param {Object} meshPayload Raw mesh description (buffers, params, materials) used to build one to many meshes.
500 | * @returns {THREE.Mesh[]} mesh Array of {@link THREE.Mesh}
501 | */
502 | Builder.prototype.buildMeshes = function ( meshPayload ) {
503 | var meshName = meshPayload.params.meshName;
504 |
505 | var bufferGeometry = new THREE.BufferGeometry();
506 | bufferGeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.vertices ), 3 ) );
507 | if ( Validator.isValid( meshPayload.buffers.indices ) ) {
508 |
509 | bufferGeometry.setIndex( new THREE.BufferAttribute( new Uint32Array( meshPayload.buffers.indices ), 1 ));
510 |
511 | }
512 | var haveVertexColors = Validator.isValid( meshPayload.buffers.colors );
513 | if ( haveVertexColors ) {
514 |
515 | bufferGeometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.colors ), 3 ) );
516 |
517 | }
518 | if ( Validator.isValid( meshPayload.buffers.normals ) ) {
519 |
520 | bufferGeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.normals ), 3 ) );
521 |
522 | } else {
523 |
524 | bufferGeometry.computeVertexNormals();
525 |
526 | }
527 | if ( Validator.isValid( meshPayload.buffers.uvs ) ) {
528 |
529 | bufferGeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.uvs ), 2 ) );
530 |
531 | }
532 |
533 | var material, materialName, key;
534 | var materialNames = meshPayload.materials.materialNames;
535 | var createMultiMaterial = meshPayload.materials.multiMaterial;
536 | var multiMaterials = [];
537 | for ( key in materialNames ) {
538 |
539 | materialName = materialNames[ key ];
540 | material = this.materials[ materialName ];
541 | if ( createMultiMaterial ) multiMaterials.push( material );
542 |
543 | }
544 | if ( createMultiMaterial ) {
545 |
546 | material = multiMaterials;
547 | var materialGroups = meshPayload.materials.materialGroups;
548 | var materialGroup;
549 | for ( key in materialGroups ) {
550 |
551 | materialGroup = materialGroups[ key ];
552 | bufferGeometry.addGroup( materialGroup.start, materialGroup.count, materialGroup.index );
553 |
554 | }
555 |
556 | }
557 |
558 | var meshes = [];
559 | var mesh;
560 | var callbackOnMeshAlter = this.callbacks.onMeshAlter;
561 | var callbackOnMeshAlterResult;
562 | var useOrgMesh = true;
563 | if ( Validator.isValid( callbackOnMeshAlter ) ) {
564 |
565 | callbackOnMeshAlterResult = callbackOnMeshAlter(
566 | {
567 | detail: {
568 | meshName: meshName,
569 | bufferGeometry: bufferGeometry,
570 | material: material
571 | }
572 | }
573 | );
574 | if ( Validator.isValid( callbackOnMeshAlterResult ) ) {
575 |
576 | if ( ! callbackOnMeshAlterResult.isDisregardMesh() && callbackOnMeshAlterResult.providesAlteredMeshes() ) {
577 |
578 | for ( var i in callbackOnMeshAlterResult.meshes ) {
579 |
580 | meshes.push( callbackOnMeshAlterResult.meshes[ i ] );
581 |
582 | }
583 |
584 | }
585 | useOrgMesh = false;
586 |
587 | }
588 |
589 | }
590 | if ( useOrgMesh ) {
591 |
592 | mesh = new THREE.Mesh( bufferGeometry, material );
593 | mesh.name = meshName;
594 | meshes.push( mesh );
595 |
596 | }
597 |
598 | var progressMessage;
599 | if ( Validator.isValid( meshes ) && meshes.length > 0 ) {
600 |
601 | var meshNames = [];
602 | for ( var i in meshes ) {
603 |
604 | mesh = meshes[ i ];
605 | meshNames[ i ] = mesh.name;
606 |
607 | }
608 | progressMessage = 'Adding mesh(es) (' + meshNames.length + ': ' + meshNames + ') from input mesh: ' + meshName;
609 | progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)';
610 |
611 | } else {
612 |
613 | progressMessage = 'Not adding mesh: ' + meshName;
614 | progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)';
615 |
616 | }
617 | var callbackOnProgress = this.callbacks.onProgress;
618 | if ( Validator.isValid( callbackOnProgress ) ) {
619 |
620 | var event = new CustomEvent( 'BuilderEvent', {
621 | detail: {
622 | type: 'progress',
623 | modelName: meshPayload.params.meshName,
624 | text: progressMessage,
625 | numericalValue: meshPayload.progress.numericalValue
626 | }
627 | } );
628 | callbackOnProgress( event );
629 |
630 | }
631 |
632 | return meshes;
633 | };
634 |
635 | /**
636 | * Updates the materials with contained material objects (sync) or from alteration instructions (async).
637 | * @memberOf THREE.LoaderSupport.Builder
638 | *
639 | * @param {Object} materialPayload Material update instructions
640 | */
641 | Builder.prototype.updateMaterials = function ( materialPayload ) {
642 | var material, materialName;
643 | var materialCloneInstructions = materialPayload.materials.materialCloneInstructions;
644 | if ( Validator.isValid( materialCloneInstructions ) ) {
645 |
646 | var materialNameOrg = materialCloneInstructions.materialNameOrg;
647 | var materialOrg = this.materials[ materialNameOrg ];
648 | material = materialOrg.clone();
649 |
650 | materialName = materialCloneInstructions.materialName;
651 | material.name = materialName;
652 |
653 | var materialProperties = materialCloneInstructions.materialProperties;
654 | for ( var key in materialProperties ) {
655 |
656 | if ( material.hasOwnProperty( key ) && materialProperties.hasOwnProperty( key ) ) material[ key ] = materialProperties[ key ];
657 |
658 | }
659 | this.materials[ materialName ] = material;
660 |
661 | }
662 |
663 | var materials = materialPayload.materials.serializedMaterials;
664 | if ( Validator.isValid( materials ) && Object.keys( materials ).length > 0 ) {
665 |
666 | var loader = new THREE.MaterialLoader();
667 | var materialJson;
668 | for ( materialName in materials ) {
669 |
670 | materialJson = materials[ materialName ];
671 | if ( Validator.isValid( materialJson ) ) {
672 |
673 | material = loader.parse( materialJson );
674 | this.logger.logInfo( 'De-serialized material with name "' + materialName + '" will be added.' );
675 | this.materials[ materialName ] = material;
676 | }
677 |
678 | }
679 |
680 | }
681 |
682 | materials = materialPayload.materials.runtimeMaterials;
683 | if ( Validator.isValid( materials ) && Object.keys( materials ).length > 0 ) {
684 |
685 | for ( materialName in materials ) {
686 |
687 | material = materials[ materialName ];
688 | this.logger.logInfo( 'Material with name "' + materialName + '" will be added.' );
689 | this.materials[ materialName ] = material;
690 |
691 | }
692 |
693 | }
694 | };
695 |
696 | /**
697 | * Returns the mapping object of material name and corresponding jsonified material.
698 | *
699 | * @returns {Object} Map of Materials in JSON representation
700 | */
701 | Builder.prototype.getMaterialsJSON = function () {
702 | var materialsJSON = {};
703 | var material;
704 | for ( var materialName in this.materials ) {
705 |
706 | material = this.materials[ materialName ];
707 | materialsJSON[ materialName ] = material.toJSON();
708 | }
709 |
710 | return materialsJSON;
711 | };
712 |
713 | /**
714 | * Returns the mapping object of material name and corresponding material.
715 | *
716 | * @returns {Object} Map of {@link THREE.Material}
717 | */
718 | Builder.prototype.getMaterials = function () {
719 | return this.materials;
720 | };
721 |
722 | return Builder;
723 | })();
724 |
725 | /**
726 | * Base class to be used by loaders.
727 | * @class
728 | *
729 | * @param {THREE.DefaultLoadingManager} [manager] The loadingManager for the loader to use. Default is {@link THREE.DefaultLoadingManager}
730 | * @param {THREE.LoaderSupport.ConsoleLogger} logger logger to be used
731 | */
732 | THREE.LoaderSupport.LoaderBase = (function () {
733 |
734 | var Validator = THREE.LoaderSupport.Validator;
735 | var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
736 |
737 | function LoaderBase( manager, logger ) {
738 | this.manager = Validator.verifyInput( manager, THREE.DefaultLoadingManager );
739 | this.logger = Validator.verifyInput( logger, new ConsoleLogger() );
740 |
741 | this.modelName = '';
742 | this.instanceNo = 0;
743 | this.path = '';
744 | this.useIndices = false;
745 | this.disregardNormals = false;
746 |
747 | this.loaderRootNode = new THREE.Group();
748 | this.builder = new THREE.LoaderSupport.Builder( this.logger );
749 | this._createDefaultMaterials();
750 | this.callbacks = new THREE.LoaderSupport.Callbacks();
751 | };
752 |
753 | LoaderBase.prototype._createDefaultMaterials = function () {
754 | var defaultMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
755 | defaultMaterial.name = 'defaultMaterial';
756 |
757 | var vertexColorMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
758 | vertexColorMaterial.name = 'vertexColorMaterial';
759 | vertexColorMaterial.vertexColors = THREE.VertexColors;
760 |
761 | var runtimeMaterials = {};
762 | runtimeMaterials[ defaultMaterial.name ] = defaultMaterial;
763 | runtimeMaterials[ vertexColorMaterial.name ] = vertexColorMaterial;
764 |
765 | this.builder.updateMaterials(
766 | {
767 | cmd: 'materialData',
768 | materials: {
769 | materialCloneInstructions: null,
770 | serializedMaterials: null,
771 | runtimeMaterials: runtimeMaterials
772 | }
773 | }
774 | );
775 | };
776 |
777 | LoaderBase.prototype._applyPrepData = function ( prepData ) {
778 | if ( Validator.isValid( prepData ) ) {
779 |
780 | this.setModelName( prepData.modelName );
781 | this.setStreamMeshesTo( prepData.streamMeshesTo );
782 | this.builder.setMaterials( prepData.materials );
783 | this.setUseIndices( prepData.useIndices );
784 | this.setDisregardNormals( prepData.disregardNormals );
785 |
786 | this._setCallbacks( prepData.getCallbacks() );
787 | }
788 | };
789 |
790 | LoaderBase.prototype._setCallbacks = function ( callbacks ) {
791 | if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
792 | if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
793 | if ( Validator.isValid( callbacks.onLoad ) ) this.callbacks.setCallbackOnLoad( callbacks.onLoad );
794 | if ( Validator.isValid( callbacks.onLoadMaterials ) ) this.callbacks.setCallbackOnLoadMaterials( callbacks.onLoadMaterials );
795 |
796 | this.builder._setCallbacks( this.callbacks );
797 | };
798 |
799 | /**
800 | * Provides access to console logging wrapper.
801 | *
802 | * @returns {THREE.LoaderSupport.ConsoleLogger}
803 | */
804 | LoaderBase.prototype.getLogger = function () {
805 | return this.logger;
806 | };
807 |
808 | /**
809 | * Set the name of the model.
810 | * @memberOf THREE.LoaderSupport.LoaderBase
811 | *
812 | * @param {string} modelName
813 | */
814 | LoaderBase.prototype.setModelName = function ( modelName ) {
815 | this.modelName = Validator.verifyInput( modelName, this.modelName );
816 | };
817 |
818 | /**
819 | * The URL of the base path.
820 | * @memberOf THREE.LoaderSupport.LoaderBase
821 | *
822 | * @param {string} path URL
823 | */
824 | LoaderBase.prototype.setPath = function ( path ) {
825 | this.path = Validator.verifyInput( path, this.path );
826 | };
827 |
828 | /**
829 | * Set the node where the loaded objects will be attached directly.
830 | * @memberOf THREE.LoaderSupport.LoaderBase
831 | *
832 | * @param {THREE.Object3D} streamMeshesTo Object already attached to scenegraph where new meshes will be attached to
833 | */
834 | LoaderBase.prototype.setStreamMeshesTo = function ( streamMeshesTo ) {
835 | this.loaderRootNode = Validator.verifyInput( streamMeshesTo, this.loaderRootNode );
836 | };
837 |
838 | /**
839 | * Set materials loaded by MTLLoader or any other supplier of an Array of {@link THREE.Material}.
840 | * @memberOf THREE.LoaderSupport.LoaderBase
841 | *
842 | * @param {THREE.Material[]} materials Array of {@link THREE.Material}
843 | */
844 | LoaderBase.prototype.setMaterials = function ( materials ) {
845 | this.builder.setMaterials( materials );
846 | };
847 |
848 | /**
849 | * Instructs loaders to create indexed {@link THREE.BufferGeometry}.
850 | * @memberOf THREE.LoaderSupport.LoaderBase
851 | *
852 | * @param {boolean} useIndices=false
853 | */
854 | LoaderBase.prototype.setUseIndices = function ( useIndices ) {
855 | this.useIndices = useIndices === true;
856 | };
857 |
858 | /**
859 | * Tells whether normals should be completely disregarded and regenerated.
860 | * @memberOf THREE.LoaderSupport.LoaderBase
861 | *
862 | * @param {boolean} disregardNormals=false
863 | */
864 | LoaderBase.prototype.setDisregardNormals = function ( disregardNormals ) {
865 | this.disregardNormals = disregardNormals === true;
866 | };
867 |
868 | /**
869 | * Announce feedback which is give to the registered callbacks.
870 | * @memberOf THREE.LoaderSupport.LoaderBase
871 | * @private
872 | *
873 | * @param {string} type The type of event
874 | * @param {string} text Textual description of the event
875 | * @param {number} numericalValue Numerical value describing the progress
876 | */
877 | LoaderBase.prototype.onProgress = function ( type, text, numericalValue ) {
878 | var content = Validator.isValid( text ) ? text: '';
879 | var event = {
880 | detail: {
881 | type: type,
882 | modelName: this.modelName,
883 | instanceNo: this.instanceNo,
884 | text: content,
885 | numericalValue: numericalValue
886 | }
887 | };
888 |
889 | if ( Validator.isValid( this.callbacks.onProgress ) ) this.callbacks.onProgress( event );
890 |
891 | this.logger.logDebug( content );
892 | };
893 |
894 | return LoaderBase;
895 | })();
896 |
897 | /**
898 | * Default implementation of the WorkerRunner responsible for creation and configuration of the parser within the worker.
899 | *
900 | * @class
901 | */
902 | THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
903 |
904 | function WorkerRunnerRefImpl() {
905 | var scope = this;
906 | var scopedRunner = function( event ) {
907 | scope.processMessage( event.data );
908 | };
909 | self.addEventListener( 'message', scopedRunner, false );
910 | }
911 |
912 | /**
913 | * Applies values from parameter object via set functions or via direct assignment.
914 | * @memberOf THREE.LoaderSupport.WorkerRunnerRefImpl
915 | *
916 | * @param {Object} parser The parser instance
917 | * @param {Object} params The parameter object
918 | */
919 | WorkerRunnerRefImpl.prototype.applyProperties = function ( parser, params ) {
920 | var property, funcName, values;
921 | for ( property in params ) {
922 | funcName = 'set' + property.substring( 0, 1 ).toLocaleUpperCase() + property.substring( 1 );
923 | values = params[ property ];
924 |
925 | if ( typeof parser[ funcName ] === 'function' ) {
926 |
927 | parser[ funcName ]( values );
928 |
929 | } else if ( parser.hasOwnProperty( property ) ) {
930 |
931 | parser[ property ] = values;
932 |
933 | }
934 | }
935 | };
936 |
937 | /**
938 | * Configures the Parser implementation according the supplied configuration object.
939 | * @memberOf THREE.LoaderSupport.WorkerRunnerRefImpl
940 | *
941 | * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes.
942 | */
943 | WorkerRunnerRefImpl.prototype.processMessage = function ( payload ) {
944 | var logEnabled = payload.logger.enabled;
945 | var logDebug = payload.logger.enabled;
946 | if ( payload.cmd === 'run' ) {
947 |
948 | var callbacks = {
949 | callbackBuilder: function ( payload ) {
950 | self.postMessage( payload );
951 | },
952 | callbackProgress: function ( text ) {
953 | if ( logEnabled && logDebug ) console.debug( 'WorkerRunner: progress: ' + text );
954 | }
955 | };
956 |
957 | // Parser is expected to be named as such
958 | var parser = new Parser();
959 | if ( typeof parser[ 'setLogConfig' ] === 'function' ) parser.setLogConfig( logEnabled, logDebug );
960 | this.applyProperties( parser, payload.params );
961 | this.applyProperties( parser, payload.materials );
962 | this.applyProperties( parser, callbacks );
963 | parser.workerScope = self;
964 | parser.parse( payload.data.input, payload.data.options );
965 |
966 | if ( logEnabled ) console.log( 'WorkerRunner: Run complete!' );
967 |
968 | callbacks.callbackBuilder( {
969 | cmd: 'complete',
970 | msg: 'WorkerRunner completed run.'
971 | } );
972 |
973 | } else {
974 |
975 | console.error( 'WorkerRunner: Received unknown command: ' + payload.cmd );
976 |
977 | }
978 | };
979 |
980 | return WorkerRunnerRefImpl;
981 | })();
982 |
983 | /**
984 | * This class provides means to transform existing parser code into a web worker. It defines a simple communication protocol
985 | * which allows to configure the worker and receive raw mesh data during execution.
986 | * @class
987 | *
988 | * @param {THREE.LoaderSupport.ConsoleLogger} logger logger to be used
989 | */
990 | THREE.LoaderSupport.WorkerSupport = (function () {
991 |
992 | var WORKER_SUPPORT_VERSION = '2.0.1';
993 |
994 | var Validator = THREE.LoaderSupport.Validator;
995 |
996 | var LoaderWorker = (function () {
997 |
998 | function LoaderWorker( logger ) {
999 | this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
1000 | this._reset();
1001 | }
1002 |
1003 | LoaderWorker.prototype._reset = function () {
1004 | this.worker = null;
1005 | this.runnerImplName = null;
1006 | this.callbacks = {
1007 | builder: null,
1008 | onLoad: null
1009 | };
1010 | this.terminateRequested = false;
1011 | this.queuedMessage = null;
1012 | this.started = false;
1013 | };
1014 |
1015 | LoaderWorker.prototype.initWorker = function ( code, runnerImplName ) {
1016 | this.runnerImplName = runnerImplName;
1017 | var blob = new Blob( [ code ], { type: 'application/javascript' } );
1018 | this.worker = new Worker( window.URL.createObjectURL( blob ) );
1019 | this.worker.onmessage = this._receiveWorkerMessage;
1020 |
1021 | // set referemce to this, then processing in worker scope within "_receiveWorkerMessage" can access members
1022 | this.worker.runtimeRef = this;
1023 |
1024 | // process stored queuedMessage
1025 | this._postMessage();
1026 | };
1027 |
1028 | /**
1029 | * Executed in worker scope
1030 | */
1031 | LoaderWorker.prototype._receiveWorkerMessage = function ( e ) {
1032 | var payload = e.data;
1033 | switch ( payload.cmd ) {
1034 | case 'meshData':
1035 | case 'materialData':
1036 | case 'imageData':
1037 | this.runtimeRef.callbacks.builder( payload );
1038 | break;
1039 |
1040 | case 'complete':
1041 | this.runtimeRef.queuedMessage = null;
1042 | this.started = false;
1043 | this.runtimeRef.callbacks.onLoad( payload.msg );
1044 |
1045 | if ( this.runtimeRef.terminateRequested ) {
1046 |
1047 | this.runtimeRef.logger.logInfo( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Run is complete. Terminating application on request!' );
1048 | this.runtimeRef._terminate();
1049 |
1050 | }
1051 | break;
1052 |
1053 | case 'error':
1054 | this.runtimeRef.logger.logError( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Reported error: ' + payload.msg );
1055 | this.runtimeRef.queuedMessage = null;
1056 | this.started = false;
1057 | this.runtimeRef.callbacks.onLoad( payload.msg );
1058 |
1059 | if ( this.runtimeRef.terminateRequested ) {
1060 |
1061 | this.runtimeRef.logger.logInfo( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Run reported error. Terminating application on request!' );
1062 | this.runtimeRef._terminate();
1063 |
1064 | }
1065 | break;
1066 |
1067 | default:
1068 | this.runtimeRef.logger.logError( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Received unknown command: ' + payload.cmd );
1069 | break;
1070 |
1071 | }
1072 | };
1073 |
1074 | LoaderWorker.prototype.setCallbacks = function ( builder, onLoad ) {
1075 | this.callbacks.builder = Validator.verifyInput( builder, this.callbacks.builder );
1076 | this.callbacks.onLoad = Validator.verifyInput( onLoad, this.callbacks.onLoad );
1077 | };
1078 |
1079 | LoaderWorker.prototype.run = function( payload ) {
1080 | if ( Validator.isValid( this.queuedMessage ) ) {
1081 |
1082 | console.warn( 'Already processing message. Rejecting new run instruction' );
1083 | return;
1084 |
1085 | } else {
1086 |
1087 | this.queuedMessage = payload;
1088 | this.started = true;
1089 |
1090 | }
1091 | if ( ! Validator.isValid( this.callbacks.builder ) ) throw 'Unable to run as no "builder" callback is set.';
1092 | if ( ! Validator.isValid( this.callbacks.onLoad ) ) throw 'Unable to run as no "onLoad" callback is set.';
1093 | if ( payload.cmd !== 'run' ) payload.cmd = 'run';
1094 | if ( Validator.isValid( payload.logger ) ) {
1095 |
1096 | payload.logger.enabled = Validator.verifyInput( payload.logger.enabled, true );
1097 | payload.logger.debug = Validator.verifyInput( payload.logger.debug, false );
1098 |
1099 | } else {
1100 |
1101 | payload.logger = {
1102 | enabled: true,
1103 | debug: false
1104 | }
1105 |
1106 | }
1107 | this._postMessage();
1108 | };
1109 |
1110 | LoaderWorker.prototype._postMessage = function () {
1111 | if ( Validator.isValid( this.queuedMessage ) && Validator.isValid( this.worker ) ) {
1112 |
1113 | if ( this.queuedMessage.data.input instanceof ArrayBuffer ) {
1114 |
1115 | this.worker.postMessage( this.queuedMessage, [ this.queuedMessage.data.input ] );
1116 |
1117 | } else {
1118 |
1119 | this.worker.postMessage( this.queuedMessage );
1120 |
1121 | }
1122 |
1123 | }
1124 | };
1125 |
1126 | LoaderWorker.prototype.setTerminateRequested = function ( terminateRequested ) {
1127 | this.terminateRequested = terminateRequested === true;
1128 | if ( this.terminateRequested && Validator.isValid( this.worker ) && ! Validator.isValid( this.queuedMessage ) && this.started ) {
1129 |
1130 | this.logger.logInfo( 'Worker is terminated immediately as it is not running!' );
1131 | this._terminate();
1132 |
1133 | }
1134 | };
1135 |
1136 | LoaderWorker.prototype._terminate = function () {
1137 | this.worker.terminate();
1138 | this._reset();
1139 | };
1140 |
1141 | return LoaderWorker;
1142 |
1143 | })();
1144 |
1145 | function WorkerSupport( logger ) {
1146 | this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
1147 | this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerSupport version: ' + WORKER_SUPPORT_VERSION );
1148 |
1149 | // check worker support first
1150 | if ( window.Worker === undefined ) throw "This browser does not support web workers!";
1151 | if ( window.Blob === undefined ) throw "This browser does not support Blob!";
1152 | if ( typeof window.URL.createObjectURL !== 'function' ) throw "This browser does not support Object creation from URL!";
1153 |
1154 | this.loaderWorker = new LoaderWorker( this.logger );
1155 | }
1156 |
1157 | /**
1158 | * Validate the status of worker code and the derived worker.
1159 | * @memberOf THREE.LoaderSupport.WorkerSupport
1160 | *
1161 | * @param {Function} functionCodeBuilder Function that is invoked with funcBuildObject and funcBuildSingelton that allows stringification of objects and singletons.
1162 | * @param {String[]} libLocations URL of libraries that shall be added to worker code relative to libPath
1163 | * @param {String} libPath Base path used for loading libraries
1164 | * @param {THREE.LoaderSupport.WorkerRunnerRefImpl} runnerImpl The default worker parser wrapper implementation (communication and execution). An extended class could be passed here.
1165 | */
1166 | WorkerSupport.prototype.validate = function ( functionCodeBuilder, libLocations, libPath, runnerImpl ) {
1167 | if ( Validator.isValid( this.loaderWorker.worker ) ) return;
1168 |
1169 | this.logger.logInfo( 'WorkerSupport: Building worker code...' );
1170 | this.logger.logTimeStart( 'buildWebWorkerCode' );
1171 |
1172 | if ( Validator.isValid( runnerImpl ) ) {
1173 |
1174 | this.logger.logInfo( 'WorkerSupport: Using "' + runnerImpl.name + '" as Runncer class for worker.' );
1175 |
1176 | } else {
1177 |
1178 | runnerImpl = THREE.LoaderSupport.WorkerRunnerRefImpl;
1179 | this.logger.logInfo( 'WorkerSupport: Using DEFAULT "THREE.LoaderSupport.WorkerRunnerRefImpl" as Runncer class for worker.' );
1180 |
1181 | }
1182 |
1183 | var userWorkerCode = functionCodeBuilder( buildObject, buildSingelton );
1184 | userWorkerCode += buildSingelton( runnerImpl.name, runnerImpl.name, runnerImpl );
1185 | userWorkerCode += 'new ' + runnerImpl.name + '();\n\n';
1186 |
1187 | var scope = this;
1188 | if ( Validator.isValid( libLocations ) && libLocations.length > 0 ) {
1189 |
1190 | var libsContent = '';
1191 | var loadAllLibraries = function ( path, locations ) {
1192 | if ( locations.length === 0 ) {
1193 |
1194 | scope.loaderWorker.initWorker( libsContent + userWorkerCode, scope.logger, runnerImpl.name );
1195 | scope.logger.logTimeEnd( 'buildWebWorkerCode' );
1196 |
1197 | } else {
1198 |
1199 | var loadedLib = function ( contentAsString ) {
1200 | libsContent += contentAsString;
1201 | loadAllLibraries( path, locations );
1202 | };
1203 |
1204 | var fileLoader = new THREE.FileLoader();
1205 | fileLoader.setPath( path );
1206 | fileLoader.setResponseType( 'text' );
1207 | fileLoader.load( locations[ 0 ], loadedLib );
1208 | locations.shift();
1209 |
1210 | }
1211 | };
1212 | loadAllLibraries( libPath, libLocations );
1213 |
1214 | } else {
1215 |
1216 | this.loaderWorker.initWorker( userWorkerCode, this.logger, runnerImpl.name );
1217 | this.logger.logTimeEnd( 'buildWebWorkerCode' );
1218 |
1219 | }
1220 | };
1221 |
1222 | /**
1223 | * Specify functions that should be build when new raw mesh data becomes available and when the parser is finished.
1224 | * @memberOf THREE.LoaderSupport.WorkerSupport
1225 | *
1226 | * @param {Function} builder The builder function. Default is {@link THREE.LoaderSupport.Builder}.
1227 | * @param {Function} onLoad The function that is called when parsing is complete.
1228 | */
1229 | WorkerSupport.prototype.setCallbacks = function ( builder, onLoad ) {
1230 | this.loaderWorker.setCallbacks( builder, onLoad );
1231 | };
1232 |
1233 | /**
1234 | * Runs the parser with the provided configuration.
1235 | * @memberOf THREE.LoaderSupport.WorkerSupport
1236 | *
1237 | * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes.
1238 | */
1239 | WorkerSupport.prototype.run = function ( payload ) {
1240 | this.loaderWorker.run( payload );
1241 | };
1242 |
1243 | /**
1244 | * Request termination of worker once parser is finished.
1245 | * @memberOf THREE.LoaderSupport.WorkerSupport
1246 | *
1247 | * @param {boolean} terminateRequested True or false.
1248 | */
1249 | WorkerSupport.prototype.setTerminateRequested = function ( terminateRequested ) {
1250 | this.loaderWorker.setTerminateRequested( terminateRequested );
1251 | };
1252 |
1253 | var buildObject = function ( fullName, object ) {
1254 | var objectString = fullName + ' = {\n';
1255 | var part;
1256 | for ( var name in object ) {
1257 |
1258 | part = object[ name ];
1259 | if ( typeof( part ) === 'string' || part instanceof String ) {
1260 |
1261 | part = part.replace( '\n', '\\n' );
1262 | part = part.replace( '\r', '\\r' );
1263 | objectString += '\t' + name + ': "' + part + '",\n';
1264 |
1265 | } else if ( part instanceof Array ) {
1266 |
1267 | objectString += '\t' + name + ': [' + part + '],\n';
1268 |
1269 | } else if ( Number.isInteger( part ) ) {
1270 |
1271 | objectString += '\t' + name + ': ' + part + ',\n';
1272 |
1273 | } else if ( typeof part === 'function' ) {
1274 |
1275 | objectString += '\t' + name + ': ' + part + ',\n';
1276 |
1277 | }
1278 |
1279 | }
1280 | objectString += '}\n\n';
1281 |
1282 | return objectString;
1283 | };
1284 |
1285 | var buildSingelton = function ( fullName, internalName, object ) {
1286 | var objectString = fullName + ' = (function () {\n\n';
1287 | objectString += '\t' + object.prototype.constructor.toString() + '\n\n';
1288 | objectString = objectString.replace( object.name, internalName );
1289 |
1290 | var funcString;
1291 | var objectPart;
1292 | for ( var name in object.prototype ) {
1293 |
1294 | objectPart = object.prototype[ name ];
1295 | if ( typeof objectPart === 'function' ) {
1296 |
1297 | funcString = objectPart.toString();
1298 | objectString += '\t' + internalName + '.prototype.' + name + ' = ' + funcString + ';\n\n';
1299 |
1300 | }
1301 |
1302 | }
1303 | objectString += '\treturn ' + internalName + ';\n';
1304 | objectString += '})();\n\n';
1305 |
1306 | return objectString;
1307 | };
1308 |
1309 | return WorkerSupport;
1310 |
1311 | })();
1312 |
1313 | /**
1314 | * Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).
1315 | * Workflow:
1316 | * prepareWorkers
1317 | * enqueueForRun
1318 | * processQueue
1319 | * tearDown (to force stop)
1320 | *
1321 | * @class
1322 | *
1323 | * @param {string} classDef Class definition to be used for construction
1324 | * @param {THREE.LoaderSupport.ConsoleLogger} logger logger to be used
1325 | */
1326 | THREE.LoaderSupport.WorkerDirector = (function () {
1327 |
1328 | var LOADER_WORKER_DIRECTOR_VERSION = '2.1.0';
1329 |
1330 | var Validator = THREE.LoaderSupport.Validator;
1331 |
1332 | var MAX_WEB_WORKER = 16;
1333 | var MAX_QUEUE_SIZE = 8192;
1334 |
1335 | function WorkerDirector( classDef, logger ) {
1336 | this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
1337 | this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerDirector version: ' + LOADER_WORKER_DIRECTOR_VERSION );
1338 |
1339 | this.maxQueueSize = MAX_QUEUE_SIZE ;
1340 | this.maxWebWorkers = MAX_WEB_WORKER;
1341 | this.crossOrigin = null;
1342 |
1343 | if ( ! Validator.isValid( classDef ) ) throw 'Provided invalid classDef: ' + classDef;
1344 |
1345 | this.workerDescription = {
1346 | classDef: classDef,
1347 | globalCallbacks: {},
1348 | workerSupports: {}
1349 | };
1350 | this.objectsCompleted = 0;
1351 | this.instructionQueue = [];
1352 | this.instructionQueuePointer = 0;
1353 |
1354 | this.callbackOnFinishedProcessing = null;
1355 | }
1356 |
1357 | /**
1358 | * Returns the maximum length of the instruction queue.
1359 | * @memberOf THREE.LoaderSupport.WorkerDirector
1360 | *
1361 | * @returns {number}
1362 | */
1363 | WorkerDirector.prototype.getMaxQueueSize = function () {
1364 | return this.maxQueueSize;
1365 | };
1366 |
1367 | /**
1368 | * Returns the maximum number of workers.
1369 | * @memberOf THREE.LoaderSupport.WorkerDirector
1370 | *
1371 | * @returns {number}
1372 | */
1373 | WorkerDirector.prototype.getMaxWebWorkers = function () {
1374 | return this.maxWebWorkers;
1375 | };
1376 |
1377 | /**
1378 | * Sets the CORS string to be used.
1379 | * @memberOf THREE.LoaderSupport.WorkerDirector
1380 | *
1381 | * @param {string} crossOrigin CORS value
1382 | */
1383 | WorkerDirector.prototype.setCrossOrigin = function ( crossOrigin ) {
1384 | this.crossOrigin = crossOrigin;
1385 | };
1386 |
1387 | /**
1388 | * Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
1389 | * @memberOf THREE.LoaderSupport.WorkerDirector
1390 | *
1391 | * @param {THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks} globalCallbacks Register global callbacks used by all web workers
1392 | * @param {number} maxQueueSize Set the maximum size of the instruction queue (1-1024)
1393 | * @param {number} maxWebWorkers Set the maximum amount of workers (1-16)
1394 | */
1395 | WorkerDirector.prototype.prepareWorkers = function ( globalCallbacks, maxQueueSize, maxWebWorkers ) {
1396 | if ( Validator.isValid( globalCallbacks ) ) this.workerDescription.globalCallbacks = globalCallbacks;
1397 | this.maxQueueSize = Math.min( maxQueueSize, MAX_QUEUE_SIZE );
1398 | this.maxWebWorkers = Math.min( maxWebWorkers, MAX_WEB_WORKER );
1399 | this.maxWebWorkers = Math.min( this.maxWebWorkers, this.maxQueueSize );
1400 | this.objectsCompleted = 0;
1401 | this.instructionQueue = [];
1402 | this.instructionQueuePointer = 0;
1403 |
1404 | for ( var instanceNo = 0; instanceNo < this.maxWebWorkers; instanceNo++ ) {
1405 |
1406 | this.workerDescription.workerSupports[ instanceNo ] = {
1407 | instanceNo: instanceNo,
1408 | inUse: false,
1409 | terminateRequested: false,
1410 | workerSupport: new THREE.LoaderSupport.WorkerSupport( this.logger ),
1411 | loader: null
1412 | };
1413 |
1414 | }
1415 | };
1416 |
1417 | /**
1418 | * Store run instructions in internal instructionQueue.
1419 | * @memberOf THREE.LoaderSupport.WorkerDirector
1420 | *
1421 | * @param {THREE.LoaderSupport.PrepData} prepData
1422 | */
1423 | WorkerDirector.prototype.enqueueForRun = function ( prepData ) {
1424 | if ( this.instructionQueue.length < this.maxQueueSize ) {
1425 | this.instructionQueue.push( prepData );
1426 | }
1427 | };
1428 |
1429 | /**
1430 | * Returns if any workers are running.
1431 | *
1432 | * @memberOf THREE.LoaderSupport.WorkerDirector
1433 | * @returns {boolean}
1434 | */
1435 | WorkerDirector.prototype.isRunning = function () {
1436 | var wsKeys = Object.keys( this.workerDescription.workerSupports );
1437 | return ( ( this.instructionQueue.length > 0 && this.instructionQueuePointer < this.instructionQueue.length ) || wsKeys.length > 0 );
1438 | };
1439 |
1440 | /**
1441 | * Process the instructionQueue until it is depleted.
1442 | * @memberOf THREE.LoaderSupport.WorkerDirector
1443 | */
1444 | WorkerDirector.prototype.processQueue = function () {
1445 | var prepData, supportDesc;
1446 | for ( var instanceNo in this.workerDescription.workerSupports ) {
1447 |
1448 | supportDesc = this.workerDescription.workerSupports[ instanceNo ];
1449 | if ( ! supportDesc.inUse ) {
1450 |
1451 | if ( this.instructionQueuePointer < this.instructionQueue.length ) {
1452 |
1453 | prepData = this.instructionQueue[ this.instructionQueuePointer ];
1454 | this._kickWorkerRun( prepData, supportDesc );
1455 | this.instructionQueuePointer++;
1456 |
1457 | } else {
1458 |
1459 | this._deregister( supportDesc );
1460 |
1461 | }
1462 |
1463 | }
1464 |
1465 | }
1466 |
1467 | if ( ! this.isRunning() && this.callbackOnFinishedProcessing !== null ) {
1468 |
1469 | this.callbackOnFinishedProcessing();
1470 | this.callbackOnFinishedProcessing = null;
1471 |
1472 | }
1473 | };
1474 |
1475 | WorkerDirector.prototype._kickWorkerRun = function( prepData, supportDesc ) {
1476 | supportDesc.inUse = true;
1477 | supportDesc.workerSupport.setTerminateRequested( supportDesc.terminateRequested );
1478 |
1479 | this.logger.logInfo( '\nAssigning next item from queue to worker (queue length: ' + this.instructionQueue.length + ')\n\n' );
1480 |
1481 | var scope = this;
1482 | var prepDataCallbacks = prepData.getCallbacks();
1483 | var globalCallbacks = this.workerDescription.globalCallbacks;
1484 | var wrapperOnLoad = function ( event ) {
1485 | if ( Validator.isValid( globalCallbacks.onLoad ) ) globalCallbacks.onLoad( event );
1486 | if ( Validator.isValid( prepDataCallbacks.onLoad ) ) prepDataCallbacks.onLoad( event );
1487 | scope.objectsCompleted++;
1488 | supportDesc.inUse = false;
1489 |
1490 | scope.processQueue();
1491 | };
1492 |
1493 | var wrapperOnProgress = function ( event ) {
1494 | if ( Validator.isValid( globalCallbacks.onProgress ) ) globalCallbacks.onProgress( event );
1495 | if ( Validator.isValid( prepDataCallbacks.onProgress ) ) prepDataCallbacks.onProgress( event );
1496 | };
1497 |
1498 | var wrapperOnMeshAlter = function ( event ) {
1499 | if ( Validator.isValid( globalCallbacks.onMeshAlter ) ) globalCallbacks.onMeshAlter( event );
1500 | if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) prepDataCallbacks.onMeshAlter( event );
1501 | };
1502 |
1503 | supportDesc.loader = this._buildLoader( supportDesc.instanceNo );
1504 |
1505 | var updatedCallbacks = new THREE.LoaderSupport.Callbacks();
1506 | updatedCallbacks.setCallbackOnLoad( wrapperOnLoad );
1507 | updatedCallbacks.setCallbackOnProgress( wrapperOnProgress );
1508 | updatedCallbacks.setCallbackOnMeshAlter( wrapperOnMeshAlter );
1509 | prepData.callbacks = updatedCallbacks;
1510 |
1511 | supportDesc.loader.run( prepData, supportDesc.workerSupport );
1512 | };
1513 |
1514 | WorkerDirector.prototype._buildLoader = function ( instanceNo ) {
1515 | var classDef = this.workerDescription.classDef;
1516 | var loader = Object.create( classDef.prototype );
1517 | this.workerDescription.classDef.call( loader, THREE.DefaultLoadingManager, this.logger );
1518 |
1519 | // verify that all required functions are implemented
1520 | if ( ! loader.hasOwnProperty( 'instanceNo' ) ) throw classDef.name + ' has no property "instanceNo".';
1521 | loader.instanceNo = instanceNo;
1522 |
1523 | if ( ! loader.hasOwnProperty( 'workerSupport' ) ) {
1524 |
1525 | throw classDef.name + ' has no property "workerSupport".';
1526 |
1527 | }
1528 | if ( typeof loader.run !== 'function' ) throw classDef.name + ' has no function "run".';
1529 | if ( ! loader.hasOwnProperty( 'callbacks' ) || ! Validator.isValid( loader.callbacks ) ) {
1530 |
1531 | this.logger.logWarn( classDef.name + ' has an invalid property "callbacks". Will change to "THREE.LoaderSupport.Callbacks"' );
1532 | loader.callbacks = new THREE.LoaderSupport.Callbacks();
1533 |
1534 | }
1535 | return loader;
1536 | };
1537 |
1538 | WorkerDirector.prototype._deregister = function ( supportDesc ) {
1539 | if ( Validator.isValid( supportDesc ) ) {
1540 |
1541 | supportDesc.workerSupport.setTerminateRequested( true );
1542 | this.logger.logInfo( 'Requested termination of worker #' + supportDesc.instanceNo + '.' );
1543 |
1544 | var loaderCallbacks = supportDesc.loader.callbacks;
1545 | if ( Validator.isValid( loaderCallbacks.onProgress ) ) loaderCallbacks.onProgress( { detail: { text: '' } } );
1546 | delete this.workerDescription.workerSupports[ supportDesc.instanceNo ];
1547 |
1548 | }
1549 | };
1550 |
1551 | /**
1552 | * Terminate all workers.
1553 | * @memberOf THREE.LoaderSupport.WorkerDirector
1554 | *
1555 | * @param {callback} callbackOnFinishedProcessing Function called once all workers finished processing.
1556 | */
1557 | WorkerDirector.prototype.tearDown = function ( callbackOnFinishedProcessing ) {
1558 | this.logger.logInfo( 'WorkerDirector received the deregister call. Terminating all workers!' );
1559 |
1560 | this.instructionQueuePointer = this.instructionQueue.length;
1561 | this.callbackOnFinishedProcessing = Validator.verifyInput( callbackOnFinishedProcessing, null );
1562 |
1563 | for ( var name in this.workerDescription.workerSupports ) {
1564 |
1565 | this.workerDescription.workerSupports[ name ].terminateRequested = true;
1566 |
1567 | }
1568 | };
1569 |
1570 | return WorkerDirector;
1571 |
1572 | })();
1573 |
--------------------------------------------------------------------------------