UNPKG

d3-3d

Version:

D3.js plugin for 3d visualization written in Typescript

469 lines • 16.5 kB
//#region src/types.d.ts export type Point2D = { x: number; y: number; }; export type Point3D = { x: number; y: number; z: number; }; export type ProjectedPoint = Point2D & { projected: Point2D; }; export type RotatedPoint = Point2D & { rotated: Point3D; }; export type TransformedPoint<T> = T & { rotated: Point3D; projected: Point2D; }; /** * The fields a shape carries on its array besides its points, such as a * `color` set with `Object.assign(points, { color })`. `.data` keeps them. * The indices of a tuple are string keys, so `${number}` leaves them out. */ export type ShapeFields<Shape extends unknown[]> = Omit<Shape, keyof unknown[] | `${number}`>; export interface RotationAngles { x: number; y: number; z: number; rotateCenter: Point3D; } export interface TransformOptions<Datum> { origin: Point2D; rotateCenter: Point3D; rotateX: number; rotateY: number; rotateZ: number; scale: number; /** The distance of the eye from the rotation center; `Infinity`, the default, is orthographic. */ perspective?: number; x: (point: Datum) => number; y: (point: Datum) => number; z: (point: Datum) => number; } /** * An axis aligned box in world space. * * `x`, `y` and `z` are the corner of the box, `w`, `d` and `h` its extent * along the three axes and `r` the corner radius of its plan outline. */ export interface IsoBoxSpec { x: number; y: number; z: number; w: number; d: number; h: number; r?: number; } /** * A rectangle in world space, described by its corner and the two vectors * that span it. */ export interface IsoPlaneSpec { origin: Point3D; u: Point3D; v: Point3D; } /** * One axis of a chart box in data units: its extent, from the first to the * last value of `domain`, and the values of its ticks. */ export interface AxisSpec { domain: number[]; ticks: number[]; } /** * The three axes of a chart box. */ export interface AxesSpec { x: AxisSpec; y: AxisSpec; z: AxisSpec; } /** * The viewport that frames a projected scene. */ export interface IsoFrame { viewBox: string; width: number; height: number; } //#endregion //#region src/shapes/shape.d.ts /** * The view of a scene: how it is turned, scaled and placed on the screen. * Every shape is a camera, and `camera3D()` is a camera without data. */ interface Camera3DInstance { scale(): number; scale(scale: number): this; origin(): Point2D; origin(origin: Point2D): this; perspective(): number; perspective(distance: number): this; rotateX(): number; rotateX(angle: number): this; rotateY(): number; rotateY(angle: number): this; rotateZ(): number; rotateZ(angle: number): this; rotationCenter(): Point3D; rotationCenter(center: Point3D): this; rotationCenter(center?: Point3D): this | Point3D; camera(camera: Camera3DInstance): this; unproject(point: Point2D, planePoint: Point3D, planeNormal: Point3D): Point3D | null; matrix(viewport?: { width: number; height: number; depth?: number; }): Float32Array; viewDirection(): Point3D; } interface ShapeInstance<Datum = Point3D> extends Camera3DInstance { x(): (point: Datum) => number; x(x: (point: Datum) => number): this; y(): (point: Datum) => number; y(y: (point: Datum) => number): this; z(): (point: Datum) => number; z(z: (point: Datum) => number): this; } /** * A camera without data: one view for several shapes, for a canvas or for a * WebGL shader. */ export declare function camera3D(): Camera3DInstance; //#endregion //#region src/shapes/axes.d.ts /** * One wall of the chart box: its four corners, whether it faces the camera * and its gridlines, one segment per tick inside the box. `axis` is the axis * the wall stands across and `side` the end of its domain the wall sits at, * 0 at the first value and 1 at the last. */ type AxisWall = TransformedPoint<Point3D>[] & { axis: keyof AxesSpec; side: 0 | 1; ccw: boolean; centroid: Point3D; grid: TransformedPoint<Point3D>[][]; }; /** * One edge of the chart box along an axis: its ticks, which keep their * value under the axis key, and the screen direction away from the box. * `sides` are the ends of the two other axes the edge runs at, in the order * of the walls they span, and `chosen` marks the edge `axes` puts the axis on. */ type AxisEdge = TransformedPoint<Point3D>[] & { axis: keyof AxesSpec; normal: Point2D; sides: [0 | 1, 0 | 1]; chosen: boolean; }; interface Axes3DInstance extends ShapeInstance<Point3D> { data(spec: AxesSpec): AxisWall[]; draw(wall: AxisWall): string; axes(spec: AxesSpec): AxisEdge[]; edges(spec: AxesSpec): AxisEdge[]; } export declare function axes3D(): Axes3DInstance; //#endregion //#region src/shapes/cubes.d.ts type CubeFaceName = "front" | "back" | "left" | "right" | "top" | "bottom"; type CubeFace<Datum = Point3D> = TransformedPoint<Datum>[] & { centroid: Point3D; ccw: boolean; face: CubeFaceName; }; type Cube<Datum = Point3D, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { faces: CubeFace<Datum>[]; centroid: Point3D; }; interface Cubes3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): Cube<Datum, Shape>[]; draw(face: TransformedPoint<Datum>[]): string; } export declare function cubes3D<Datum = Point3D>(): Cubes3DInstance<Datum>; //#endregion //#region src/shapes/gridPlanes.d.ts type GridPlane<Datum> = TransformedPoint<Datum>[] & { ccw: boolean; centroid: Point3D; plane: string; }; interface GridPlanes3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { rows(): number; rows(rows: number): this; data(data: Datum[]): GridPlane<Datum>[]; draw(gridPlanes: TransformedPoint<Datum>[]): string; } export declare function gridPlanes3D<Datum = Point3D>(): GridPlanes3DInstance<Datum>; //#endregion //#region src/shapes/iso.d.ts /** * The affine frame of a face: the transform that carries the local * coordinates of the face onto the screen. */ type IsoPlane = { matrix: string; }; /** * A projected box: the two visible paths and the frames of its faces. */ type IsoBox = { /** The rotated centre of the box, ready for `sort`. */ centroid: Point3D; /** The path of the visible side of the box. */ wall: string; /** The path of the top face. */ top: string; topPlane: IsoPlane; frontPlane: IsoPlane; sidePlane: IsoPlane; }; interface Iso3DInstance extends ShapeInstance<Point3D> { data(data: IsoBoxSpec[]): IsoBox[]; plane(spec: IsoPlaneSpec): IsoPlane; path(points: Point3D[]): string; project(points: Point3D[]): Point2D[]; frame(points: Point3D[], margin?: number, aspect?: number): IsoFrame; } export declare function iso3D(): Iso3DInstance; //#endregion //#region src/shapes/lines.d.ts type Line<Datum, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { centroid: Point3D; }; interface Lines3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): Line<Datum, Shape>[]; draw(line: TransformedPoint<Datum>[]): string; } export declare function lines3D<Datum = Point3D>(): Lines3DInstance<Datum>; //#endregion //#region src/shapes/lineStrips.d.ts type LineStrip<Datum, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { centroid: Point3D; }; interface LineStrips3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): LineStrip<Datum, Shape>[]; draw(lineStrip: TransformedPoint<Datum>[]): string; } export declare function lineStrips3D<Datum = Point3D>(): LineStrips3DInstance<Datum>; //#endregion //#region src/shapes/planes.d.ts type Plane<Datum, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { ccw: boolean; centroid: Point3D; }; interface Planes3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): Plane<Datum, Shape>[]; draw(plane: TransformedPoint<Datum>[]): string; } export declare function planes3D<Datum = Point3D>(): Planes3DInstance<Datum>; //#endregion //#region src/shapes/points.d.ts type Point<Datum> = TransformedPoint<Datum> & { centroid: Point3D; }; interface Points3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data(data: Datum[]): Point<Datum>[]; } export declare function points3D<Datum = Point3D>(): Points3DInstance<Datum>; //#endregion //#region src/shapes/polygons.d.ts type Polygon<Datum, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { ccw: boolean; centroid: Point3D; }; interface Polygons3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): Polygon<Datum, Shape>[]; draw(polygon: TransformedPoint<Datum>[]): string; } export declare function polygons3D<Datum = Point3D>(): Polygons3DInstance<Datum>; //#endregion //#region src/shapes/triangles.d.ts type Triangle<Datum, Shape extends Datum[] = Datum[]> = TransformedPoint<Datum>[] & ShapeFields<Shape> & { ccw: boolean; centroid: Point3D; }; interface Triangles3DInstance<Datum = Point3D> extends ShapeInstance<Datum> { data<Shape extends Datum[]>(data: Shape[]): Triangle<Datum, Shape>[]; draw(triangle: TransformedPoint<Datum>[]): string; } export declare function triangles3D<Datum = Point3D>(): Triangles3DInstance<Datum>; //#endregion //#region src/sort.d.ts interface HasCentroid { centroid: { z: number; }; } export declare function sort<T extends HasCentroid>(a: T, b: T): number; //#endregion //#region src/counter-clockwise.d.ts export declare function ccw<T>(polygon: ReadonlyArray<TransformedPoint<T>>): boolean; //#endregion //#region src/centroid.d.ts export declare function centroid<T>(polygon: ReadonlyArray<TransformedPoint<T>>): Point3D; //#endregion //#region src/normal.d.ts /** * The unit normal of a polygon, by Newell's method: exact for a flat * polygon of any size, an average for a slightly bent one. * * It points to the side from which the vertices run counter-clockwise on * the screen, where y grows downwards: the side `ccw` reports. So the faces * of `cubes3D` point outwards, and a face faces the camera where * `dot(normal, viewDirection) > 0`, or in perspective where * `dot(normal, eye − vertex) > 0`. * * Returns the zero vector for a polygon without an area. */ export declare function normal(polygon: ReadonlyArray<Point3D>): Point3D; //#endregion //#region src/box.d.ts /** * The eight corners of a box in the order `cubes3D` expects: front top * left, front bottom left, front bottom right and front top right, then * the same four at the back. * * The box stands on the point (x, y, z): its footprint is centered on x and * z, `width` along x and `depth` along z, and it rises `height` from y * upwards, towards -y as on the screen. Its front is the side at +z. * * `topWidth` and `topDepth` size the top apart from the footprint, for a * tapered shaft; a top of zero width is a ridge, one of zero size an apex. */ export declare function box(spec: { x: number; y: number; z: number; width: number; height: number; depth: number; topWidth?: number; topDepth?: number; }): Point3D[]; //#endregion //#region src/lathe.d.ts /** * The surface of revolution of a profile: the triangles that `triangles3D` * expects. * * The profile lies in the x-y plane, x the radius and y the height, and is * turned around the y axis in `segments` steps. Between two rings every step * is a quad of two triangles. A ring of radius 0 is a single point, so a * quad next to it is one triangle, and a profile that starts and ends on the * axis closes into a solid. * * The profile runs upwards, from a large y to a small one as on the screen. * Then every triangle runs counter-clockwise when it is seen from outside: * its `normal` points outwards and `ccw` tells the outside from the inside. * A profile that runs downwards turns the surface inside out. */ export declare function lathe(profile: ReadonlyArray<Point2D>, segments: number): Point3D[][]; //#endregion //#region src/sphere.d.ts /** * The triangles of a sphere around the point (x, y, z): the triangles that * `triangles3D` expects. * * A half circle from the bottom pole to the top one is turned around the y * axis by `lathe` in `segments` steps, and half as many bands, rounded up, * run from pole to pole, so the quads between them are close to square. The * poles lie on the axis, so the bands next to them close in fans. Below 3 * segments there is no sphere and the list is empty. * * Every triangle runs counter-clockwise when it is seen from outside: its * `normal` points outwards and `ccw` tells the front of the sphere from its * back. */ export declare function sphere(spec: { x: number; y: number; z: number; radius: number; }, segments: number): Point3D[][]; //#endregion //#region src/strips.d.ts /** * Cuts a polyline into strips of `size` points that share their end points, * the last one shorter if the points run out. * * `sort` orders a line strip by the depth of its middle, so a long line that * passes in front of a shape and behind it again is painted wrong as a * whole. Cut into strips, every piece sorts on its own depth. A `size` of 2 * cuts the line into its segments. */ export declare function strips<T>(points: ReadonlyArray<T>, size: number): T[][]; //#endregion //#region src/catmull-rom.d.ts /** * The uniform Catmull–Rom spline through `points`, `steps` samples per * segment: a smooth curve that passes through every point, ready for * `lineStrips3D`. * * The end points stand in for their missing neighbours, so the curve starts * on the first point and ends on the last. */ export declare function catmullRom(points: ReadonlyArray<Point3D>, steps: number): Point3D[]; //#endregion //#region src/axis-spec.d.ts /** * A continuous scale with ticks, such as d3's `scaleLinear`. */ interface TickScale { domain(): number[]; ticks(count?: number): number[]; } /** * One axis of `axes3D` from a scale: the domain of the scale and about * `count` of its ticks. * * Call `.nice()` on the scale first, so the box ends on a tick. */ export declare function axisSpec(scale: TickScale, count?: number): AxisSpec; //#endregion //#region src/transform.d.ts export declare function transform<Datum = Point3D>(data: Datum[], options: TransformOptions<Datum>): TransformedPoint<Datum>[]; //#endregion //#region src/projection-orthographic.d.ts interface OrthographicOptions { origin: Point2D; scale: number; } export declare function orthographic(d: Point3D, options: OrthographicOptions): Point2D; //#endregion //#region src/projection-perspective.d.ts interface PerspectiveOptions extends OrthographicOptions { rotateCenter: Point3D; /** The distance of the eye from the rotation center, in model units. */ distance: number; } /** * Projects a rotated point as seen from an eye `distance` in front of the * rotation center, on the rotated z axis that points towards the viewer. * * A point in the plane of the center keeps the scale of `orthographic`, a * nearer one is drawn larger and a farther one smaller, by * `k = distance / (distance − (z − center.z))`. An infinite distance gives * `k = 1`: the orthographic projection. The point has to lie in front of * the eye. */ export declare function perspective(d: Point3D, options: PerspectiveOptions): Point2D; //#endregion //#region src/projection-matrix.d.ts /** * Projects packed x, y, z triples through `matrix` into `out`: screen x, * screen y and depth, three numbers per point. Pass the same `out` every * frame to project a large point cloud without allocating. * * x and y are divided by w, which is 1 unless the matrix is perspective. * The depth is not, so it stays the rotated z that `sort` reads. */ export declare function projectPositions(positions: ArrayLike<number>, matrix: ArrayLike<number>, out?: Float32Array): Float32Array; //#endregion export type { Axes3DInstance, AxisEdge, AxisWall, Camera3DInstance, Cube, CubeFace, CubeFaceName, Cubes3DInstance, GridPlane, GridPlanes3DInstance, HasCentroid, Iso3DInstance, IsoBox, IsoPlane, Line, LineStrip, LineStrips3DInstance, Lines3DInstance, OrthographicOptions, PerspectiveOptions, Plane, Planes3DInstance, Point, Points3DInstance, Polygon, Polygons3DInstance, ShapeInstance, TickScale, Triangle, Triangles3DInstance }; //# sourceMappingURL=index.d.ts.map