Skip to content

Commit

Permalink
feat: support applying CSS Transfrom on container #1161
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Sep 29, 2022
1 parent 1b954b7 commit 5c26bd8
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 16 deletions.
2 changes: 2 additions & 0 deletions packages/g-lite/src/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export class Canvas extends EventTarget implements ICanvas {
createImage,
supportsPointerEvents,
supportsTouchEvents,
supportsCSSTransform,
isTouchEvent,
isMouseEvent,
} = config;
Expand Down Expand Up @@ -212,6 +213,7 @@ export class Canvas extends EventTarget implements ICanvas {
background: background || 'transparent',
createImage,
document,
supportsCSSTransform,
});

this.initDefaultCamera(canvasWidth, canvasHeight);
Expand Down
23 changes: 14 additions & 9 deletions packages/g-lite/src/css/parser/__tests__/color.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,20 @@ describe('Property Color', () => {
expect((result[1].value as RadialGradient).steps[2].offset.toString()).to.be.eqls('100%');

// TODO: multiple gradients, use 0 as 0%
result = parseColor(`radial-gradient(circle at 50% 0%,
rgba(255,0,0,.5),
rgba(255,0,0,0) 70.71%),
radial-gradient(circle at 6.7% 75%,
rgba(0,0,255,.5),
rgba(0,0,255,0) 70.71%),
radial-gradient(circle at 93.3% 75%,
rgba(0,255,0,.5),
rgba(0,255,0,0) 70.71%)`) as CSSGradientValue[];
// result = parseColor(`radial-gradient(circle at 50% 0%,
// rgba(255,0,0,.5),
// rgba(255,0,0,0) 70.71%),
// radial-gradient(circle at 6.7% 75%,
// rgba(0,0,255,.5),
// rgba(0,0,255,0) 70.71%),
// radial-gradient(circle at 93.3% 75%,
// rgba(0,255,0,.5),
// rgba(0,255,0,0) 70.71%)`) as CSSGradientValue[];

// result = parseColor(
// `radial-gradient(circle 480px at 256px 496px, rgb(196, 217, 245) 0%, rgb(50, 80, 176) 50%, rgb(41, 47, 117) 100%)`,
// );
// console.log(result);
});

it('should parse legacy linear gradient color correctly', () => {
Expand Down
30 changes: 23 additions & 7 deletions packages/g-lite/src/plugins/EventPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, singleton } from 'mana-syringe';
import { isUndefined } from '@antv/util';
import { isNil, isUndefined } from '@antv/util';
import type { FederatedMouseEvent, ICanvas } from '../dom';
import { FederatedPointerEvent } from '../dom/FederatedPointerEvent';
import { FederatedWheelEvent } from '../dom/FederatedWheelEvent';
Expand Down Expand Up @@ -146,6 +146,26 @@ export class EventPlugin implements RenderingPlugin {
this.setCursor(this.eventService.cursor);
};

private getViewportXY(nativeEvent: PointerEvent | WheelEvent) {
let x: number;
let y: number;
/**
* Should account for CSS Transform applied on container.
* @see https://github.com/antvis/G/issues/1161
* @see https://developer.mozilla.org/zh-CN/docs/Web/API/MouseEvent/offsetX
*/
const { offsetX, offsetY, clientX, clientY } = nativeEvent;
if (this.canvasConfig.supportsCSSTransform && !isNil(offsetX) && !isNil(offsetY)) {
x = offsetX;
y = offsetY;
} else {
const point = this.eventService.client2Viewport(new Point(clientX, clientY));
x = point.x;
y = point.y;
}
return { x, y };
}

private bootstrapEvent(
event: FederatedPointerEvent,
nativeEvent: PointerEvent,
Expand All @@ -167,9 +187,7 @@ export class EventPlugin implements RenderingPlugin {
event.twist = nativeEvent.twist;
this.transferMouseData(event, nativeEvent);

const { x, y } = this.eventService.client2Viewport(
new Point(nativeEvent.clientX, nativeEvent.clientY),
);
const { x, y } = this.getViewportXY(nativeEvent);
event.viewport.x = x;
event.viewport.y = y;
const { x: canvasX, y: canvasY } = this.eventService.viewport2Canvas(event.viewport);
Expand Down Expand Up @@ -201,9 +219,7 @@ export class EventPlugin implements RenderingPlugin {
event.deltaY = nativeEvent.deltaY;
event.deltaZ = nativeEvent.deltaZ;

const { x, y } = this.eventService.client2Viewport(
new Point(nativeEvent.clientX, nativeEvent.clientY),
);
const { x, y } = this.getViewportXY(nativeEvent);
event.viewport.x = x;
event.viewport.y = y;
const { x: canvasX, y: canvasY } = this.eventService.viewport2Canvas(event.viewport);
Expand Down
5 changes: 5 additions & 0 deletions packages/g-lite/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ export interface CanvasConfig {
isTouchEvent?: (event: InteractivePointerEvent) => event is TouchEvent;
isMouseEvent?: (event: InteractivePointerEvent) => event is MouseEvent;

/**
* Should we account for CSS Transform applied on container?
*/
supportsCSSTransform?: boolean;

/**
* 画布宽度
*/
Expand Down
13 changes: 13 additions & 0 deletions packages/site/docs/api/canvas.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ const canvas = new Canvas({
});
```

## supportsCSSTransform

Optional. 是否支持在容器上应用 CSS Transform 的情况下确保交互事件坐标转换正确。

Whether or not CSS Transform is supported on the container to ensure that the interaction event coordinates are transformed correctly.

In this [example](/en/examples/canvas#supports-css-transform), we have enlarged the container by a factor of 1.1, and with this configuration enabled, mouse movement over the circle changes the mouse style correctly.

```js
const $wrapper = document.getElementById('container');
$wrapper.style.transform = 'scale(1.1)';
```

## supportsPointerEvents

Optional. Whether PointerEvent is supported or not, the default will use `! !globalThis.PointerEvent`. If `false` is passed, the event listener plugin will not listen for PointerEvent such as `pointerdown`.
Expand Down
11 changes: 11 additions & 0 deletions packages/site/docs/api/canvas.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ const canvas = new Canvas({
});
```

## supportsCSSTransform

可选。是否支持在容器上应用 CSS Transform 的情况下确保交互事件坐标转换正确。

在该 [示例](/zh/examples/canvas#supports-css-transform) 中,我们将容器放大了 1.1 倍,开启该配置项后,鼠标移动到圆上可以正确变化鼠标样式:

```js
const $wrapper = document.getElementById('container');
$wrapper.style.transform = 'scale(1.1)';
```

## supportsPointerEvents

可选。是否支持 PointerEvent,默认将使用 `!!globalThis.PointerEvent` 判断。如果传入 `false`,事件监听插件将不会监听例如 `pointerdown` 等 PointerEvent。
Expand Down
7 changes: 7 additions & 0 deletions packages/site/examples/canvas/demo/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@
"zh": "通过 API 方式完成拾取",
"en": "Use picking API"
}
},
{
"filename": "supports-css-transform.js",
"title": {
"zh": "支持在容器上应用 CSS Transform",
"en": "Support applying CSS Transform on container"
}
}
]
}
89 changes: 89 additions & 0 deletions packages/site/examples/canvas/demo/supports-css-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Canvas, CanvasEvent, Circle } from '@antv/g';
import { Renderer as CanvasRenderer } from '@antv/g-canvas';
import { Renderer as CanvaskitRenderer } from '@antv/g-canvaskit';
import { Renderer as SVGRenderer } from '@antv/g-svg';
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Renderer as WebGPURenderer } from '@antv/g-webgpu';
import * as lil from 'lil-gui';
import Stats from 'stats.js';

const $wrapper = document.getElementById('container');
$wrapper.style.transform = 'scale(1.1)';

// create a renderer
const canvasRenderer = new CanvasRenderer();
const svgRenderer = new SVGRenderer();
const webglRenderer = new WebGLRenderer();
const webgpuRenderer = new WebGPURenderer();
const canvaskitRenderer = new CanvaskitRenderer({
wasmDir: '/',
});

// create a canvas
const canvas = new Canvas({
container: 'container',
width: 600,
height: 500,
renderer: canvasRenderer,
supportsCSSTransform: true,
});

// create a circle
const circle = new Circle({
style: {
cx: 300,
cy: 200,
r: 100,
fill: '#1890FF',
stroke: '#F04864',
lineWidth: 4,
shadowColor: 'black',
shadowBlur: 20,
cursor: 'pointer',
},
});

canvas.addEventListener(CanvasEvent.READY, () => {
// add a circle to canvas
canvas.appendChild(circle);
});

// stats
const stats = new Stats();
stats.showPanel(0);
const $stats = stats.dom;
$stats.style.position = 'absolute';
$stats.style.left = '0px';
$stats.style.top = '0px';
$wrapper.appendChild($stats);
canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => {
if (stats) {
stats.update();
}
});

// GUI
const gui = new lil.GUI({ autoPlace: false });
$wrapper.appendChild(gui.domElement);
const rendererFolder = gui.addFolder('renderer');
const rendererConfig = {
renderer: 'canvas',
};
rendererFolder
.add(rendererConfig, 'renderer', ['canvas', 'svg', 'webgl', 'webgpu', 'canvaskit'])
.onChange((rendererName) => {
let renderer;
if (rendererName === 'canvas') {
renderer = canvasRenderer;
} else if (rendererName === 'svg') {
renderer = svgRenderer;
} else if (rendererName === 'webgl') {
renderer = webglRenderer;
} else if (rendererName === 'webgpu') {
renderer = webgpuRenderer;
} else if (rendererName === 'canvaskit') {
renderer = canvaskitRenderer;
}
canvas.setRenderer(renderer);
});
rendererFolder.open();

0 comments on commit 5c26bd8

Please sign in to comment.