Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: html element's getBounds logic exception (#1743) #1764

Merged
merged 1 commit into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/silver-chicken-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@antv/g-plugin-html-renderer': patch
'@antv/g-lite': patch
---

fix: html element's `getBounds` logic exception (#1743)
29 changes: 21 additions & 8 deletions demo/camera+html.html → demo/issues/issue-1743.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
padding: 0;
}

html,
body {
height: 100vh;
padding: 111px 0 0 111px;
/* padding: 100px 0 0 100px; */
}

#container {
/* border: 1px solid #ddd; */
background-color: #ddd;
width: 100%;
height: 100%;
}
Expand All @@ -29,16 +32,14 @@
<body>
<div id="container"></div>
<script
src="../packages/g/dist/index.umd.min.js"
src="../../packages/g/dist/index.umd.min.js"
type="application/javascript"
></script>
<script
src="../packages/g-canvas/dist/index.umd.min.js"
src="../../packages/g-canvas/dist/index.umd.min.js"
type="application/javascript"
></script>
<script src="../packages/g-plugin-control/dist/index.umd.min.js"></script>
<!-- <script src="../packages/g-svg/dist/index.umd.min.js" type="application/javascript"></script>
<script src="../packages/g-webgl/dist/index.umd.min.js" type="application/javascript"></script> -->
<script src="../../packages/g-plugin-control/dist/index.umd.min.js"></script>
<script>
console.log(window.G);
const { Circle, CanvasEvent, Canvas, HTML } = window.G;
Expand All @@ -50,8 +51,8 @@
// create a canvas
const canvas = new Canvas({
container: 'container',
width: 800,
height: 800,
width: 600,
height: 600,
renderer: canvasRenderer,
});

Expand All @@ -61,6 +62,9 @@
cy: 200,
r: 50,
fill: 'red',
transform: 'translate(120px, 120px) scale(2)',
transformOrigin: 'center center',
// transformOrigin: '200px 200px',
},
});

Expand All @@ -72,13 +76,22 @@
height: 100,
innerHTML:
'<h1 style="width: 100px; height: 100px;">This is Title</h1>',
transform: 'translate(120px, 120px) scale(2)',
transformOrigin: 'center center',
// transformOrigin: '50px 50px',
},
});

canvas.addEventListener(CanvasEvent.READY, () => {
canvas.appendChild(circle);
canvas.appendChild(html);

// console.log(
// 'transform',
// circle.getWorldTransform(),
// html.getWorldTransform(),
// );

console.log('canvas.getCamera()', canvas.getCamera(), circle, html);
console.log(
'circle',
Expand Down
60 changes: 27 additions & 33 deletions packages/g-lite/src/display-objects/HTML.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mat4 } from 'gl-matrix';
import type { DisplayObjectConfig } from '../dom';
import { runtime } from '../global-runtime';
import { AABB, Rectangle } from '../shapes';
import { AABB } from '../shapes';
import type { BaseStyleProps, ParsedBaseStyleProps } from '../types';
import { Shape } from '../types';
import { DisplayObject } from './DisplayObject';
Expand Down Expand Up @@ -61,45 +61,39 @@ export class HTML extends DisplayObject<HTMLStyleProps, ParsedHTMLStyleProps> {
/**
* override with $el.getBoundingClientRect
* @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect
*
* ! The calculation logic of the html element should be consistent with that of the canvas element
*/
getBoundingClientRect(): Rectangle {
if (this.parsedStyle.$el) {
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);
}
}
// getBoundingClientRect(): Rectangle {
// if (this.parsedStyle.$el) {
// return this.parsedStyle.$el.getBoundingClientRect();
// } else {
// const { x, y, width, height } = this.parsedStyle;
// return new Rectangle(x, y, width, height);
// }
// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个函数注释掉是要去掉还是保留?可能有一些库依赖了这个函数,需要确认下

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的实现原本是覆盖了基类的实现,而且计算结果与 canvas 元素的也不一致,现在注释掉就相当于采用基类的实现了,保持 html 与 canvas 元素的计算结果一致,但在某些情况下会导致与 dom api 的计算结果不一致


getClientRects() {
return [this.getBoundingClientRect()];
}

getBounds() {
const clientRect = this.getBoundingClientRect();
// calc context's offset
// @ts-ignore
const canvasRect = this.ownerDocument?.defaultView
?.getContextService()
.getBoundingClientRect();
// getBounds() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里也一样,采用基类的实现,保证 html 元素与 canvas 元素的实现一致,获取的结果也一致

// const clientRect = this.getBoundingClientRect();
// // calc context's offset
// // @ts-ignore
// const canvasRect = this.ownerDocument?.defaultView
// ?.getContextService()
// .getBoundingClientRect();

const aabb = new AABB();
const minX = clientRect.left - (canvasRect?.left || 0);
const minY = clientRect.top - (canvasRect?.top || 0);
aabb.setMinMax(
[minX, minY, 0],
[minX + clientRect.width, minY + clientRect.height, 0],
);
return aabb;
}
// const aabb = new AABB();
// const minX = clientRect.left - (canvasRect?.left || 0);
// const minY = clientRect.top - (canvasRect?.top || 0);
// aabb.setMinMax(
// [minX, minY, 0],
// [minX + clientRect.width, minY + clientRect.height, 0],
// );
// return aabb;
// }

getLocalBounds() {
if (this.parentNode) {
Expand Down
3 changes: 2 additions & 1 deletion packages/g-lite/src/global-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
RectUpdater,
TextService,
TextUpdater,
HTMLUpdater,
} from './services';
import { CanvasLike, Shape } from './types';

Expand Down Expand Up @@ -104,7 +105,7 @@ const geometryUpdaterFactory: Record<Shape, GeometryAABBUpdater<any>> = (() => {
[Shape.POLYLINE]: polylineUpdater,
[Shape.POLYGON]: polylineUpdater,
[Shape.PATH]: new PathUpdater(),
[Shape.HTML]: null,
[Shape.HTML]: new HTMLUpdater(),
[Shape.MESH]: null,
};
})();
Expand Down
15 changes: 15 additions & 0 deletions packages/g-lite/src/services/aabb/HTMLUpdater.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { HTML, ParsedHTMLStyleProps } from '../../display-objects/HTML';
import type { GeometryAABBUpdater } from './interfaces';

export class HTMLUpdater implements GeometryAABBUpdater<ParsedHTMLStyleProps> {
update(parsedStyle: ParsedHTMLStyleProps, object: HTML) {
const { x = 0, y = 0, width = 0, height = 0 } = parsedStyle;

return {
cx: x + width / 2,
cy: y + height / 2,
hwidth: width / 2,
hheight: height / 2,
};
}
}
1 change: 1 addition & 0 deletions packages/g-lite/src/services/aabb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { PolylineUpdater } from './PolylineUpdater';
export { RectUpdater } from './RectUpdater';
export { TextUpdater } from './TextUpdater';
export { GroupUpdater } from './GroupUpdater';
export { HTMLUpdater } from './HTMLUpdater';
25 changes: 16 additions & 9 deletions packages/g-plugin-html-renderer/src/HTMLRenderingPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
Shape,
} from '@antv/g-lite';
import { isNil, isNumber, isString } from '@antv/util';
import type { mat4 } from 'gl-matrix';
import type { mat4, vec3 } from 'gl-matrix';

const CANVAS_CAMERA_ID = 'g-canvas-camera';

Expand All @@ -36,14 +36,17 @@ export class HTMLRenderingPlugin implements RenderingPlugin {
HTMLElement
>();

private joinTransformMatrix(matrix: mat4) {
/**
* ! The reason for adding `offset` is that the `transform-origin` coordinate system of DOM is the local coordinate system of the element, while the `transform-origin` coordinate system of canvas drawing is the local coordinate system of the element's parent element. At the same time, the `transform` attribute value of the DOM element does not include `transform-origin`.
*/
private joinTransformMatrix(matrix: mat4, offset: vec3 = [0, 0, 0]) {
return `matrix(${[
matrix[0],
matrix[1],
matrix[4],
matrix[5],
matrix[12],
matrix[13],
matrix[12] + offset[0],
matrix[13] + offset[1],
].join(',')})`;
}

Expand All @@ -56,6 +59,7 @@ export class HTMLRenderingPlugin implements RenderingPlugin {
const setTransform = (object: HTML, $el: HTMLElement) => {
$el.style.transform = this.joinTransformMatrix(
object.getWorldTransform(),
object.getOrigin(),
);
};

Expand Down Expand Up @@ -118,8 +122,8 @@ export class HTMLRenderingPlugin implements RenderingPlugin {
const handleCanvasResize = () => {
if (this.$camera) {
const { width, height } = this.context.config;
this.$camera.style.width = `${width || 0}px`;
this.$camera.style.height = `${height || 0}px`;
this.$camera.parentElement.style.width = `${width || 0}px`;
this.$camera.parentElement.style.height = `${height || 0}px`;
}
};

Expand Down Expand Up @@ -237,6 +241,7 @@ export class HTMLRenderingPlugin implements RenderingPlugin {
$existedElement.style['will-change'] = 'transform';
$existedElement.style.transform = this.joinTransformMatrix(
object.getWorldTransform(),
object.getOrigin(),
);
}

Expand All @@ -263,9 +268,11 @@ export class HTMLRenderingPlugin implements RenderingPlugin {
break;
case 'transformOrigin':
const { transformOrigin } = object.parsedStyle;
$el.style[
'transform-origin'
] = `${transformOrigin[0].value} ${transformOrigin[1].value}`;
$el.style['transform-origin'] = `${transformOrigin[0].buildCSSText(
null,
null,
'',
)} ${transformOrigin[1].buildCSSText(null, null, '')}`;
break;
case 'width':
if (this.context.enableCSSParsing) {
Expand Down
Loading