Skip to content

Commit

Permalink
fix: attr映射逻辑优化 (#1261)
Browse files Browse the repository at this point in the history
* fix: attr映射逻辑优化

* feat:具体的attr下沉到attrController

* fix:CR
  • Loading branch information
ACERY1 committed Nov 16, 2021
1 parent 0349d22 commit 7662cc7
Show file tree
Hide file tree
Showing 17 changed files with 859 additions and 180 deletions.
2 changes: 1 addition & 1 deletion packages/f2/src/attr/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Base {
const { scale, field, data } = this;
if (!scale && data) {
const values = arrayValues(data, field);
this.scale = this.createScale({ values });
this.scale = this.createScale({ values, field });
}
}

Expand Down
25 changes: 21 additions & 4 deletions packages/f2/src/attr/linear.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
import { Linear as LinearScale, ScaleConfig } from '@antv/scale';
import { isArray } from '@antv/util';
import { interpolate } from 'd3-interpolate'
import Base from './base';

class Linear extends Base {
interpolate: any;

constructor(options) {
super(options);
this._updateInterpolate();
}
createScale(scaleConfig: ScaleConfig) {
return new LinearScale(scaleConfig);
}

_updateInterpolate () {
const [min, max] = this.range;
this.interpolate = interpolate(min, max)
}

update(options) {
super.update(options);
this._updateInterpolate();
}

_mapping(value: any) {
const { scale, range } = this;
const [min, max] = range;
const { scale, interpolate } = this;

if (isArray(value)) {
return value.map((v) => {
return min + (max - min) * scale.scale(v);
return interpolate(scale.scale(v));
});
}
return min + (max - min) * scale.scale(value);

return interpolate(scale.scale(value));
}

normalize(value: any) {
Expand Down
2 changes: 1 addition & 1 deletion packages/f2/src/components/axis/withAxis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default (View) => {
};
}

_getDimType() {
_getDimType(): 'x' | 'y' {
const { props } = this;
const { field, chart } = props;
const xScales = chart.getXScales();
Expand Down
117 changes: 36 additions & 81 deletions packages/f2/src/components/geometry/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isFunction, each, upperFirst, mix, groupToMap, isObject } from '@antv/util';
import { isFunction, each, upperFirst, mix, groupToMap, isObject, includes } from '@antv/util';
import Component from '../../base/component';
import { group as arrayGroup, merge as arrayMerge, values } from '../../util/array';
import * as Adjust from '../../adjust';
Expand All @@ -10,10 +10,6 @@ import equal from '../../base/equal';

// 保留原始数据的字段
const FIELD_ORIGIN = 'origin';
// 需要映射的属性名
const ATTRS = ['x', 'y', 'color', 'size', 'shape'];
// 分组处理的属性
const GROUP_ATTRS = ['color', 'size', 'shape'];

class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
isGeometry = true;
Expand Down Expand Up @@ -43,10 +39,11 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {

const { chart } = props;

this.attrController = new AttrController(chart.scale);
const attrsRange = this._getThemeAttrsRange();
this.attrController = new AttrController(chart.scale, attrsRange);
const { attrController } = this;

const attrOptions = this._getAttrOptions(props);
const attrOptions = attrController.getAttrOptions(props);
attrController.create(attrOptions);
}

Expand All @@ -55,8 +52,8 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
const { data: nextData, adjust: nextAdjust } = nextProps;
const { data: lastData, adjust: lastAdjust } = lastProps;

const nextAttrOptions = this._getAttrOptions(nextProps);
const lastAttrOptions = this._getAttrOptions(lastProps);
const nextAttrOptions = attrController.getAttrOptions(nextProps);
const lastAttrOptions = attrController.getAttrOptions(lastProps);
if (!equal(nextAttrOptions, lastAttrOptions)) {
attrController.update(nextAttrOptions);
this.records = null;
Expand Down Expand Up @@ -85,37 +82,12 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
}

_createAttrs() {
const { attrController, props } = this;
const { chart } = props;
const { attrController } = this;
attrController.attrs = {};
this.attrs = attrController.getAttrs();
}

_getAttrOptions(props) {
if (!props.x || !props.y) {
throw new Error('x, y are required !');
}
const options = {};
const ranges = this._getAttrRanges();
const { attrController } = this;
ATTRS.forEach((attrName) => {
if (!props[attrName]) return;
const option = attrController.parseOption(props[attrName]);
if (!option.range) {
option.range = ranges[attrName];
}
options[attrName] = option;
});
// @ts-ignore
const { x, y } = options;

// x, y 都是固定Linear 映射
x.type = Linear;
y.type = Linear;
return options;
}

_getAttrRanges() {
_getThemeAttrsRange() {
const { context, props, geomType } = this;
const { coord } = props;
const { theme } = context;
Expand All @@ -130,15 +102,6 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
};
}

getDefaultAttrValues() {
const attrRanges = this._getAttrRanges();
const { color, shape } = attrRanges;
return {
color: color[0],
shape: shape && shape[0],
};
}

_adjustScales() {
const { attrs, props, startOnZero: defaultStartOnZero } = this;
const { chart, startOnZero = defaultStartOnZero } = props;
Expand All @@ -149,24 +112,9 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
}
}

_getGroupScales() {
const { attrs } = this;
const scales = [];
each(GROUP_ATTRS, (attrName) => {
const attr = attrs[attrName];
if (!attr) {
return;
}
const { scale } = attr;
if (scale && scale.isCategory && scales.indexOf(scale) === -1) {
scales.push(scale);
}
});
return scales;
}

_groupData(data) {
const groupScales = this._getGroupScales();
const { attrController } = this;
const groupScales = attrController.getGroupScales();
if (!groupScales.length) {
return [{ children: data }];
}
Expand Down Expand Up @@ -352,52 +300,59 @@ class Geometry<T extends GeometryProps = GeometryProps> extends Component<T> {
return shapeStyle;
}

/**
* 数据映射到视图属性核心逻辑
* x、y 每个元素走 normalize 然后 convertPoint
* color、size、shape
* 如果是Linear,则每个元素 走 mapping
* 如果是Category/Identity 则第一个元素走 mapping
*/
_mapping(records) {
const { attrs, props } = this;
const { attrs, props, attrController } = this;
const { coord } = props;
const attrNames = Object.keys(attrs);
const linearAttrs = [];
const nolinearAttrs = [];
attrNames.forEach((attrName) => {
if (attrs[attrName].constructor === Linear) {
linearAttrs.push(attrName);
} else {
nolinearAttrs.push(attrName);
}
});

const defaultAttrValues = this.getDefaultAttrValues();
const { linearAttrs, nonlinearAttrs } = attrController.getAttrsByLinear();
const defaultAttrValues = attrController.getDefaultAttrValues();

for (let i = 0, len = records.length; i < len; i++) {
const record = records[i];
const { children } = record;
// 非线性映射只用映射第一项就可以了
const attrValues = {
...defaultAttrValues,
};
const firstChild = children[0];
for (let k = 0, len = nolinearAttrs.length; k < len; k++) {
const attrName = nolinearAttrs[k];

// 非线性映射
for (let k = 0, len = nonlinearAttrs.length; k < len; k++) {
const attrName = nonlinearAttrs[k];
const attr = attrs[attrName];
// 非线性映射只用映射第一项就可以了
attrValues[attrName] = attr.mapping(firstChild[attr.field]);
}

// 线性映射
const linearAttrsLength = linearAttrs.length;
// 线性属性映射
for (let j = 0, childrenLen = children.length; j < childrenLen; j++) {
const child = children[j];
const normalized: any = {};
for (let k = 0; k < linearAttrsLength; k++) {
for (let k = 0; k < linearAttrs.length; k++) {
const attrName = linearAttrs[k];
const attr = attrs[attrName];
normalized[attrName] = attr.normalize(child[attr.field]);
// 分类属性的线性映射
if (attrController.isGroupAttr(attrName)) {
attrValues[attrName] = attr.mapping(child[attr.field]);
} else {
normalized[attrName] = attr.normalize(child[attr.field]);
}
}

const { x, y } = coord.convertPoint({
x: normalized.x,
y: normalized.y,
});

// 获取shape的style
const shape = this._getShapeStyle(attrValues.shape, child.origin);

mix(child, attrValues, {
normalized,
x,
Expand Down
33 changes: 1 addition & 32 deletions packages/f2/src/components/interval/util.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
import { isArray } from '@antv/util';

function convertRect({ x, y, size, y0 }) {
let xMin: number;
let xMax: number;
if (isArray(x)) {
xMin = x[0];
xMax = x[1];
} else {
xMin = x - size / 2;
xMax = x + size / 2;
}

let yMin: number;
let yMax: number;
if (isArray(y)) {
yMin = y[0];
yMax = y[1];
} else {
yMin = Math.min(y0, y);
yMax = Math.max(y0, y);
}

return {
xMin,
xMax,
yMin,
yMax,
};
}

function convertToPoints({ xMin, xMax, yMin, yMax }) {
return [
{ x: xMin, y: yMin }, // tl
Expand All @@ -38,4 +7,4 @@ function convertToPoints({ xMin, xMax, yMin, yMax }) {
];
}

export { convertRect, convertToPoints };
export { convertToPoints };
20 changes: 14 additions & 6 deletions packages/f2/src/components/interval/withInterval.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { jsx } from '../../jsx';
import { mix } from '@antv/util';
import { mix, isNil } from '@antv/util';
import Geometry from '../geometry';
import { convertRect } from './util';
import { GeomType } from '../geometry/interface';

export default (Views) => {
Expand Down Expand Up @@ -59,17 +58,26 @@ export default (Views) => {
const { props } = this;
const { coord } = props;
const y0 = this.getY0Value();
const coordY0 = coord.convertPoint({ x: 0, y: y0 }).y;
const defaultSize = this.getDefaultSize();

for (let i = 0, len = records.length; i < len; i++) {
const record = records[i];
const { children } = record;
for (let j = 0, len = children.length; j < len; j++) {
const child = children[j];
const { normalized } = child;
const { x, y, size = defaultSize } = normalized;
const rect = convertRect({ x, y, size, y0 });
mix(child, coord.convertRect(rect));
const { normalized, size: mappedSize } = child;

// 没有指定size,则根据数据来计算默认size
if (isNil(mappedSize)) {
const { x, y, size = defaultSize } = normalized;
mix(child, coord.convertRect({ x, y, y0, size }));
} else {
const { x, y } = child;
const rect = { size: mappedSize, x, y, y0: coordY0 };

mix(child, coord.transformToRect(rect));
}
}
}
return records;
Expand Down
2 changes: 1 addition & 1 deletion packages/f2/src/components/line/lineView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ export default (props: LineViewProps) => {
points: points.map((point) => {
return { x: point.x, y: point.y };
}),
...shape,
stroke: color,
lineWidth: size,
...shape,
}}
animation={{
update: {
Expand Down
4 changes: 2 additions & 2 deletions packages/f2/src/components/line/withLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ export default (View) => {

record.children = splitPoints.map((points) => {
const [topPoints, bottomPoints] = isArray(y)
? this.splitPoints(points)
: [points, undefined];
? this.splitPoints(points)
: [points, undefined];
return {
size,
color,
Expand Down
2 changes: 1 addition & 1 deletion packages/f2/src/components/point/pointView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default (props: any) => {
update: {
easing: 'linear',
duration: 450,
property: ['x', 'y', 'r'],
property: ['x', 'y', 'r', 'fill'],
},
}}
/>
Expand Down
8 changes: 4 additions & 4 deletions packages/f2/src/components/sunburst/withSunburst.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ export default (View): any => {
const color = colorAttr.mapping(root.data[colorAttr.field]);
node.color = color;
const rect = coord.convertRect({
xMin: node.x0,
xMax: node.x1,
yMin: node.y0,
yMax: node.y1,
x: node.x0,
y: node.y1,
y0: node.y0,
size: node.x1 - node.x0,
});
mix(node, rect);
// 递归处理
Expand Down
Loading

0 comments on commit 7662cc7

Please sign in to comment.