Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/config/elementSizeObserver.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Disposable } from '../../../base/common/lifecycle.js';
7
import { IDimension } from '../../common/core/2d/dimension.js';
8
import { Emitter, Event } from '../../../base/common/event.js';
9
import { getWindow, scheduleAtNextAnimationFrame } from '../../../base/browser/dom.js';
10
11
export class ElementSizeObserver extends Disposable {
12
13
private _onDidChange = this._register(new Emitter<void>());
14
public readonly onDidChange: Event<void> = this._onDidChange.event;
15
16
private readonly _referenceDomElement: HTMLElement | null;
17
private _width: number;
18
private _height: number;
19
private _resizeObserver: ResizeObserver | null;
20
21
constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined) {
22
super();
23
this._referenceDomElement = referenceDomElement;
24
this._width = -1;
25
this._height = -1;
26
this._resizeObserver = null;
27
this.measureReferenceDomElement(false, dimension);
28
}
29
30
public override dispose(): void {
31
this.stopObserving();
32
super.dispose();
33
}
34
35
public getWidth(): number {
36
return this._width;
37
}
38
39
public getHeight(): number {
40
return this._height;
41
}
42
43
public startObserving(): void {
44
if (!this._resizeObserver && this._referenceDomElement) {
45
// We want to react to the resize observer only once per animation frame
46
// The first time the resize observer fires, we will react to it immediately.
47
// Otherwise we will postpone to the next animation frame.
48
// We'll use `observeContentRect` to store the content rect we received.
49
50
let observedDimenstion: IDimension | null = null;
51
const observeNow = () => {
52
if (observedDimenstion) {
53
this.observe({ width: observedDimenstion.width, height: observedDimenstion.height });
54
} else {
55
this.observe();
56
}
57
};
58
59
let shouldObserve = false;
60
let alreadyObservedThisAnimationFrame = false;
61
62
const update = () => {
63
if (shouldObserve && !alreadyObservedThisAnimationFrame) {
64
try {
65
shouldObserve = false;
66
alreadyObservedThisAnimationFrame = true;
67
observeNow();
68
} finally {
69
scheduleAtNextAnimationFrame(getWindow(this._referenceDomElement), () => {
70
alreadyObservedThisAnimationFrame = false;
71
update();
72
});
73
}
74
}
75
};
76
77
this._resizeObserver = new ResizeObserver((entries) => {
78
if (entries && entries[0] && entries[0].contentRect) {
79
observedDimenstion = { width: entries[0].contentRect.width, height: entries[0].contentRect.height };
80
} else {
81
observedDimenstion = null;
82
}
83
shouldObserve = true;
84
update();
85
});
86
this._resizeObserver.observe(this._referenceDomElement);
87
}
88
}
89
90
public stopObserving(): void {
91
if (this._resizeObserver) {
92
this._resizeObserver.disconnect();
93
this._resizeObserver = null;
94
}
95
}
96
97
public observe(dimension?: IDimension): void {
98
this.measureReferenceDomElement(true, dimension);
99
}
100
101
private measureReferenceDomElement(emitEvent: boolean, dimension?: IDimension): void {
102
let observedWidth = 0;
103
let observedHeight = 0;
104
if (dimension) {
105
observedWidth = dimension.width;
106
observedHeight = dimension.height;
107
} else if (this._referenceDomElement) {
108
observedWidth = this._referenceDomElement.clientWidth;
109
observedHeight = this._referenceDomElement.clientHeight;
110
}
111
observedWidth = Math.max(5, observedWidth);
112
observedHeight = Math.max(5, observedHeight);
113
if (this._width !== observedWidth || this._height !== observedHeight) {
114
this._width = observedWidth;
115
this._height = observedHeight;
116
if (emitEvent) {
117
this._onDidChange.fire();
118
}
119
}
120
}
121
}
122
123