Skip to content

Commit 6bed9a4

Browse files
authored
feat: VT tile data support gzip decode (#2779)
* feat:VT tile data support gzip decode by 'needDecodeGZip' * UPDATE * updates * updates * updates * updates * update spec * auto Identify gzip * updates * updates * updates * updates
1 parent fead83c commit 6bed9a4

File tree

4 files changed

+90
-18
lines changed

4 files changed

+90
-18
lines changed

packages/maptalks/test/profile/ProfileSpec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ describe('Map.Profile', function () {
200200
expect(profile.layers[1]).to.be.eql(vectorLayer2.toJSON());
201201
});
202202

203-
it('get map from various profile', function () {
203+
it.skip('get map from various profile', function () {
204204
map.setBaseLayer(tile);
205205
var tile2 = new maptalks.TileLayer('road', {
206206
urlTemplate:'#',

packages/vt/src/layer/layer/VectorTileLayer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const defaultOptions: VectorTileLayerOptionsType = {
3838
forceRenderOnMoving: true,
3939
forceRenderOnRotating: true,
4040
tileSize: [512, 512],
41-
// features: false,
41+
features: true,//always open features
4242
schema: false,
4343
cascadeTiles: true,
4444
collision: true,
@@ -1992,7 +1992,7 @@ function checkStyleExist(styles, idx) {
19921992
export type VectorTileLayerOptionsType = {
19931993
renderer?: "gl",
19941994
altitudeProperty?: string,
1995-
// features?: boolean,
1995+
features?: boolean,
19961996
schema?: boolean,
19971997
collision?: boolean,
19981998
collisionBuffserSize?: number,
@@ -2038,7 +2038,7 @@ export type VectorTileLayerOptionsType = {
20382038
loadTileErrorLog?: boolean,
20392039
loadTileErrorLogIgnoreCodes?: Array<number>;
20402040
loadTileCachMaxSize?: number;//unit is MB
2041-
loadTileCacheLog?: boolean,
2041+
loadTileCacheLog?: boolean;
20422042

20432043
renderBeforeTerrain?: boolean,
20442044
} & TileLayerOptionsType;

packages/vt/src/worker/layer/VectorTileLayerWorker.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Ajax from '../util/Ajax';
55
import { isNil, hasOwn, isString } from '../../common/Util';
66
import { PROP_OMBB } from '../../common/Constant';
77
import { projectOMBB } from '../builder/Ombb.js';
8-
import { calArrayBufferSize, isNumber } from '../util/index';
8+
import { calArrayBufferSize, isNumber, arraybufferIsGZip, decompressGzipWithBlob } from '../util/index';
99

1010
const ALTITUDE_ERRORS = {
1111
'MISSING_ALTITUDE_ELEMENT': 2,
@@ -50,33 +50,59 @@ export default class VectorTileLayerWorker extends LayerWorker {
5050
}
5151
fetchOptions.referrer = context.referrer;
5252
fetchOptions.errorLog = context.loadTileErrorLog;
53-
const { loadTileCachMaxSize, loadTileCacheLog, } = context;
53+
const { loadTileCachMaxSize, loadTileCacheLog } = context;
54+
5455
return Ajax.getArrayBuffer(url, fetchOptions, (err, response) => {
5556
if (!this._cache) {
5657
// removed
5758
return;
5859
}
60+
let arrayBuffer, hasData = false;
61+
62+
const readTile = () => {
63+
this._readTile(url, altitudePropertyName, disableAltitudeWarning, err, arrayBuffer, cb);
64+
};
65+
5966
if (err) {
6067
if (!err.loading) {
6168
this._cache.add(url, { err, data: response && response.data, cacheIndex: context.workerCacheIndex });
6269
}
6370
} else if (response && response.data) {
64-
let needCache = true;
65-
if (isNumber(loadTileCachMaxSize) && loadTileCachMaxSize > 0) {
66-
const bufferSize = calArrayBufferSize(response.data);
67-
if (bufferSize > loadTileCachMaxSize) {
68-
needCache = false;
69-
if (loadTileCacheLog) {
70-
console.warn(`url:${url},loadTileCachMaxSize exceeded: ${bufferSize} > ${loadTileCachMaxSize},the tile will not be cached.`);
71+
hasData = true;
72+
arrayBuffer = response.data;
73+
const isGZip = arraybufferIsGZip(arrayBuffer);
74+
75+
const resolveTile = () => {
76+
let needCache = true;
77+
if (arrayBuffer && isNumber(loadTileCachMaxSize) && loadTileCachMaxSize > 0) {
78+
const bufferSize = calArrayBufferSize(arrayBuffer);
79+
if (bufferSize > loadTileCachMaxSize) {
80+
needCache = false;
81+
if (loadTileCacheLog) {
82+
console.warn(`url:${url},loadTileCachMaxSize exceeded: ${bufferSize} > ${loadTileCachMaxSize},the tile will not be cached.`);
83+
}
7184
}
7285
}
73-
}
74-
if (needCache) {
75-
this._cache.add(url, { err: null, data: response.data, cacheIndex: context.workerCacheIndex });
86+
if (needCache && arrayBuffer) {
87+
this._cache.add(url, { err: null, data: arrayBuffer, cacheIndex: context.workerCacheIndex });
88+
}
89+
readTile();
90+
};
91+
92+
if (isGZip) {
93+
decompressGzipWithBlob(arrayBuffer, (buffer => {
94+
if (buffer) {
95+
arrayBuffer = buffer;
96+
}
97+
resolveTile();
98+
}))
99+
} else {
100+
resolveTile();
76101
}
77102
}
78-
79-
this._readTile(url, altitudePropertyName, disableAltitudeWarning, err, response && response.data, cb);
103+
if (!hasData) {
104+
readTile();
105+
}
80106
});
81107
}
82108

packages/vt/src/worker/util/index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,49 @@ export function calArrayBufferSize(buffer) {
1212
export function isNumber(val) {
1313
return (typeof val === 'number') && !isNaN(val);
1414
}
15+
16+
// https://gist.github.com/leommoore/f9e57ba2aa4bf197ebc5
17+
// https://stackoverflow.com/questions/30063196/gzipstream-complains-magic-number-in-header-is-not-correct
18+
export function arraybufferIsGZip(buffer) {
19+
if (!buffer) {
20+
return false;
21+
}
22+
if (!(buffer instanceof ArrayBuffer)) {
23+
return false;
24+
}
25+
try {
26+
const array = new Uint8Array(buffer);
27+
const v1 = array[0], v2 = array[1];
28+
return v1 === 0x1F && v2 === 0x8B;
29+
30+
} catch (error) {
31+
console.error('arraybufferIsGZip read buffer error:', error);
32+
}
33+
return false;
34+
}
35+
36+
export function decompressGzipWithBlob(compressedArrayBuffer, callback) {
37+
try {
38+
// 创建解压缩流
39+
const decompressionStream = new DecompressionStream('gzip');
40+
41+
// 创建 Blob 并获取可读流
42+
const blob = new Blob([compressedArrayBuffer]);
43+
const readableStream = blob.stream();
44+
45+
// 管道传输
46+
const decompressedStream = readableStream.pipeThrough(decompressionStream);
47+
48+
// 转换为响应并获取数据
49+
const response = new Response(decompressedStream);
50+
response.arrayBuffer().then(arrayBuffer => {
51+
callback(arrayBuffer)
52+
}).catch(error => {
53+
console.error('decompressGzipWithBlob:', error);
54+
callback();
55+
})
56+
} catch (error) {
57+
console.error('decompressGzipWithBlob:', error);
58+
callback();
59+
}
60+
}

0 commit comments

Comments
 (0)