Skip to content

Commit

Permalink
支持 Surface Plot (#10)
Browse files Browse the repository at this point in the history
* feat: surface

* feat: add surface plot
  • Loading branch information
xiaoiver authored Nov 15, 2023
1 parent 8ce5c5b commit 35afc15
Show file tree
Hide file tree
Showing 13 changed files with 640 additions and 13 deletions.
53 changes: 44 additions & 9 deletions 3d/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ The [threed](https://github.com/antvis/G2/blob/v5/src/lib/std.ts) lib for G2.
Create a renderer and register relative plugins which provides 3D rendering capabilities:

```ts
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Plugin as ThreeDPlugin } from '@antv/g-plugin-3d';
import { Plugin as ControlPlugin } from '@antv/g-plugin-control';
import { Renderer as WebGLRenderer } from "@antv/g-webgl";
import { Plugin as ThreeDPlugin } from "@antv/g-plugin-3d";
import { Plugin as ControlPlugin } from "@antv/g-plugin-control";

const renderer = new WebGLRenderer();
renderer.registerPlugin(new ThreeDPlugin());
Expand All @@ -19,12 +19,12 @@ renderer.registerPlugin(new ControlPlugin());
Then extend the runtime of G2 with 3D lib:

```ts
import { threedlib } from '@antv/g2-extension-3d';
import { Runtime, corelib, extend } from '@antv/g2';
import { threedlib } from "@antv/g2-extension-3d";
import { Runtime, corelib, extend } from "@antv/g2";

const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
const chart = new Chart({
container: 'container',
container: "container",
renderer,
depth: 400,
});
Expand All @@ -33,20 +33,55 @@ const chart = new Chart({
Now we can use 3D marks like this:

```ts
chart
.point3D()
.data({});
chart.point3D().data({});
```

⚠️ For now we only support Chart API and leave the Spec usage in the future.

## Scatter

[DEMO](https://g2.antv.antgroup.com/examples#threed-scatter)

<img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*KNCUQqzw2JsAAAAAAAAAAAAADmJ7AQ/original" alt="scatter" width="400"/>

## Line

[DEMO](https://g2.antv.antgroup.com/examples#threed-line)

<img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*Ak1iTZ1dpI0AAAAAAAAAAAAADmJ7AQ/original" alt="line" width="400"/>

## Bar

[DEMO](https://g2.antv.antgroup.com/examples#threed-bar)

<img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ZgMYT50XDQkAAAAAAAAAAAAADmJ7AQ/original" alt="surface" width="400"/>

## Surface

[DEMO](https://g2.antv.antgroup.com/examples#threed-surface)

<img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*4LJeR4SqvEoAAAAAAAAAAAAADmJ7AQ/original" alt="surface" width="400"/>

Use surface3D mark:

```ts
chart
.surface3D()
.data(points)
.encode("x", "x")
.encode("y", "y")
.encode("z", "z")
.encode("color", "z")
.coordinate({ type: "cartesian3D" })
.scale("x", { nice: true })
.scale("y", { nice: true })
.scale("z", { nice: true })
.scale("color", { palette: "spectral" })
.legend(false)
.axis("x", { gridLineWidth: 1 })
.axis("y", { gridLineWidth: 1, titleBillboardRotation: -Math.PI / 2 })
.axis("z", { gridLineWidth: 1 })
.style({
palette: "spectral",
});
```
4 changes: 2 additions & 2 deletions 3d/__tests__/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
}

async function render() {
if (typeof preClear === "function") preClear();
// if (typeof preClear === "function") preClear();
const fn = plots[select.value];
const [finished, destroy] = await fn({ container: "container" });
const { finished, destroy } = await fn({ container: "container" });
preClear = destroy;
}
</script>
Expand Down
1 change: 1 addition & 0 deletions 3d/__tests__/plots/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { Line } from "./line";
export { LinePerspective } from "./line-perspective";
export { Bar } from "./bar";
export { BarPerspective } from "./bar-perspective";
export { Surface } from "./surface";
63 changes: 63 additions & 0 deletions 3d/__tests__/plots/surface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { CameraType } from "@antv/g";
import { Renderer as WebGLRenderer } from "@antv/g-webgl";
import { Plugin as ThreeDPlugin } from "@antv/g-plugin-3d";
import { Plugin as ControlPlugin } from "@antv/g-plugin-control";
import { Runtime, extend, corelib } from "@antv/g2";
import { threedlib } from "../../src";
import diric from "dirichlet";

const size = 100;
const points: { x: number; y: number; z: number }[] = [];
for (let i = 0; i < size + 1; i++) {
for (let j = 0; j < size + 1; j++) {
points.push({
x: i,
y: j,
z: 0.1 * size * diric(5, (5.0 * (i - size / 2)) / size) * diric(5, (5.0 * (j - size / 2)) / size),
});
}
}

export function Surface(context) {
const { container } = context;

// Create a WebGL renderer.
const renderer = new WebGLRenderer();
renderer.registerPlugin(new ThreeDPlugin());
renderer.registerPlugin(new ControlPlugin());

const Chart = extend(Runtime, { ...corelib(), ...threedlib() });
const chart = new Chart({
container,
renderer,
width: 500,
height: 500,
depth: 300,
});

chart
.surface3D()
.data(points)
.encode("x", "x")
.encode("y", "y")
.encode("z", "z")
.encode("color", "z")
.coordinate({ type: "cartesian3D" })
.scale("x", { nice: true })
.scale("y", { nice: true })
.scale("z", { nice: true })
.scale("color", { palette: "spectral" })
.legend(false)
.axis("x", { gridLineWidth: 1 })
.axis("y", { gridLineWidth: 1, titleBillboardRotation: -Math.PI / 2 })
.axis("z", { gridLineWidth: 1 });

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

return { finished, destroy: () => chart.destroy() };
}
16 changes: 14 additions & 2 deletions 3d/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@antv/g2-extension-3d",
"version": "0.1.1",
"version": "0.1.2",
"main": "lib/index.js",
"module": "esm/index.js",
"unpkg": "dist/index.umd.min.js",
Expand Down Expand Up @@ -30,20 +30,32 @@
"@antv/g-webgl": "^1.9.8",
"@antv/g-plugin-3d": "^1.9.5",
"@antv/g-plugin-control": "^1.9.5",
"@antv/util": "^3.3.5"
"@antv/util": "^3.3.5",
"ndarray": "^1.0.19",
"ndarray-fill": "latest",
"ndarray-ops": "latest",
"ndarray-pack": "latest",
"ndarray-gradient": "latest",
"typedarray-pool": "latest",
"colormap": "latest"
},
"peerDependencies": {
"@antv/g": "^5.18.19",
"@antv/g2": "^5.1.8"
},
"devDependencies": {
"@types/d3-array": "3.0.5",
"@types/ndarray": "^1.0.14",
"@types/typedarray-pool": "^1.1.5",
"@types/ndarray-ops": "^1.2.7",
"@types/colormap": "^2.3.4",
"@antv/g": "^5.18.19",
"@antv/g2": "^5.1.8",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-terser": "^0.4.3",
"@rollup/plugin-typescript": "^11.1.3",
"dirichlet": "latest",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"rimraf": "^5.0.5",
Expand Down
2 changes: 2 additions & 0 deletions 3d/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { runtime } from "@antv/g";
import { Interval3D } from "./mark/interval3D";
import { Point3D } from "./mark/point3D";
import { Line3D } from "./mark/line3D";
import { Surface3D } from "./mark/surface3D";
import { Cartesian3D } from "./coordinate/coordinate3D";
import { AxisZ } from "./component/axisZ";

Expand All @@ -14,5 +15,6 @@ export function threedlib() {
"mark.point3D": Point3D,
"mark.line3D": Line3D,
"mark.interval3D": Interval3D,
"mark.surface3D": Surface3D,
} as const;
}
2 changes: 2 additions & 0 deletions 3d/src/mark/interval3D.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Interval3D.props = {
{ name: "series", scale: "band" },
{ name: "size" },
],
// @ts-ignore
preInference: [...basePreInference(), { type: MaybeZeroX }, { type: MaybeZeroY1 }, { type: MaybeZeroZ }],
// @ts-ignore
postInference: [...basePostInference(), { type: MaybeSize }, ...tooltip3d()],
};
2 changes: 2 additions & 0 deletions 3d/src/mark/line3D.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ Line3D.props = {
{ name: "size" },
{ name: "series", scale: "identity" },
],
// @ts-ignore
preInference: [...basePreInference(), { type: MaybeSeries }],
// @ts-ignore
postInference: [...basePostInference(), ...tooltip3d()],
interaction: {
shareTooltip: false,
Expand Down
2 changes: 2 additions & 0 deletions 3d/src/mark/point3D.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Point3D.props = {
{ name: "dy", scale: "identity" },
{ name: "dz", scale: "identity" },
],
// @ts-ignore
preInference: [...basePreInference(), { type: MaybeZeroX }, { type: MaybeZeroY }, { type: MaybeZeroZ }],
// @ts-ignore
postInference: [...basePostInference(), { type: MaybeSize }, ...tooltip3d()],
};
56 changes: 56 additions & 0 deletions 3d/src/mark/surface3D.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Coordinate3D } from "@antv/coord";
import { MarkComponent as MC, BaseMark, Vector3, MaybeZeroX, MaybeZeroY, MaybeZeroZ, MaybeSize } from "@antv/g2";
import { Surface } from "../shape/surface3D/surface";
import { baseGeometryChannels, basePostInference, basePreInference, tooltip3d } from "./utils";

// @ts-ignore
type Surface3DMark = BaseMark<"surface">;

export type Surface3DOptions = Omit<Surface3DMark, "type">;

export const Surface3D: MC<Surface3DOptions> = (options) => {
return (index, _, value, coordinate) => {
const { x: X, y: Y, z: Z } = value;
// const [width, height, depth] = (
// coordinate as unknown as Coordinate3D
// ).getSize();
const xyz: (i: number) => Vector3 = (i) => {
const x = +X[i] || 0;
const y = +Y[i] || 0;
const z = +Z[i || 0];
return [x, y, z];
};
const P = Array.from(index, (i) => {
const [cx, cy, cz] = xyz(i);
return [...(coordinate as unknown as Coordinate3D).map([cx, cy, cz])] as Vector3;
});
return [[0], [P]];
};
};

const shape = {
surface: Surface,
};

Surface3D.props = {
defaultShape: "surface",
defaultLabelShape: "label",
composite: false,
shape,
channels: [
...baseGeometryChannels({ shapes: Object.keys(shape) }),
{ name: "x", required: true },
{ name: "y", required: true },
{ name: "z", required: true },
// { name: 'color', scale: 'identity', required: true },
],
// @ts-ignore
preInference: [...basePreInference(), { type: MaybeZeroX }, { type: MaybeZeroY }, { type: MaybeZeroZ }],
// @ts-ignore
postInference: [...basePostInference(), { type: MaybeSize }, ...tooltip3d()],
interaction: {
shareTooltip: false,
seriesTooltip: false,
crosshairs: false,
},
};
Loading

0 comments on commit 35afc15

Please sign in to comment.