Skip to content

Commit

Permalink
feat: sphere shape used in 3d lib #5375
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Aug 16, 2023
1 parent 909a88a commit 741d931
Show file tree
Hide file tree
Showing 24 changed files with 423 additions and 12 deletions.
5 changes: 4 additions & 1 deletion __tests__/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Canvas } from '@antv/g';
import { Canvas, CameraType } from '@antv/g';
import { Renderer as CanvasRenderer } from '@antv/g-canvas';
import { Plugin as DragAndDropPlugin } from '@antv/g-plugin-dragndrop';
import { Plugin as ControlPlugin } from '@antv/g-plugin-control';
Expand Down Expand Up @@ -162,6 +162,9 @@ function createSpecRender(object) {
renderer,
});

const camera = canvas.getCamera();
camera.setType(CameraType.ORBITING);

// @ts-ignore
window.__g_instances__ = [canvas];
const renderChart = mounted ? renderToMountedElement : render;
Expand Down
34 changes: 34 additions & 0 deletions __tests__/plots/static/body-point-scatter-plot-3d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { G2Spec } from '../../../src';

export function bodyPointScatterPlot3D(): G2Spec {
return {
type: 'point3D',
padding: 'auto',
data: {
type: 'fetch',
value: 'data/cars2.csv',
},
encode: {
x: 'Horsepower',
y: 'Miles_per_Gallon',
z: 'Weight_in_lbs',
size: 'Origin',
color: 'Cylinders',
shape: 'sphere',
},
scale: {
x: { nice: true },
y: { nice: true },
z: { nice: true },
},
coordinate: { type: 'cartesian3D', depth: 300 },
axis: {
x: { gridLineWidth: 3 },
y: { gridLineWidth: 3 },
z: { gridLineWidth: 3 },
},
// legend: false,
};
}

bodyPointScatterPlot3D.maxError = 100;
1 change: 1 addition & 0 deletions __tests__/plots/static/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { alphabetIntervalDataSort } from './alphabet-interval-data-sort';
export { alphabetIntervalFunnel } from './alphabet-interval-funnel';
export { alphabetIntervalPyramid } from './alphabet-interval-pyramid';
export { bodyPointScatterPlot } from './body-point-scatter-plot';
export { bodyPointScatterPlot3D } from './body-point-scatter-plot-3d';
export { bodyPointScatterPlotSizeOpacity } from './body-point-scatter-plot-size-opacity';
export { bodyPointScatterPlotOpacity } from './body-point-scatter-plot-opacity';
export { gammaRandomLineSortXQuantitative } from './gamma-random-line-sortx-quantitative';
Expand Down
5 changes: 5 additions & 0 deletions src/component/axis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,11 @@ const LinearAxisComponent: GCC<AxisOptions> = (options) => {
);

const internalAxisStyle = {
tickIsBillboard: true,
lineIsBillboard: true,
labelIsBillboard: true,
titleIsBillboard: true,
gridIsBillboard: true,
...defaultStyle,
...style,
...userDefinitions,
Expand Down
38 changes: 38 additions & 0 deletions src/component/axisZ.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { GuideComponentComponent as GCC } from '../runtime';
import { LinearAxis, AxisOptions } from './axis';

export type AxisXOptions = AxisOptions;

/**
* LinearAxis component bind to z scale.
*/
export const AxisZ: GCC<AxisXOptions> = (options) => {
return (...args) => {
// empirical value for crossPadding
const axis = LinearAxis(
Object.assign(
{},
{
crossPadding: 10,
},
options,
),
)(...args);
// const axisY = LinearAxis(Object.assign({}, { crossPadding: 10 }, options))(
// ...args,
// );

axis.setOrigin(0, 0, 0);
// rotate around Y axis
axis.rotate(0, -90, 0);

return axis;
};
};

AxisZ.props = {
...LinearAxis.props,
defaultPosition: 'bottom',
};

export function axisZConfig() {}
1 change: 1 addition & 0 deletions src/component/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { LinearAxis as AxisLinear, ArcAxis as AxisArc } from './axis';
export { AxisX } from './axisX';
export { AxisY } from './axisY';
export { AxisZ } from './axisZ';
export { AxisRadar } from './axisRadar';
export { LegendCategory } from './legendCategory';
export { LegendContinuous } from './legendContinuous';
Expand Down
11 changes: 11 additions & 0 deletions src/coordinate/cartesian3D.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Coordinate3DComponent as CC } from '../runtime';
import { Cartesian3DCoordinate } from '../spec';

export type Cartesian3DOptions = Cartesian3DCoordinate;

/**
* Default coordinate3D transformation for all charts.
*/
export const Cartesian3D: CC<Cartesian3DCoordinate> = () => [['cartesian3D']];

Cartesian3D.props = {};
2 changes: 2 additions & 0 deletions src/coordinate/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { Cartesian } from './cartesian';
export { Cartesian3D } from './cartesian3D';
export { Polar, getPolarOptions } from './polar';
export { Helix } from './helix';
export { Transpose } from './transpose';
Expand All @@ -9,6 +10,7 @@ export { Fisheye } from './fisheye';
export { Radar } from './radar';

export type { CartesianOptions } from './cartesian';
export type { Cartesian3DOptions } from './cartesian3D';
export type { PolarOptions } from './polar';
export type { HelixOptions } from './helix';
export type { TransposeOptions } from './transpose';
Expand Down
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export { corelib } from './core';
export { geolib } from './geo';
export { graphlib } from './graph';
export { plotlib } from './plot';
export { threedlib } from './threed';
export { stdlib } from './std';
export { litelib } from './lite';
2 changes: 2 additions & 0 deletions src/lib/std.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { corelib } from './core';
import { geolib } from './geo';
import { graphlib } from './graph';
import { plotlib } from './plot';
import { threedlib } from './threed';

export function stdlib() {
return {
...geolib(),
...graphlib(),
...plotlib(),
...threedlib(),
...corelib(),
} as const;
}
11 changes: 11 additions & 0 deletions src/lib/threed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Cartesian3D } from '../coordinate';
import { AxisZ } from '../component';
import { Point3D } from '../mark';

export function threedlib() {
return {
'coordinate.cartesian3D': Cartesian3D,
'component.axisZ': AxisZ,
'mark.point3D': Point3D,
} as const;
}
1 change: 1 addition & 0 deletions src/mark/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { Interval } from './interval';
export { Rect } from './rect';
export { Line } from './line';
export { Point } from './point';
export { Point3D } from './point3D';
export { Text } from './text';
export { Cell } from './cell';
export { Area } from './area';
Expand Down
84 changes: 84 additions & 0 deletions src/mark/point3D.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Coordinate3D } from '@antv/coord';
import { MarkComponent as MC, Vector2, Vector3 } from '../runtime';
import { PointMark } from '../spec';
import { MaybeZeroX, MaybeZeroY, MaybeSize } from '../transform';
import { Sphere, Cube } from '../shape';
import {
baseGeometryChannels,
basePostInference,
basePreInference,
createBandOffset,
tooltip3d,
} from './utils';

export type PointOptions = Omit<PointMark, 'type'>;

/**
* Convert value for each channel to point shapes.
* Calc the bbox of each point based on x, y and r.
* This is for allowing their radius can be affected by coordinate(e.g. fisheye).
*/
export const Point3D: MC<PointOptions> = (options) => {
return (index, scale, value, coordinate) => {
const { x: X, y: Y, z: Z, x1: X1, y1: Y1, size: S, dx: DX, dy: DY } = value;
const [width, height, depth] = (
coordinate as unknown as Coordinate3D
).getSize();
const offset = createBandOffset(scale, value, options);
const xyz: (i: number) => Vector3 = (i) => {
const dx = +(DX?.[i] || 0);
const dy = +(DY?.[i] || 0);
const x = X1 ? (+X[i] + +X1[i]) / 2 : +X[i];
const y = Y1 ? (+Y[i] + +Y1[i]) / 2 : +Y[i];
const cx = x + dx;
const cy = y + dy;
return [cx, cy, (Z[i] as number) || 0];
};
const P = S
? Array.from(index, (i) => {
const [cx, cy, cz] = xyz(i);
const r = +S[i];
const a = r / width;
const b = r / height;
const p1: Vector2 = [cx - a, cy - b];
const p2: Vector2 = [cx + a, cy + b];
return [
coordinate.map([...offset(p1, i), cz]),
coordinate.map([...offset(p2, i), cz]),
] as Vector3[];
})
: Array.from(index, (i) => {
const [cx, cy, cz] = xyz(i);
return [coordinate.map([...offset([cx, cy], i), cz])] as Vector3[];
});
return [index, P];
};
};

const shape = {
sphere: Sphere,
cube: Cube,
};

Point3D.props = {
defaultShape: 'sphere',
defaultLabelShape: 'label',
composite: false,
shape,
channels: [
...baseGeometryChannels({ shapes: Object.keys(shape) }),
{ name: 'x', required: true },
{ name: 'y', required: true },
{ name: 'z' },
{ name: 'series', scale: 'band' },
{ name: 'size', quantitative: 'sqrt' },
{ name: 'dx', scale: 'identity' },
{ name: 'dy', scale: 'identity' },
],
preInference: [
...basePreInference(),
{ type: MaybeZeroX },
{ type: MaybeZeroY },
],
postInference: [...basePostInference(), { type: MaybeSize }, ...tooltip3d()],
};
7 changes: 7 additions & 0 deletions src/mark/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ export function baseGeometryChannels(options: ChannelOptions = {}): Channel[] {
return [...baseChannels(options), { name: 'title', scale: 'identity' }];
}

export function tooltip3d() {
return [
{ type: MaybeTitle, channel: 'color' },
{ type: MaybeTooltip, channel: ['x', 'y', 'z'] },
];
}

export function tooltip2d() {
return [
{ type: MaybeTitle, channel: 'color' },
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,10 @@ function inferAxisComponentType(
if (isRadial(coordinates)) return ['axisArc', [scale]];
return [isTranspose(coordinates) ? 'axisX' : 'axisY', [scale]];
}
// Only support linear axis for z.
if (name.startsWith('z')) {
return ['axisZ', [scale]];
}
if (name.startsWith('position')) {
if (isRadar(coordinates)) return ['axisRadar', [scale]];
if (!isPolar(coordinates)) return ['axisY', [scale]];
Expand Down
24 changes: 19 additions & 5 deletions src/runtime/coordinate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Coordinate } from '@antv/coord';
import { Coordinate, Coordinate3D } from '@antv/coord';
import { G2View, G2CoordinateOptions, G2Library } from './types/options';
import { CoordinateComponent, CoordinateTransform } from './types/component';
import { useLibrary } from './library';
Expand Down Expand Up @@ -26,7 +26,9 @@ export function createCoordinate(
} = layout;
const { coordinates: partialTransform = [] } = partialOptions;
const transform = inferCoordinate(partialTransform);
const coordinate = new Coordinate({

const isCartesian3D = transform[0].type === 'cartesian3D';
const options = {
// @todo Find a better solution.
// Store more layout information for component.
...layout,
Expand All @@ -35,8 +37,17 @@ export function createCoordinate(
width: innerWidth - insetLeft - insetRight,
height: innerHeight - insetBottom - insetTop,
transformations: transform.map(useCoordinate).flat(),
});
return coordinate;
};

const coordinate = isCartesian3D
? // @ts-ignore
new Coordinate3D({
...options,
z: transform[0].z,
depth: transform[0].depth,
})
: new Coordinate(options);
return coordinate as Coordinate;
}

export function coordinate2Transform(node: G2View, library: G2Library): G2View {
Expand Down Expand Up @@ -112,6 +123,9 @@ export function isReflectY(coordinates: G2CoordinateOptions[]) {
function inferCoordinate(
coordinates: G2CoordinateOptions[],
): G2CoordinateOptions[] {
if (coordinates.find((d) => d.type === 'cartesian')) return coordinates;
if (
coordinates.find((d) => d.type === 'cartesian' || d.type === 'cartesian3D')
)
return coordinates;
return [...coordinates, { type: 'cartesian' }];
}
1 change: 1 addition & 0 deletions src/runtime/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export type Channel = {
};

export type Vector2 = [number, number];
export type Vector3 = [number, number, number];

export type BBox = {
x?: number;
Expand Down
14 changes: 13 additions & 1 deletion src/runtime/types/component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Coordinate, Transformation } from '@antv/coord';
import {
Coordinate,
Coordinate3D,
Transformation,
Transformation3D,
} from '@antv/coord';
import EventEmitter from '@antv/event-emitter';
import { DisplayObject, IAnimation as GAnimation, IDocument } from '@antv/g';
import {
Expand Down Expand Up @@ -115,6 +120,13 @@ export type CoordinateComponent<O = Record<string, unknown>> = G2BaseComponent<
CoordinateProps
>;

export type Coordinate3DTransform = Transformation3D[];
export type Coordinate3DProps = {
transform?: boolean;
};
export type Coordinate3DComponent<O = Record<string, unknown>> =
G2BaseComponent<Coordinate3DTransform, O, Coordinate3DProps>;

export type Palette = string[];
export type PaletteComponent<O = Record<string, unknown>> = G2BaseComponent<
Palette,
Expand Down
2 changes: 2 additions & 0 deletions src/shape/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export { Square as PointSquare } from './point/square';
export { Tick as PointTick } from './point/tick';
export { Triangle as PointTriangle } from './point/triangle';
export { TriangleDown as PointTriangleDown } from './point/triangleDown';
export { Sphere } from './point3D/sphere';
export { Cube } from './point3D/cube';
export { Vector as VectorShape } from './vector/vector';
export { Text as TextShape } from './text/text';
export { Badge as TextBadge } from './text/badge';
Expand Down
Loading

0 comments on commit 741d931

Please sign in to comment.