Skip to content

Commit

Permalink
feat: add heatmap mark and shape
Browse files Browse the repository at this point in the history
  • Loading branch information
hustcc committed May 18, 2023
1 parent f961d24 commit 97d03d1
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 0 deletions.
4 changes: 4 additions & 0 deletions __tests__/unit/stdlib/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
WordCloud as WordCloudGeometry,
Gauge,
Density as DensityGeometry,
Heatmap,
} from '../../../src/mark';
import { Category10, Category20 } from '../../../src/palette';
import {
Expand Down Expand Up @@ -111,6 +112,7 @@ import {
Path as PathShape,
HollowPath,
Density as DensityShape,
Heatmap as HeatmapShape,
Shape as CustomShape,
} from '../../../src/shape';
import { Classic, ClassicDark, Academy } from '../../../src/theme';
Expand Down Expand Up @@ -370,6 +372,7 @@ describe('stdlib', () => {
'mark.wordCloud': WordCloudGeometry,
'mark.density': DensityGeometry,
'mark.gauge': Gauge,
'mark.heatmap': Heatmap,
'palette.category10': Category10,
'palette.category20': Category20,
'scale.linear': Linear,
Expand Down Expand Up @@ -446,6 +449,7 @@ describe('stdlib', () => {
'shape.path.path': PathShape,
'shape.path.hollow': HollowPath,
'shape.density.density': DensityShape,
'shape.heatmap.heatmap': HeatmapShape,
'theme.classic': Classic,
'theme.classicDark': ClassicDark,
'theme.academy': Academy,
Expand Down
69 changes: 69 additions & 0 deletions src/mark/heatmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { MarkComponent as MC, Vector2 } from '../runtime';
import { HeatmapMark } from '../spec';
import {
baseGeometryChannels,
basePostInference,
basePreInference,
createBandOffset,
tooltip2d,
} from './utils';

export type HeatmapOptions = Omit<HeatmapMark, 'type'>;

/**
* Draw heatmap with gradient.
*/
export const Heatmap: MC<HeatmapOptions> = (options) => {
return (index, scale, value, coordinate) => {
const { x: X, y: Y, x1: X1, y1: Y1, size: S } = value;
const [width, height] = coordinate.getSize();
const offset = createBandOffset(scale, value, options);
const xy: (i: number) => Vector2 = (i) => {
const x = X1 ? (+X[i] + +X1[i]) / 2 : +X[i];
const y = Y1 ? (+Y[i] + +Y1[i]) / 2 : +Y[i];
return [x, y];
};
const P = S
? Array.from(index, (i) => {
const [cx, cy] = xy(i);
const r = +S[i];
const a = r / width;
const b = r / height;
const p1: Vector2 = [cx - a, cy - b];
const p2: Vector2 = [cx + a, cy + b];
return [
coordinate.map(offset(p1, i)),
coordinate.map(offset(p2, i)),
] as Vector2[];
})
: Array.from(
index,
(i) => [coordinate.map(offset(xy(i), i))] as Vector2[],
);
return [index, P];
};
};

const shapes = ['heatmap'];

Heatmap.props = {
defaultShape: 'heatmap',
defaultLabelShape: 'label',
composite: false,
channels: [
...baseGeometryChannels({ shapes }),
{ name: 'x', required: true },
{ name: 'y', required: true },
{ name: 'size' },
],
preInference: [
...basePreInference(),
{ type: 'maybeZeroY' },
{ type: 'maybeZeroX' },
],
postInference: [
...basePostInference(),
{ type: 'maybeSize' },
...tooltip2d(),
],
};
2 changes: 2 additions & 0 deletions src/mark/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export { Tree } from './tree';
export { WordCloud } from './wordCloud';
export { Gauge } from './gauge';
export { Density } from './density';
export { Heatmap } from './heatmap';

export type { IntervalOptions } from './interval';
export type { RectOptions } from './rect';
Expand Down Expand Up @@ -55,3 +56,4 @@ export type { TreeOptions } from './tree';
export type { WordCloudOptions } from './wordCloud';
export type { GaugeOptions } from './gauge';
export type { DensityOptions } from './density';
export type { HeatmapOptions } from './heatmap';
33 changes: 33 additions & 0 deletions src/shape/heatmap/heatmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Image as GImage } from '@antv/g';
import { applyStyle, getShapeTheme } from '../utils';
import { select } from '../../utils/selection';
import { ShapeComponent as SC, Vector2 } from '../../runtime';

export type HeatmapOptions = Record<string, any>;

export const Heatmap: SC<HeatmapOptions> = (options) => {
const { ...style } = options;
return (points, value, coordinate, theme) => {
const { mark, shape, defaultShape, color, transform } = value;
const {
defaultColor,
fill = defaultColor,
stroke = defaultColor,
...shapeTheme
} = getShapeTheme(theme, mark, shape, defaultShape);

return select(new GImage())
.call(applyStyle, shapeTheme)
.style('src', '')
.style('transform', transform)
.call(applyStyle, style)
.node();
};
};

Box.props = {
defaultMarker: 'point',
defaultEnterAnimation: 'fadeIn',
defaultUpdateAnimation: 'morphing',
defaultExitAnimation: 'fadeOut',
};
2 changes: 2 additions & 0 deletions src/shape/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export { Label } from './label/label';
export { Path } from './path/path';
export { Hollow as HollowPath } from './path/hollow';
export { Density } from './density/density';
export { Heatmap } from './heatmap/heatmap';
export { Shape } from './shape/shape';

export type { RectOptions } from './interval/rect';
Expand Down Expand Up @@ -96,6 +97,7 @@ export type { ImageOptions } from './image/image';
export type { PolygonOptions } from './polygon/polygon';
export type { BoxOptions } from './box/box';
export type { ViolinOptions } from './box/violin';
export type { HeatmapOptions } from './heatmap/heatmap';

export type { LineOptions as LineXYOptions } from './lineXY/line';
export type { ConnectorOptions } from './connector/connector';
Expand Down
2 changes: 2 additions & 0 deletions src/spec/mark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export type MarkTypes =
| 'wordCloud'
| 'gauge'
| 'density'
| 'heatmap'
| MarkComponent;

export type ChannelTypes =
Expand Down Expand Up @@ -373,5 +374,6 @@ export type GaugeMark = BaseMark<
>;

export type DensityMark = BaseMark<'density', ChannelTypes | 'series'>;
export type HeatmapMark = BaseMark<'heatmap'>;

export type CustomMark = BaseMark<MarkComponent, ChannelTypes>;
4 changes: 4 additions & 0 deletions src/stdlib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
WordCloud as WordCloudGeometry,
Density as DensityGeometry,
Gauge,
Heatmap,
} from '../mark';
import { Category10, Category20 } from '../palette';
import {
Expand Down Expand Up @@ -112,6 +113,7 @@ import {
HollowPath,
Density as DensityShape,
Shape as CustomShape,
Heatmap as HeatmapShape,
} from '../shape';
import { Classic, ClassicDark, Academy } from '../theme';
import {
Expand Down Expand Up @@ -356,6 +358,7 @@ export function createLibrary(): G2Library {
'mark.tree': TreeGeometry,
'mark.wordCloud': WordCloudGeometry,
'mark.density': DensityGeometry,
'mark.heatmap': Heatmap,
'palette.category10': Category10,
'palette.category20': Category20,
'scale.linear': Linear,
Expand Down Expand Up @@ -432,6 +435,7 @@ export function createLibrary(): G2Library {
'shape.path.path': PathShape,
'shape.path.hollow': HollowPath,
'shape.density.density': DensityShape,
'shape.heatmap.heatmap': HeatmapShape,
'theme.classic': Classic,
'theme.classicDark': ClassicDark,
'theme.academy': Academy,
Expand Down

0 comments on commit 97d03d1

Please sign in to comment.