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: interval shape has max/min width #5123

Merged
merged 3 commits into from
May 30, 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions __tests__/plots/static/alphabet-interval-max-width-transposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { G2Spec } from '../../../src';

export function alphabetIntervalMaxWidthTransposed(): G2Spec {
return {
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
data: {
type: 'fetch',
value: 'data/alphabet.csv',
transform: [
{
type: 'slice',
start: 0,
end: 3,
},
],
},
encode: {
x: 'letter',
y: 'frequency',
color: 'steelblue',
},
scale: {
x: { padding: 0.1 },
},
style: {
maxWidth: 10,
},
axis: {
y: { labelFormatter: '.0%' },
},
};
}
32 changes: 32 additions & 0 deletions __tests__/plots/static/alphabet-interval-max-width.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { G2Spec } from '../../../src';

export function alphabetIntervalMaxWidth(): G2Spec {
return {
type: 'interval',
data: {
type: 'fetch',
value: 'data/alphabet.csv',
transform: [
{
type: 'slice',
start: 0,
end: 3,
},
],
},
encode: {
x: 'letter',
y: 'frequency',
color: 'steelblue',
},
scale: {
x: { padding: 0.1 },
},
style: {
maxWidth: 10,
},
axis: {
y: { labelFormatter: '.0%' },
},
};
}
26 changes: 26 additions & 0 deletions __tests__/plots/static/alphabet-interval-min-width-transposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { G2Spec } from '../../../src';

export function alphabetIntervalMinWidthTransposed(): G2Spec {
return {
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
data: {
type: 'fetch',
value: 'data/alphabet.csv',
},
encode: {
x: 'letter',
y: 'frequency',
color: 'steelblue',
},
scale: {
x: { padding: 0.9 },
},
style: {
minWidth: 10,
},
axis: {
y: { labelFormatter: '.0%' },
},
};
}
25 changes: 25 additions & 0 deletions __tests__/plots/static/alphabet-interval-min-width.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { G2Spec } from '../../../src';

export function alphabetIntervalMinWidth(): G2Spec {
return {
type: 'interval',
data: {
type: 'fetch',
value: 'data/alphabet.csv',
},
encode: {
x: 'letter',
y: 'frequency',
color: 'steelblue',
},
scale: {
x: { padding: 0.9 },
},
style: {
minWidth: 16,
},
axis: {
y: { labelFormatter: '.0%' },
},
};
}
4 changes: 4 additions & 0 deletions __tests__/plots/static/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export { alphabetInterval } from './alphabet-interval';
export { alphabetIntervalMaxWidth } from './alphabet-interval-max-width';
export { alphabetIntervalMinWidth } from './alphabet-interval-min-width';
export { alphabetIntervalMaxWidthTransposed } from './alphabet-interval-max-width-transposed';
export { alphabetIntervalMinWidthTransposed } from './alphabet-interval-min-width-transposed';
export { alphabetIntervalTitle } from './alphabet-interval-title';
export { alphabetIntervalLabelOverflowHide } from './alphabet-interval-label-overflow-hide';
export { alphabetIntervalLabelContrastReverse } from './alphabet-interval-label-contrast-reverse';
Expand Down
9 changes: 9 additions & 0 deletions __tests__/unit/utils/number.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { clamp } from '../../../src/utils/number';

describe('number', () => {
it('clame should return value between lower and upper', () => {
expect(clamp(1, 0, 2)).toBe(1);
expect(clamp(1, 2, 3)).toBe(2);
expect(clamp(5, 2, 3)).toBe(3);
});
});
2 changes: 2 additions & 0 deletions site/docs/spec/mark/interval.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ chart.render();

| 属性 | 描述 | 类型 | 默认值 |
| ---------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | --------- |
| minWidth | 柱子的最小宽度,单位为像素 | `number` | `-Infinity` |
| maxWidth | 柱子的最大宽度,单位为像素 | `number` | `Infinity` |
| radius | 外层矩形的四个圆角大小 | `number` \| `Function<number>` | 0 |
| radiusTopLeft | 外层左上角的圆角 | `number` \| `Function<number>` | 0 |
| radiusTopRight | 外层右上角的圆角 | `number` \| `Function<number>` | 0 |
Expand Down
18 changes: 18 additions & 0 deletions site/examples/general/interval/demo/column-maxwidth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Chart } from '@antv/g2';

const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});

chart
.interval()
.data([{ letter: 'A', frequency: 120 }])
.encode('x', 'letter')
.encode('y', 'frequency')
.scale('x', { padding: 0.5 })
// .style('minWidth', 500)
.style('maxWidth', 200);

chart.render();
10 changes: 9 additions & 1 deletion site/examples/general/interval/demo/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@
{
"filename": "column.ts",
"title": {
"zh": "条形图",
"zh": "柱形图",
"en": "Column Chart"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*vhCKQJ9UJX4AAAAAAAAAAAAADmJ7AQ/original"
},
{
"filename": "column-maxwidth.ts",
"title": {
"zh": "限制宽度的柱形图",
"en": "Column with maxWidth"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*fu-BSYg7U_kAAAAAAAAAAAAADmJ7AQ/original"
},
{
"filename": "bar.ts",
"title": {
Expand Down
34 changes: 29 additions & 5 deletions src/shape/interval/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { arc } from 'd3-shape';
import { Vector2, ShapeComponent as SC } from '../../runtime';
import { isPolar, isHelix, isTranspose } from '../../utils/coordinate';
import { select } from '../../utils/selection';
import { sub } from '../.././utils/vector';
import { sub } from '../../utils/vector';
import { clamp } from '../../utils/number';
import {
applyStyle,
getArcObject,
Expand All @@ -14,6 +15,14 @@ import {

export type ColorOptions = {
colorAttribute: 'fill' | 'stroke';
/**
* Minimum width of each interval.
*/
minWidth?: number;
/**
* Maximum width of each interval.
*/
maxWidth?: number;
[key: string]: any;
};

Expand All @@ -35,6 +44,8 @@ export function rect(
radiusBottomRight = radius,
radiusTopLeft = radius,
radiusTopRight = radius,
minWidth = -Infinity,
maxWidth = Infinity,
...rest
} = style;
if (!isPolar(coordinate) && !isHelix(coordinate)) {
Expand All @@ -53,11 +64,20 @@ export function rect(
const finalWidth = absWidth - (insetLeft + insetRight);
const finalHeight = absHeight - (insetTop + insetBottom);

const clampWidth = tpShape
? finalWidth
: clamp(finalWidth, minWidth, maxWidth);
const clampHeight = tpShape
? clamp(finalHeight, minWidth, maxWidth)
: finalHeight;
const clampX = finalX - (clampWidth - finalWidth) / 2;
const clampY = finalY - (clampHeight - finalHeight) / 2;

return select(new Rect({}))
.style('x', finalX)
.style('y', finalY)
.style('width', finalWidth)
.style('height', finalHeight)
.style('x', clampX)
.style('y', clampY)
.style('width', clampWidth)
.style('height', clampHeight)
.style('radius', [
radiusTopLeft,
radiusTopRight,
Expand Down Expand Up @@ -128,6 +148,8 @@ export const Color: SC<ColorOptions> = (options) => {
insetRight = inset,
insetBottom = inset,
insetTop = inset,
minWidth,
maxWidth,
...rest
} = style;
const { color = defaultColor, opacity } = value;
Expand Down Expand Up @@ -160,6 +182,8 @@ export const Color: SC<ColorOptions> = (options) => {
insetRight,
insetBottom,
insetTop,
minWidth,
maxWidth,
};

return (
Expand Down
11 changes: 10 additions & 1 deletion src/shape/interval/rect.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { ShapeComponent as SC } from '../../runtime';
import { Color } from './color';

export type RectOptions = Record<string, any>;
export type RectOptions = {
/**
* Minimum width of each interval.
*/
minWidth?: number;
/**
* Maximum width of each interval.
*/
maxWidth?: number;
};

/**
* Render rect in different coordinate and using color channel for stroke and fill attribute.
Expand Down
6 changes: 6 additions & 0 deletions src/utils/number.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Clamp number within the inclusive range within the lower and upper bounds.
*/
export function clamp(v: number, lower: number, upper: number): number {
return Math.max(lower, Math.min(v, upper));
}