Skip to content

Commit

Permalink
chore: update usage of threelib
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Aug 18, 2023
1 parent 1707045 commit 716054a
Show file tree
Hide file tree
Showing 18 changed files with 260 additions and 82 deletions.
91 changes: 41 additions & 50 deletions __tests__/plots/api/chart-render-3d-scatter-plot-perspective.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { CameraType, Canvas } from '@antv/g';
import { CameraType } from '@antv/g';
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Plugin as ThreeDPlugin, DirectionalLight } from '@antv/g-plugin-3d';
import { Plugin as ControlPlugin } from '@antv/g-plugin-control';
import { Chart } from '../../../src/api';
import { Runtime, extend } from '../../../src/api';
import { corelib, threedlib } from '../../../src/lib';

export function chartRender3dScatterPlotPerspective(context) {
const { container } = context;
Expand All @@ -12,61 +13,51 @@ export function chartRender3dScatterPlotPerspective(context) {
renderer.registerPlugin(new ThreeDPlugin());
renderer.registerPlugin(new ControlPlugin());

const canvas = new Canvas({
const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
const chart = new Chart({
container,
width: 640,
height: 480,
theme: 'classic',
renderer,
depth: 400,
});

const camera = canvas.getCamera();
camera.setPerspective(0.1, 5000, 45, 500 / 500);
camera.setType(CameraType.ORBITING);

// Add a directional light into scene.
const light = new DirectionalLight({
style: {
intensity: 3,
fill: 'white',
direction: [-1, 0, 1],
},
});
canvas.appendChild(light);

const chart = new Chart({ theme: 'classic', container, canvas });
chart.options({
width: 500,
height: 500,
depth: 400,
type: 'point3D',
padding: 'auto',
data: {
chart
.point3D()
.data({
type: 'fetch',
value: 'data/cars2.csv',
},
encode: {
x: 'Horsepower',
y: 'Miles_per_Gallon',
z: 'Weight_in_lbs',
size: 'Origin',
color: 'Cylinders',
shape: 'cube',
},
scale: {
x: { nice: true },
y: { nice: true },
z: { nice: true },
},
coordinate: { type: 'cartesian3D' },
axis: {
x: { gridLineWidth: 3 },
y: { gridLineWidth: 3, titleBillboardRotation: -Math.PI / 2 },
z: { gridLineWidth: 3 },
},
legend: false,
});
})
.encode('x', 'Horsepower')
.encode('y', 'Miles_per_Gallon')
.encode('z', 'Weight_in_lbs')
.encode('size', 'Origin')
.encode('color', 'Cylinders')
.encode('shape', 'cube')
.coordinate({ type: 'cartesian3D' })
.scale('x', { nice: true })
.scale('y', { nice: true })
.scale('z', { nice: true })
.legend(false)
.axis('x', { gridLineWidth: 2 })
.axis('y', { gridLineWidth: 2, titleBillboardRotation: -Math.PI / 2 })
.axis('z', { gridLineWidth: 2 });

const finished = chart.render();
const finished = chart.render().then(() => {
const { canvas } = chart.getContext();
const camera = canvas!.getCamera();

Check warning on line 47 in __tests__/plots/api/chart-render-3d-scatter-plot-perspective.ts

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion
camera.setPerspective(0.1, 5000, 45, 500 / 500);
camera.setType(CameraType.ORBITING);

// Add a directional light into scene.
const light = new DirectionalLight({
style: {
intensity: 3,
fill: 'white',
direction: [-1, 0, 1],
},
});
canvas!.appendChild(light);

Check warning on line 59 in __tests__/plots/api/chart-render-3d-scatter-plot-perspective.ts

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion
});

return { finished };
}
Expand Down
4 changes: 3 additions & 1 deletion __tests__/plots/api/chart-render-3d-scatter-plot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { CameraType } from '@antv/g';
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Plugin as ThreeDPlugin, DirectionalLight } from '@antv/g-plugin-3d';
import { Plugin as ControlPlugin } from '@antv/g-plugin-control';
import { Chart } from '../../../src/api';
import { Runtime, extend } from '../../../src/api';
import { corelib, threedlib } from '../../../src/lib';

export function chartRender3dScatterPlot(context) {
const { container } = context;
Expand All @@ -12,6 +13,7 @@ export function chartRender3dScatterPlot(context) {
renderer.registerPlugin(new ThreeDPlugin());
renderer.registerPlugin(new ControlPlugin());

const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
const chart = new Chart({
container,
theme: 'classic',
Expand Down
8 changes: 8 additions & 0 deletions site/.dumirc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ export default defineConfig({
},
order: 14,
},
{
slug: 'spec/3d',
title: {
zh: '3D 图表 - 3D Charts',
en: '3D',
},
order: 15,
},
{
slug: 'spec/theme',
title: {
Expand Down
3 changes: 2 additions & 1 deletion site/docs/api/chart.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ chart.render();
| container | 指定 chart 绘制的 DOM,可以传入 DOM id,也可以直接传入 dom 实例 | `string \| HTMLElement` | |
| width | 图表宽度 | `number` | 640 |
| height | 图表高度 | `number` | 480 |
| depth | 图表深度,在 3D 图表中使用 | `number` | 0 |
| renderer | 指定渲染引擎,默认使用 canvas。 | | |
| plugins | 指定渲染时使用的插件 ,具体见 [plugin](/api/plugin/rough) | `any[]` | |
| autoFit | 图表是否自适应容器宽高,默认为 `false`,用户需要手动设置 `width``height`。<br/>当 `autoFit: true` 时,会自动取图表容器的宽高,如果用户设置了 `height`,那么会以用户设置的 `height` 为准。 | `boolean` | false |
Expand Down Expand Up @@ -196,7 +197,7 @@ chart.render();

### `chart.point3D`

添加 point3D 图形,具体见 [mark](/spec/mark/point3D)
添加 point3D 图形,具体见 [3d](/spec/3d/point3-d)

## 设置属性

Expand Down
2 changes: 1 addition & 1 deletion site/docs/manual/extra-topics/3d-charts.en.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: 3D Charts
title: Use 3D Charts
order: 11
---

Expand Down
139 changes: 128 additions & 11 deletions site/docs/manual/extra-topics/3d-charts.zh.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
title: 3D 图表
title: 绘制 3D 图表
order: 11
---

以 3D 散点图为例,创建图表需要以下步骤:

- 创建 WebGL 渲染器和插件
- 扩展 threedlib
- 设置 z 通道、比例尺和坐标轴
- 在场景中设置相机
- 添加光源
Expand All @@ -18,7 +19,7 @@ order: 11
首先安装依赖:

```bash
$ npm install @antv/g-webgl @antv/g-plugin-3d @antv/g-plugin-control --save;
$ npm install @antv/g-webgl @antv/g-plugin-3d @antv/g-plugin-control --save
```

然后使用 [@antv/g-webgl](https://g.antv.antgroup.com/api/renderer/webgl) 作为渲染器并注册以下两个插件:
Expand All @@ -36,6 +37,16 @@ renderer.registerPlugin(new ThreeDPlugin());
renderer.registerPlugin(new ControlPlugin());
```

## 扩展 threedlib

由于 3D 相关的功能代码体积巨大,我们将其分离到 `threedlib` 中,在运行时扩展它并自定义 Chart 对象:

```ts
import { Runtime, corelib, threedlib, extend } from '@antv/g2';

const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
```

## 设置 z 通道、比例尺和坐标轴

在创建 Chart 时通过 `depth` 指定深度:
Expand All @@ -49,7 +60,7 @@ const chart = new Chart({
});
```

我们使用 [point3D](/spec/mark/point3-d) Mark 并选择 cube 作为 shape 进行绘制。
我们使用 [point3D](/spec/3d/point3-d) Mark 并选择 cube 作为 shape 进行绘制。
随后设置 z 通道、比例尺和坐标轴。

```ts
Expand Down Expand Up @@ -92,15 +103,125 @@ chart.render().then(() => {

效果如下:

<img alt="perspective" src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*KNCUQqzw2JsAAAAAAAAAAAAADmJ7AQ/original" width="400" />
```js | ob { pin: false }
(() => {
const renderer = new gWebgl.Renderer();
renderer.registerPlugin(new gPluginControl.Plugin());
renderer.registerPlugin(new gPlugin3d.Plugin());

const Chart = G2.extend(G2.Runtime, { ...G2.corelib(), ...G2.threedlib() });

// 初始化图表实例
const chart = new Chart({
theme: 'classic',
renderer,
depth: 400,
});

chart
.point3D()
.data({
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/bmw-prod/2c813e2d-2276-40b9-a9af-cf0a0fb7e942.csv',
})
.encode('x', 'Horsepower')
.encode('y', 'Miles_per_Gallon')
.encode('z', 'Weight_in_lbs')
.encode('color', 'Cylinders')
.encode('shape', 'cube')
.coordinate({ type: 'cartesian3D' })
.scale('x', { nice: true })
.scale('y', { nice: true })
.scale('z', { nice: true })
.legend(false)
.axis('x', { gridLineWidth: 2 })
.axis('y', { gridLineWidth: 2, titleBillboardRotation: -Math.PI / 2 })
.axis('z', { gridLineWidth: 2 });

chart.render().then(() => {
const { canvas } = chart.getContext();
const camera = canvas.getCamera();
camera.setPerspective(0.1, 5000, 45, 500 / 500);
camera.setType(g.CameraType.ORBITING);

// Add a directional light into scene.
const light = new gPlugin3d.DirectionalLight({
style: {
intensity: 3,
fill: 'white',
direction: [-1, 0, 1],
},
});
canvas.appendChild(light);
});

return chart.getContainer();
})();
```

我们还可以让相机固定视点进行一定角度的旋转,这里使用了 [rotate](https://g.antv.antgroup.com/api/camera/action#rotate)

```ts
camera.rotate(-20, -20, 0);
```

<img alt="orthographic" src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*7MdMQY-QksEAAAAAAAAAAAAADmJ7AQ/original" width="400" />
```js | ob { pin: false }
(() => {
const renderer = new gWebgl.Renderer();
renderer.registerPlugin(new gPluginControl.Plugin());
renderer.registerPlugin(new gPlugin3d.Plugin());

const Chart = G2.extend(G2.Runtime, { ...G2.corelib(), ...G2.threedlib() });

// 初始化图表实例
const chart = new Chart({
theme: 'classic',
renderer,
depth: 400,
});

chart
.point3D()
.data({
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/bmw-prod/2c813e2d-2276-40b9-a9af-cf0a0fb7e942.csv',
})
.encode('x', 'Horsepower')
.encode('y', 'Miles_per_Gallon')
.encode('z', 'Weight_in_lbs')
.encode('color', 'Cylinders')
.encode('shape', 'cube')
.coordinate({ type: 'cartesian3D' })
.scale('x', { nice: true })
.scale('y', { nice: true })
.scale('z', { nice: true })
.legend(false)
.axis('x', { gridLineWidth: 2 })
.axis('y', { gridLineWidth: 2, titleBillboardRotation: -Math.PI / 2 })
.axis('z', { gridLineWidth: 2 });

chart.render().then(() => {
const { canvas } = chart.getContext();
const camera = canvas.getCamera();
camera.setType(g.CameraType.ORBITING);
camera.rotate(-20, -20, 0);

// Add a directional light into scene.
const light = new gPlugin3d.DirectionalLight({
style: {
intensity: 3,
fill: 'white',
direction: [-1, 0, 1],
},
});
canvas.appendChild(light);
});

return chart.getContainer();
})();
```

## 添加光源

Expand All @@ -121,10 +242,6 @@ canvas.appendChild(light);

## 使用相机交互

3D 场景下的交互和 2D 场景有很大的不同,[g-plugin-control](https://g.antv.antgroup.com/plugins/control) 提供了 3D 场景下基于相机的交互。当我们拖拽画布时,会控制相机绕视点进行旋转操作,而鼠标滚轮的缩放会让相机进行 dolly 操作:

<img alt="perspective control" src="https://user-images.githubusercontent.com/3608471/261231166-30515059-aba7-49ae-b805-4fa9a5b95a27.gif" width="400" />

需要注意的是缩放操作在正交投影下是没有效果的,但旋转操作依然有效:
3D 场景下的交互和 2D 场景有很大的不同,[g-plugin-control](https://g.antv.antgroup.com/plugins/control) 提供了 3D 场景下基于相机的交互。当我们拖拽画布时,会控制相机绕视点进行旋转操作,而鼠标滚轮的缩放会让相机进行 dolly 操作。

<img alt="orthographic control" src="https://user-images.githubusercontent.com/3608471/261231186-7b4be85a-6d05-4abe-98b4-a9b35b9bff0e.gif" width="400" />
需要注意的是缩放操作在正交投影下是没有效果的,但旋转操作依然有效。
2 changes: 1 addition & 1 deletion site/docs/manual/introduction/why-g2.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ import { Runtime, corelib, extend } from '@antv/g2';
// 基于 corelib 对 Runtime 进行扩展
// 1. 增加类型(如果使用的 TypeScript)
// 2. 增加 Mark
const Chart = extend(Runtime, corelib);
const Chart = extend(Runtime, { ...corelib() });

const chart = new Chart({ container: 'container' });

Expand Down
6 changes: 6 additions & 0 deletions site/docs/spec/3d/point3D.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: point3D
order: 1
---

<embed src="@/docs/spec/3d/point3D.zh.md"></embed>
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ import { CameraType } from '@antv/g';
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Plugin as ThreeDPlugin, DirectionalLight } from '@antv/g-plugin-3d';
import { Plugin as ControlPlugin } from '@antv/g-plugin-control';
import { Chart } from '@antv/g2';
import { Runtime, corelib, threedlib, extend } from '@antv/g2';

const renderer = new WebGLRenderer();
renderer.registerPlugin(new ThreeDPlugin());
renderer.registerPlugin(new ControlPlugin());

const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
const chart = new Chart({
container: 'container',
theme: 'classic',
Expand Down Expand Up @@ -61,9 +62,6 @@ chart.render().then(() => {
const camera = canvas.getCamera();
camera.setType(CameraType.ORBITING);

// TODO: infer by depth in layout process.
canvas.document.documentElement.translate(0, 0, -200);

// Add a directional light into scene.
const light = new DirectionalLight({
style: {
Expand Down
Loading

0 comments on commit 716054a

Please sign in to comment.