From f7ea1c0969193b9ca390f85d19c314b108267743 Mon Sep 17 00:00:00 2001 From: hu de yi Date: Fri, 22 Aug 2025 11:10:42 +0800 Subject: [PATCH 1/4] TileLayer detectRetina implemented --- packages/maptalks/src/layer/tile/TileLayer.ts | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/maptalks/src/layer/tile/TileLayer.ts b/packages/maptalks/src/layer/tile/TileLayer.ts index 192624656f..efffae8028 100644 --- a/packages/maptalks/src/layer/tile/TileLayer.ts +++ b/packages/maptalks/src/layer/tile/TileLayer.ts @@ -166,7 +166,8 @@ const options: TileLayerOptionsType = { 'depthMask': true, 'currentTilesFirst': true, 'forceRenderOnMoving': true, - 'tileErrorScale': 1 + 'tileErrorScale': 1, + 'detectRetina': false }; const URL_PATTERN = /\{ *([\w_]+) *\}/g; @@ -185,6 +186,30 @@ const TILE_MIN = [0, 0, 0]; const TILE_MAX = [0, 0, 0]; const ARR3: Vector3 = [0, 0, 0]; +const RetinaScales = [0.25, 0.5, 1, 2, 4]; + +function getRetinaScale(dpr: number, reverse?: boolean) { + if (reverse) { + for (let i = RetinaScales.length - 1; i >= 0; i--) { + const retinaScale = RetinaScales[i]; + if (reverse) { + if (dpr >= retinaScale) { + return retinaScale + } + } + } + } else { + for (let i = 0, len = RetinaScales.length; i < len; i++) { + const retinaScale = RetinaScales[i]; + if (dpr <= retinaScale) { + return retinaScale + } + } + } + + return null; +} + /** * A layer used to display tiled map services, such as [google maps](http://maps.google.com), [open street maps](http://www.osm.org) * @category layer @@ -238,6 +263,8 @@ class TileLayer extends Layer { */ constructor(id: string, options?: TileLayerOptionsType) { super(id, options); + //record original zoomOffset + this.options._zoomOffset = this.options['zoomOffset']; } /** @@ -286,6 +313,27 @@ class TileLayer extends Layer { size = [size, size]; } this._tileSize = new Size(size); + if (!this.options.detectRetina) { + return this._tileSize; + } + const map = this.getMap(); + if (map) { + const dpr = map.getDevicePixelRatio(); + if (Math.abs(dpr - 1) > 0) { + const scale = getRetinaScale(dpr, dpr < 1); + if (scale && scale !== 1) { + const [width, height] = size; + const w = Math.floor(width / scale), h = Math.floor(height / scale); + let offset = Math.max(width, w) / Math.min(width, w) / 2; + if (dpr < 1) { + offset = -offset; + + } + this.options.zoomOffset = this.options._zoomOffset + offset; + this._tileSize = new Size(w, h); + } + } + } return this._tileSize; } @@ -1752,6 +1800,8 @@ export type TileLayerOptionsType = LayerOptionsType & { mipmapTexture?: boolean; currentTilesFirst?: boolean; tileErrorScale?: number; + detectRetina?: boolean; + _zoomOffset?: number; }; enum TileVisibility { From 87a265f9b05afcc08bc0189b6de1d9329893f0fa Mon Sep 17 00:00:00 2001 From: hu de yi Date: Fri, 22 Aug 2025 11:15:59 +0800 Subject: [PATCH 2/4] updates --- packages/maptalks/src/layer/tile/TileLayer.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/maptalks/src/layer/tile/TileLayer.ts b/packages/maptalks/src/layer/tile/TileLayer.ts index efffae8028..0ab079cea2 100644 --- a/packages/maptalks/src/layer/tile/TileLayer.ts +++ b/packages/maptalks/src/layer/tile/TileLayer.ts @@ -192,10 +192,8 @@ function getRetinaScale(dpr: number, reverse?: boolean) { if (reverse) { for (let i = RetinaScales.length - 1; i >= 0; i--) { const retinaScale = RetinaScales[i]; - if (reverse) { - if (dpr >= retinaScale) { - return retinaScale - } + if (dpr >= retinaScale) { + return retinaScale } } } else { From 1bc4b5c532f755983fe827e0b75266346f4187a4 Mon Sep 17 00:00:00 2001 From: hu de yi Date: Fri, 22 Aug 2025 11:26:06 +0800 Subject: [PATCH 3/4] fix --- packages/maptalks/src/layer/tile/TileLayer.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/maptalks/src/layer/tile/TileLayer.ts b/packages/maptalks/src/layer/tile/TileLayer.ts index 0ab079cea2..2d2f11fb59 100644 --- a/packages/maptalks/src/layer/tile/TileLayer.ts +++ b/packages/maptalks/src/layer/tile/TileLayer.ts @@ -252,6 +252,8 @@ class TileLayer extends Layer { //record spatial reference in current rendering frame //@internal _spatialRef: SpatialReference; + //@internal + _zoomOffset: number; options: TileLayerOptionsType; /** @@ -262,7 +264,7 @@ class TileLayer extends Layer { constructor(id: string, options?: TileLayerOptionsType) { super(id, options); //record original zoomOffset - this.options._zoomOffset = this.options['zoomOffset']; + this._zoomOffset = this.options['zoomOffset'] || 0; } /** @@ -327,7 +329,7 @@ class TileLayer extends Layer { offset = -offset; } - this.options.zoomOffset = this.options._zoomOffset + offset; + this.options.zoomOffset = this._zoomOffset + offset; this._tileSize = new Size(w, h); } } @@ -1799,7 +1801,6 @@ export type TileLayerOptionsType = LayerOptionsType & { currentTilesFirst?: boolean; tileErrorScale?: number; detectRetina?: boolean; - _zoomOffset?: number; }; enum TileVisibility { From d8a0f06262cde6df57cbc45add9c4201619464a6 Mon Sep 17 00:00:00 2001 From: hu de yi Date: Thu, 18 Sep 2025 14:51:21 +0800 Subject: [PATCH 4/4] VectorTileLayer add loadTileErrorLog for log loadTile error (#2641) * VectorTileLayer add loadTileErrorLog for log loadTile error * fix typing --- .../vt/src/layer/layer/VectorTileLayer.ts | 22 +++++++++++-------- .../layer/renderer/VectorTileLayerRenderer.js | 4 ++++ packages/vt/src/worker/index.js | 15 ++++++++++--- .../src/worker/layer/VectorTileLayerWorker.js | 1 + packages/vt/src/worker/util/Ajax.js | 18 ++++++++++----- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/packages/vt/src/layer/layer/VectorTileLayer.ts b/packages/vt/src/layer/layer/VectorTileLayer.ts index 38a0f1b062..7b3d6143f1 100644 --- a/packages/vt/src/layer/layer/VectorTileLayer.ts +++ b/packages/vt/src/layer/layer/VectorTileLayer.ts @@ -88,7 +88,9 @@ const defaultOptions: VectorTileLayerOptionsType = { tileStackDepth: 2, altitudePropertyName: null, - disableAltitudeWarning: false + disableAltitudeWarning: false, + loadTileErrorLog: true, + loadTileErrorLogIgnoreCodes: [404, 204] }; /** @@ -347,12 +349,12 @@ class VectorTileLayer extends maptalks.TileLayer { } forceReload(): this { - // expire cached tiles in worker - const renderer = this.getRenderer() as any; - if (renderer) { - renderer._incrWorkerCacheIndex(); - } - return super.forceReload(); + // expire cached tiles in worker + const renderer = this.getRenderer() as any; + if (renderer) { + renderer._incrWorkerCacheIndex(); + } + return super.forceReload(); } onWorkerReady() { } @@ -1832,7 +1834,7 @@ class VectorTileLayer extends maptalks.TileLayer { clear() { const renderer = this.getRenderer(); if (renderer) { - renderer.clearData(); + renderer.clearData(); } return super.clear(); } @@ -2011,7 +2013,9 @@ export type VectorTileLayerOptionsType = { style?: any, altitudePropertyName?: string, - disableAltitudeWarning?: boolean + disableAltitudeWarning?: boolean, + loadTileErrorLog?: boolean, + loadTileErrorLogIgnoreCodes?: Array; } & TileLayerOptionsType; export type AsyncFeatureQueryOptions = { diff --git a/packages/vt/src/layer/renderer/VectorTileLayerRenderer.js b/packages/vt/src/layer/renderer/VectorTileLayerRenderer.js index 026076ed3d..948757e1f7 100644 --- a/packages/vt/src/layer/renderer/VectorTileLayerRenderer.js +++ b/packages/vt/src/layer/renderer/VectorTileLayerRenderer.js @@ -537,6 +537,8 @@ class VectorTileLayerRenderer extends CanvasCompatible(TileLayerRendererable(Lay const referrer = window && window.location.href; const altitudePropertyName = this.layer.options['altitudePropertyName']; const disableAltitudeWarning = this.layer.options['disableAltitudeWarning']; + const loadTileErrorLog = this.layer.options.loadTileErrorLog; + const loadTileErrorLogIgnoreCodes = this.layer.options.loadTileErrorLogIgnoreCodes; const loadTileOpitons = { tileInfo: { res: tileInfo.res, @@ -549,6 +551,8 @@ class VectorTileLayerRenderer extends CanvasCompatible(TileLayerRendererable(Lay }, glScale, disableAltitudeWarning, + loadTileErrorLog, + loadTileErrorLogIgnoreCodes, altitudePropertyName, zScale: this._zScale, centimeterToPoint, diff --git a/packages/vt/src/worker/index.js b/packages/vt/src/worker/index.js index 5ef654ad29..bebf74ec97 100644 --- a/packages/vt/src/worker/index.js +++ b/packages/vt/src/worker/index.js @@ -1,3 +1,4 @@ +import { isNumber } from '../common/Util'; import Dispatcher from './Dispatcher'; export const initialize = function () { @@ -15,11 +16,19 @@ export const onmessage = function (message, postResponse) { } } else { const command = data.command; + const loadTileErrorLog = (data.params || {}).loadTileErrorLog; + const loadTileErrorLogIgnoreCodes = (data.params || {}).loadTileErrorLogIgnoreCodes || []; this.dispatcher[command]({ actorId: message.actorId, mapId: data.mapId, layerId: data.layerId, params: data.params }, (err, data, buffers) => { - if (err && err.status !== 404 && err.status !== 204 && !err.loading) { - // err.loading 为true时,说明geojson-vt正在创建索引 - console.error(command, err); + if (loadTileErrorLog && err && !err.loading) { + const status = err.status; + if (isNumber(status) && loadTileErrorLogIgnoreCodes.indexOf(status) === -1) { + console.error(command, err); + } } + // if (err && err.status !== 404 && err.status !== 204 && !err.loading) { + // // err.loading 为true时,说明geojson-vt正在创建索引 + // console.error(command, err); + // } postResponse(err, data, buffers); }); } diff --git a/packages/vt/src/worker/layer/VectorTileLayerWorker.js b/packages/vt/src/worker/layer/VectorTileLayerWorker.js index e88c8d220d..459861896d 100644 --- a/packages/vt/src/worker/layer/VectorTileLayerWorker.js +++ b/packages/vt/src/worker/layer/VectorTileLayerWorker.js @@ -48,6 +48,7 @@ export default class VectorTileLayerWorker extends LayerWorker { }, 1); } fetchOptions.referrer = context.referrer; + fetchOptions.errorLog = context.loadTileErrorLog; return Ajax.getArrayBuffer(url, fetchOptions, (err, response) => { if (!this._cache) { // removed diff --git a/packages/vt/src/worker/util/Ajax.js b/packages/vt/src/worker/util/Ajax.js index 70811de528..e49224fc04 100644 --- a/packages/vt/src/worker/util/Ajax.js +++ b/packages/vt/src/worker/util/Ajax.js @@ -1,6 +1,6 @@ -import { isFunction, uid } from '../../common/Util'; +import { isFunction, isNil, uid } from '../../common/Util'; -const USE_FETCH = typeof fetch === 'function' && typeof AbortController === 'function'; +const USE_FETCH = typeof fetch === 'function' && typeof AbortController === 'function'; /** * @classdesc @@ -68,6 +68,10 @@ const Ajax = { options = t; } options = options || {}; + let errorLog = options.errorLog; + if (isNil(errorLog)) { + errorLog = true; + } if (options.method) { options.method = options.method.toUpperCase(); } @@ -115,14 +119,18 @@ const Ajax = { } }).catch(err => { if (!err.code || err.code !== DOMException.ABORT_ERR) { - console.error('Fetch error:', url, err); + if (errorLog) { + console.error('Fetch error:', url, err); + } cb(err); } }); } }).catch(err => { if (!err.code || err.code !== DOMException.ABORT_ERR) { - console.error('Fetch error:', url, err); + if (errorLog) { + console.error('Fetch error:', url, err); + } cb(err); } }); @@ -185,7 +193,7 @@ const Ajax = { client = new XMLHttpRequest(); } catch (e) { try { client = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { - try { client = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} + try { client = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { } } } client.onreadystatechange = Ajax._wrapCallback(client, cb);