Skip to content

Commit ddd905e

Browse files
authored
Layer RourceCache support ImageBItMap key (#2524)
1 parent 2cd2833 commit ddd905e

16 files changed

+317
-145
lines changed
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
import Browser from './Browser';
2+
import { isSVG, isImageBitMap, isString, hasOwn } from './util';
3+
4+
type ResourceUrl = string | string[];
5+
6+
type ResourceCacheItem = {
7+
image: ImageBitmap;
8+
width: number;
9+
height: number;
10+
refCnt: number;
11+
}
12+
13+
/**
14+
* resouce key support ImageBitMap by Map
15+
* this.resources.set(imagebitmap,cache);
16+
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map
17+
*/
18+
19+
20+
class ResourceCacheMap {
21+
resources: Map<string | ImageBitmap, ResourceCacheItem>;
22+
23+
//@internal
24+
_errors: Map<string | ImageBitmap, number>;
25+
26+
constructor() {
27+
this.resources = new Map();
28+
this._errors = new Map();
29+
}
30+
31+
32+
addResource(url: [string, number | string, number | string], img) {
33+
const imgUrl = this._getImgUrl(url as any);
34+
this.resources.set(imgUrl, {
35+
image: img,
36+
width: +url[1],
37+
height: +url[2],
38+
refCnt: 0
39+
})
40+
//is Image
41+
if (img && img.width && img.height && !img.close && Browser.imageBitMap && !Browser.safari && !Browser.iosWeixin) {
42+
if (img.src && isSVG(img.src)) {
43+
return;
44+
}
45+
createImageBitmap(img).then(imageBitmap => {
46+
if (!this.resources.has(imgUrl)) {
47+
//removed
48+
return;
49+
}
50+
this.resources.get(imgUrl).image = imageBitmap;
51+
});
52+
}
53+
}
54+
55+
isResourceLoaded(url: ResourceUrl, checkSVG?: boolean) {
56+
if (!url) {
57+
return false;
58+
}
59+
const imgUrl = this._getImgUrl(url);
60+
if (this._errors.has(imgUrl)) {
61+
return true;
62+
}
63+
const img = this.resources.get(imgUrl);
64+
if (!img) {
65+
return false;
66+
}
67+
if (checkSVG && isSVG(url[0]) && (+url[1] > img.width || +url[2] > img.height)) {
68+
return false;
69+
}
70+
return true;
71+
}
72+
73+
login(url: string) {
74+
const res = this.resources.get(url);
75+
if (res) {
76+
res.refCnt++;
77+
}
78+
}
79+
80+
logout(url: string) {
81+
const res = this.resources.get(url);
82+
if (res && res.refCnt-- <= 0) {
83+
if (res.image && res.image.close) {
84+
res.image.close();
85+
}
86+
this.resources.delete(url);
87+
}
88+
}
89+
90+
getImage(url: ResourceUrl) {
91+
const imgUrl = this._getImgUrl(url);
92+
if (!this.isResourceLoaded(url) || this._errors.has(imgUrl)) {
93+
return null;
94+
}
95+
return this.resources.get(imgUrl).image;
96+
}
97+
98+
markErrorResource(url: ResourceUrl) {
99+
const imgUrl = this._getImgUrl(url);
100+
this._errors.set(imgUrl, 1);
101+
}
102+
103+
merge(res: ResourceCacheMap) {
104+
if (!res) {
105+
return this;
106+
}
107+
const otherResource = res.resources;
108+
if (otherResource) {
109+
otherResource.forEach((value, key) => {
110+
const img = value;
111+
this.addResource([key as string, img.width, img.height], img.image);
112+
})
113+
}
114+
return this;
115+
}
116+
117+
forEach(fn: (key: string | ImageBitmap, value: any) => void) {
118+
if (!this.resources) {
119+
return this;
120+
}
121+
this.resources.forEach((value, key) => {
122+
fn(key, value);
123+
})
124+
return this;
125+
}
126+
127+
//@internal
128+
_getImgUrl(url: ResourceUrl) {
129+
if (isImageBitMap(url)) {
130+
return url;
131+
}
132+
let imgUrl;
133+
if (Array.isArray(url)) {
134+
imgUrl = url[0];
135+
} else if (isString(url)) {
136+
imgUrl = url;
137+
}
138+
if (!imgUrl) {
139+
console.error(`get url key error,the url is:`, url);
140+
}
141+
return imgUrl;
142+
}
143+
144+
remove() {
145+
if (!this.resources) {
146+
return this;
147+
}
148+
this.resources.forEach((value) => {
149+
if (value && value.image && value.image.close) {
150+
value.image.close();
151+
}
152+
})
153+
this.resources.clear();
154+
return this;
155+
}
156+
}
157+
158+
159+
export class ResourceCache {
160+
resources: any;
161+
162+
//@internal
163+
_errors: any;
164+
165+
constructor() {
166+
this.resources = {};
167+
this._errors = {};
168+
}
169+
170+
addResource(url: [string, number | string, number | string], img) {
171+
this.resources[url[0]] = {
172+
image: img,
173+
width: +url[1],
174+
height: +url[2],
175+
refCnt: 0
176+
};
177+
if (img && img.width && img.height && !img.close && Browser.imageBitMap && !Browser.safari && !Browser.iosWeixin) {
178+
if (img.src && isSVG(img.src)) {
179+
return;
180+
}
181+
createImageBitmap(img).then(imageBitmap => {
182+
if (!this.resources[url[0]]) {
183+
//removed
184+
return;
185+
}
186+
this.resources[url[0]].image = imageBitmap;
187+
});
188+
}
189+
}
190+
191+
isResourceLoaded(url: ResourceUrl, checkSVG?: boolean) {
192+
if (!url) {
193+
return false;
194+
}
195+
const imgUrl = this._getImgUrl(url);
196+
if (this._errors[imgUrl]) {
197+
return true;
198+
}
199+
const img = this.resources[imgUrl];
200+
if (!img) {
201+
return false;
202+
}
203+
if (checkSVG && isSVG(url[0]) && (+url[1] > img.width || +url[2] > img.height)) {
204+
return false;
205+
}
206+
return true;
207+
}
208+
209+
login(url: string) {
210+
const res = this.resources[url];
211+
if (res) {
212+
res.refCnt++;
213+
}
214+
}
215+
216+
logout(url: string) {
217+
const res = this.resources[url];
218+
if (res && res.refCnt-- <= 0) {
219+
if (res.image && res.image.close) {
220+
res.image.close();
221+
}
222+
delete this.resources[url];
223+
}
224+
}
225+
226+
getImage(url: ResourceUrl) {
227+
const imgUrl = this._getImgUrl(url);
228+
if (!this.isResourceLoaded(url) || this._errors[imgUrl]) {
229+
return null;
230+
}
231+
return this.resources[imgUrl].image;
232+
}
233+
234+
markErrorResource(url: ResourceUrl) {
235+
this._errors[this._getImgUrl(url)] = 1;
236+
}
237+
238+
merge(res: any) {
239+
if (!res) {
240+
return this;
241+
}
242+
for (const p in res.resources) {
243+
const img = res.resources[p];
244+
this.addResource([p, img.width, img.height], img.image);
245+
}
246+
return this;
247+
}
248+
249+
forEach(fn: (key: string, value: any) => void) {
250+
if (!this.resources) {
251+
return this;
252+
}
253+
for (const p in this.resources) {
254+
if (hasOwn(this.resources, p)) {
255+
fn(p, this.resources[p]);
256+
}
257+
}
258+
return this;
259+
}
260+
261+
//@internal
262+
_getImgUrl(url: ResourceUrl) {
263+
if (!Array.isArray(url)) {
264+
return url;
265+
}
266+
return url[0];
267+
}
268+
269+
remove() {
270+
for (const p in this.resources) {
271+
const res = this.resources[p];
272+
if (res && res.image && res.image.close) {
273+
// close bitmap
274+
res.image.close();
275+
}
276+
}
277+
this.resources = {};
278+
}
279+
}
280+
281+
// Dynamically obtain resource cache instances
282+
export function getResouceCacheInstance(): ResourceCache {
283+
if (Browser.decodeImageInWorker) {
284+
return new ResourceCacheMap() as ResourceCache;
285+
}
286+
return new ResourceCache();
287+
}

packages/maptalks/src/core/util/draw.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import PointExtent from '../../geo/PointExtent';
33
import { isGradient } from './style';
44
import { isNumber } from './common';
55
import Canvas from '../Canvas';
6-
import { ResourceCache } from '../../renderer/layer/LayerAbstractRenderer'
76
import { BBOX } from './bbox';
7+
import { ResourceCache } from '../ResourceCacheManager';
88

99
export function drawImageMarker(ctx: CanvasRenderingContext2D, image, point, symbol) {
1010
let w = symbol && symbol['markerWidth'];

packages/maptalks/src/core/util/marker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Point from '../../geo/Point';
66
import PointExtent from '../../geo/PointExtent';
77
import Size from '../../geo/Size';
88
import { type MarkerType } from './draw'
9-
import { ResourceCache } from '../../renderer/layer/LayerAbstractRenderer'
9+
import { ResourceCache } from '../ResourceCacheManager';
1010

1111
export const DEFAULT_MARKER_SYMBOLS = {
1212
markerWidth: 10,

packages/maptalks/src/geometry/ext/Geometry.Drag.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import Handler from '../../handler/Handler';
66
import Geometry from '../Geometry';
77
import DragHandler from '../../handler/Drag';
88
import { ConnectorLine } from '../ConnectorLine';
9-
import { ResourceCache } from '../../renderer/layer/LayerAbstractRenderer';
109
import Point from '../../geo/Point';
1110
import Coordinate from '../../geo/Coordinate';
11+
import { getResouceCacheInstance } from '../../core/ResourceCacheManager';
1212

1313
const DRAG_STAGE_LAYER_ID = INTERNAL_LAYER_PREFIX + '_drag_stage';
1414

@@ -193,7 +193,7 @@ class GeometryDragHandler extends Handler {
193193
});
194194
map.addLayer(this._dragStageLayer);
195195
//copy resources to avoid repeat resource loading.
196-
const resources = new ResourceCache();
196+
const resources = getResouceCacheInstance();
197197
resources.merge(layer._getRenderer().resources);
198198
this._dragStageLayer._getRenderer().resources = resources;
199199
}
@@ -415,7 +415,7 @@ class GeometryDragHandler extends Handler {
415415
delete this._shadowConnectors;
416416
}
417417
if (this._dragStageLayer) {
418-
this._dragStageLayer._getRenderer().resources = new ResourceCache();
418+
this._dragStageLayer._getRenderer().resources = getResouceCacheInstance();
419419
this._dragStageLayer.remove();
420420
}
421421
}

packages/maptalks/src/layer/ImageLayer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import Browser from '../core/Browser';
44
import Point from '../geo/Point';
55
import ImageGLRenderable from '../renderer/layer/ImageGLRenderable';
66
import CanvasRenderer from '../renderer/layer/CanvasRenderer';
7-
import { ResourceCache } from '../renderer/layer/LayerAbstractRenderer';
87
import Extent from '../geo/Extent';
98
import Layer, { LayerOptionsType } from './Layer';
109
import { PointExtent } from '../geo';
10+
import { getResouceCacheInstance } from '../core/ResourceCacheManager';
1111

1212

1313
/**
@@ -152,7 +152,7 @@ export class ImageLayerCanvasRenderer extends CanvasRenderer {
152152
let urls = layer._imageData.map(img => [img.url, null, null]);
153153
if (this.resources) {
154154
const unloaded = [];
155-
const resources = new ResourceCache();
155+
const resources = getResouceCacheInstance();
156156
urls.forEach(url => {
157157
if (this.resources.isResourceLoaded(url)) {
158158
const img = this.resources.getImage(url);

packages/maptalks/src/renderer/edit/EditHandle.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import Eventable from '../../core/Eventable';
22
import Class from '../../core/Class';
33
import Point, { type PointJson } from '../../geo/Point';
4-
import { ResourceCache } from '../layer/LayerAbstractRenderer';
54
import { drawVectorMarker } from '../../core/util/draw';
65
import { isNil } from '../../core/util/';
76
import { getSymbolHash } from '../../core/util';
@@ -10,8 +9,9 @@ import DragHandler from '../../handler/Drag';
109
import { BBOX, bufferBBOX, getDefaultBBOX } from '../../core/util/bbox';
1110
import type Map from '../../map/Map';
1211
import type GeometryEditor from '../../geometry/editor/GeometryEditor';
12+
import { getResouceCacheInstance } from '../../core/ResourceCacheManager';
1313

14-
const resources = new ResourceCache();
14+
const resources = getResouceCacheInstance();
1515
let prevX, prevY;
1616

1717
type EventParams = any;

packages/maptalks/src/renderer/geometry/CollectionPainter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import PointExtent from '../../geo/PointExtent';
33
import { BBOX, getDefaultBBOX, resetBBOX, setBBOX, validateBBOX } from '../../core/util/bbox';
44
import Painter from './Painter';
55
import Extent from '../../geo/Extent';
6-
import { ResourceCache } from '../layer/LayerAbstractRenderer';
76
import { Geometries } from '../../geometry'
7+
import { ResourceCache } from '../../core/ResourceCacheManager';
88

99
const TEMP_EXTENT = new PointExtent();
1010

packages/maptalks/src/renderer/geometry/Painter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { BBOX, getDefaultBBOX, resetBBOX, setBBOX, validateBBOX } from '../../co
1111
import Map from '../../map/Map'
1212
import { DebugSymbolizer } from './symbolizers';
1313
import Extent from '../../geo/Extent';
14-
import { ResourceCache } from '../layer/LayerAbstractRenderer';
1514
import type { WithUndef } from '../../types/typings';
1615
import { Geometries } from '../../geometry'
16+
import { ResourceCache } from '../../core/ResourceCacheManager';
1717

1818
//registered symbolizers
1919
//the latter will paint at the last

0 commit comments

Comments
 (0)