@@ -4,7 +4,10 @@ import {
44 parseJSON ,
55 isArrayHasData ,
66 pushIn ,
7- isNumber
7+ isNumber ,
8+ extend ,
9+ getAbsoluteURL ,
10+ GUID
811} from '../core/util' ;
912import Marker from './Marker' ;
1013import LineString from './LineString' ;
@@ -17,6 +20,8 @@ import Geometry from './Geometry';
1720import { GEOJSON_TYPES } from '../core/Constants' ;
1821import PromisePolyfill from './../core/Promise' ;
1922import { runTaskAsync } from '../core/MicroTask' ;
23+ import Actor from '../core/worker/Actor' ;
24+ import { registerWorkerAdapter } from '../core/worker/Worker' ;
2025
2126const types = {
2227 'Marker' : Marker ,
@@ -27,6 +32,106 @@ const types = {
2732 'MultiPolygon' : MultiPolygon
2833} ;
2934
35+ const WORKER_KEY = 'geojson-fetch-worker-page-async' ;
36+ const WORKER_CODE = `
37+ function (exports) {
38+ const resultMap = {};
39+
40+ function handleResult(msg, postResponse) {
41+ const data = msg.data || {};
42+ const { taskId } = data;
43+ const features = resultMap[taskId];
44+ if (!features) {
45+ postResponse('not find geojson dataset the taskId:' + taskId);
46+ return;
47+ }
48+ if (features.length === 0) {
49+ delete resultMap[taskId];
50+ postResponse(null, []);
51+ return;
52+ }
53+ const pageSize = data.pageSize || 2000;
54+ const pageFeatures = features.slice(0, pageSize);
55+ resultMap[taskId] = features.slice(pageSize, Infinity);
56+ postResponse(null, pageFeatures);
57+ }
58+ //worker init
59+ exports.initialize = function () {
60+ // console.log("geojson fetch init");
61+ };
62+ //recive message
63+ exports.onmessage = function (msg, postResponse) {
64+ const { taskId, type, url } = msg.data || {};
65+ if (!taskId) {
66+ postResponse('not find task id for get geojson dataset,taskId=' + taskId);
67+ return;
68+ }
69+ if (type === 'fetchdata') {
70+ if (!url) {
71+ postResponse('url is null,url=' + url);
72+ return;
73+ }
74+ fetch(url).then(res => res.json()).then(geojson => {
75+ let features;
76+ if (Array.isArray(geojson)) {
77+ features = geojson;
78+ } else if (geojson.features) {
79+ features = geojson.features;
80+ } else {
81+ features = [geojson];
82+ }
83+ resultMap[taskId] = features;
84+ handleResult(msg, postResponse);
85+ }).catch(errror => {
86+ postResponse(errror.message);
87+ });
88+ } else if (type === 'pagefeatures') {
89+ handleResult(msg, postResponse);
90+ } else {
91+ postResponse('not support task type:' + type);
92+ }
93+ };
94+ }` ;
95+
96+ class GeoJSONFetchActor extends Actor {
97+
98+ constructor ( ) {
99+ super ( WORKER_KEY ) ;
100+ }
101+
102+ _sendMsg ( options , featuresList , cb ) {
103+ this . send ( options , [ ] , ( error , data ) => {
104+ if ( error ) {
105+ cb ( error ) ;
106+ } else {
107+ this . _pageFeatures ( options , data , featuresList , cb ) ;
108+ }
109+ } , options . workerId ) ;
110+ }
111+
112+ _fetchGeoJSON ( url , options , featuresList = [ ] , cb ) {
113+ const opts = extend ( { } , options ) ;
114+ opts . type = 'fetchdata' ;
115+ opts . url = url ;
116+ this . _sendMsg ( opts , featuresList , cb ) ;
117+ }
118+
119+ _pageFeatures ( options , features , featuresList , cb ) {
120+ featuresList . push ( features ) ;
121+ if ( features . length === 0 ) {
122+ cb ( null , featuresList ) ;
123+ return ;
124+ }
125+ const opts = extend ( { } , options ) ;
126+ opts . type = 'pagefeatures' ;
127+ this . _sendMsg ( opts , featuresList , cb ) ;
128+ }
129+ }
130+
131+ registerWorkerAdapter ( WORKER_KEY , function ( ) { return WORKER_CODE ; } ) ;
132+
133+ let fetchActor ;
134+
30135/**
31136 * GeoJSON utilities
32137 * @class
@@ -255,6 +360,50 @@ const GeoJSON = {
255360 }
256361 return false ;
257362
363+ } ,
364+ /**
365+ * Requesting a large volume geojson file.Solve the problem of main thread blocking
366+ * @param {String } url - GeoJSON file path
367+ * @param {Number } [countPerTime=2000] - Number of graphics converted per time
368+ * @return {Promise }
369+ * @example
370+ * GeoJSON.fetch('https://abc.com/file.geojson',2000).then(geojson=>{
371+ * console.log(geojson);
372+ * })
373+ * */
374+ fetch ( url , countPerTime = 2000 ) {
375+ return new PromisePolyfill ( ( resolve , reject ) => {
376+ if ( ! url || ! isString ( url ) ) {
377+ reject ( 'url is error,It should be string' ) ;
378+ return ;
379+ }
380+ const options = extend ( { pageSize : 2000 } , { pageSize : countPerTime } ) ;
381+ url = getAbsoluteURL ( url ) ;
382+ if ( ! fetchActor ) {
383+ fetchActor = new GeoJSONFetchActor ( ) ;
384+ }
385+ const workerCount = fetchActor . workers . length ;
386+ let workerId = Math . floor ( Math . random ( ) * workerCount ) ;
387+ workerId = Math . min ( workerCount - 1 , workerId ) ;
388+ options . workerId = workerId ;
389+ options . taskId = GUID ( ) ;
390+ fetchActor . _fetchGeoJSON ( url , options , [ ] , ( error , featuresList ) => {
391+ if ( error ) {
392+ reject ( error ) ;
393+ return ;
394+ }
395+ const result = [ ] ;
396+ featuresList . forEach ( features => {
397+ for ( let i = 0 , len = features . length ; i < len ; i ++ ) {
398+ result . push ( features [ i ] ) ;
399+ }
400+ } ) ;
401+ resolve ( {
402+ type : 'FeatureCollection' ,
403+ features : result
404+ } ) ;
405+ } ) ;
406+ } ) ;
258407 }
259408} ;
260409
0 commit comments