Skip to content

Commit

Permalink
getTile support Array<Tile>
Browse files Browse the repository at this point in the history
  • Loading branch information
deyihu committed Jan 20, 2025
1 parent df413a5 commit ec79c07
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 32 deletions.
23 changes: 23 additions & 0 deletions src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,29 @@ export function getBlankTile(tileSize?: number) {
return canvas.transferToImageBitmap();
}

export function mergeTiles(images: Array<ImageBitmap>) {
if (images.length === 1) {
return images[0];
}
if (images.length === 0) {
return new Error('merge tiles error,not find imagebitmaps');
}
for (let i = 0, len = images.length; i < len; i++) {
const image = images[i];
if (!(image instanceof ImageBitmap)) {
return new Error('merge tiles error,images not imagebitmap');
}
}
const tileSize = images[0].width;
const canvas = getCanvas(tileSize);
const ctx = getCanvasContext(canvas);
clearCanvas(ctx);
images.forEach(image => {
ctx.drawImage(image, 0, 0, tileSize, tileSize);
});
return canvas.transferToImageBitmap();
}

export function imageClip(canvas: OffscreenCanvas, polygons, image) {
const ctx = getCanvasContext(canvas);
clearCanvas(ctx);
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ registerWorkerAdapter(WORKERNAME, WORKERCODE as unknown as string);
const maskMap = {};

export type getTileOptions = {
url: string;
url: string | Array<string>;
referrer?: string;
filter?: string;
headers?: Record<string, string>;
fetchOptions?: Record<string, any>;
}

export type getTileWithMaxZoomOptions = Omit<getTileOptions, 'url'> & {
urlTemplate: string;
urlTemplate: string | Array<string>;
maxAvailableZoom: number;
x: number;
y: number;
Expand Down
87 changes: 61 additions & 26 deletions src/tileget.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getTileOptions, getTileWithMaxZoomOptions } from './index';
import { getCanvas, imageFilter, imageTileScale } from './canvas';
import { getCanvas, imageFilter, imageTileScale, mergeTiles } from './canvas';
import LRUCache from './LRUCache';

const CANVAS_ERROR_MESSAGE = new Error('not find canvas.The current environment does not support OffscreenCanvas');
Expand All @@ -13,6 +13,13 @@ function isNumber(value) {
return typeof value === 'number';
}

function checkTileUrl(url: string | Array<string>): Array<string> {
if (Array.isArray(url)) {
return url;
}
return [url];
}

const tileCache = new LRUCache(200, (image) => {
if (image && image.close) {
image.close();
Expand Down Expand Up @@ -52,22 +59,31 @@ export function getTile(url, options: getTileOptions) {
reject(new Error('url is null'));
return;
}
const urls = checkTileUrl(url);
const headers = Object.assign({}, HEADERS, options.headers || {});
fetchTile(url, headers, options).then(imagebit => {
const fetchTiles = urls.map(tileUrl => {
return fetchTile(tileUrl, headers, options)
});
Promise.all(fetchTiles).then(imagebits => {
const canvas = getCanvas();
if (!canvas) {
reject(CANVAS_ERROR_MESSAGE);
return;
}
const image = mergeTiles(imagebits);
if (image instanceof Error) {
reject(image);
return;
}
const filter = options.filter;
if (filter) {
const canvas = getCanvas();
if (!canvas) {
reject(CANVAS_ERROR_MESSAGE);
} else {
resolve(imageFilter(canvas, imagebit, filter));
}
resolve(imageFilter(canvas, image, filter));
} else {
resolve(imagebit);
resolve(image);
}
}).catch(error => {
reject(error);
});
})
});
}

Expand All @@ -87,6 +103,7 @@ export function getTileWithMaxZoom(options: getTileWithMaxZoomOptions) {
reject(new Error('x/y/z is error'));
return;
}
const urlTemplates = checkTileUrl(urlTemplate);
let dxScale, dyScale, wScale, hScale;
let tileX = x, tileY = y, tileZ = z;
const zoomOffset = z - maxAvailableZoom;
Expand Down Expand Up @@ -123,39 +140,57 @@ export function getTileWithMaxZoom(options: getTileWithMaxZoomOptions) {
tileY = py;
tileZ = maxAvailableZoom;
}
const url = urlTemplate.replace('{x}', tileX as unknown as string).replace('{y}', tileY as unknown as string).replace('{z}', tileZ as unknown as string);
const urls = urlTemplates.map(urlTemplate => {
let key = '{x}';
while (urlTemplate.indexOf(key) > -1) {
urlTemplate = urlTemplate.replace(key, tileX as unknown as string);
}
key = '{y}';
while (urlTemplate.indexOf(key) > -1) {
urlTemplate = urlTemplate.replace(key, tileY as unknown as string);
}
key = '{z}';
while (urlTemplate.indexOf(key) > -1) {
urlTemplate = urlTemplate.replace(key, tileZ as unknown as string);
}
return urlTemplate;
});
const headers = Object.assign({}, HEADERS, options.headers || {});

fetchTile(url, headers, options).then(imagebit => {
const fetchTiles = urls.map(url => {
return fetchTile(url, headers, options);
})

Promise.all(fetchTiles).then(imagebits => {
const canvas = getCanvas();
if (!canvas) {
reject(CANVAS_ERROR_MESSAGE);
return;
}

const mergeImage = mergeTiles(imagebits);
if (mergeImage instanceof Error) {
reject(mergeImage);
return;
}
let image;
const filter = options.filter;
if (filter) {
const canvas = getCanvas();
if (!canvas) {
reject(CANVAS_ERROR_MESSAGE);
return;
} else {
image = (imageFilter(canvas, imagebit, filter));
}
image = (imageFilter(canvas, mergeImage, filter));
} else {
image = imagebit;
image = mergeImage;
}
if (zoomOffset <= 0) {
resolve(image);
return;
}
const canvas = getCanvas();
if (!canvas) {
reject(CANVAS_ERROR_MESSAGE);
return;
}
const { width, height } = image;
const dx = width * dxScale, dy = height * dyScale, w = width * wScale, h = height * hScale;
const imageBitMap = imageTileScale(canvas, image, dx, dy, w, h);
resolve(imageBitMap);
}).catch(error => {
reject(error);
});
})
});

}
1 change: 1 addition & 0 deletions src/worker/canvas.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export declare function getCanvas(tileSize?: number): OffscreenCanvas;
export declare function getCanvasContext(canvas: OffscreenCanvas): OffscreenCanvasRenderingContext2D;
export declare function getBlankTile(tileSize?: number): ImageBitmap;
export declare function mergeTiles(images: Array<ImageBitmap>): ImageBitmap | Error;
export declare function imageClip(canvas: OffscreenCanvas, polygons: any, image: any): ImageBitmap;
export declare function toBlobURL(imagebitmap: ImageBitmap): Promise<Blob>;
export declare function imageFilter(canvas: OffscreenCanvas, imagebitmap: ImageBitmap, filter: string): ImageBitmap;
Expand Down
4 changes: 2 additions & 2 deletions src/worker/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { worker } from 'maptalks';
import { BBOXtype } from './bbox';
export type getTileOptions = {
url: string;
url: string | Array<string>;
referrer?: string;
filter?: string;
headers?: Record<string, string>;
fetchOptions?: Record<string, any>;
};
export type getTileWithMaxZoomOptions = Omit<getTileOptions, 'url'> & {
urlTemplate: string;
urlTemplate: string | Array<string>;
maxAvailableZoom: number;
x: number;
y: number;
Expand Down
2 changes: 1 addition & 1 deletion src/worker/tileclip.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { clipTileOptions, GeoJSONMultiPolygon, GeoJSONPolygon } from './index';
export declare function isPolygon(feature: GeoJSONPolygon | GeoJSONMultiPolygon): boolean;
export declare function isEPSG3857(projection: string): projection is "EPSG:3857";
export declare function injectMask(maskId: string, geojson: GeoJSONPolygon | GeoJSONMultiPolygon): GeoJSONPolygon | GeoJSONMultiPolygon | Error;
export declare function injectMask(maskId: string, geojson: GeoJSONPolygon | GeoJSONMultiPolygon): Error | GeoJSONPolygon | GeoJSONMultiPolygon;
export declare function removeMask(maskId: string): void;
export declare function clip(options: clipTileOptions): Promise<unknown>;
2 changes: 1 addition & 1 deletion src/worker/worker.bundle.js

Large diffs are not rendered by default.

0 comments on commit ec79c07

Please sign in to comment.