Skip to content

Commit

Permalink
feat: interval shape has max/min width (#5123)
Browse files Browse the repository at this point in the history
* feat(interval): add minWidth maxWidth options for interval shape

* docs: add docs and demo

* test: add test case screenshots
  • Loading branch information
hustcc authored May 30, 2023
1 parent ea20755 commit 7b50766
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 7 deletions.
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));
}

0 comments on commit 7b50766

Please sign in to comment.