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: add auto adjust for polar #43

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions __tests__/unit/transforms/polar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,17 @@ describe('Polar', () => {
expect(v1).toBe(100);
expect(v2).toBeCloseTo(20);
});

test.only('polar() maps normalized value to normalized polar coordinate with auto adjust', () => {
const coord = new Coordinate({
width: 200,
height: 300,
transformations: [['polar', (-11 / 10) * Math.PI, (1 / 10) * Math.PI, 0, 1, true]],
});

expect(coord.map([0.7, 0.58])).toEqual([0.6324264444247805, 0.5211192142721996]);
const [v1, v2] = coord.invert([0.6324264444247805, 0.5211192142721996]);
expect(v1).toBeCloseTo(0.7);
expect(v2).toBeCloseTo(0.58);
});
});
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ module.exports = [
format: 'umd',
sourcemap: false,
},
plugins: [resolve(), typescript(), commonjs(), uglify()],
plugins: [resolve(), commonjs(), typescript(), uglify()],
},
];
23 changes: 21 additions & 2 deletions src/coordinate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,28 @@ export class Coordinate {
* Returns the center of the bounding box of the coordinate.
* @returns [centerX, centerY]
*/
public getCenter(): [number, number] {
public getBoxCenter(): [number, number] {
const { x, y, width, height } = this.options;
return [(x * 2 + width) / 2, (y * 2 + height) / 2];
return [x + width / 2, y + height / 2];
}

/**
* Returns the radial center when polar exists, or else returns center of bounding box of the coordinate.
* @returns [centerX, centerY]
*/
public getCenter(): [number, number] {
const { x, y, width, height, transformations } = this.options;

// If has polar transoformer.
const polar = transformations.find((transformation) => transformation[0] === 'polar');
if (polar) {
const [name, ...params] = polar;
const createTransformer = this.transformers[name];
// @ts-ignore
const { offsetX, offsetY } = createTransformer([...params], x, y, width, height);
return [x + (width / 2) * (1 + offsetX), y + (height / 2) * (1 - offsetY)];
}
return this.getBoxCenter();
}

/**
Expand Down
17 changes: 10 additions & 7 deletions src/transforms/polar.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Linear } from '@antv/scale';
import { Vector2, CreateTransformer } from '../type';
import { adjustAngle } from '../utils';
import { adjustAngle, autoPolar } from '../utils';

/**
* Maps normalized value to normalized polar coordinate at the center of the bounding box.
* It is used for Nightingale Rose Diagram.
* @param params [x0, x1, y0, y1]
* @param params [x0, x1, y0, y1, auto]
* @param x x of the the bounding box of coordinate
* @param y y of the the bounding box of coordinate
* @param width width of the the bounding box of coordinate
* @param height height of the the bounding box of coordinate
* @returns transformer
*/
export const polar: CreateTransformer = (params, x, y, width, height) => {
const [startAngle, endAngle, innerRadius, outerRadius] = params as number[];
const [startAngle, endAngle, innerRadius, outerRadius, auto] = params as [number, number, number, number, boolean];
const radius = new Linear({
range: [innerRadius, outerRadius],
});
Expand All @@ -24,19 +24,22 @@ export const polar: CreateTransformer = (params, x, y, width, height) => {
const aspect = height / width;
const sx = aspect > 1 ? 1 : aspect;
const sy = aspect > 1 ? 1 / aspect : 1;
const [offsetX, offsetY, radiusOffset] = auto ? autoPolar(startAngle, endAngle, width, height) : [0, 0, 0];

return {
offsetX,
offsetY,
transform(vector: Vector2) {
const [v1, v2] = vector;
const theta = angle.map(v1);
const r = radius.map(v2);

const r = radius.map(v2) * (1 + radiusOffset);
// 根据长宽比调整,使得极坐标系内切外接矩形
const x = r * Math.cos(theta) * sx;
const y = r * Math.sin(theta) * sy;

// 将坐标的原点移动到外接矩形的中心,并且将长度设置为一半
const dx = x * 0.5 + 0.5;
const dy = y * 0.5 + 0.5;
const dx = x * 0.5 + 0.5 * (1 + offsetX);
const dy = y * 0.5 + 0.5 * (1 - offsetY);
return [dx, dy];
},
untransform(vector: Vector2) {
Expand Down
2 changes: 1 addition & 1 deletion src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type Translate = ['translate', number, number];
type Cartesian = ['cartesian'];
type Custom = ['custom', TransformCallback];
type Matrix = ['matrix', Matrix3];
type Polar = ['polar', number, number, number, number];
type Polar = ['polar', number, number, number, number, boolean?];
type Transpose = ['transpose'];
type Scale = ['scale', number, number];
type ShearX = ['shear.x', number];
Expand Down
53 changes: 53 additions & 0 deletions src/utils/auto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Sample to calucation the polar bbox.
*/
function getPolarBbox(startTheta: number, endTheta: number) {
if (Math.abs(endTheta - startTheta) >= Math.PI * 2) {
return {
minX: -0.5,
maxX: 0.5,
minY: -0.5,
maxY: 0.5,
};
}

const xs = [0, Math.cos(startTheta), Math.cos(endTheta)];
const ys = [0, Math.sin(startTheta), Math.sin(endTheta)];

for (let i = Math.min(startTheta, endTheta); i < Math.max(startTheta, endTheta); i += Math.PI / 18) {
xs.push(Math.cos(i));
ys.push(Math.sin(i));
}

return {
minX: Math.min(...xs) / 2,
maxX: Math.max(...xs) / 2,
minY: Math.min(...ys) / 2,
maxY: Math.max(...ys) / 2,
};
}
/**
* Adjust x,y and radius in polar automatically.
*/
export function autoPolar(startTheta: number, endTheta: number, width: number, height: number) {
const { minX, maxX, minY, maxY } = getPolarBbox(startTheta, endTheta);

const w = maxX - minX;
const h = maxY - minY;

const max = Math.max(width, height);

// Calucate base on width.
const offsetRadius = Math.min(width / w, height / h) / max - 1;
const offsetX = Math.abs(maxX + minX) * (1 + offsetRadius);
const offsetY = Math.abs(maxY + minY) * (1 + offsetRadius);

return [
// x
offsetX * (Math.abs(maxX) - Math.abs(minX) ? -1 : 1),
// y
offsetY * (Math.abs(maxY) - Math.abs(minY) ? -1 : 1),
// r
offsetRadius,
];
}
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { compose } from './compose';
export { isMatrix } from './isMatrix';
export { extend } from './extend';
export { adjustAngle } from './adjustAngle';
export { autoPolar } from './auto';