Skip to content

Commit

Permalink
feat(api): use api and spec together (#5074)
Browse files Browse the repository at this point in the history
* feat(api): use api and spec together

* feat(node): node.getNodeByType
  • Loading branch information
pearmini committed May 23, 2023
1 parent 826e000 commit e18cc84
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 40 deletions.
13 changes: 11 additions & 2 deletions __tests__/unit/api/node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ describe('Node', () => {
expect(n1.value).toEqual({ a: 2 });
});

it('node.getNodeByType(type) should return the first node.', () => {
const node = new Node({ a: 1 }, 'a');
const n1 = node.append(Node);
n1.type = 'b';
const n2 = node.append(Node);
n2.type = 'b';
expect(node.getNodeByType('b')).toBe(n1);
});

it('node.getNodesByType(type) should get the children node by type.', () => {
const node = new Node({ a: 1 }, 'node1');
const n1 = node.append(Node);
Expand All @@ -96,15 +105,15 @@ describe('Node', () => {
let targetNodes = node.getNodesByType('node1');

expect(targetNodes.length).toEqual(1);
expect(targetNodes[0]).toEqual(node);
expect(targetNodes[0]).toBe(node);

const n1 = node.append(Node);
n1.type = 'n';
const n2 = n1.append(Node);
n2.type = 'n';
targetNodes = node.getNodesByType('n');
expect(targetNodes.length).toEqual(2);
expect(targetNodes[0]).toEqual(n1);
expect(targetNodes[0]).toBe(n1);

expect(node.getNodesByType('undefined')).toEqual([]);
});
Expand Down
187 changes: 185 additions & 2 deletions __tests__/unit/api/options.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Chart } from '../../../src';
import { Point } from '../../../src/api/mark/mark';

describe('API and Options', () => {
it('', () => {
describe('chart api and options', () => {
it('chart.options({...}) should create node instance from spec.', () => {
const chart = new Chart({});

chart.options({
Expand All @@ -18,5 +19,187 @@ describe('API and Options', () => {
y: 'sold',
},
});

expect(chart.getNodeByType('view')).toBeDefined();
expect(chart.getNodeByType('interval')).toBeDefined();
});

it('chart.options({...}) should bubble view options', () => {
const chart = new Chart({});

chart.options({
type: 'interval',
width: 100,
height: 100,
padding: 10,
paddingLeft: 10,
paddingRight: 10,
paddingBottom: 10,
paddingTop: 10,
inset: 10,
insetLeft: 10,
insetRight: 10,
insetTop: 10,
insetBottom: 10,
margin: 10,
marginLeft: 10,
marginRight: 10,
marginTop: 10,
marginBottom: 10,
autoFit: 10,
theme: 10,
});

expect(chart.options()).toEqual({
type: 'view',
width: 100,
height: 100,
padding: 10,
paddingLeft: 10,
paddingRight: 10,
paddingBottom: 10,
paddingTop: 10,
inset: 10,
insetLeft: 10,
insetRight: 10,
insetTop: 10,
insetBottom: 10,
margin: 10,
marginLeft: 10,
marginRight: 10,
marginTop: 10,
marginBottom: 10,
autoFit: 10,
theme: 10,
children: [{ type: 'interval' }],
});
});

it('chart.options({...}) should create nested node tree from spec.', () => {
const chart = new Chart({});
const options = {
type: 'spaceFlex',
flex: [1, 2],
children: [
{
type: 'spaceLayer',
children: [
{
type: 'view',
children: [
{ type: 'interval', data: [2, 3, 4] },
{ type: 'point' },
],
},
],
},
{ type: 'interval', data: [1, 2, 3] },
],
};

chart.options(options);

expect(chart.options()).toEqual(options);
expect(chart.getNodeByType('point')).toBeInstanceOf(Point);
});

it('chart.options({...}) should update node with same height and index.', () => {
const chart = new Chart({});

chart.options({
type: 'view',
children: [{ type: 'interval' }],
});

chart.options({
children: [{ data: [1, 2, 3] }],
});

expect(chart.getNodeByType('interval').value.data).toEqual([1, 2, 3]);
});

it('chart.options({...}) should update nested node tree.', () => {
const chart = new Chart({});

chart.options({
type: 'spaceFlex',
flex: [1, 2],
children: [
{
type: 'spaceLayer',
children: [
{
type: 'view',
children: [
{ type: 'interval', data: [2, 3, 4] },
{ type: 'point' },
],
},
],
},
{ type: 'interval', data: [1, 2, 3] },
],
});

chart.options({
flex: [2, 3, 4],
children: [
{ children: [{ children: [{}, { data: [1, 2, 3] }] }] },
{ data: [2, 3, 4], scale: { x: { nice: true } } },
],
});

expect(chart.options()).toEqual({
type: 'spaceFlex',
flex: [2, 3, 4],
children: [
{
type: 'spaceLayer',
children: [
{
type: 'view',
children: [
{ type: 'interval', data: [2, 3, 4] },
{ type: 'point', data: [1, 2, 3] },
],
},
],
},
{ type: 'interval', data: [2, 3, 4], scale: { x: { nice: true } } },
],
});
});

it('chart.options({...}) should transform node.', () => {
const chart = new Chart({});

chart.options({
type: 'view',
children: [
{ type: 'interval', scale: { x: { nice: true } }, data: [1, 2, 3] },
],
});

chart.options({
type: 'view',
children: [{ type: 'line', data: [4, 5, 6] }],
});

const line = chart.getNodeByType('line');
expect(line.type).toBe('line');
expect(line.value).toEqual({ data: [4, 5, 6] });
});

it('chart.options({...}) should update node tree specified by API.', () => {
const chart = new Chart({});

const interval = chart.interval().data([1, 2, 3]);

chart.options({
type: 'view',
children: [{ data: [2, 3, 4] }],
});

expect(interval.data()).toEqual([2, 3, 4]);
});
});
28 changes: 13 additions & 15 deletions src/api/chart.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IRenderer, RendererPlugin, Canvas as GCanvas } from '@antv/g';
import { Renderer as CanvasRenderer } from '@antv/g-canvas';
import { Plugin as DragAndDropPlugin } from '@antv/g-plugin-dragndrop';
import { debounce, deepMix } from '@antv/util';
import { debounce } from '@antv/util';
import EventEmitter from '@antv/event-emitter';
import { G2Context, render, destroy } from '../runtime';
import { ViewComposition } from '../spec';
Expand All @@ -27,6 +27,8 @@ import {
removeContainer,
sizeOf,
optionsOf,
updateRoot,
VIEW_KEYS,
} from './utils';

export const G2_CHART_KEY = 'G2_CHART_KEY';
Expand Down Expand Up @@ -84,7 +86,6 @@ export class Chart extends View<ChartOptions> {
private _container: HTMLElement;
private _context: G2Context;
private _emitter: EventEmitter;
private _options: G2ViewTree;
private _width: number;
private _height: number;
private _renderer: IRenderer;
Expand Down Expand Up @@ -161,20 +162,11 @@ export class Chart extends View<ChartOptions> {
* @returns {Chart|G2ViewTree}
*/
options(options?: G2ViewTree): Chart | G2ViewTree {
if (arguments.length === 0) {
return this._options || optionsOf(this);
}
this._options = deepMix(this._options || optionsOf(this), options);
if (arguments.length === 0) return optionsOf(this);
updateRoot(this, options);
return this;
}

// @todo Remove it when implement updateRoot.
changeData(data: any): Promise<Chart> {
// Update options data.
this.options({ data });
return super.changeData(data);
}

getContainer(): HTMLElement {
return this._container;
}
Expand Down Expand Up @@ -206,7 +198,7 @@ export class Chart extends View<ChartOptions> {
clear() {
const options = this.options();
this.emit(ChartEvent.BEFORE_CLEAR);
this._options = {};
this._reset();
destroy(options, this._context, false);
this.emit(ChartEvent.AFTER_CLEAR);
}
Expand All @@ -215,7 +207,7 @@ export class Chart extends View<ChartOptions> {
const options = this.options();
this.emit(ChartEvent.BEFORE_DESTROY);
this._unbindAutoFit();
this._options = {};
this._reset();
destroy(options, this._context, true);
removeContainer(this._container);
this.emit(ChartEvent.AFTER_DESTROY);
Expand Down Expand Up @@ -252,6 +244,12 @@ export class Chart extends View<ChartOptions> {
return finished;
}

private _reset() {
this.type = 'view';
this.value = {};
this.children = [];
}

private _onResize = debounce(() => {
this.forceFit();
}, 300);
Expand Down
11 changes: 10 additions & 1 deletion src/api/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Chart } from './chart';
function bfs(node: Node, callback?: (...args: any[]) => void) {
const discovered: Node[] = [node];
while (discovered.length) {
const currentNode = discovered.pop();
const currentNode = discovered.shift();
callback && callback(currentNode);
const children = currentNode.children || [];
for (const child of children) {
Expand Down Expand Up @@ -115,6 +115,15 @@ export class Node<
return nodes;
}

getNodeByType(type: string): Node {
let node = null;
bfs(this, (current: Node) => {
if (node) return;
if (type === current.type) node = current;
});
return node;
}

/**
* Apply specified callback to the node value.
*/
Expand Down

0 comments on commit e18cc84

Please sign in to comment.