Skip to content

Commit

Permalink
refactor(shape): api
Browse files Browse the repository at this point in the history
  • Loading branch information
pearmini committed Jun 8, 2023
1 parent 58ac49c commit 68113b3
Show file tree
Hide file tree
Showing 68 changed files with 462 additions and 502 deletions.
4 changes: 2 additions & 2 deletions __tests__/plots/api/register-shape.ts
Expand Up @@ -4,8 +4,8 @@ import { register, Chart } from '../../../src/api';
export function registerShape(context) {
const { container, canvas } = context;
register('shape.interval.triangle', (style) => {
return (P, value, coordinate, theme) => {
const { defaultColor } = theme;
return (P, value, defaults) => {
const { color: defaultColor } = defaults;
const [p0, p1, p2, p3] = P;
const pm = [(p0[0] + p1[0]) / 2, p0[1]];
const { color = defaultColor } = value;
Expand Down
1 change: 1 addition & 0 deletions src/interaction/elementHighlight.ts
Expand Up @@ -45,6 +45,7 @@ export function elementHighlight(
...subObject(state.active, 'link'),
});
const [appendBackground, removeBackground, isBackground] = renderBackground({
document: root.ownerDocument,
scale,
coordinate,
background,
Expand Down
1 change: 1 addition & 0 deletions src/interaction/elementSelect.ts
Expand Up @@ -46,6 +46,7 @@ export function elementSelect(
});

const [appendBackground, removeBackground] = renderBackground({
document: root.ownerDocument,
background,
coordinate,
scale,
Expand Down
3 changes: 2 additions & 1 deletion src/interaction/utils.ts
Expand Up @@ -335,6 +335,7 @@ export function offsetTransform(element, offset, coordinate) {
}

export function renderBackground({
document,
background,
scale,
coordinate,
Expand Down Expand Up @@ -384,7 +385,7 @@ export function renderBackground({
].map((d) => coordinate.map(d));
const { __data__: data } = element;
const { y: dy, y1: dy1 } = data;
return rect(points, { y: dy, y1: dy1 }, coordinate, style);
return rect(document, points, { y: dy, y1: dy1 }, coordinate, style);
};

// Shape without ordinal style.
Expand Down
5 changes: 3 additions & 2 deletions src/mark/gauge.ts
Expand Up @@ -60,13 +60,14 @@ function getTextContent(textStyle, { target, total }) {
return content ? content(target, total) : target.toString();
}

const indicatorShape: SC<ColorOptions> = (options) => {
const indicatorShape: SC<ColorOptions> = (options, context) => {
const { shape, radius, ...style } = options;
const pointerStyle = subObject(style, 'pointer');
const pinStyle = subObject(style, 'pin');
const { shape: pointerShape, ...resPointerStyle } = pointerStyle;
const { shape: pinShape, ...resPinStyle } = pinStyle;
return (points, value, coordinate, theme) => {
const { coordinate, theme } = context;
return (points, value) => {
// Invert points.
const invertedPoints = points.map((p) => coordinate.invert(p));
// Get new coordinate.
Expand Down
15 changes: 11 additions & 4 deletions src/runtime/library.ts
@@ -1,5 +1,6 @@
import { IDocument } from '@antv/g';
import { error } from '../utils/helper';
import { G2ComponentOptions, G2Library } from './types/options';
import { G2ComponentOptions, G2Context, G2Library } from './types/options';
import {
G2Component,
G2ComponentNamespaces,
Expand All @@ -13,15 +14,21 @@ export function useLibrary<
>(
namespace: G2ComponentNamespaces,
library: G2Library,
): [(options: O) => V, (type: O['type']) => C] {
): [(options: O, context?) => V, (type: O['type']) => C] {
const create = (type: O['type']) => {
if (typeof type !== 'string') return type;
const key = `${namespace}.${type}`;
return library[key] || error(`Unknown Component: ${key}`);
};
const use = (options: O) => {
const use = (options: O, context?) => {
const { type, ...rest } = options;
return create(type)({ ...rest });
return create(type)(rest, context);
};
return [use, create];
}

export function documentOf(library: G2Context): IDocument {
const { canvas, group } = library;
if (group) return group.ownerDocument;
return canvas.document;
}
64 changes: 55 additions & 9 deletions src/runtime/plot.ts
Expand Up @@ -28,7 +28,7 @@ import {
} from './constant';
import { coordinate2Transform, createCoordinate } from './coordinate';
import { computeLayout, placeComponents } from './layout';
import { useLibrary } from './library';
import { documentOf, useLibrary } from './library';
import { initializeMark } from './mark';
import {
applyScale,
Expand All @@ -39,6 +39,7 @@ import {
import { applyDataTransform } from './transform';
import {
G2MarkState,
G2Theme,
G2ViewDescriptor,
G2ViewInstance,
Primitive,
Expand Down Expand Up @@ -914,7 +915,7 @@ async function plotView(
}

// Plot label for this view.
plotLabel(view, selection, transitions, library);
plotLabel(view, selection, transitions, library, context);
}

/**
Expand All @@ -925,6 +926,7 @@ function plotLabel(
selection: Selection,
transitions: GAnimation[],
library: G2Library,
context: G2Context,
) {
const [useLabelTransform] = useLibrary<
G2LabelTransformOptions,
Expand All @@ -943,7 +945,13 @@ function plotLabel(
// Get all labels for this view.
const labels = Array.from(markState.entries()).flatMap(([mark, state]) => {
const { labels: labelOptions = [], key } = mark;
const shapeFunction = createLabelShapeFunction(mark, state, view, library);
const shapeFunction = createLabelShapeFunction(
mark,
state,
view,
library,
context,
);
const elements = selection
.select(`#${key}`)
.selectAll(className(ELEMENT_CLASS_NAME))
Expand Down Expand Up @@ -1100,6 +1108,7 @@ function createLabelShapeFunction(
state: G2MarkState,
view: G2ViewDescriptor,
library: G2Library,
context: G2Context,
): (options: Record<string, any>) => DisplayObject {
const [useShape] = useLibrary<G2ShapeOptions, ShapeComponent, Shape>(
'shape',
Expand All @@ -1108,8 +1117,18 @@ function createLabelShapeFunction(
const { data: abstractData } = mark;
const { data: visualData, defaultLabelShape } = state;
const point2d = visualData.map((d) => d.points);

// Assemble Context.
const { theme, coordinate } = view;
const shapeContext = {
...context,
document: documentOf(context),
theme,
coordinate,
};

return (options) => {
// Computed values from data and styles.
const { index, points } = options;
const datum = abstractData[index];
const {
Expand All @@ -1125,8 +1144,13 @@ function createLabelShapeFunction(
const { shape = defaultLabelShape, text, ...style } = visualOptions;
const f = typeof formatter === 'string' ? format(formatter) : formatter;
const value = { ...style, text: f(text, datum, index, abstractData) };
const shapeFunction = useShape({ type: `label.${shape}`, ...style });
return shapeFunction(points, value, coordinate, theme, point2d);

// Params for create shape.
const shapeOptions = { type: `label.${shape}`, ...style };
const shapeFunction = useShape(shapeOptions, shapeContext);
const defaults = getDefaultsStyle(theme, 'label', shape, 'label');

return shapeFunction(points, value, defaults, point2d);
};
}

Expand Down Expand Up @@ -1256,10 +1280,16 @@ function createMarkShapeFunction(
const point2d = data.map((d) => d.points);
const { theme, coordinate } = view;
const { type: markType, style = {} } = mark;
const shapeContext = {
...context,
document: documentOf(context),
coordinate,
theme,
};
return (data) => {
const { shape: styleShape = defaultShape } = style;
const { shape = styleShape, points, seriesIndex, index: i, ...v } = data;
const value = { ...v, shape, mark: markType, defaultShape, index: i };
const value = { ...v, index: i };

// Get data-driven style.
// If it is a series shape, such as area and line,
Expand All @@ -1275,14 +1305,30 @@ function createMarkShapeFunction(
valueOf(d, abstractDatum, I, abstractData),
);

const shapeFunction = useShape({
const shapeOptions = {
...visualStyle,
type: shapeName(mark, shape),
});
return shapeFunction(points, value, coordinate, theme, point2d, context);
};
const shapeFunction = useShape(shapeOptions, shapeContext);

const defaults = getDefaultsStyle(theme, markType, shape, defaultShape);
return shapeFunction(points, value, defaults, point2d);
};
}

function getDefaultsStyle(
theme: G2Theme,
mark: string | MarkComponent,
shape: string,
defaultShape: string,
) {
if (typeof mark !== 'string') return;
const { defaultColor } = theme;
const markTheme = theme[mark] || {};
const shapeTheme = markTheme[shape] || markTheme[defaultShape];
return Object.assign({ color: defaultColor }, shapeTheme);
}

function createAnimationFunction(
type: 'enter' | 'exit' | 'update',
mark: G2Mark,
Expand Down
17 changes: 11 additions & 6 deletions src/runtime/types/component.ts
@@ -1,6 +1,6 @@
import { Coordinate, Transformation } from '@antv/coord';
import EventEmitter from '@antv/event-emitter';
import { DisplayObject, IAnimation as GAnimation } from '@antv/g';
import { DisplayObject, IAnimation as GAnimation, IDocument } from '@antv/g';
import {
G2Theme,
G2ViewInstance,
Expand Down Expand Up @@ -78,8 +78,9 @@ export type G2BaseComponent<
R = any,
O = Record<string, unknown> | void,
P = Record<string, unknown>,
C = Record<string, unknown>,
> = {
(options?: O): R;
(options?: O, context?: C): R;
props?: P;
};

Expand Down Expand Up @@ -142,21 +143,25 @@ export type Shape = (
index?: number;
[key: string]: any;
},
coordinate: Coordinate,
theme: G2Theme,
defaults?: Record<string, any>,
point2d?: Vector2[][],
context?: G2Context,
) => DisplayObject;
export type ShapeProps = {
defaultMarker?: string;
defaultEnterAnimation?: string;
defaultUpdateAnimation?: string;
defaultExitAnimation?: string;
};
export type ShapeContext = {
document: IDocument;
coordinate: Coordinate;
[key: string]: any; // TODO
};
export type ShapeComponent<O = Record<string, unknown>> = G2BaseComponent<
Shape,
O,
ShapeProps
ShapeProps,
ShapeContext
>;

export type Theme = G2Theme;
Expand Down
7 changes: 4 additions & 3 deletions src/shape/area/area.ts
Expand Up @@ -5,10 +5,11 @@ import { Curve } from './curve';

export type AreaOptions = Record<string, any>;

export const Area: SC<AreaOptions> = (options) => {
return (P, value, coordinate, theme) => {
export const Area: SC<AreaOptions> = (options, context) => {
const { coordinate } = context;
return (...params) => {
const curve = isPolar(coordinate) ? curveLinearClosed : curveLinear;
return Curve({ curve: curve, ...options })(P, value, coordinate, theme);
return Curve({ curve: curve, ...options }, context)(...params);
};
};

Expand Down
49 changes: 20 additions & 29 deletions src/shape/area/curve.ts
@@ -1,30 +1,12 @@
import { area, areaRadial, CurveFactory } from 'd3-shape';
import { Path } from '@antv/g';
import { select } from '../../utils/selection';
import { isPolar, isTranspose } from '../../utils/coordinate';
import { Vector2, ShapeComponent as SC } from '../../runtime';
import { angleWithQuadrant, sub, dist } from '../../utils/vector';
import {
applyStyle,
computeGradient,
getShapeTheme,
getTransform,
} from '../utils';
import { applyStyle, computeGradient, getTransform } from '../utils';
import { subObject } from '../../utils/helper';
import { createElement } from '../../utils/createElement';

const DoubleArea = createElement((g) => {
const { areaPath, connectPath, areaStyle, connectStyle } = g.attributes;
select(g)
.maybeAppend('connect-path', () => new Path({}))
.style('d', connectPath)
.call(applyStyle, connectStyle);
select(g)
.maybeAppend('area-path', () => new Path({}))
.style('d', areaPath)
.call(applyStyle, areaStyle);
});

/**
* Given a points sequence, split it into an array of defined points
* and an array of undefined segments.
Expand Down Expand Up @@ -76,22 +58,31 @@ export type CurveOptions = {
[key: string]: any;
};

export const Curve: SC<CurveOptions> = (options) => {
const DoubleArea = createElement((g) => {
const { areaPath, connectPath, areaStyle, connectStyle } = g.attributes;
const document = g.ownerDocument;
select(g)
.maybeAppend('connect-path', () => document.createElement('path', {}))
.style('d', connectPath)
.call(applyStyle, connectStyle);
select(g)
.maybeAppend('area-path', () => document.createElement('path', {}))
.style('d', areaPath)
.call(applyStyle, areaStyle);
});

export const Curve: SC<CurveOptions> = (options, context) => {
const {
curve,
gradient = false,
defined = (d) => !Number.isNaN(d) && d !== undefined && d !== null,
connect: connectNulls = false,
...style
} = options;
return (P, value, coordinate, theme) => {
const { mark, shape, defaultShape } = value;
const { defaultColor, ...defaults } = getShapeTheme(
theme,
mark,
shape,
defaultShape,
);
const { coordinate, document } = context;

return (P, value, defaults) => {
const { color: defaultColor } = defaults;
const {
color = defaultColor,
seriesColor: sc,
Expand All @@ -115,7 +106,7 @@ export const Curve: SC<CurveOptions> = (options) => {
const missing = !!MS.length;

const getPathNode = (path) => {
return select(new Path({}))
return select(document.createElement('path', {}))
.style('d', path)
.call(applyStyle, finalStyle)
.node();
Expand Down

0 comments on commit 68113b3

Please sign in to comment.