Skip to content

Commit 80b5bd4

Browse files
gabeboningfelixpalmer
authored andcommitted
fix(IconManager) Fix icon frame x/y for auto packed icons (#9928)
1 parent 240845d commit 80b5bd4

File tree

3 files changed

+45
-28
lines changed

3 files changed

+45
-28
lines changed

modules/layers/src/icon-layer/icon-layer.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,13 @@ export default class IconLayer<DataT = any, ExtraPropsT extends {} = {}> extends
309309
});
310310
}
311311

312-
private _onUpdate(): void {
313-
this.setNeedsRedraw();
312+
private _onUpdate(didFrameChange: boolean): void {
313+
if (didFrameChange) {
314+
this.getAttributeManager()?.invalidate('getIcon');
315+
this.setNeedsUpdate();
316+
} else {
317+
this.setNeedsRedraw();
318+
}
314319
}
315320

316321
private _onError(evt: LoadIconErrorContext): void {

modules/layers/src/icon-layer/icon-manager.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export function getDiffIcons(
296296
export default class IconManager {
297297
device: Device;
298298

299-
private onUpdate: () => void;
299+
private onUpdate: (didFrameChange: boolean) => void;
300300
private onError: (context: LoadIconErrorContext) => void;
301301
private _loadOptions: any = null;
302302
private _texture: Texture | null = null;
@@ -326,7 +326,7 @@ export default class IconManager {
326326
onError = noop
327327
}: {
328328
/** Callback when the texture updates */
329-
onUpdate: () => void;
329+
onUpdate: (didFrameChange: boolean) => void;
330330
/** Callback when an error is encountered */
331331
onError: (context: LoadIconErrorContext) => void;
332332
}
@@ -435,7 +435,7 @@ export default class IconManager {
435435
);
436436
}
437437

438-
this.onUpdate();
438+
this.onUpdate(true);
439439

440440
// load images
441441
this._canvas = this._canvas || document.createElement('canvas');
@@ -461,7 +461,7 @@ export default class IconManager {
461461
const id = getIconId(icon);
462462

463463
const iconDef = this._mapping[id];
464-
const {x, y, width: maxWidth, height: maxHeight} = iconDef;
464+
const {x: initialX, y: initialY, width: maxWidth, height: maxHeight} = iconDef;
465465

466466
const {image, width, height} = resizeImage(
467467
ctx,
@@ -470,20 +470,25 @@ export default class IconManager {
470470
maxHeight
471471
);
472472

473+
const x = initialX + (maxWidth - width) / 2;
474+
const y = initialY + (maxHeight - height) / 2;
475+
473476
this._texture?.copyExternalImage({
474477
image,
475-
x: x + (maxWidth - width) / 2,
476-
y: y + (maxHeight - height) / 2,
478+
x,
479+
y,
477480
width,
478481
height
479482
});
483+
iconDef.x = x;
484+
iconDef.y = y;
480485
iconDef.width = width;
481486
iconDef.height = height;
482487

483488
// Call to regenerate mipmaps after modifying texture(s)
484489
this._texture?.generateMipmapsWebGL();
485490

486-
this.onUpdate();
491+
this.onUpdate(width !== maxWidth || height !== maxHeight);
487492
})
488493
.catch(error => {
489494
this.onError({

test/modules/layers/icon-manager.spec.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,30 @@ test('IconManager#resize', t => {
251251
const testImage =
252252
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAACXBIWXMAAD2EAAA9hAHVrK90AAAAjElEQVQYlXWPMQrCQBBFn7NJI9oobraz1kqv4zk9h4iCEDsLq4gBR4LgGi3WNRhxmj88Zv6f6Sz5LuEPSNMWsLYFnHs3SRBjMY8I+iPoCpMKCiUBHUwFGFPvNKwcynkPuK40ml5ygFyblAzvyZoUcec1M7etAbMAhrfN3R+FKk6UJ+C5Nx+PcFKQn29fOzIjztSX8AwAAAAASUVORK5CYII=';
253253
let updateCount = 0;
254+
255+
const icons = [
256+
{id: 'no-resize', width: 16, height: 16},
257+
{id: 'down-size', width: 12, height: 12},
258+
{id: 'preserve-aspect-ratio-landscape', width: 32, height: 24},
259+
{id: 'preserve-aspect-ratio-portrait', width: 12, height: 16}
260+
];
261+
262+
const assertIconFrame = (id, expected) => {
263+
const mapping = iconManager.getIconMapping({id});
264+
t.is(mapping.x, expected.x, `${id} x`);
265+
t.is(mapping.y, expected.y, `${id} y`);
266+
t.is(mapping.width, expected.width, `${id} width`);
267+
t.is(mapping.height, expected.height, `${id} height`);
268+
};
269+
254270
const onUpdate = () => {
255271
updateCount++;
256-
if (updateCount > 3) {
257-
t.is(iconManager.getIconMapping({id: 'no-resize'}).width, 16, 'no-resize');
258-
t.is(iconManager.getIconMapping({id: 'down-size'}).width, 12, 'down-size');
259-
t.is(
260-
iconManager.getIconMapping({id: 'preserve-aspect-ratio'}).width,
261-
24,
262-
'preserve-aspect-ratio'
263-
);
272+
if (updateCount > icons.length) {
273+
assertIconFrame('no-resize', {x: 0, y: 0, width: 16, height: 16});
274+
assertIconFrame('down-size', {x: 20, y: 0, width: 12, height: 12});
275+
assertIconFrame('preserve-aspect-ratio-landscape', {x: 40, y: 0, width: 24, height: 24});
276+
assertIconFrame('preserve-aspect-ratio-portrait', {x: 72, y: 2, width: 12, height: 12});
277+
264278
t.end();
265279
}
266280
};
@@ -275,15 +289,8 @@ test('IconManager#resize', t => {
275289
iconManager.setProps({
276290
autoPacking: true
277291
});
278-
iconManager.packIcons(
279-
[
280-
{id: 'no-resize', width: 16, height: 16},
281-
{id: 'down-size', width: 12, height: 12},
282-
{id: 'preserve-aspect-ratio', width: 32, height: 24}
283-
],
284-
d => ({
285-
...d,
286-
url: testImage
287-
})
288-
);
292+
iconManager.packIcons(icons, d => ({
293+
...d,
294+
url: testImage
295+
}));
289296
});

0 commit comments

Comments
 (0)