Skip to content

Commit

Permalink
feat: 增加Pictorial组件
Browse files Browse the repository at this point in the history
  • Loading branch information
xuying.xu committed May 28, 2024
1 parent 450be5a commit 675d874
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/f2/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ export {
withCandlestick,
CandlestickView,
} from './candlestick';
export { default as Pictorial, PictorialProps } from './pictorial';
4 changes: 4 additions & 0 deletions packages/f2/src/components/pictorial/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Pictorial, { PictorialProps } from './pictorial';

export { PictorialProps, Pictorial };
export default Pictorial;
109 changes: 109 additions & 0 deletions packages/f2/src/components/pictorial/pictorial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { jsx } from '@antv/f-engine';
import { GeometryProps } from '../geometry';
import { withInterval } from '../interval';
import { DataRecord } from '../../chart/Data';
import { deepMix } from '@antv/util';

const parsePercent = (value: number | string, total: number) => {
if (typeof value === 'number') {
return value;
} else if (typeof value === 'string') {
if (value.endsWith('%')) {
return (parseFloat(value) / 100) * total;
} else {
return 0;
}
}
};

export interface PictorialProps<TRecord extends DataRecord = DataRecord>
extends GeometryProps<TRecord> {
symbol?: any;
symbolSize?: (number | string)[];
symbolOffset?: (number | string)[];
}

export default class Pictorial extends withInterval({}) {
props: PictorialProps;
// 默认初始大小
symbolDefaultSize: number = 400;

defalutBound(type) {
switch (type) {
case 'ellipse':
return {
rx: this.symbolDefaultSize / 2,
ry: this.symbolDefaultSize / 2,
};

default:
return {
width: this.symbolDefaultSize,
height: this.symbolDefaultSize,
};
}
}

preSymbolBound(symbol) {
symbol.props = deepMix(
{
style: this.defalutBound(symbol?.type),
},
symbol.props
);

return {
width: this.symbolDefaultSize,
height: this.symbolDefaultSize,
};
}

parsePercentArray(array, [w, h]) {
const x = parsePercent(array[0], w);
const y = parsePercent(array[1], h);
return [x, y];
}

render() {
const { props, context } = this;
const { px2hd } = context;
const { symbol, symbolSize = ['100%', '100%'], symbolOffset = [0, 0] } = px2hd(props);
const records = this.mapping();

const { width: symbolW, height: symbolH } = this.preSymbolBound(symbol);

return (
<group>
{records.map((record) => {
const { key, children } = record;
return (
<group key={key}>
{children.map((item) => {
const [width, height] = this.parsePercentArray(symbolSize, [
item.xMax - item.xMin,
item.yMax - item.yMin,
]);
const [offsetX, offsetY] = this.parsePercentArray(symbolOffset, [width, height]);
const position = [item.xMin + offsetX, item.yMin + offsetY];

const symbolScale = [width / symbolW, height / symbolH];
const transform = `translate(${position[0]},${position[1]}) scale(${symbolScale[0]},${symbolScale[1]})`;

return deepMix(
{
props: {
style: {
transform,
},
},
},
symbol
);
})}
</group>
);
})}
</group>
);
}
}
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.
134 changes: 134 additions & 0 deletions packages/f2/test/components/pictorial/basic.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { jsx } from '../../../src';
import { Canvas, Chart, Pictorial, Axis, Tooltip } from '../../../src';
import { createContext, delay, gestureSimulator } from '../../util';
const context = createContext();

const symbol = (
<image
style={{
src:
'https://gw.alipayobjects.com/zos/finxbff/compress-tinypng/mNyB6MXFwnxLMwzfEWHYt/juxingbeifen_6.png',
}}
/>
);

const symbolTop = (
<image
style={{
src:
'https://gw.alipayobjects.com/zos/finxbff/compress-tinypng/VV9WVNGexcXLVYpQxjBFH/tuoyuanxingbeifen_13.png',
}}
/>
);

const symbolBottom = (
<image
style={{
src:
'https://gw.alipayobjects.com/zos/finxbff/compress-tinypng/76LdyFixxEmUqrGG6rmCG/tuoyuanxingbeifen_32.png',
}}
/>
);
const data = [
{
x: '产品1',
value: 4927,
bValue: 0,
},
{
x: '产品2',
value: 11607,
bValue: 0,
},
];

describe('pictorial', () => {
it('image symbol', async () => {
const { props } = (
<Canvas context={context} pixelRatio={1}>
<Chart data={data}>
<Axis field="value" min={0}></Axis>

<Pictorial
x="x"
y="bValue"
symbol={symbolBottom}
symbolOffset={[0, '-50%']}
symbolSize={['100%', '20px']}
/>

<Pictorial x="x" y="value" symbol={symbol} />
<Pictorial
x="x"
y="value"
symbol={symbolTop}
symbolSize={['100%', '20px']}
symbolOffset={[0, '-50%']}
/>
</Chart>
</Canvas>
);

const canvas = new Canvas(props);
await canvas.render();

await delay(1000);
expect(context).toMatchImageSnapshot();
});

it('ellipse symbol', async () => {
const { props } = (
<Canvas context={context} pixelRatio={1}>
<Chart data={data}>
<Axis field="value" min={0}></Axis>

<Pictorial
x="x"
y="bValue"
symbol={
<ellipse
style={{
fill: 'l(90) 0:#1f7eff 1:#64adff',
}}
/>
}
symbolOffset={['50%', 0]}
symbolSize={['100%', '40px']}
/>

<Pictorial
x="x"
y="value"
symbol={
<rect
style={{
fill: 'l(90) 0:#9cc1ff 1:#ecf5ff',
fillOpacity: 0.9,
}}
/>
}
/>
<Pictorial
x="x"
y="value"
symbol={
<ellipse
style={{
fill: 'l(90) 0:#1f7eff 1:#64adff',
}}
/>
}
symbolSize={['100%', '40px']}
symbolOffset={['50%', 0]}
/>
</Chart>
</Canvas>
);

const canvas = new Canvas(props);
await canvas.render();

await delay(1000);
expect(context).toMatchImageSnapshot();
});
});

0 comments on commit 675d874

Please sign in to comment.