Skip to content

Commit db5e1e8

Browse files
Track canvas resizes performed through attributes
1 parent 1023035 commit db5e1e8

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

packages/browser-rum/src/domain/record/trackers/trackCanvas.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,39 @@ describe('trackCanvas2DMutations', () => {
7777
expect(markCanvasDirtySpy.calls.argsFor(1)[0]).toBe(canvas)
7878
})
7979

80-
it('stops tracking drawing operations', () => {
80+
it('marks the canvas dirty when it is resized through attributes', () => {
81+
tracker = trackCanvas2DMutations(markCanvasDirtySpy)
82+
83+
canvas.setAttribute('width', '100')
84+
canvas.setAttribute('HEIGHT', '50')
85+
canvas.removeAttribute('width')
86+
canvas.removeAttribute('height')
87+
88+
expect(markCanvasDirtySpy).toHaveBeenCalledTimes(4)
89+
markCanvasDirtySpy.calls.allArgs().forEach(([dirtyCanvas]) => expect(dirtyCanvas).toBe(canvas))
90+
})
91+
92+
it('does not mark the canvas dirty for unrelated attribute mutations', () => {
93+
tracker = trackCanvas2DMutations(markCanvasDirtySpy)
94+
const div = document.createElement('div')
95+
96+
canvas.setAttribute('class', 'foo')
97+
canvas.removeAttribute('class')
98+
canvas.removeAttribute('width')
99+
div.setAttribute('width', '100')
100+
div.removeAttribute('width')
101+
102+
expect(markCanvasDirtySpy).not.toHaveBeenCalled()
103+
})
104+
105+
it('stops tracking canvas mutations', () => {
81106
const clock: Clock = mockClock()
82107
tracker = trackCanvas2DMutations(markCanvasDirtySpy)
83108
tracker.stop()
84109

85110
context.fillRect(0, 0, 1, 1)
86111
canvas.width = 100
112+
canvas.setAttribute('height', '50')
87113
clock.tick(0)
88114

89115
expect(markCanvasDirtySpy).not.toHaveBeenCalled()

packages/browser-rum/src/domain/record/trackers/trackCanvas.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const CANVAS_2D_DRAWING_METHODS: readonly Canvas2DDrawingMethod[] = [
3030
'reset',
3131
]
3232

33+
const CANVAS_SIZE_ATTRIBUTES = ['width', 'height']
34+
3335
export function trackCanvas2DMutations(markCanvasDirty: MarkCanvasDirty): Tracker {
3436
const instrumentationStoppers: Tracker[] = []
3537

@@ -46,11 +48,29 @@ export function trackCanvas2DMutations(markCanvasDirty: MarkCanvasDirty): Tracke
4648
if (typeof HTMLCanvasElement !== 'undefined') {
4749
instrumentationStoppers.push(
4850
instrumentSetter(HTMLCanvasElement.prototype, 'width', markCanvasDirty),
49-
instrumentSetter(HTMLCanvasElement.prototype, 'height', markCanvasDirty)
51+
instrumentSetter(HTMLCanvasElement.prototype, 'height', markCanvasDirty),
52+
instrumentMethod(Element.prototype, 'setAttribute', ({ target, parameters, onPostCall }) => {
53+
if (target instanceof HTMLCanvasElement && isCanvasSizeAttribute(parameters[0])) {
54+
onPostCall(() => markCanvasDirty(target))
55+
}
56+
}),
57+
instrumentMethod(Element.prototype, 'removeAttribute', ({ target, parameters, onPostCall }) => {
58+
if (
59+
target instanceof HTMLCanvasElement &&
60+
isCanvasSizeAttribute(parameters[0]) &&
61+
target.hasAttribute(parameters[0])
62+
) {
63+
onPostCall(() => markCanvasDirty(target))
64+
}
65+
})
5066
)
5167
}
5268

5369
return {
5470
stop: () => instrumentationStoppers.forEach((stopper) => stopper.stop()),
5571
}
5672
}
73+
74+
function isCanvasSizeAttribute(attributeName: string): boolean {
75+
return CANVAS_SIZE_ATTRIBUTES.includes(attributeName.toLowerCase())
76+
}

0 commit comments

Comments
 (0)