Skip to content

Commit

Permalink
feat(transform): add pack padding and direction (#5964)
Browse files Browse the repository at this point in the history
* fix: fix the tooltip shown on one element line chart

* fix: change test examples

* feat: rebase v5

* fix: code style
  • Loading branch information
Runtus authored Dec 21, 2023
1 parent 019e984 commit 082606c
Show file tree
Hide file tree
Showing 8 changed files with 33,220 additions and 45 deletions.
16,538 changes: 16,538 additions & 0 deletions __tests__/integration/snapshots/static/titanicPointPackSharedDataPadding.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16,538 changes: 16,538 additions & 0 deletions __tests__/integration/snapshots/static/titanicPointPackSharedRowData.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions __tests__/plots/static/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,5 @@ export { premierLeagueTable } from './premier-league-table';
export { singlePointBasic } from './single-point-basic';
export { populationFlowChordDefault } from './population-flow-chord-default';
export { aaplLineRrangeXY } from './aapl-line-rangeXY';
export { titanicPointPackSharedRowData } from './titanic-point-pack-shared-row-data';
export { titanicPointPackSharedDataPadding } from './titanic-point-pack-shared-data-padding';
41 changes: 41 additions & 0 deletions __tests__/plots/static/titanic-point-pack-shared-data-padding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { G2Spec } from '../../../src';

export function titanicPointPackSharedDataPadding(): G2Spec {
return {
type: 'facetRect',
data: {
type: 'fetch',
value: 'data/titanic.csv',
transform: [
{
type: 'sortBy',
fields: ['survived'],
},
{
type: 'map',
callback: ({ survived, ...d }) => ({
...d,
survived: survived + '',
}),
},
],
},
shareData: true,
encode: {
x: 'pclass',
},
children: [
{
type: 'point',
transform: [{ type: 'pack', padding: 2 }],
legend: {
color: { labelFormatter: (d) => (d === '1' ? 'Yes' : 'No') },
},
encode: {
color: 'survived',
shape: 'point',
},
},
],
};
}
41 changes: 41 additions & 0 deletions __tests__/plots/static/titanic-point-pack-shared-row-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { G2Spec } from '../../../src';

export function titanicPointPackSharedRowData(): G2Spec {
return {
type: 'facetRect',
data: {
type: 'fetch',
value: 'data/titanic.csv',
transform: [
{
type: 'sortBy',
fields: ['survived'],
},
{
type: 'map',
callback: ({ survived, ...d }) => ({
...d,
survived: survived + '',
}),
},
],
},
shareData: true,
encode: {
x: 'pclass',
},
children: [
{
type: 'point',
transform: [{ type: 'pack', direction: 'row' }],
legend: {
color: { labelFormatter: (d) => (d === '1' ? 'Yes' : 'No') },
},
encode: {
color: 'survived',
shape: 'point',
},
},
],
};
}
7 changes: 7 additions & 0 deletions site/docs/spec/transform/pack.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ facetRect

chart.render();
```

## 选项

| 属性 | 描述 | 类型 | 默认值 |
|-------------------|------------------------------------------------|---------------------|-----------------------|
| padding | 每个元素之间的间距,单位为px | `number` | `0` |
| direction | 元素的堆叠方向 | `'row' \| 'col'` | `col` |
2 changes: 2 additions & 0 deletions src/spec/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ export type FlexXTransform = {

export type PackTransform = {
type?: 'pack';
padding?: number;
direction?: 'row' | 'col';
};

export type Reducer =
Expand Down
96 changes: 51 additions & 45 deletions src/transform/pack.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,74 @@
import { deepMix } from '@antv/util';
import { TransformComponent as TC } from '../runtime';
import { calcBBox } from '../utils/vector';
import { PackTransform } from '../spec';

export type PackOptions = Record<string, unknown>;
export type PackOptions = Omit<PackTransform, 'type'>;

function modifier(P, count, layout) {
const pcount = P.length;
if (pcount === 0) return [];
function pack(options: PackOptions) {
const { padding = 0, direction = 'col' } = options;
return (P, count, layout) => {
const pcount = P.length;
if (pcount === 0) return [];

// col * row >= count
// row is close to col * aspect, so
// col * (col * aspect) >= count
const { innerWidth, innerHeight } = layout;
const aspect = innerHeight / innerWidth;
let col = Math.ceil(Math.sqrt(count / aspect));
// col * row >= count
// row is close to col * aspect, so
// col * (col * aspect) >= count
const { innerWidth, innerHeight } = layout;
const aspect = innerHeight / innerWidth;
let col = Math.ceil(Math.sqrt(count / aspect));

// Increase col to avoid total height of packed shape
// being large than height of bbox.
let size = innerWidth / col;
let row = Math.ceil(count / col);
let h0 = row * size;
while (h0 > innerHeight) {
col = col + 1;
size = innerWidth / col;
row = Math.ceil(count / col);
h0 = row * size;
}
// Increase col to avoid total height of packed shape
// being large than height of bbox.
let size = innerWidth / col;
let row = Math.ceil(count / col);
let h0 = row * size;
while (h0 > innerHeight) {
col = col + 1;
size = innerWidth / col;
row = Math.ceil(count / col);
h0 = row * size;
}

// Some offset to increase the space usage.
const space = innerHeight - row * size;
const intervalY = row <= 1 ? 0 : space / (row - 1);
const [offsetX, offsetY] =
row <= 1
? [(innerWidth - pcount * size) / (pcount - 1), (innerHeight - size) / 2]
: [0, 0];
// Some offset to increase the space usage.
const space = innerHeight - row * size;
const intervalY = row <= 1 ? 0 : space / (row - 1);
const [offsetX, offsetY] =
row <= 1
? [
(innerWidth - pcount * size) / (pcount - 1),
(innerHeight - size) / 2,
]
: [0, 0];

return P.map((points, m) => {
const [x, y, width, height] = calcBBox(points);
return P.map((points, m) => {
const [x, y, width, height] = calcBBox(points);
const i = direction === 'col' ? m % col : Math.floor(m / row);
const j = direction === 'col' ? Math.floor(m / col) : m % row;

const i = m % col;
const j = Math.floor(m / col);
const newX = i * size;
const newY = (row - j - 1) * size + space;

const newX = i * size;
const newY = (row - j - 1) * size + space;
const sx = (size - padding) / width;
const sy = (size - padding) / height;

const sx = size / width;
const sy = size / height;

// Translate the shape and mark to make sure the center of
// shape is overlap before and after scale transformation.
const tx = newX - x + offsetX * i;
const ty = newY - y - intervalY * j - offsetY;
return `translate(${tx}, ${ty}) scale(${sx}, ${sy})`;
});
// Translate the shape and mark to make sure the center of
// shape is overlap before and after scale transformation.
const tx = newX - x + offsetX * i + (1 / 2) * padding;
const ty = newY - y - intervalY * j - offsetY + (1 / 2) * padding;
return `translate(${tx}, ${ty}) scale(${sx}, ${sy})`;
});
};
}

/**
* Uniform pack to avid overlap.
* @todo Improve or change algorithm to increase space usage.
* @todo Take some special case into account.
*/
export const Pack: TC<PackOptions> = () => {
export const Pack: TC<PackOptions> = (options) => {
return (I, mark) => {
return [I, deepMix({}, mark, { modifier, axis: false })];
return [I, deepMix({}, mark, { modifier: pack(options), axis: false })];
};
};

Expand Down

0 comments on commit 082606c

Please sign in to comment.