diff --git a/.changeset/friendly-avocados-drum.md b/.changeset/friendly-avocados-drum.md
new file mode 100644
index 000000000..9aa4543b0
--- /dev/null
+++ b/.changeset/friendly-avocados-drum.md
@@ -0,0 +1,5 @@
+---
+'@antv/g-lite': patch
+---
+
+fix: HTML element bounding box calculation logic (#1743)
diff --git a/demo/camera+html.html b/demo/camera+html.html
new file mode 100644
index 000000000..87182a935
--- /dev/null
+++ b/demo/camera+html.html
@@ -0,0 +1,138 @@
+
+
+
+
+
+ Camera
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/g-lite/src/display-objects/HTML.ts b/packages/g-lite/src/display-objects/HTML.ts
index 88aad7890..f947dab22 100644
--- a/packages/g-lite/src/display-objects/HTML.ts
+++ b/packages/g-lite/src/display-objects/HTML.ts
@@ -64,7 +64,15 @@ export class HTML extends DisplayObject {
*/
getBoundingClientRect(): Rectangle {
if (this.parsedStyle.$el) {
- return this.parsedStyle.$el.getBoundingClientRect();
+ const cameraMatrix = this.ownerDocument.defaultView
+ .getCamera()
+ .getOrthoMatrix();
+ const bBox = this.parsedStyle.$el.getBoundingClientRect();
+
+ return Rectangle.applyTransform(
+ bBox,
+ mat4.invert(mat4.create(), cameraMatrix),
+ );
} else {
const { x, y, width, height } = this.parsedStyle;
return new Rectangle(x, y, width, height);
diff --git a/packages/g-lite/src/shapes/Rectangle.ts b/packages/g-lite/src/shapes/Rectangle.ts
index b482ef26c..1135d4deb 100644
--- a/packages/g-lite/src/shapes/Rectangle.ts
+++ b/packages/g-lite/src/shapes/Rectangle.ts
@@ -1,9 +1,87 @@
+import { mat4, vec4 } from 'gl-matrix';
+
+type RectangleLike = {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+};
+
export class Rectangle implements DOMRect {
+ /**
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect/fromRect_static
+ */
+ static fromRect(rect: RectangleLike) {
+ return new Rectangle(rect.x, rect.y, rect.width, rect.height);
+ }
+
+ /**
+ * will return a new rect instance
+ */
+ static applyTransform(rect: Rectangle, matrix: mat4) {
+ const topLeft = vec4.fromValues(rect.x, rect.y, 0, 1);
+ const topRight = vec4.fromValues(rect.x + rect.width, rect.y, 0, 1);
+ const bottomLeft = vec4.fromValues(rect.x, rect.y + rect.height, 0, 1);
+ const bottomRight = vec4.fromValues(
+ rect.x + rect.width,
+ rect.y + rect.height,
+ 0,
+ 1,
+ );
+
+ const transformedTopLeft = vec4.create();
+ const transformedTopRight = vec4.create();
+ const transformedBottomLeft = vec4.create();
+ const transformedBottomRight = vec4.create();
+
+ vec4.transformMat4(transformedTopLeft, topLeft, matrix);
+ vec4.transformMat4(transformedTopRight, topRight, matrix);
+ vec4.transformMat4(transformedBottomLeft, bottomLeft, matrix);
+ vec4.transformMat4(transformedBottomRight, bottomRight, matrix);
+
+ const minX = Math.min(
+ transformedTopLeft[0],
+ transformedTopRight[0],
+ transformedBottomLeft[0],
+ transformedBottomRight[0],
+ );
+ const minY = Math.min(
+ transformedTopLeft[1],
+ transformedTopRight[1],
+ transformedBottomLeft[1],
+ transformedBottomRight[1],
+ );
+ const maxX = Math.max(
+ transformedTopLeft[0],
+ transformedTopRight[0],
+ transformedBottomLeft[0],
+ transformedBottomRight[0],
+ );
+ const maxY = Math.max(
+ transformedTopLeft[1],
+ transformedTopRight[1],
+ transformedBottomLeft[1],
+ transformedBottomRight[1],
+ );
+
+ return Rectangle.fromRect({
+ x: minX,
+ y: minY,
+ width: maxX - minX,
+ height: maxY - minY,
+ });
+ }
+
left: number;
right: number;
top: number;
bottom: number;
- constructor(public x: number, public y: number, public width: number, public height: number) {
+ constructor(
+ public x: number,
+ public y: number,
+ public width: number,
+ public height: number,
+ ) {
this.left = x;
this.right = x + width;
this.top = y;