diff --git a/packages/f2-next/src/components/geometry/index.tsx b/packages/f2-next/src/components/geometry/index.tsx
index d35d1bf0d..fe1760a8f 100644
--- a/packages/f2-next/src/components/geometry/index.tsx
+++ b/packages/f2-next/src/components/geometry/index.tsx
@@ -78,7 +78,7 @@ class Geometry extends Component implements AttrMixin {
const { chart } = props;
const attrOptions = {};
- ATTRS.forEach(attrName => {
+ ATTRS.forEach((attrName) => {
if (props[attrName]) {
attrOptions[attrName] = this.createAttrOption(props[attrName]);
}
@@ -86,7 +86,7 @@ class Geometry extends Component implements AttrMixin {
this.attrOptions = attrOptions;
// 收集需要创建scale的字段
- each(attrOptions, option => {
+ each(attrOptions, (option) => {
const { field, ...cfg } = option;
chart.setScale(field, cfg);
});
@@ -131,7 +131,7 @@ class Geometry extends Component implements AttrMixin {
_getGroupScales() {
const { attrs } = this;
const scales = [];
- each(GROUP_ATTRS, function(attrName) {
+ each(GROUP_ATTRS, function (attrName) {
const attr = attrs[attrName];
if (attr) {
const { scale } = attr;
@@ -151,7 +151,7 @@ class Geometry extends Component implements AttrMixin {
const appendConditions = {};
const names = [];
- groupScales.forEach(scale => {
+ groupScales.forEach((scale) => {
const field = scale.field;
names.push(field);
});
@@ -279,9 +279,9 @@ class Geometry extends Component implements AttrMixin {
'onPan',
'onPanStart',
'onPanEnd',
- ].forEach(eventName => {
+ ].forEach((eventName) => {
if (props[eventName]) {
- canvas.on(eventName.substr(2).toLowerCase(), ev => {
+ canvas.on(eventName.substr(2).toLowerCase(), (ev) => {
ev.geometry = this;
props[eventName](ev);
});
@@ -455,6 +455,7 @@ class Geometry extends Component implements AttrMixin {
const { coord } = props;
const invertPoint = coord.invertPoint(point);
const xScale = this.getXScale();
+ const yScale = this.getYScale();
// 如果不在coord坐标范围内,直接返回空
if (invertPoint.x < 0 || invertPoint.y < 0) {
@@ -466,12 +467,17 @@ class Geometry extends Component implements AttrMixin {
if (!value) {
return rst;
}
- const { field: xfield } = xScale;
+ const { field: xField } = xScale;
+ const { field: yField } = yScale;
for (let i = 0; i < mappedArray.length; i++) {
const data = mappedArray[i];
for (let j = 0, len = data.length; j < len; j++) {
- const record = data[j];
- const originValue = record[FIELD_ORIGIN][xfield];
+ const record = {
+ ...data[j],
+ xField,
+ yField,
+ };
+ const originValue = record[FIELD_ORIGIN][xField];
if (xScale.type === 'timeCat' && toTimeStamp(originValue) === value) {
rst.push(record);
} else if (originValue === value) {
@@ -494,7 +500,7 @@ class Geometry extends Component implements AttrMixin {
if (!this.getAttrRange('color')) {
colorAttr.setRange(theme.colors);
}
- const items = ticks.map(tick => {
+ const items = ticks.map((tick) => {
const { text, tickValue } = tick;
const color = colorAttr.mapping(tickValue) || theme.colors[0];
return {
diff --git a/packages/f2-next/src/components/interval/withInterval.tsx b/packages/f2-next/src/components/interval/withInterval.tsx
index 2a14b265f..8267db16e 100644
--- a/packages/f2-next/src/components/interval/withInterval.tsx
+++ b/packages/f2-next/src/components/interval/withInterval.tsx
@@ -4,7 +4,7 @@ import { mix } from '@antv/util';
import Geometry from '../geometry';
import { convertRect, mappingRect } from './util';
-export default View => {
+export default (View) => {
return class Interval extends Geometry {
startOnZero = true;
@@ -55,6 +55,7 @@ export default View => {
const rect = convertRect({ ...position, size, y0 });
mix(position, rect);
mix(record, coord.convertRect(rect));
+ mix(record, coord.convertPoint(position));
}
}
return mappedArray;
diff --git a/packages/f2-next/src/components/tooltip/tooltipView.tsx b/packages/f2-next/src/components/tooltip/tooltipView.tsx
index 602d5d5d9..9e402003d 100644
--- a/packages/f2-next/src/components/tooltip/tooltipView.tsx
+++ b/packages/f2-next/src/components/tooltip/tooltipView.tsx
@@ -1,60 +1,242 @@
+import Component from '../../base/component';
import { jsx } from '../../jsx';
-export default props => {
- const { records, context } = props;
- if (!records || !records.length) return null;
- const { width } = context;
- return (
-
+// view 的默认配置
+const defaultStyle = {
+ showTitle: false,
+ showCrosshairs: false,
+ crosshairsType: 'y',
+ crosshairsStyle: {
+ stroke: 'rgba(0, 0, 0, 0.25)',
+ lineWidth: '2px',
+ },
+ showTooltipMarker: true,
+ background: {
+ radius: '2px',
+ fill: 'rgba(0, 0, 0, 0.65)',
+ padding: ['6px', '10px'],
+ },
+ titleStyle: {
+ fontSize: '24px',
+ fill: '#fff',
+ textAlign: 'start',
+ textBaseline: 'top',
+ },
+ nameStyle: {
+ fontSize: '24px',
+ fill: 'rgba(255, 255, 255, 0.65)',
+ textAlign: 'start',
+ textBaseline: 'middle',
+ },
+ valueStyle: {
+ fontSize: '24px',
+ fill: '#fff',
+ textAlign: 'start',
+ textBaseline: 'middle',
+ },
+ joinString: ': ',
+ showItemMarker: true,
+ itemMarkerStyle: {
+ width: '12px',
+ radius: '6px',
+ symbol: 'circle',
+ lineWidth: '2px',
+ stroke: '#fff',
+ },
+ layout: 'horizontal',
+ snap: false,
+};
+
+function directionEnabled(mode: string, dir: string) {
+ if (mode === undefined) {
+ return true;
+ } else if (typeof mode === 'string') {
+ return mode.indexOf(dir) !== -1;
+ }
+
+ return false;
+}
+
+export default class TooltipView extends Component {
+ rootRef: any;
+ itemsRef: any;
+
+ constructor(props) {
+ super(props);
+ this.rootRef = { current: null };
+ this.itemsRef = { current: null };
+ }
+ didUpdate() {
+ const { props, rootRef, itemsRef } = this;
+ const group = rootRef.current;
+ if (!group) {
+ return;
+ }
+ const { records, coord } = props;
+ if (!records || !records.length) return null;
+ const firstRecord = records[0];
+ const { x } = firstRecord;
+ const { left: coordLeft, width: coordWidth } = coord;
+ const { width } = group.get('attrs');
+ const halfWidth = width / 2;
+ const moveX = Math.min(
+ Math.max(x - coordLeft - halfWidth, 0),
+ coordWidth - halfWidth
+ );
+ itemsRef.current.moveTo(moveX, 0);
+ }
+ render() {
+ const { props } = this;
+ const { records, chart, coord, layout } = props;
+ const { top: layoutTop } = layout;
+ if (!records || !records.length) return null;
+ const {
+ left: coordLeft,
+ top: coordTop,
+ right: coordRight,
+ bottom: coordBottom,
+ width: coordWidth,
+ } = coord;
+ const firstRecord = records[0];
+ const { x, y, xField, yField, origin: firstOrigin } = firstRecord;
+ const yScale = chart.getScale(yField);
+ const {
+ background,
+ showTitle,
+ titleStyle,
+ showItemMarker = defaultStyle.showItemMarker,
+ itemMarkerStyle: customItemMarkerStyle,
+ nameStyle,
+ valueStyle,
+ joinString = defaultStyle.joinString,
+ showCrosshairs = defaultStyle.showCrosshairs,
+ crosshairsStyle,
+ crosshairsType = defaultStyle.crosshairsType,
+ } = props;
+ const itemMarkerStyle = {
+ ...customItemMarkerStyle,
+ ...defaultStyle.itemMarkerStyle,
+ };
+
+ return (
- {records.map(record => {
- return (
-
+ {showTitle ? (
+
-
+ ) : null}
+
+ {records.map((record) => {
+ const value = yScale.getText(record[yField]);
+ return (
+
+ {showItemMarker ? (
+
+ ) : null}
+
+
+
+ );
+ })}
+
+
+ {showCrosshairs ? (
+
+ {directionEnabled(crosshairsType, 'x') ? (
+
-
-
- );
- })}
+ ) : null}
+
+ ) : null}
+ {/* */}
-
- );
-};
+ );
+ }
+}
diff --git a/packages/f2-next/src/components/tooltip/withTooltip.tsx b/packages/f2-next/src/components/tooltip/withTooltip.tsx
index e8292d773..bff0d1e79 100644
--- a/packages/f2-next/src/components/tooltip/withTooltip.tsx
+++ b/packages/f2-next/src/components/tooltip/withTooltip.tsx
@@ -1,7 +1,7 @@
import { jsx } from '../../jsx';
import Component from '../../base/component';
-export default View => {
+export default (View) => {
return class Tooltip extends Component {
constructor(props) {
super(props);
@@ -15,16 +15,23 @@ export default View => {
}
_initEvent() {
- const { context } = this;
+ const { context, props } = this;
const { canvas } = context;
+ const {
+ triggerOn = 'press',
+ triggerOff = 'pressend',
+ alwaysShow = false,
+ } = props;
- canvas.on('press', ev => {
+ canvas.on(triggerOn, (ev) => {
const { points } = ev;
this.show(points[0]);
});
- canvas.on('pressend', ev => {
- this.hide();
+ canvas.on(triggerOff, (ev) => {
+ if (!alwaysShow) {
+ this.hide();
+ }
});
}
diff --git a/packages/f2-next/src/jsx/shape/marker.ts b/packages/f2-next/src/jsx/shape/marker.ts
index d876ceec3..9d830568c 100644
--- a/packages/f2-next/src/jsx/shape/marker.ts
+++ b/packages/f2-next/src/jsx/shape/marker.ts
@@ -3,7 +3,7 @@ export default (layout) => {
const r = width / 2;
return {
x: left + r,
- y: top + r,
+ y: top,
radius: r,
- }
-}
+ };
+};
diff --git a/packages/f2-next/src/mixins/coord.ts b/packages/f2-next/src/mixins/coord.ts
index 0a32d02ee..9cfb0d483 100644
--- a/packages/f2-next/src/mixins/coord.ts
+++ b/packages/f2-next/src/mixins/coord.ts
@@ -1,18 +1,27 @@
-import Coord, { Rect } from '../coord';
-import { isFunction } from '@antv/util';
+import Coord, { Rect, Polar } from '../coord';
+import { isString, isFunction } from '@antv/util';
-class CoordAvailable {
- createCoord(cfg, layout): Coord {
- if (isFunction(cfg)) {
+const coordMap = {
+ rect: Rect,
+ polar: Polar,
+};
+
+class CoordMixin {
+ createCoord(cfg: any, layout): Coord {
+ if (isString(cfg)) {
+ cfg = {
+ type: coordMap[cfg] || Rect,
+ };
+ } else if (isFunction(cfg)) {
cfg = {
- type: cfg
+ type: cfg,
};
}
const coordCfg = {
// 默认直角坐标系
type: Rect,
...layout,
- ...cfg
+ ...cfg,
};
const { type, ...option } = coordCfg;
const coord = new type(option);
@@ -24,4 +33,4 @@ class CoordAvailable {
}
}
-export default CoordAvailable;
+export default CoordMixin;
diff --git a/packages/f2-next/test/chart/index.test.tsx b/packages/f2-next/test/chart/index.test.tsx
index 9d5e068d5..f08e41de0 100644
--- a/packages/f2-next/test/chart/index.test.tsx
+++ b/packages/f2-next/test/chart/index.test.tsx
@@ -12,7 +12,7 @@ const data = [
{ type: 'b', genre: 'Strategy', sold: 10 },
{ type: 'b', genre: 'Action', sold: 20 },
{ type: 'b', genre: 'Shooter', sold: 20 },
- { type: 'b', genre: 'Other', sold: 40 }
+ { type: 'b', genre: 'Other', sold: 40 },
];
describe('Chart', () => {
diff --git a/packages/f2-next/test/components/tooltip.test.tsx b/packages/f2-next/test/components/tooltip.test.tsx
deleted file mode 100644
index 06f9d20e4..000000000
--- a/packages/f2-next/test/components/tooltip.test.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { jsx } from '../../src/jsx';
-import { Line, Tooltip } from '../../src/components';
-import { createContext } from '../util';
-import { Canvas, Chart } from '../../src';
-const context = createContext();
-
-const data = [
- { genre: 'Sports', sold: 275, type: 'a' },
- { genre: 'Strategy', sold: 115, type: 'a' },
- { genre: 'Action', sold: 120, type: 'a' },
- { genre: 'Shooter', sold: 350, type: 'a' },
- { genre: 'Other', sold: 150, type: 'a' },
-];
-
-describe.skip('Tooltip', () => {
- it('render', () => {
- const { type, props } = (
-
- {
- // console.log(ev.records);
- // }}
- />
-
-
- );
-
- // @ts-ignore
- const chart = new type(props);
- chart.render();
-
- // const container = chart.container;
- // console.log(container);
-
- // expect(container.get('children').length).toBe(2);
- });
-});
diff --git a/packages/f2-next/test/components/tooltip/tooltip.test.tsx b/packages/f2-next/test/components/tooltip/tooltip.test.tsx
new file mode 100644
index 000000000..1394d1d86
--- /dev/null
+++ b/packages/f2-next/test/components/tooltip/tooltip.test.tsx
@@ -0,0 +1,49 @@
+import { jsx, Canvas, Chart, Axis, Interval, Tooltip } from '../../../src';
+import { createContext } from '../../util';
+const context = createContext();
+
+const data = [
+ { type: 'a', genre: 'Sports', sold: 5 },
+ { type: 'a', genre: 'Strategy', sold: 10 },
+ { type: 'a', genre: 'Action', sold: 20 },
+ { type: 'a', genre: 'Shooter', sold: 20 },
+ { type: 'a', genre: 'Other', sold: 40 },
+ // { type: 'a', genre: 'Sports', sold: 5 },
+ // { type: 'a', genre: 'Strategy', sold: 10 },
+ // { type: 'a', genre: 'Action', sold: 20 },
+ // { type: 'a', genre: 'Shooter', sold: 20 },
+ // { type: 'a', genre: 'Other', sold: 40 },
+ // { type: 'a', genre: 'Shooter', sold: 20 },
+ // { type: 'a', genre: 'Other', sold: 40 },
+];
+
+describe('tooltip', () => {
+ it('Tooltip render', () => {
+ const { type, props } = (
+
+ );
+
+ // @ts-ignored
+ const canvas = new Canvas(props);
+ canvas.render();
+ });
+});