Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(transform): add pack padding and direction #5964

Merged
merged 4 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading